From f77ff2d396da04d9ef1bfdbed71c63051d2edd89 Mon Sep 17 00:00:00 2001 From: Pete Harverson Date: Wed, 26 May 2021 17:48:03 +0100 Subject: [PATCH 01/77] [ML] Adds functional tests for anomaly detection job custom URLs (#100455) * [ML] Adds functional tests for anomaly detection job custom URLs * [ML] Remove debug test tag from custom URL tests * [ML] Update custom URL editor Jest snapshots * [ML] Clean up in embeddables tests to fix dashboard test * [ML] Delete test dashboard after test suites complete * [ML] Edits to custom URL tests following review Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../__snapshots__/editor.test.tsx.snap | 28 +++ .../__snapshots__/list.test.tsx.snap | 9 + .../components/custom_url_editor/editor.tsx | 9 +- .../components/custom_url_editor/list.tsx | 3 + .../edit_job_flyout/edit_job_flyout.js | 7 + .../apps/ml/anomaly_detection/advanced_job.ts | 2 +- .../ml/anomaly_detection/anomaly_explorer.ts | 4 + .../anomaly_detection/categorization_job.ts | 2 +- .../apps/ml/anomaly_detection/custom_urls.ts | 188 ++++++++++++++++ .../apps/ml/anomaly_detection/index.ts | 1 + .../ml/anomaly_detection/multi_metric_job.ts | 2 +- .../ml/anomaly_detection/population_job.ts | 2 +- .../ml/anomaly_detection/single_metric_job.ts | 2 +- .../test/functional/services/ml/common_ui.ts | 19 ++ .../functional/services/ml/custom_urls.ts | 146 ++++++++++++- x-pack/test/functional/services/ml/index.ts | 2 +- .../test/functional/services/ml/job_table.ts | 206 +++++++++++++++++- .../services/ml/job_wizard_common.ts | 2 +- .../functional/services/ml/test_resources.ts | 4 + 19 files changed, 622 insertions(+), 16 deletions(-) create mode 100644 x-pack/test/functional/apps/ml/anomaly_detection/custom_urls.ts diff --git a/x-pack/plugins/ml/public/application/jobs/components/custom_url_editor/__snapshots__/editor.test.tsx.snap b/x-pack/plugins/ml/public/application/jobs/components/custom_url_editor/__snapshots__/editor.test.tsx.snap index 7d5c73b42f15b..d14fc6df06693 100644 --- a/x-pack/plugins/ml/public/application/jobs/components/custom_url_editor/__snapshots__/editor.test.tsx.snap +++ b/x-pack/plugins/ml/public/application/jobs/components/custom_url_editor/__snapshots__/editor.test.tsx.snap @@ -18,6 +18,7 @@ exports[`CustomUrlEditor renders the editor for a dashboard type URL with a labe /> = ({ - + @@ -239,6 +239,7 @@ export const CustomUrlEditor: FC = ({ idSelected={type} onChange={onTypeChange} className="url-link-to-radio" + data-test-subj="mlJobCustomUrlLinkToTypeInput" /> @@ -256,6 +257,7 @@ export const CustomUrlEditor: FC = ({ options={dashboardOptions} value={kibanaSettings.dashboardId} onChange={onDashboardChange} + data-test-subj="mlJobCustomUrlDashboardNameInput" compressed /> @@ -275,6 +277,7 @@ export const CustomUrlEditor: FC = ({ options={indexPatternOptions} value={kibanaSettings.discoverIndexPatternId} onChange={onDiscoverIndexPatternChange} + data-test-subj="mlJobCustomUrlDiscoverIndexPatternInput" compressed /> @@ -298,6 +301,7 @@ export const CustomUrlEditor: FC = ({ selectedOptions={selectedEntityOptions} onChange={onQueryEntitiesChange} isClearable={true} + data-test-subj="mlJobCustomUrlQueryEntitiesInput" /> )} @@ -321,6 +325,7 @@ export const CustomUrlEditor: FC = ({ options={timeRangeOptions} value={timeRange.type} onChange={onTimeRangeTypeChange} + data-test-subj="mlJobCustomUrlTimeRangeInput" compressed /> @@ -343,6 +348,7 @@ export const CustomUrlEditor: FC = ({ value={timeRange.interval} onChange={onTimeRangeIntervalChange} isInvalid={isInvalidTimeRange} + data-test-subj="mlJobCustomUrlTimeRangeIntervalInput" compressed /> @@ -365,6 +371,7 @@ export const CustomUrlEditor: FC = ({ rows={2} value={otherUrlSettings.urlValue} onChange={onOtherUrlValueChange} + data-test-subj="mlJobCustomUrlOtherTypeUrlInput" compressed /> diff --git a/x-pack/plugins/ml/public/application/jobs/components/custom_url_editor/list.tsx b/x-pack/plugins/ml/public/application/jobs/components/custom_url_editor/list.tsx index 5c61de38df37b..96b09aff64f0c 100644 --- a/x-pack/plugins/ml/public/application/jobs/components/custom_url_editor/list.tsx +++ b/x-pack/plugins/ml/public/application/jobs/components/custom_url_editor/list.tsx @@ -160,6 +160,7 @@ export const CustomUrlList: FC = ({ job, customUrls, setCust } isInvalid={isInvalidLabel} error={invalidLabelError} + data-test-subj="mlJobEditCustomUrlItemLabel" > = ({ job, customUrls, setCust aria-label={i18n.translate('xpack.ml.customUrlEditorList.testCustomUrlAriaLabel', { defaultMessage: 'Test custom URL', })} + data-test-subj="mlJobEditTestCustomUrlButton" /> @@ -264,6 +266,7 @@ export const CustomUrlList: FC = ({ job, customUrls, setCust defaultMessage: 'Delete custom URL', } )} + data-test-subj={`mlJobEditDeleteCustomUrlButton_${index}`} /> 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 758e3fa472a0b..d7f42daf5f3c1 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 @@ -326,6 +326,7 @@ export class EditJobFlyoutUI extends Component { const tabs = [ { id: 'job-details', + 'data-test-subj': 'mlEditJobFlyout-jobDetails', name: i18n.translate('xpack.ml.jobsList.editJobFlyout.jobDetailsTitle', { defaultMessage: 'Job details', }), @@ -346,6 +347,7 @@ export class EditJobFlyoutUI extends Component { }, { id: 'detectors', + 'data-test-subj': 'mlEditJobFlyout-detectors', name: i18n.translate('xpack.ml.jobsList.editJobFlyout.detectorsTitle', { defaultMessage: 'Detectors', }), @@ -359,6 +361,7 @@ export class EditJobFlyoutUI extends Component { }, { id: 'datafeed', + 'data-test-subj': 'mlEditJobFlyout-datafeed', name: i18n.translate('xpack.ml.jobsList.editJobFlyout.datafeedTitle', { defaultMessage: 'Datafeed', }), @@ -376,6 +379,7 @@ export class EditJobFlyoutUI extends Component { }, { id: 'custom-urls', + 'data-test-subj': 'mlEditJobFlyout-customUrls', name: i18n.translate('xpack.ml.jobsList.editJobFlyout.customUrlsTitle', { defaultMessage: 'Custom URLs', }), @@ -395,6 +399,7 @@ export class EditJobFlyoutUI extends Component { this.closeFlyout(); }} size="m" + data-test-subj="mlJobEditFlyout" > @@ -419,6 +424,7 @@ export class EditJobFlyoutUI extends Component { this.closeFlyout(); }} flush="left" + data-test-subj="mlEditJobFlyoutCloseButton" > { + await ml.testResources.deleteMLTestDashboard(); + }); + for (const testData of testDataList) { describe(testData.suiteSuffix, function () { before(async () => { diff --git a/x-pack/test/functional/apps/ml/anomaly_detection/categorization_job.ts b/x-pack/test/functional/apps/ml/anomaly_detection/categorization_job.ts index 611c7be8b0677..85eeacc58514e 100644 --- a/x-pack/test/functional/apps/ml/anomaly_detection/categorization_job.ts +++ b/x-pack/test/functional/apps/ml/anomaly_detection/categorization_job.ts @@ -278,7 +278,7 @@ export default function ({ getService }: FtrProviderContext) { await ml.jobWizardCommon.ensureAdditionalSettingsSectionOpen(); await ml.testExecution.logTestStep('job cloning persists custom urls'); - await ml.customUrls.assertCustomUrlItem(0, 'check-kibana-dashboard'); + await ml.customUrls.assertCustomUrlLabel(0, 'check-kibana-dashboard'); await ml.testExecution.logTestStep('job cloning persists assigned calendars'); await ml.jobWizardCommon.assertCalendarsSelection([calendarId]); diff --git a/x-pack/test/functional/apps/ml/anomaly_detection/custom_urls.ts b/x-pack/test/functional/apps/ml/anomaly_detection/custom_urls.ts new file mode 100644 index 0000000000000..a743e00b64add --- /dev/null +++ b/x-pack/test/functional/apps/ml/anomaly_detection/custom_urls.ts @@ -0,0 +1,188 @@ +/* + * 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 { FtrProviderContext } from '../../../ftr_provider_context'; +import { Job, Datafeed } from '../../../../../plugins/ml/common/types/anomaly_detection_jobs'; +import { + TimeRangeType, + TIME_RANGE_TYPE, +} from '../../../../../plugins/ml/public/application/jobs/components/custom_url_editor/constants'; + +interface DiscoverUrlConfig { + label: string; + indexPattern: string; + queryEntityFieldNames: string[]; + timeRange: TimeRangeType; + timeRangeInterval?: string; +} + +interface DashboardUrlConfig { + label: string; + dashboardName: string; + queryEntityFieldNames: string[]; + timeRange: TimeRangeType; + timeRangeInterval?: string; +} + +interface OtherUrlConfig { + label: string; + url: string; +} + +// @ts-expect-error doesn't implement the full interface +const JOB_CONFIG: Job = { + job_id: `fq_multi_1_custom_urls`, + description: 'mean(responsetime) partition=airline on farequote dataset with 30m bucket span', + groups: ['farequote', 'automated', 'multi-metric'], + analysis_config: { + bucket_span: '30m', + influencers: ['airline'], + detectors: [{ function: 'mean', field_name: 'responsetime', partition_field_name: 'airline' }], + }, + data_description: { time_field: '@timestamp' }, + analysis_limits: { model_memory_limit: '20mb' }, + model_plot_config: { enabled: true }, +}; + +// @ts-expect-error doesn't implement the full interface +const DATAFEED_CONFIG: Datafeed = { + datafeed_id: 'datafeed-fq_multi_1_custom_urls', + indices: ['ft_farequote'], + job_id: 'fq_multi_1_custom_urls', + query: { bool: { must: [{ match_all: {} }] } }, +}; + +const testDiscoverCustomUrl: DiscoverUrlConfig = { + label: 'Show data', + indexPattern: 'ft_farequote', + queryEntityFieldNames: ['airline'], + timeRange: TIME_RANGE_TYPE.AUTO, +}; + +const testDashboardCustomUrl: DashboardUrlConfig = { + label: 'Show dashboard', + dashboardName: 'ML Test', + queryEntityFieldNames: [], + timeRange: TIME_RANGE_TYPE.INTERVAL, + timeRangeInterval: '1h', +}; + +const testOtherCustomUrl: OtherUrlConfig = { + label: 'elastic.co', + url: 'https://www.elastic.co/', +}; + +export default function ({ getService }: FtrProviderContext) { + const esArchiver = getService('esArchiver'); + const ml = getService('ml'); + const browser = getService('browser'); + + describe('custom urls', function () { + this.tags(['mlqa']); + before(async () => { + await esArchiver.loadIfNeeded('ml/farequote'); + await ml.testResources.createIndexPatternIfNeeded('ft_farequote', '@timestamp'); + await ml.testResources.createMLTestDashboardIfNeeded(); + await ml.testResources.setKibanaTimeZoneToUTC(); + + await ml.api.createAndRunAnomalyDetectionLookbackJob(JOB_CONFIG, DATAFEED_CONFIG); + await ml.securityUI.loginAsMlPowerUser(); + }); + + after(async () => { + await ml.testResources.deleteMLTestDashboard(); + await ml.api.cleanMlIndices(); + }); + + it('opens the custom URLs tab in the edit job flyout', async () => { + await ml.testExecution.logTestStep('load the job management page'); + await ml.navigation.navigateToMl(); + await ml.navigation.navigateToJobManagement(); + + await ml.testExecution.logTestStep('open the custom URLs tab in the edit job flyout'); + await ml.jobTable.openEditCustomUrlsForJobTab(JOB_CONFIG.job_id); + await ml.jobTable.closeEditJobFlyout(); + }); + + it('adds a custom URL with query entities to Discover in the edit job flyout', async () => { + await ml.jobTable.addDiscoverCustomUrl(JOB_CONFIG.job_id, testDiscoverCustomUrl); + }); + + it('adds a custom URL to Dashboard in the edit job flyout', async () => { + await ml.jobTable.addDashboardCustomUrl(JOB_CONFIG.job_id, testDashboardCustomUrl); + }); + + it('adds a custom URL to an external page in the edit job flyout', async () => { + await ml.jobTable.addOtherTypeCustomUrl(JOB_CONFIG.job_id, testOtherCustomUrl); + }); + + it('tests other type custom URL', async () => { + await ml.jobTable.testOtherTypeCustomUrlAction(JOB_CONFIG.job_id, 2, testOtherCustomUrl.url); + }); + + it('edits other type custom URL', async () => { + const edit = { + label: `${testOtherCustomUrl.url} edited`, + url: `${testOtherCustomUrl.url}guide/index.html`, + }; + await ml.testExecution.logTestStep('edit the custom URL in the edit job flyout'); + await ml.jobTable.editCustomUrl(JOB_CONFIG.job_id, 2, edit); + + await ml.testExecution.logTestStep('tests custom URL edit has been applied'); + await ml.jobTable.testOtherTypeCustomUrlAction(JOB_CONFIG.job_id, 2, edit.url); + await ml.jobTable.closeEditJobFlyout(); + }); + + it('deletes a custom URL', async () => { + await ml.jobTable.deleteCustomUrl(JOB_CONFIG.job_id, 2); + }); + + // wrapping into own describe to make sure new tab is cleaned up even if test failed + // see: https://github.com/elastic/kibana/pull/67280#discussion_r430528122 + describe('tests Discover type custom URL', () => { + let tabsCount = 1; + const docCountFormatted = '268'; + + it('opens Discover page from test link in the edit job flyout', async () => { + await ml.jobTable.openTestCustomUrl(JOB_CONFIG.job_id, 0); + await browser.switchTab(1); + tabsCount++; + await ml.jobTable.testDiscoverCustomUrlAction(docCountFormatted); + }); + + after(async () => { + if (tabsCount > 1) { + await browser.closeCurrentWindow(); + await browser.switchTab(0); + await ml.jobTable.closeEditJobFlyout(); + } + }); + }); + + // wrapping into own describe to make sure new tab is cleaned up even if test failed + // see: https://github.com/elastic/kibana/pull/67280#discussion_r430528122 + describe('tests Dashboard type custom URL', () => { + let tabsCount = 1; + const testDashboardPanelCount = 0; // ML Test dashboard has no content. + + it('opens Dashboard page from test link in the edit job flyout', async () => { + await ml.jobTable.openTestCustomUrl(JOB_CONFIG.job_id, 1); + await browser.switchTab(1); + tabsCount++; + await ml.jobTable.testDashboardCustomUrlAction(testDashboardPanelCount); + }); + + after(async () => { + if (tabsCount > 1) { + await browser.closeCurrentWindow(); + await browser.switchTab(0); + await ml.jobTable.closeEditJobFlyout(); + } + }); + }); + }); +} diff --git a/x-pack/test/functional/apps/ml/anomaly_detection/index.ts b/x-pack/test/functional/apps/ml/anomaly_detection/index.ts index 6b7afacbb721a..d87da8469db11 100644 --- a/x-pack/test/functional/apps/ml/anomaly_detection/index.ts +++ b/x-pack/test/functional/apps/ml/anomaly_detection/index.ts @@ -23,5 +23,6 @@ export default function ({ loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./date_nanos_job')); loadTestFile(require.resolve('./annotations')); loadTestFile(require.resolve('./aggregated_scripted_job')); + loadTestFile(require.resolve('./custom_urls')); }); } diff --git a/x-pack/test/functional/apps/ml/anomaly_detection/multi_metric_job.ts b/x-pack/test/functional/apps/ml/anomaly_detection/multi_metric_job.ts index b12eff71d8258..256f9da313e4e 100644 --- a/x-pack/test/functional/apps/ml/anomaly_detection/multi_metric_job.ts +++ b/x-pack/test/functional/apps/ml/anomaly_detection/multi_metric_job.ts @@ -299,7 +299,7 @@ export default function ({ getService }: FtrProviderContext) { await ml.jobWizardCommon.ensureAdditionalSettingsSectionOpen(); await ml.testExecution.logTestStep('job cloning persists custom urls'); - await ml.customUrls.assertCustomUrlItem(0, 'check-kibana-dashboard'); + await ml.customUrls.assertCustomUrlLabel(0, 'check-kibana-dashboard'); await ml.testExecution.logTestStep('job cloning persists assigned calendars'); await ml.jobWizardCommon.assertCalendarsSelection([calendarId]); diff --git a/x-pack/test/functional/apps/ml/anomaly_detection/population_job.ts b/x-pack/test/functional/apps/ml/anomaly_detection/population_job.ts index 8fea197e05667..2bdda2c81c71d 100644 --- a/x-pack/test/functional/apps/ml/anomaly_detection/population_job.ts +++ b/x-pack/test/functional/apps/ml/anomaly_detection/population_job.ts @@ -336,7 +336,7 @@ export default function ({ getService }: FtrProviderContext) { await ml.jobWizardCommon.ensureAdditionalSettingsSectionOpen(); await ml.testExecution.logTestStep('job cloning persists custom urls'); - await ml.customUrls.assertCustomUrlItem(0, 'check-kibana-dashboard'); + await ml.customUrls.assertCustomUrlLabel(0, 'check-kibana-dashboard'); await ml.testExecution.logTestStep('job cloning persists assigned calendars'); await ml.jobWizardCommon.assertCalendarsSelection([calendarId]); diff --git a/x-pack/test/functional/apps/ml/anomaly_detection/single_metric_job.ts b/x-pack/test/functional/apps/ml/anomaly_detection/single_metric_job.ts index 4f9b265c3b1ed..eedb130215f7f 100644 --- a/x-pack/test/functional/apps/ml/anomaly_detection/single_metric_job.ts +++ b/x-pack/test/functional/apps/ml/anomaly_detection/single_metric_job.ts @@ -262,7 +262,7 @@ export default function ({ getService }: FtrProviderContext) { await ml.jobWizardCommon.ensureAdditionalSettingsSectionOpen(); await ml.testExecution.logTestStep('job cloning persists custom urls'); - await ml.customUrls.assertCustomUrlItem(0, 'check-kibana-dashboard'); + await ml.customUrls.assertCustomUrlLabel(0, 'check-kibana-dashboard'); await ml.testExecution.logTestStep('job cloning persists assigned calendars'); await ml.jobWizardCommon.assertCalendarsSelection([calendarId]); diff --git a/x-pack/test/functional/services/ml/common_ui.ts b/x-pack/test/functional/services/ml/common_ui.ts index b7288d5927b4c..b61bc8871482f 100644 --- a/x-pack/test/functional/services/ml/common_ui.ts +++ b/x-pack/test/functional/services/ml/common_ui.ts @@ -123,6 +123,25 @@ export function MachineLearningCommonUIProvider({ getService }: FtrProviderConte await this.assertRadioGroupValue(testSubject, value); }, + async assertSelectSelectedOptionVisibleText(testSubject: string, visibleText: string) { + // Need to validate the selected option text, as the option value may be different to the visible text. + const selectControl = await testSubjects.find(testSubject); + const selectedValue = await selectControl.getAttribute('value'); + const selectedOption = await selectControl.findByCssSelector(`[value="${selectedValue}"]`); + const selectedOptionText = await selectedOption.getVisibleText(); + expect(selectedOptionText).to.eql( + visibleText, + `Expected selected option visible text to be '${visibleText}' (got '${selectedOptionText}')` + ); + }, + + async selectSelectValueByVisibleText(testSubject: string, visibleText: string) { + // Cannot use await testSubjects.selectValue as the option value may be different to the text. + const selectControl = await testSubjects.find(testSubject); + await selectControl.type(visibleText); + await this.assertSelectSelectedOptionVisibleText(testSubject, visibleText); + }, + async setMultiSelectFilter(testDataSubj: string, fieldTypes: string[]) { await testSubjects.clickWhenNotDisabled(`${testDataSubj}-button`); await testSubjects.existOrFail(`${testDataSubj}-popover`); diff --git a/x-pack/test/functional/services/ml/custom_urls.ts b/x-pack/test/functional/services/ml/custom_urls.ts index 0b24c565b2fa8..67640eff7129e 100644 --- a/x-pack/test/functional/services/ml/custom_urls.ts +++ b/x-pack/test/functional/services/ml/custom_urls.ts @@ -12,10 +12,25 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export type MlCustomUrls = ProvidedType; -export function MachineLearningCustomUrlsProvider({ getService }: FtrProviderContext) { +export function MachineLearningCustomUrlsProvider({ + getService, + getPageObjects, +}: FtrProviderContext) { const testSubjects = getService('testSubjects'); + const retry = getService('retry'); + const comboBox = getService('comboBox'); + const PageObjects = getPageObjects(['dashboard', 'discover', 'header']); return { + async assertCustomUrlsLength(expectedLength: number) { + const customUrls = await testSubjects.findAll('mlJobEditCustomUrlItemLabel'); + const actualLength = customUrls.length; + expect(expectedLength).to.eql( + actualLength, + `Expected number of custom urls to be '${expectedLength}' (got '${actualLength}')` + ); + }, + async assertCustomUrlLabelValue(expectedValue: string) { const actualCustomUrlLabel = await testSubjects.getAttribute( 'mlJobCustomUrlLabelInput', @@ -27,15 +42,68 @@ export function MachineLearningCustomUrlsProvider({ getService }: FtrProviderCon ); }, - async setCustomUrlLabel(customUrlsLabel: string) { - await testSubjects.setValue('mlJobCustomUrlLabelInput', customUrlsLabel, { + async setCustomUrlLabel(customUrlLabel: string) { + await testSubjects.setValue('mlJobCustomUrlLabelInput', customUrlLabel, { clearWithKeyboard: true, }); - await this.assertCustomUrlLabelValue(customUrlsLabel); + await this.assertCustomUrlLabelValue(customUrlLabel); }, - async assertCustomUrlItem(index: number, expectedLabel: string) { - await testSubjects.existOrFail(`mlJobEditCustomUrlItem_${index}`); + async assertCustomUrlQueryEntitySelection(expectedFieldNames: string[]) { + const actualFieldNames = await comboBox.getComboBoxSelectedOptions( + 'mlJobCustomUrlQueryEntitiesInput > comboBoxInput' + ); + expect(actualFieldNames).to.eql( + expectedFieldNames, + `Expected query entity selection to be '${expectedFieldNames}' (got '${actualFieldNames}')` + ); + }, + + async setCustomUrlQueryEntityFieldNames(fieldNames: string[]) { + for (const fieldName of fieldNames) { + await comboBox.set('mlJobCustomUrlQueryEntitiesInput > comboBoxInput', fieldName); + } + await this.assertCustomUrlQueryEntitySelection(fieldNames); + }, + + async assertCustomUrlTimeRangeIntervalValue(expectedInterval: string) { + const actualCustomUrlTimeRangeInterval = await testSubjects.getAttribute( + 'mlJobCustomUrlTimeRangeIntervalInput', + 'value' + ); + expect(actualCustomUrlTimeRangeInterval).to.eql( + expectedInterval, + `Expected custom url time range interval to be '${expectedInterval}' (got '${actualCustomUrlTimeRangeInterval}')` + ); + }, + + async setCustomUrlTimeRangeInterval(interval: string) { + await testSubjects.setValue('mlJobCustomUrlTimeRangeIntervalInput', interval, { + clearWithKeyboard: true, + }); + await this.assertCustomUrlTimeRangeIntervalValue(interval); + }, + + async assertCustomUrlOtherTypeUrlValue(expectedUrl: string) { + const actualCustomUrlValue = await testSubjects.getAttribute( + 'mlJobCustomUrlOtherTypeUrlInput', + 'value' + ); + expect(actualCustomUrlValue).to.eql( + expectedUrl, + `Expected other type custom url value to be '${expectedUrl}' (got '${actualCustomUrlValue}')` + ); + }, + + async setCustomUrlOtherTypeUrl(url: string) { + await testSubjects.setValue('mlJobCustomUrlOtherTypeUrlInput', url, { + clearWithKeyboard: true, + }); + await this.assertCustomUrlOtherTypeUrlValue(url); + }, + + async assertCustomUrlLabel(index: number, expectedLabel: string) { + await testSubjects.existOrFail(`mlJobEditCustomUrlLabelInput_${index}`); const actualLabel = await testSubjects.getAttribute( `mlJobEditCustomUrlLabelInput_${index}`, 'value' @@ -46,6 +114,44 @@ export function MachineLearningCustomUrlsProvider({ getService }: FtrProviderCon ); }, + async assertCustomUrlUrlValue(index: number, expectedUrl: string) { + await testSubjects.existOrFail(`mlJobEditCustomUrlInput_${index}`); + const actualUrl = await testSubjects.getAttribute( + `mlJobEditCustomUrlInput_${index}`, + 'value' + ); + expect(actualUrl).to.eql( + expectedUrl, + `Expected custom url item to be '${expectedUrl}' (got '${actualUrl}')` + ); + }, + + async editCustomUrlLabel(index: number, label: string) { + await testSubjects.existOrFail(`mlJobEditCustomUrlLabelInput_${index}`); + await testSubjects.setValue(`mlJobEditCustomUrlLabelInput_${index}`, label, { + clearWithKeyboard: true, + }); + await this.assertCustomUrlLabel(index, label); + }, + + async editCustomUrlUrlValue(index: number, urlValue: string) { + await testSubjects.existOrFail(`mlJobEditCustomUrlInput_${index}`); + await testSubjects.setValue(`mlJobEditCustomUrlInput_${index}`, urlValue, { + clearWithKeyboard: true, + }); + + // Click away, so the textarea reverts back to the standard input. + await testSubjects.click(`mlJobEditCustomUrlLabelInput_${index}`); + await this.assertCustomUrlUrlValue(index, urlValue); + }, + + async deleteCustomUrl(index: number) { + await testSubjects.existOrFail(`mlJobEditDeleteCustomUrlButton_${index}`); + const beforeCustomUrls = await testSubjects.findAll('mlJobEditCustomUrlItemLabel'); + await testSubjects.click(`mlJobEditDeleteCustomUrlButton_${index}`); + await this.assertCustomUrlsLength(beforeCustomUrls.length - 1); + }, + /** * Submits the custom url form and adds it to the list. * @param formContainerSelector - selector for the element that wraps the custom url creation form. @@ -54,5 +160,33 @@ export function MachineLearningCustomUrlsProvider({ getService }: FtrProviderCon await testSubjects.click('mlJobAddCustomUrl'); await testSubjects.missingOrFail(formContainerSelector, { timeout: 10 * 1000 }); }, + + async clickTestCustomUrl(index: number) { + await testSubjects.existOrFail(`mlJobEditCustomUrlItem_${index}`); + await testSubjects.click(`mlJobEditCustomUrlItem_${index} > mlJobEditTestCustomUrlButton`); + await PageObjects.header.waitUntilLoadingHasFinished(); + }, + + async assertDiscoverCustomUrlAction(expectedHitCountFormatted: string) { + await PageObjects.discover.waitForDiscoverAppOnScreen(); + await retry.tryForTime(5000, async () => { + const hitCount = await PageObjects.discover.getHitCount(); + expect(hitCount).to.eql( + expectedHitCountFormatted, + `Expected Discover hit count to be '${expectedHitCountFormatted}' (got '${hitCount}')` + ); + }); + }, + + async assertDashboardCustomUrlAction(expectedPanelCount: number) { + await PageObjects.dashboard.waitForRenderComplete(); + await retry.tryForTime(5000, async () => { + const panelCount = await PageObjects.dashboard.getPanelCount(); + expect(panelCount).to.eql( + expectedPanelCount, + `Expected Dashboard panel count to be '${expectedPanelCount}' (got '${panelCount}')` + ); + }); + }, }; } diff --git a/x-pack/test/functional/services/ml/index.ts b/x-pack/test/functional/services/ml/index.ts index 6a2e1158e70a3..64298bbdedd63 100644 --- a/x-pack/test/functional/services/ml/index.ts +++ b/x-pack/test/functional/services/ml/index.ts @@ -90,7 +90,7 @@ export function MachineLearningProvider(context: FtrProviderContext) { const jobManagement = MachineLearningJobManagementProvider(context, api); const jobSelection = MachineLearningJobSelectionProvider(context); const jobSourceSelection = MachineLearningJobSourceSelectionProvider(context); - const jobTable = MachineLearningJobTableProvider(context); + const jobTable = MachineLearningJobTableProvider(context, commonUI, customUrls); const jobTypeSelection = MachineLearningJobTypeSelectionProvider(context); const jobWizardAdvanced = MachineLearningJobWizardAdvancedProvider(context, commonUI); const jobWizardCategorization = MachineLearningJobWizardCategorizationProvider(context); diff --git a/x-pack/test/functional/services/ml/job_table.ts b/x-pack/test/functional/services/ml/job_table.ts index a179983a4627f..a39e62d6281fe 100644 --- a/x-pack/test/functional/services/ml/job_table.ts +++ b/x-pack/test/functional/services/ml/job_table.ts @@ -8,8 +8,20 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../../ftr_provider_context'; - -export function MachineLearningJobTableProvider({ getService }: FtrProviderContext) { +import { MlCommonUI } from './common_ui'; +import { MlCustomUrls } from './custom_urls'; + +import { + TimeRangeType, + TIME_RANGE_TYPE, + URL_TYPE, +} from '../../../../plugins/ml/public/application/jobs/components/custom_url_editor/constants'; + +export function MachineLearningJobTableProvider( + { getService }: FtrProviderContext, + mlCommonUI: MlCommonUI, + customUrls: MlCustomUrls +) { const testSubjects = getService('testSubjects'); const retry = getService('retry'); @@ -311,6 +323,12 @@ export function MachineLearningJobTableProvider({ getService }: FtrProviderConte await testSubjects.existOrFail('~mlPageJobWizard'); } + public async clickEditJobAction(jobId: string) { + await this.ensureJobActionsMenuOpen(jobId); + await testSubjects.click('mlActionButtonEditJob'); + await testSubjects.existOrFail('mlJobEditFlyout'); + } + public async clickDeleteJobAction(jobId: string) { await this.ensureJobActionsMenuOpen(jobId); await testSubjects.click('mlActionButtonDeleteJob'); @@ -456,5 +474,189 @@ export function MachineLearningJobTableProvider({ getService }: FtrProviderConte } }); } + + public async openEditCustomUrlsForJobTab(jobId: string) { + await this.clickEditJobAction(jobId); + // click Custom URLs tab + await testSubjects.click('mlEditJobFlyout-customUrls'); + await this.ensureEditCustomUrlTabOpen(); + } + + public async ensureEditCustomUrlTabOpen() { + await testSubjects.existOrFail('mlJobOpenCustomUrlFormButton', { timeout: 5000 }); + } + + public async closeEditJobFlyout() { + if (await testSubjects.exists('mlEditJobFlyoutCloseButton')) { + await testSubjects.click('mlEditJobFlyoutCloseButton'); + await testSubjects.missingOrFail('mlJobEditFlyout'); + } + } + + public async saveEditJobFlyoutChanges() { + await testSubjects.click('mlEditJobFlyoutSaveButton'); + await testSubjects.missingOrFail('mlJobEditFlyout', { timeout: 5000 }); + } + + public async clickOpenCustomUrlEditor() { + await this.ensureEditCustomUrlTabOpen(); + await testSubjects.click('mlJobOpenCustomUrlFormButton'); + await testSubjects.existOrFail('mlJobCustomUrlForm'); + } + + public async addDiscoverCustomUrl( + jobId: string, + customUrl: { + label: string; + indexPattern: string; + queryEntityFieldNames: string[]; + timeRange: TimeRangeType; + timeRangeInterval?: string; + } + ) { + await this.openEditCustomUrlsForJobTab(jobId); + + const existingCustomUrls = await testSubjects.findAll('mlJobEditCustomUrlItemLabel'); + + // Fill-in the form + await this.clickOpenCustomUrlEditor(); + await customUrls.setCustomUrlLabel(customUrl.label); + await mlCommonUI.selectRadioGroupValue( + `mlJobCustomUrlLinkToTypeInput`, + URL_TYPE.KIBANA_DISCOVER + ); + await mlCommonUI.selectSelectValueByVisibleText( + 'mlJobCustomUrlDiscoverIndexPatternInput', + customUrl.indexPattern + ); + await customUrls.setCustomUrlQueryEntityFieldNames(customUrl.queryEntityFieldNames); + await mlCommonUI.selectSelectValueByVisibleText( + 'mlJobCustomUrlTimeRangeInput', + customUrl.timeRange + ); + if (customUrl.timeRange === TIME_RANGE_TYPE.INTERVAL) { + await customUrls.setCustomUrlTimeRangeInterval(customUrl.timeRangeInterval!); + } + + // Save custom URL + await testSubjects.click('mlJobAddCustomUrl'); + const expectedIndex = existingCustomUrls.length; + await customUrls.assertCustomUrlLabel(expectedIndex, customUrl.label); + + // Save the job + await this.saveEditJobFlyoutChanges(); + } + + public async addDashboardCustomUrl( + jobId: string, + customUrl: { + label: string; + dashboardName: string; + queryEntityFieldNames: string[]; + timeRange: TimeRangeType; + timeRangeInterval?: string; + } + ) { + await this.openEditCustomUrlsForJobTab(jobId); + + const existingCustomUrls = await testSubjects.findAll('mlJobEditCustomUrlItemLabel'); + + // Fill-in the form + await this.clickOpenCustomUrlEditor(); + await customUrls.setCustomUrlLabel(customUrl.label); + await mlCommonUI.selectRadioGroupValue( + `mlJobCustomUrlLinkToTypeInput`, + URL_TYPE.KIBANA_DASHBOARD + ); + await mlCommonUI.selectSelectValueByVisibleText( + 'mlJobCustomUrlDashboardNameInput', + customUrl.dashboardName + ); + await customUrls.setCustomUrlQueryEntityFieldNames(customUrl.queryEntityFieldNames); + await mlCommonUI.selectSelectValueByVisibleText( + 'mlJobCustomUrlTimeRangeInput', + customUrl.timeRange + ); + if (customUrl.timeRange === TIME_RANGE_TYPE.INTERVAL) { + await customUrls.setCustomUrlTimeRangeInterval(customUrl.timeRangeInterval!); + } + + // Save custom URL + await testSubjects.click('mlJobAddCustomUrl'); + const expectedIndex = existingCustomUrls.length; + await customUrls.assertCustomUrlLabel(expectedIndex, customUrl.label); + + // Save the job + await this.saveEditJobFlyoutChanges(); + } + + public async addOtherTypeCustomUrl(jobId: string, customUrl: { label: string; url: string }) { + await this.openEditCustomUrlsForJobTab(jobId); + + const existingCustomUrls = await testSubjects.findAll('mlJobEditCustomUrlItemLabel'); + + // Fill-in the form + await this.clickOpenCustomUrlEditor(); + await customUrls.setCustomUrlLabel(customUrl.label); + await mlCommonUI.selectRadioGroupValue(`mlJobCustomUrlLinkToTypeInput`, URL_TYPE.OTHER); + await customUrls.setCustomUrlOtherTypeUrl(customUrl.url); + + // Save custom URL + await testSubjects.click('mlJobAddCustomUrl'); + const expectedIndex = existingCustomUrls.length; + await customUrls.assertCustomUrlLabel(expectedIndex, customUrl.label); + + // Save the job + await this.saveEditJobFlyoutChanges(); + } + + public async editCustomUrl( + jobId: string, + indexInList: number, + customUrl: { label: string; url: string } + ) { + await this.openEditCustomUrlsForJobTab(jobId); + await customUrls.editCustomUrlLabel(indexInList, customUrl.label); + await customUrls.editCustomUrlUrlValue(indexInList, customUrl.url); + + // Save the edit + await this.saveEditJobFlyoutChanges(); + } + + public async deleteCustomUrl(jobId: string, indexInList: number) { + await this.openEditCustomUrlsForJobTab(jobId); + const beforeCustomUrls = await testSubjects.findAll('mlJobEditCustomUrlItemLabel'); + await customUrls.deleteCustomUrl(indexInList); + + // Save the edit and check the custom URL has been deleted. + await testSubjects.click('mlEditJobFlyoutSaveButton'); + await this.openEditCustomUrlsForJobTab(jobId); + await customUrls.assertCustomUrlsLength(beforeCustomUrls.length - 1); + await this.closeEditJobFlyout(); + } + + public async openTestCustomUrl(jobId: string, indexInList: number) { + await this.openEditCustomUrlsForJobTab(jobId); + await customUrls.clickTestCustomUrl(indexInList); + } + + public async testDiscoverCustomUrlAction(expectedHitCountFormatted: string) { + await customUrls.assertDiscoverCustomUrlAction(expectedHitCountFormatted); + } + + public async testDashboardCustomUrlAction(expectedPanelCount: number) { + await customUrls.assertDashboardCustomUrlAction(expectedPanelCount); + } + + public async testOtherTypeCustomUrlAction( + jobId: string, + indexInList: number, + expectedUrl: string + ) { + // Can't test the contents of the external page, so just check the expected URL. + await this.openEditCustomUrlsForJobTab(jobId); + await customUrls.assertCustomUrlUrlValue(indexInList, expectedUrl); + await this.closeEditJobFlyout(); + } })(); } diff --git a/x-pack/test/functional/services/ml/job_wizard_common.ts b/x-pack/test/functional/services/ml/job_wizard_common.ts index 7754432c99aba..2990f70059767 100644 --- a/x-pack/test/functional/services/ml/job_wizard_common.ts +++ b/x-pack/test/functional/services/ml/job_wizard_common.ts @@ -527,7 +527,7 @@ export function MachineLearningJobWizardCommonProvider( const expectedIndex = existingCustomUrls.length; - await customUrls.assertCustomUrlItem(expectedIndex, customUrl.label); + await customUrls.assertCustomUrlLabel(expectedIndex, customUrl.label); }, async ensureAdvancedSectionOpen() { diff --git a/x-pack/test/functional/services/ml/test_resources.ts b/x-pack/test/functional/services/ml/test_resources.ts index f967099e10fa3..a8db7ccb7a764 100644 --- a/x-pack/test/functional/services/ml/test_resources.ts +++ b/x-pack/test/functional/services/ml/test_resources.ts @@ -305,6 +305,10 @@ export function MachineLearningTestResourcesProvider({ getService }: FtrProvider await this.createDashboardIfNeeded(dashboards.mlTestDashboard); }, + async deleteMLTestDashboard() { + await this.deleteDashboardByTitle(dashboards.mlTestDashboard.requestBody.attributes.title); + }, + async createDashboardIfNeeded(dashboard: any) { const title = dashboard.requestBody.attributes.title; const dashboardId = await this.getDashboardId(title); From ba7c0275ca7e80cb3c0ea354a87334094900905a Mon Sep 17 00:00:00 2001 From: Jen Huang Date: Wed, 26 May 2021 09:59:09 -0700 Subject: [PATCH 02/77] [Fleet] Support browsing granular integrations (#99866) * Manual cherry pick of work to support integration tiles and package-level vars * Fix types * Remove registry input group typings * Show integration-specific readme, title, and icon in package details page * Revert unnecessary changes * Add package-level `vars` field to package policy SO mappings * Fix types * Fix test Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- x-pack/plugins/fleet/common/services/index.ts | 1 + .../services/package_to_package_policy.ts | 38 +- .../services/packages_with_integrations.ts | 11 + .../plugins/fleet/common/types/models/epm.ts | 36 +- .../common/types/models/package_policy.ts | 1 + .../fleet/common/types/models/package_spec.ts | 3 +- .../fleet/common/types/rest_spec/epm.ts | 6 +- .../fleet/components/package_icon.tsx | 4 +- .../fleet/constants/page_paths.ts | 17 +- .../fleet/hooks/use_package_icon_type.ts | 24 +- .../create_package_policy_page/index.tsx | 1 + .../services/validate_package_policy.ts | 15 +- .../step_configure_package.tsx | 13 +- .../step_define_package_policy.tsx | 428 +++++++++++------- .../edit_package_policy_page/index.tsx | 4 +- .../sections/epm/components/package_card.tsx | 20 +- .../epm/components/package_list_grid.tsx | 13 +- .../sections/epm/hooks/use_local_search.tsx | 7 +- .../screens/detail/components/icon_panel.tsx | 5 +- .../sections/epm/screens/detail/index.tsx | 45 +- .../epm/screens/detail/overview/overview.tsx | 18 +- .../fleet/sections/epm/screens/home/index.tsx | 167 ++++--- .../applications/fleet/services/index.ts | 2 + .../routes/package_policy/handlers.test.ts | 4 +- .../fleet/server/saved_objects/index.ts | 1 + .../ingest_pipeline/ingest_pipelines.test.ts | 2 +- .../fleet/server/services/epm/packages/get.ts | 5 +- .../server/services/epm/registry/index.ts | 12 +- .../server/services/package_policy.test.ts | 82 ++++ .../fleet/server/services/package_policy.ts | 28 +- x-pack/plugins/fleet/server/types/index.tsx | 1 + .../server/types/models/package_policy.ts | 1 + .../fleet/server/types/rest_spec/epm.ts | 1 + .../common/endpoint/generate_data.ts | 1 + 34 files changed, 673 insertions(+), 344 deletions(-) create mode 100644 x-pack/plugins/fleet/common/services/packages_with_integrations.ts diff --git a/x-pack/plugins/fleet/common/services/index.ts b/x-pack/plugins/fleet/common/services/index.ts index cee34db4c7ec4..1fea5033e645c 100644 --- a/x-pack/plugins/fleet/common/services/index.ts +++ b/x-pack/plugins/fleet/common/services/index.ts @@ -16,3 +16,4 @@ export { isValidNamespace } from './is_valid_namespace'; export { isDiffPathProtocol } from './is_diff_path_protocol'; export { LicenseService } from './license'; export { isAgentUpgradeable } from './is_agent_upgradeable'; +export { doesPackageHaveIntegrations } from './packages_with_integrations'; diff --git a/x-pack/plugins/fleet/common/services/package_to_package_policy.ts b/x-pack/plugins/fleet/common/services/package_to_package_policy.ts index 0dfeb63f3b261..8f79e633eed0c 100644 --- a/x-pack/plugins/fleet/common/services/package_to_package_policy.ts +++ b/x-pack/plugins/fleet/common/services/package_to_package_policy.ts @@ -40,6 +40,21 @@ const getStreamsForInputType = ( return streams; }; +// Reduces registry var def into config object entry +const varsReducer = ( + configObject: PackagePolicyConfigRecord, + registryVar: RegistryVarsEntry +): PackagePolicyConfigRecord => { + const configEntry: PackagePolicyConfigRecordEntry = { + value: !registryVar.default && registryVar.multi ? [] : registryVar.default, + }; + if (registryVar.type) { + configEntry.type = registryVar.type; + } + configObject![registryVar.name] = configEntry; + return configObject; +}; + /* * This service creates a package policy inputs definition from defaults provided in package info */ @@ -58,21 +73,6 @@ export const packageToPackagePolicyInputs = ( if (packagePolicyTemplate?.inputs?.length) { // Map each package package policy input to agent policy package policy input packagePolicyTemplate.inputs.forEach((packageInput) => { - // Reduces registry var def into config object entry - const varsReducer = ( - configObject: PackagePolicyConfigRecord, - registryVar: RegistryVarsEntry - ): PackagePolicyConfigRecord => { - const configEntry: PackagePolicyConfigRecordEntry = { - value: !registryVar.default && registryVar.multi ? [] : registryVar.default, - }; - if (registryVar.type) { - configEntry.type = registryVar.type; - } - configObject![registryVar.name] = configEntry; - return configObject; - }; - // Map each package input stream into package policy input stream const streams: NewPackagePolicyInputStream[] = getStreamsForInputType( packageInput.type, @@ -121,7 +121,7 @@ export const packageToPackagePolicy = ( packagePolicyName?: string, description?: string ): NewPackagePolicy => { - return { + const packagePolicy: NewPackagePolicy = { name: packagePolicyName || `${packageInfo.name}-1`, namespace, description, @@ -135,4 +135,10 @@ export const packageToPackagePolicy = ( output_id: outputId, inputs: packageToPackagePolicyInputs(packageInfo), }; + + if (packageInfo.vars?.length) { + packagePolicy.vars = packageInfo.vars.reduce(varsReducer, {}); + } + + return packagePolicy; }; diff --git a/x-pack/plugins/fleet/common/services/packages_with_integrations.ts b/x-pack/plugins/fleet/common/services/packages_with_integrations.ts new file mode 100644 index 0000000000000..d63c7518f4edb --- /dev/null +++ b/x-pack/plugins/fleet/common/services/packages_with_integrations.ts @@ -0,0 +1,11 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import type { PackageInfo, PackageListItem } from '../types'; + +export const doesPackageHaveIntegrations = (pkgInfo: PackageInfo | PackageListItem) => { + return (pkgInfo.policy_templates || []).length > 1; +}; diff --git a/x-pack/plugins/fleet/common/types/models/epm.ts b/x-pack/plugins/fleet/common/types/models/epm.ts index eab13fe5819f9..5551453b8975c 100644 --- a/x-pack/plugins/fleet/common/types/models/epm.ts +++ b/x-pack/plugins/fleet/common/types/models/epm.ts @@ -19,7 +19,12 @@ import type { } from '../../constants'; import type { ValueOf } from '../../types'; -import type { PackageSpecManifest, PackageSpecScreenshot } from './package_spec'; +import type { + PackageSpecManifest, + PackageSpecIcon, + PackageSpecScreenshot, + PackageSpecCategory, +} from './package_spec'; export type InstallationStatus = typeof installationStatuses; @@ -118,19 +123,20 @@ interface RegistryOverridePropertyValue { } export type RegistryRelease = PackageSpecManifest['release']; -export interface RegistryImage { - src: string; +export interface RegistryImage extends PackageSpecIcon { path: string; - title?: string; - size?: string; - type?: string; } export enum RegistryPolicyTemplateKeys { name = 'name', title = 'title', description = 'description', + icons = 'icons', + screenshots = 'screenshots', + categories = 'categories', + data_streams = 'data_streams', inputs = 'inputs', + readme = 'readme', multiple = 'multiple', } @@ -138,7 +144,12 @@ export interface RegistryPolicyTemplate { [RegistryPolicyTemplateKeys.name]: string; [RegistryPolicyTemplateKeys.title]: string; [RegistryPolicyTemplateKeys.description]: string; + [RegistryPolicyTemplateKeys.icons]?: RegistryImage[]; + [RegistryPolicyTemplateKeys.screenshots]?: RegistryImage[]; + [RegistryPolicyTemplateKeys.categories]?: Array; + [RegistryPolicyTemplateKeys.data_streams]?: string[]; [RegistryPolicyTemplateKeys.inputs]?: RegistryInput[]; + [RegistryPolicyTemplateKeys.readme]?: string; [RegistryPolicyTemplateKeys.multiple]?: boolean; } @@ -148,15 +159,19 @@ export enum RegistryInputKeys { description = 'description', template_path = 'template_path', condition = 'condition', + input_group = 'input_group', vars = 'vars', } +export type RegistryInputGroup = 'logs' | 'metrics'; + export interface RegistryInput { [RegistryInputKeys.type]: string; [RegistryInputKeys.title]: string; [RegistryInputKeys.description]: string; [RegistryInputKeys.template_path]?: string; [RegistryInputKeys.condition]?: string; + [RegistryInputKeys.input_group]?: RegistryInputGroup; [RegistryInputKeys.vars]?: RegistryVarsEntry[]; } @@ -273,7 +288,7 @@ export interface RegistryDataStream { [RegistryDataStreamKeys.streams]?: RegistryStream[]; [RegistryDataStreamKeys.package]: string; [RegistryDataStreamKeys.path]: string; - [RegistryDataStreamKeys.ingest_pipeline]: string; + [RegistryDataStreamKeys.ingest_pipeline]?: string; [RegistryDataStreamKeys.elasticsearch]?: RegistryElasticsearch; [RegistryDataStreamKeys.dataset_is_prefix]?: boolean; } @@ -307,7 +322,7 @@ export interface RegistryVarsEntry { [RegistryVarsEntryKeys.required]?: boolean; [RegistryVarsEntryKeys.show_user]?: boolean; [RegistryVarsEntryKeys.multi]?: boolean; - [RegistryVarsEntryKeys.default]?: string | string[]; + [RegistryVarsEntryKeys.default]?: string | string[] | boolean; [RegistryVarsEntryKeys.os]?: { [key: string]: { default: string | string[]; @@ -329,8 +344,11 @@ type Merge = Omit & { + integration?: string; + id: string; +}; -export type PackageListItem = Installable; export type PackagesGroupedByStatus = Record, PackageList>; export type PackageInfo = | Installable> diff --git a/x-pack/plugins/fleet/common/types/models/package_policy.ts b/x-pack/plugins/fleet/common/types/models/package_policy.ts index 04362e6ff9402..c0b74c2a7b025 100644 --- a/x-pack/plugins/fleet/common/types/models/package_policy.ts +++ b/x-pack/plugins/fleet/common/types/models/package_policy.ts @@ -58,6 +58,7 @@ export interface NewPackagePolicy { output_id: string; package?: PackagePolicyPackage; inputs: NewPackagePolicyInput[]; + vars?: PackagePolicyConfigRecord; } export interface UpdatePackagePolicy extends NewPackagePolicy { diff --git a/x-pack/plugins/fleet/common/types/models/package_spec.ts b/x-pack/plugins/fleet/common/types/models/package_spec.ts index 65be72cbb7b6b..57aaa0230e647 100644 --- a/x-pack/plugins/fleet/common/types/models/package_spec.ts +++ b/x-pack/plugins/fleet/common/types/models/package_spec.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { RegistryPolicyTemplate } from './epm'; +import type { RegistryPolicyTemplate, RegistryVarsEntry } from './epm'; // Based on https://github.com/elastic/package-spec/blob/master/versions/1/manifest.spec.yml#L8 export interface PackageSpecManifest { @@ -22,6 +22,7 @@ export interface PackageSpecManifest { icons?: PackageSpecIcon[]; screenshots?: PackageSpecScreenshot[]; policy_templates?: RegistryPolicyTemplate[]; + vars?: RegistryVarsEntry[]; owner: { github: string }; } diff --git a/x-pack/plugins/fleet/common/types/rest_spec/epm.ts b/x-pack/plugins/fleet/common/types/rest_spec/epm.ts index e5c7ace420c73..51772eadca69e 100644 --- a/x-pack/plugins/fleet/common/types/rest_spec/epm.ts +++ b/x-pack/plugins/fleet/common/types/rest_spec/epm.ts @@ -8,8 +8,7 @@ import type { AssetReference, CategorySummaryList, - Installable, - RegistrySearchResult, + PackageList, PackageInfo, PackageUsageStats, InstallType, @@ -18,6 +17,7 @@ import type { export interface GetCategoriesRequest { query: { experimental?: boolean; + include_policy_templates?: boolean; }; } @@ -33,7 +33,7 @@ export interface GetPackagesRequest { } export interface GetPackagesResponse { - response: Array>; + response: PackageList; } export interface GetLimitedPackagesResponse { diff --git a/x-pack/plugins/fleet/public/applications/fleet/components/package_icon.tsx b/x-pack/plugins/fleet/public/applications/fleet/components/package_icon.tsx index cb0b02527f756..bb84a79056978 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/components/package_icon.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/components/package_icon.tsx @@ -14,7 +14,7 @@ import { usePackageIconType } from '../hooks'; export const PackageIcon: React.FunctionComponent< UsePackageIconType & Omit -> = ({ packageName, version, icons, tryApi, ...euiIconProps }) => { - const iconType = usePackageIconType({ packageName, version, icons, tryApi }); +> = ({ packageName, integrationName, version, icons, tryApi, ...euiIconProps }) => { + const iconType = usePackageIconType({ packageName, integrationName, version, icons, tryApi }); return ; }; diff --git a/x-pack/plugins/fleet/public/applications/fleet/constants/page_paths.ts b/x-pack/plugins/fleet/public/applications/fleet/constants/page_paths.ts index bcb450d5ec94e..27df7a4ebf11d 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/constants/page_paths.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/constants/page_paths.ts @@ -56,7 +56,7 @@ export const PAGE_ROUTING_PATHS = { policy_details: '/policies/:policyId/:tabId?', policy_details_settings: '/policies/:policyId/settings', add_integration_from_policy: '/policies/:policyId/add-integration', - add_integration_to_policy: '/integrations/:pkgkey/add-integration', + add_integration_to_policy: '/integrations/:pkgkey/add-integration/:integration?', edit_integration: '/policies/:policyId/edit-integration/:packagePolicyId', fleet: '/fleet', fleet_agent_list: '/fleet/agents', @@ -77,17 +77,22 @@ export const pagePathGetters: { integrations: () => '/integrations', integrations_all: () => '/integrations', integrations_installed: () => '/integrations/installed', - integration_details_overview: ({ pkgkey }) => `/integrations/detail/${pkgkey}/overview`, - integration_details_policies: ({ pkgkey }) => `/integrations/detail/${pkgkey}/policies`, - integration_details_settings: ({ pkgkey }) => `/integrations/detail/${pkgkey}/settings`, - integration_details_custom: ({ pkgkey }) => `/integrations/detail/${pkgkey}/custom`, + integration_details_overview: ({ pkgkey, integration }) => + `/integrations/detail/${pkgkey}/overview${integration ? `?integration=${integration}` : ''}`, + integration_details_policies: ({ pkgkey, integration }) => + `/integrations/detail/${pkgkey}/policies${integration ? `?integration=${integration}` : ''}`, + integration_details_settings: ({ pkgkey, integration }) => + `/integrations/detail/${pkgkey}/settings${integration ? `?integration=${integration}` : ''}`, + integration_details_custom: ({ pkgkey, integration }) => + `/integrations/detail/${pkgkey}/custom${integration ? `?integration=${integration}` : ''}`, integration_policy_edit: ({ packagePolicyId }) => `/integrations/edit-integration/${packagePolicyId}`, policies: () => '/policies', policies_list: () => '/policies', policy_details: ({ policyId, tabId }) => `/policies/${policyId}${tabId ? `/${tabId}` : ''}`, add_integration_from_policy: ({ policyId }) => `/policies/${policyId}/add-integration`, - add_integration_to_policy: ({ pkgkey }) => `/integrations/${pkgkey}/add-integration`, + add_integration_to_policy: ({ pkgkey, integration }) => + `/integrations/${pkgkey}/add-integration${integration ? `/${integration}` : ''}`, edit_integration: ({ policyId, packagePolicyId }) => `/policies/${policyId}/edit-integration/${packagePolicyId}`, fleet: () => '/fleet', diff --git a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_package_icon_type.ts b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_package_icon_type.ts index 654cfc70ab418..5701dd100bfed 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_package_icon_type.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_package_icon_type.ts @@ -16,7 +16,8 @@ import { sendGetPackageInfoByKey } from './index'; type Package = PackageInfo | PackageListItem; export interface UsePackageIconType { - packageName: Package['name']; + packageName: string; + integrationName?: string; version: Package['version']; icons?: Package['icons']; tryApi?: boolean; // should it call API to try to find missing icons? @@ -26,6 +27,7 @@ const CACHED_ICONS = new Map(); export const usePackageIconType = ({ packageName, + integrationName, version, icons: paramIcons, tryApi = false, @@ -33,13 +35,13 @@ export const usePackageIconType = ({ const { toPackageImage } = useLinks(); const [iconList, setIconList] = useState(); const [iconType, setIconType] = useState(''); // FIXME: use `empty` icon during initialization - see: https://github.com/elastic/kibana/issues/60622 - const pkgKey = `${packageName}-${version}`; + const cacheKey = `${packageName}-${version}${integrationName ? `-${integrationName}` : ''}`; // Generates an icon path or Eui Icon name based on an icon list from the package // or by using the package name against logo icons from Eui useEffect(() => { - if (CACHED_ICONS.has(pkgKey)) { - setIconType(CACHED_ICONS.get(pkgKey) || ''); + if (CACHED_ICONS.has(cacheKey)) { + setIconType(CACHED_ICONS.get(cacheKey) || ''); return; } const svgIcons = (paramIcons || iconList)?.filter( @@ -48,29 +50,29 @@ export const usePackageIconType = ({ const localIconSrc = Array.isArray(svgIcons) && toPackageImage(svgIcons[0], packageName, version); if (localIconSrc) { - CACHED_ICONS.set(pkgKey, localIconSrc); - setIconType(CACHED_ICONS.get(pkgKey) || ''); + CACHED_ICONS.set(cacheKey, localIconSrc); + setIconType(CACHED_ICONS.get(cacheKey) || ''); return; } const euiLogoIcon = ICON_TYPES.find((key) => key.toLowerCase() === `logo${packageName}`); if (euiLogoIcon) { - CACHED_ICONS.set(pkgKey, euiLogoIcon); + CACHED_ICONS.set(cacheKey, euiLogoIcon); setIconType(euiLogoIcon); return; } if (tryApi && !paramIcons && !iconList) { - sendGetPackageInfoByKey(pkgKey) + sendGetPackageInfoByKey(cacheKey) .catch((error) => undefined) // Ignore API errors .then((res) => { - CACHED_ICONS.delete(pkgKey); + CACHED_ICONS.delete(cacheKey); setIconList(res?.data?.response?.icons); }); } - CACHED_ICONS.set(pkgKey, 'package'); + CACHED_ICONS.set(cacheKey, 'package'); setIconType('package'); - }, [paramIcons, pkgKey, toPackageImage, iconList, packageName, iconType, tryApi, version]); + }, [paramIcons, cacheKey, toPackageImage, iconList, packageName, iconType, tryApi, version]); return iconType; }; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/index.tsx index f312220d9faec..55861726af466 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/index.tsx @@ -333,6 +333,7 @@ export const CreatePackagePolicyPage: React.FunctionComponent = () => { packagePolicy={packagePolicy} updatePackagePolicy={updatePackagePolicy} validationResults={validationResults!} + submitAttempted={formState === 'INVALID'} /> {/* Only show the out-of-box configuration step if a UI extension is NOT registered */} diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/services/validate_package_policy.ts b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/services/validate_package_policy.ts index e36a4b46039f4..de1b8df9f9597 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/services/validate_package_policy.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/services/validate_package_policy.ts @@ -7,6 +7,7 @@ import { i18n } from '@kbn/i18n'; import { safeLoad } from 'js-yaml'; +import { keyBy } from 'lodash'; import { getFlattenedObject, isValidNamespace } from '../../../../services'; import type { @@ -32,12 +33,12 @@ export type PackagePolicyInputValidationResults = PackagePolicyConfigValidationR streams?: Record; }; -export interface PackagePolicyValidationResults { +export type PackagePolicyValidationResults = { name: Errors; description: Errors; namespace: Errors; inputs: Record | null; -} +} & PackagePolicyConfigValidationResults; /* * Returns validation information for a given package policy and package info @@ -67,6 +68,16 @@ export const validatePackagePolicy = ( validationResults.namespace = [namespaceValidation.error]; } + // Validate package-level vars + const packageVarsByName = keyBy(packageInfo.vars || [], 'name'); + const packageVars = Object.entries(packagePolicy.vars || {}); + if (packageVars.length) { + validationResults.vars = packageVars.reduce((results, [name, varEntry]) => { + results[name] = validatePackagePolicyConfig(varEntry, packageVarsByName[name]); + return results; + }, {} as ValidationEntry); + } + if ( !packageInfo.policy_templates || packageInfo.policy_templates.length === 0 || diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/step_configure_package.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/step_configure_package.tsx index 87c5af56f31b2..e64598e583d35 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/step_configure_package.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/step_configure_package.tsx @@ -25,7 +25,6 @@ import { Loading } from '../../../components'; import type { PackagePolicyValidationResults } from './services'; import { PackagePolicyInputPanel } from './components'; -import type { CreatePackagePolicyFrom } from './types'; const findStreamsForInputType = ( inputType: string, @@ -50,22 +49,12 @@ const findStreamsForInputType = ( }; export const StepConfigurePackagePolicy: React.FunctionComponent<{ - from?: CreatePackagePolicyFrom; packageInfo: PackageInfo; packagePolicy: NewPackagePolicy; - packagePolicyId?: string; updatePackagePolicy: (fields: Partial) => void; validationResults: PackagePolicyValidationResults; submitAttempted: boolean; -}> = ({ - from = 'policy', - packageInfo, - packagePolicy, - packagePolicyId, - updatePackagePolicy, - validationResults, - submitAttempted, -}) => { +}> = ({ packageInfo, packagePolicy, updatePackagePolicy, validationResults, submitAttempted }) => { // Configure inputs (and their streams) // Assume packages only export one config template for now const renderConfigureInputs = () => diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/step_define_package_policy.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/step_define_package_policy.tsx index c1626d2b14121..26a31a1394f78 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/step_define_package_policy.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/step_define_package_policy.tsx @@ -5,14 +5,13 @@ * 2.0. */ -import React, { useEffect, useState } from 'react'; +import React, { memo, useEffect, useState } from 'react'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import { EuiFormRow, EuiFieldText, EuiButtonEmpty, - EuiSpacer, EuiText, EuiComboBox, EuiDescribedFormGroup, @@ -21,180 +20,145 @@ import { EuiLink, } from '@elastic/eui'; -import type { AgentPolicy, PackageInfo, PackagePolicy, NewPackagePolicy } from '../../../types'; -import { packageToPackagePolicyInputs } from '../../../services'; +import type { + AgentPolicy, + PackageInfo, + PackagePolicy, + NewPackagePolicy, + RegistryVarsEntry, +} from '../../../types'; +import { packageToPackagePolicy } from '../../../services'; import { Loading } from '../../../components'; import { pkgKeyFromPackageInfo } from '../../../services/pkg_key_from_package_info'; +import { isAdvancedVar } from './services'; import type { PackagePolicyValidationResults } from './services'; +import { PackagePolicyInputVarField } from './components'; export const StepDefinePackagePolicy: React.FunctionComponent<{ agentPolicy: AgentPolicy; packageInfo: PackageInfo; packagePolicy: NewPackagePolicy; + integration?: string; updatePackagePolicy: (fields: Partial) => void; validationResults: PackagePolicyValidationResults; -}> = ({ agentPolicy, packageInfo, packagePolicy, updatePackagePolicy, validationResults }) => { - // Form show/hide states - const [isShowingAdvanced, setIsShowingAdvanced] = useState(false); - - // Update package policy's package and agent policy info - useEffect(() => { - const pkg = packagePolicy.package; - const currentPkgKey = pkg ? pkgKeyFromPackageInfo(pkg) : ''; - const pkgKey = pkgKeyFromPackageInfo(packageInfo); + submitAttempted: boolean; +}> = memo( + ({ + agentPolicy, + packageInfo, + packagePolicy, + integration, + updatePackagePolicy, + validationResults, + submitAttempted, + }) => { + // Form show/hide states + const [isShowingAdvanced, setIsShowingAdvanced] = useState(false); - // If package has changed, create shell package policy with input&stream values based on package info - if (currentPkgKey !== pkgKey) { - // Existing package policies on the agent policy using the package name, retrieve highest number appended to package policy name - const pkgPoliciesNamePattern = new RegExp(`${packageInfo.name}-(\\d+)`); - const pkgPoliciesWithMatchingNames = (agentPolicy.package_policies as PackagePolicy[]) - .filter((ds) => Boolean(ds.name.match(pkgPoliciesNamePattern))) - .map((ds) => parseInt(ds.name.match(pkgPoliciesNamePattern)![1], 10)) - .sort((a, b) => a - b); + // Package-level vars + const requiredVars: RegistryVarsEntry[] = []; + const advancedVars: RegistryVarsEntry[] = []; - updatePackagePolicy({ - // FIXME: Improve package policies name uniqueness - https://github.com/elastic/kibana/issues/72948 - name: `${packageInfo.name}-${ - pkgPoliciesWithMatchingNames.length - ? pkgPoliciesWithMatchingNames[pkgPoliciesWithMatchingNames.length - 1] + 1 - : 1 - }`, - package: { - name: packageInfo.name, - title: packageInfo.title, - version: packageInfo.version, - }, - inputs: packageToPackagePolicyInputs(packageInfo), + if (packageInfo.vars) { + packageInfo.vars.forEach((varDef) => { + if (isAdvancedVar(varDef)) { + advancedVars.push(varDef); + } else { + requiredVars.push(varDef); + } }); } - // If agent policy has changed, update package policy's agent policy ID and namespace - if (packagePolicy.policy_id !== agentPolicy.id) { - updatePackagePolicy({ - policy_id: agentPolicy.id, - namespace: agentPolicy.namespace, - }); - } - }, [ - packagePolicy.package, - packagePolicy.policy_id, - agentPolicy, - packageInfo, - updatePackagePolicy, - ]); + // Update package policy's package and agent policy info + useEffect(() => { + const pkg = packagePolicy.package; + const currentPkgKey = pkg ? pkgKeyFromPackageInfo(pkg) : ''; + const pkgKey = pkgKeyFromPackageInfo(packageInfo); - return validationResults ? ( - - - + // If package has changed, create shell package policy with input&stream values based on package info + if (currentPkgKey !== pkgKey) { + // Existing package policies on the agent policy using the package name, retrieve highest number appended to package policy name + const pkgPoliciesNamePattern = new RegExp(`${packageInfo.name}-(\\d+)`); + const pkgPoliciesWithMatchingNames = (agentPolicy.package_policies as PackagePolicy[]) + .filter((ds) => Boolean(ds.name.match(pkgPoliciesNamePattern))) + .map((ds) => parseInt(ds.name.match(pkgPoliciesNamePattern)![1], 10)) + .sort((a, b) => a - b); + + updatePackagePolicy( + packageToPackagePolicy( + packageInfo, + agentPolicy.id, + packagePolicy.output_id, + packagePolicy.namespace, + `${packageInfo.name}-${ + pkgPoliciesWithMatchingNames.length + ? pkgPoliciesWithMatchingNames[pkgPoliciesWithMatchingNames.length - 1] + 1 + : 1 + }`, + packagePolicy.description + ) + ); } - description={ - + + // If agent policy has changed, update package policy's agent policy ID and namespace + if (packagePolicy.policy_id !== agentPolicy.id) { + updatePackagePolicy({ + policy_id: agentPolicy.id, + namespace: agentPolicy.namespace, + }); } - > - <> - {/* Name */} - - } - > - - updatePackagePolicy({ - name: e.target.value, - }) - } - data-test-subj="packagePolicyNameInput" - /> - + }, [packagePolicy, agentPolicy, packageInfo, updatePackagePolicy, integration]); - {/* Description */} - - } - labelAppend={ - - - - } - isInvalid={!!validationResults.description} - error={validationResults.description} - > - - updatePackagePolicy({ - description: e.target.value, - }) - } - data-test-subj="packagePolicyDescriptionInput" + + } + description={ + - - - - {/* Advanced options toggle */} - - - setIsShowingAdvanced(!isShowingAdvanced)} - flush="left" + } + > + + {/* Name */} + + + } > - + updatePackagePolicy({ + name: e.target.value, + }) + } + data-test-subj="packagePolicyNameInput" /> - + - {!isShowingAdvanced && !!validationResults.namespace ? ( - - - - - - ) : null} - - {/* Advanced options content */} - {/* Todo: Populate list of existing namespaces */} - {isShowingAdvanced ? ( - <> - + {/* Description */} + } helpText={ @@ -216,30 +180,156 @@ export const StepDefinePackagePolicy: React.FunctionComponent<{ }} /> } + labelAppend={ + + + + } + isInvalid={!!validationResults.description} + error={validationResults.description} > - { - updatePackagePolicy({ - namespace: newNamespace, - }); - }} - onChange={(newNamespaces: Array<{ label: string }>) => { + updatePackagePolicy({ - namespace: newNamespaces.length ? newNamespaces[0].label : '', - }); - }} + description: e.target.value, + }) + } + data-test-subj="packagePolicyDescriptionInput" /> - - ) : null} - - - ) : ( - - ); -}; + + + {/* Required vars */} + {requiredVars.map((varDef) => { + const { name: varName, type: varType } = varDef; + if (!packagePolicy.vars || !packagePolicy.vars[varName]) return null; + const value = packagePolicy.vars[varName].value; + return ( + + { + updatePackagePolicy({ + vars: { + ...packagePolicy.vars, + [varName]: { + type: varType, + value: newValue, + }, + }, + }); + }} + errors={validationResults.vars![varName]} + forceShowErrors={submitAttempted} + /> + + ); + })} + + {/* Advanced options toggle */} + + + + setIsShowingAdvanced(!isShowingAdvanced)} + flush="left" + > + + + + {!isShowingAdvanced && !!validationResults.namespace ? ( + + + + + + ) : null} + + + + {/* Advanced options content */} + {/* Todo: Populate list of existing namespaces */} + {isShowingAdvanced ? ( + + + + + } + > + { + updatePackagePolicy({ + namespace: newNamespace, + }); + }} + onChange={(newNamespaces: Array<{ label: string }>) => { + updatePackagePolicy({ + namespace: newNamespaces.length ? newNamespaces[0].label : '', + }); + }} + /> + + + {/* Advanced vars */} + {advancedVars.map((varDef) => { + const { name: varName, type: varType } = varDef; + if (!packagePolicy.vars || !packagePolicy.vars[varName]) return null; + const value = packagePolicy.vars![varName].value; + return ( + + { + updatePackagePolicy({ + vars: { + ...packagePolicy.vars, + [varName]: { + type: varType, + value: newValue, + }, + }, + }); + }} + errors={validationResults.vars![varName]} + forceShowErrors={submitAttempted} + /> + + ); + })} + + + ) : null} + + + ) : ( + + ); + } +); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.tsx index 8df8b7ebcd4cf..3b9b5696ff7bd 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.tsx @@ -351,15 +351,14 @@ export const EditPackagePolicyForm = memo<{ packagePolicy={packagePolicy} updatePackagePolicy={updatePackagePolicy} validationResults={validationResults!} + submitAttempted={formState === 'INVALID'} /> {/* Only show the out-of-box configuration step if a UI extension is NOT registered */} {!ExtensionView && ( } - href={getHref('integration_details_overview', { pkgkey: `${name}-${urlVersion}` })} + icon={ + + } + href={getHref('integration_details_overview', { + pkgkey: `${name}-${urlVersion}`, + ...(integration ? { integration } : {}), + })} betaBadgeLabel={release && release !== 'ga' ? RELEASE_BADGE_LABEL[release] : undefined} betaBadgeTooltipContent={ release && release !== 'ga' ? RELEASE_BADGE_DESCRIPTION[release] : undefined diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/epm/components/package_list_grid.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/epm/components/package_list_grid.tsx index b79255e6889ad..d4d2b481950f6 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/epm/components/package_list_grid.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/epm/components/package_list_grid.tsx @@ -25,7 +25,6 @@ import { FormattedMessage } from '@kbn/i18n/react'; import { Loading } from '../../../components'; import type { PackageList } from '../../../types'; import { useLocalSearch, searchIdField } from '../hooks'; -import { pkgKeyFromPackageInfo } from '../../../services/pkg_key_from_package_info'; import { PackageCard } from './package_card'; @@ -153,11 +152,13 @@ function GridColumn({ list, showMissingIntegrationMessage = false }: GridColumnP return ( {list.length ? ( - list.map((item) => ( - - - - )) + list.map((item) => { + return ( + + + + ); + }) ) : ( diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/epm/hooks/use_local_search.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/epm/hooks/use_local_search.tsx index efdc2f3884542..43db5657b0615 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/epm/hooks/use_local_search.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/epm/hooks/use_local_search.tsx @@ -8,11 +8,10 @@ import { Search as LocalSearch } from 'js-search'; import { useEffect, useRef } from 'react'; -import type { PackageList, PackageListItem } from '../../../types'; +import type { PackageList } from '../../../types'; -export type SearchField = keyof PackageListItem; -export const searchIdField: SearchField = 'name'; -export const fieldsToSearch: SearchField[] = ['description', 'name', 'title']; +export const searchIdField = 'id'; +export const fieldsToSearch = ['description', 'name', 'title']; export function useLocalSearch(packageList: PackageList) { const localSearchRef = useRef(null); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/detail/components/icon_panel.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/detail/components/icon_panel.tsx index 6d5d52789a975..8a82397bd0193 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/detail/components/icon_panel.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/detail/components/icon_panel.tsx @@ -37,10 +37,11 @@ const Panel = styled(EuiPanel)` export function IconPanel({ packageName, + integrationName, version, icons, -}: Pick) { - const iconType = usePackageIconType({ packageName, version, icons }); +}: Pick) { + const iconType = usePackageIconType({ packageName, integrationName, version, icons }); return ( diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/detail/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/detail/index.tsx index a4f465cd3d619..05d2f53688655 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/detail/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/detail/index.tsx @@ -74,7 +74,9 @@ export function Detail() { const { getHref, getPath } = useLink(); const hasWriteCapabilites = useCapabilities().write; const history = useHistory(); - const location = useLocation(); + const { pathname, search, hash } = useLocation(); + const queryParams = useMemo(() => new URLSearchParams(search), [search]); + const integration = useMemo(() => queryParams.get('integration'), [queryParams]); // Package info state const [packageInfo, setPackageInfo] = useState(null); @@ -120,6 +122,16 @@ export function Detail() { } }, [packageInfoData, setPackageInstallStatus, setPackageInfo]); + const integrationInfo = useMemo( + () => + integration + ? packageInfo?.policy_templates?.find( + (policyTemplate) => policyTemplate.name === integration + ) + : undefined, + [integration, packageInfo] + ); + const headerLeftContent = useMemo( () => ( @@ -147,8 +159,9 @@ export function Detail() { ) : ( )} @@ -157,7 +170,7 @@ export function Detail() { {/* Render space in place of package name while package info loads to prevent layout from jumping around */} -

{packageInfo?.title || '\u00A0'}

+

{integrationInfo?.title || packageInfo?.title || '\u00A0'}

{packageInfo?.release && packageInfo.release !== 'ga' ? ( @@ -174,7 +187,7 @@ export function Detail() { ), - [getHref, isLoading, packageInfo] + [getHref, integrationInfo, isLoading, packageInfo] ); const handleAddIntegrationPolicyClick = useCallback( @@ -184,9 +197,9 @@ export function Detail() { // The object below, given to `createHref` is explicitly accessing keys of `location` in order // to ensure that dependencies to this `useCallback` is set correctly (because `location` is mutable) const currentPath = history.createHref({ - pathname: location.pathname, - search: location.search, - hash: location.hash, + pathname, + search, + hash, }); const redirectToPath: CreatePackagePolicyRouteState['onSaveNavigateTo'] & CreatePackagePolicyRouteState['onCancelNavigateTo'] = [ @@ -204,11 +217,12 @@ export function Detail() { history.push({ pathname: getPath('add_integration_to_policy', { pkgkey, + ...(integration ? { integration } : {}), }), state: redirectBackRouteState, }); }, - [getPath, history, location.hash, location.pathname, location.search, pkgkey] + [getPath, history, hash, pathname, search, pkgkey, integration] ); const headerRightContent = useMemo( @@ -255,6 +269,7 @@ export function Detail() { iconType="plusInCircle" href={getHref('add_integration_to_policy', { pkgkey, + ...(integration ? { integration } : {}), })} onClick={handleAddIntegrationPolicyClick} data-test-subj="addIntegrationPolicyButton" @@ -263,7 +278,7 @@ export function Detail() { id="xpack.fleet.epm.addPackagePolicyButtonText" defaultMessage="Add {packageName}" values={{ - packageName: packageInfo.title, + packageName: integrationInfo?.title || packageInfo.title, }} /> @@ -290,6 +305,8 @@ export function Detail() { getHref, handleAddIntegrationPolicyClick, hasWriteCapabilites, + integration, + integrationInfo, packageInfo, packageInstallStatus, pkgkey, @@ -316,6 +333,7 @@ export function Detail() { 'data-test-subj': `tab-overview`, href: getHref('integration_details_overview', { pkgkey: packageInfoKey, + ...(integration ? { integration } : {}), }), }, ]; @@ -333,6 +351,7 @@ export function Detail() { 'data-test-subj': `tab-policies`, href: getHref('integration_details_policies', { pkgkey: packageInfoKey, + ...(integration ? { integration } : {}), }), }); } @@ -349,6 +368,7 @@ export function Detail() { 'data-test-subj': `tab-settings`, href: getHref('integration_details_settings', { pkgkey: packageInfoKey, + ...(integration ? { integration } : {}), }), }); @@ -365,12 +385,13 @@ export function Detail() { 'data-test-subj': `tab-custom`, href: getHref('integration_details_custom', { pkgkey: packageInfoKey, + ...(integration ? { integration } : {}), }), }); } return tabs; - }, [getHref, packageInfo, panel, showCustomTab, packageInstallStatus]); + }, [packageInfo, panel, getHref, integration, packageInstallStatus, showCustomTab]); return ( - {packageInfo ? : null} + {integrationInfo ? : null} {packageInfoError ? ( - + diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/detail/overview/overview.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/detail/overview/overview.tsx index 3585e2063734b..945859ac81ffd 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/detail/overview/overview.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/detail/overview/overview.tsx @@ -4,11 +4,11 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import React, { memo } from 'react'; +import React, { memo, useMemo } from 'react'; import styled from 'styled-components'; import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; -import type { PackageInfo } from '../../../../../types'; +import type { PackageInfo, RegistryPolicyTemplate } from '../../../../../types'; import { Screenshots } from './screenshots'; import { Readme } from './readme'; @@ -16,6 +16,7 @@ import { Details } from './details'; interface Props { packageInfo: PackageInfo; + integrationInfo?: RegistryPolicyTemplate; } const LeftColumn = styled(EuiFlexItem)` @@ -25,14 +26,19 @@ const LeftColumn = styled(EuiFlexItem)` } `; -export const OverviewPage: React.FC = memo(({ packageInfo }: Props) => { +export const OverviewPage: React.FC = memo(({ packageInfo, integrationInfo }) => { + const screenshots = useMemo(() => integrationInfo?.screenshots || packageInfo.screenshots || [], [ + integrationInfo, + packageInfo.screenshots, + ]); + return ( {packageInfo.readme ? ( @@ -40,10 +46,10 @@ export const OverviewPage: React.FC = memo(({ packageInfo }: Props) => { - {packageInfo.screenshots && packageInfo.screenshots.length ? ( + {screenshots.length ? ( diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/home/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/home/index.tsx index e9bd6b7b61385..922628e7b68b1 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/home/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/home/index.tsx @@ -5,22 +5,24 @@ * 2.0. */ -import React, { useState } from 'react'; +import React, { memo, useState, useMemo } from 'react'; import { useRouteMatch, Switch, Route, useLocation, useHistory } from 'react-router-dom'; +import semverLt from 'semver/functions/lt'; import type { Props as EuiTabProps } from '@elastic/eui/src/components/tabs/tab'; import { i18n } from '@kbn/i18n'; import { installationStatuses } from '../../../../../../../common/constants'; import { PAGE_ROUTING_PATHS } from '../../../../constants'; import { useLink, useGetCategories, useGetPackages, useBreadcrumbs } from '../../../../hooks'; +import { doesPackageHaveIntegrations } from '../../../../services'; import { WithHeaderLayout } from '../../../../layouts'; -import type { CategorySummaryItem } from '../../../../types'; +import type { CategorySummaryItem, PackageList } from '../../../../types'; import { PackageListGrid } from '../../components/package_list_grid'; import { CategoryFacets } from './category_facets'; import { HeroCopy, HeroImage } from './header'; -export function EPMHomePage() { +export const EPMHomePage: React.FC = memo(() => { const { params: { tabId }, } = useRouteMatch<{ tabId?: string }>(); @@ -61,51 +63,94 @@ export function EPMHomePage() { ); -} - -function InstalledPackages() { +}); + +// Packages can export multiple integrations, aka `policy_templates` +// In the case where packages ship >1 `policy_templates`, we flatten out the +// list of packages by bringing all integrations to top-level so that +// each integration is displayed as its own tile +const packageListToIntegrationsList = (packages: PackageList): PackageList => { + return packages.reduce((acc: PackageList, pkg) => { + const { policy_templates: policyTemplates = [], ...restOfPackage } = pkg; + return [ + ...acc, + restOfPackage, + ...(doesPackageHaveIntegrations(pkg) + ? policyTemplates.map((integration) => { + const { name, title, description, icons } = integration; + return { + ...restOfPackage, + id: `${restOfPackage}-${name}`, + integration: name, + title, + description, + icons: icons || restOfPackage.icons, + }; + }) + : []), + ]; + }, []); +}; + +const InstalledPackages: React.FC = memo(() => { useBreadcrumbs('integrations_installed'); const { data: allPackages, isLoading: isLoadingPackages } = useGetPackages({ experimental: true, }); const [selectedCategory, setSelectedCategory] = useState(''); - const title = i18n.translate('xpack.fleet.epmList.installedTitle', { - defaultMessage: 'Installed integrations', - }); - - const allInstalledPackages = - allPackages && allPackages.response - ? allPackages.response.filter((pkg) => pkg.status === installationStatuses.Installed) - : []; + const allInstalledPackages = useMemo( + () => + (allPackages?.response || []).filter((pkg) => pkg.status === installationStatuses.Installed), + [allPackages?.response] + ); - const updatablePackages = allInstalledPackages.filter( - (item) => 'savedObject' in item && item.version > item.savedObject.attributes.version + const updatablePackages = useMemo( + () => + allInstalledPackages.filter( + (item) => + 'savedObject' in item && semverLt(item.savedObject.attributes.version, item.version) + ), + [allInstalledPackages] ); - const categories = [ - { - id: '', - title: i18n.translate('xpack.fleet.epmList.allFilterLinkText', { - defaultMessage: 'All', - }), - count: allInstalledPackages.length, - }, - { - id: 'updates_available', - title: i18n.translate('xpack.fleet.epmList.updatesAvailableFilterLinkText', { - defaultMessage: 'Updates available', + const title = useMemo( + () => + i18n.translate('xpack.fleet.epmList.installedTitle', { + defaultMessage: 'Installed integrations', }), - count: updatablePackages.length, - }, - ]; + [] + ); - const controls = ( - setSelectedCategory(id)} - /> + const categories = useMemo( + () => [ + { + id: '', + title: i18n.translate('xpack.fleet.epmList.allFilterLinkText', { + defaultMessage: 'All', + }), + count: allInstalledPackages.length, + }, + { + id: 'updates_available', + title: i18n.translate('xpack.fleet.epmList.updatesAvailableFilterLinkText', { + defaultMessage: 'Updates available', + }), + count: updatablePackages.length, + }, + ], + [allInstalledPackages.length, updatablePackages.length] + ); + + const controls = useMemo( + () => ( + setSelectedCategory(id)} + /> + ), + [categories, selectedCategory] ); return ( @@ -116,9 +161,9 @@ function InstalledPackages() { list={selectedCategory === 'updates_available' ? updatablePackages : allInstalledPackages} /> ); -} +}); -function AvailablePackages() { +const AvailablePackages: React.FC = memo(() => { useBreadcrumbs('integrations_all'); const history = useHistory(); const queryParams = new URLSearchParams(useLocation().search); @@ -128,24 +173,36 @@ function AvailablePackages() { const { data: categoryPackagesRes, isLoading: isLoadingCategoryPackages } = useGetPackages({ category: selectedCategory, }); - const { data: categoriesRes, isLoading: isLoadingCategories } = useGetCategories(); - const packages = - categoryPackagesRes && categoryPackagesRes.response ? categoryPackagesRes.response : []; - - const title = i18n.translate('xpack.fleet.epmList.allTitle', { - defaultMessage: 'Browse by category', + const { data: categoriesRes, isLoading: isLoadingCategories } = useGetCategories({ + include_policy_templates: true, }); + const packages = useMemo( + () => packageListToIntegrationsList(categoryPackagesRes?.response || []), + [categoryPackagesRes] + ); - const categories = [ - { - id: '', - title: i18n.translate('xpack.fleet.epmList.allPackagesFilterLinkText', { - defaultMessage: 'All', + const title = useMemo( + () => + i18n.translate('xpack.fleet.epmList.allTitle', { + defaultMessage: 'Browse by category', }), - count: allPackagesRes?.response?.length || 0, - }, - ...(categoriesRes ? categoriesRes.response : []), - ]; + [] + ); + + const categories = useMemo( + () => [ + { + id: '', + title: i18n.translate('xpack.fleet.epmList.allPackagesFilterLinkText', { + defaultMessage: 'All', + }), + count: allPackagesRes?.response?.length || 0, + }, + ...(categoriesRes ? categoriesRes.response : []), + ], + [allPackagesRes?.response?.length, categoriesRes] + ); + const controls = categories ? ( ); -} +}); diff --git a/x-pack/plugins/fleet/public/applications/fleet/services/index.ts b/x-pack/plugins/fleet/public/applications/fleet/services/index.ts index 8d59496d8f9d0..07fb04628ea2e 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/services/index.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/services/index.ts @@ -20,6 +20,7 @@ export { outputRoutesService, settingsRoutesService, appRoutesService, + packageToPackagePolicy, packageToPackagePolicyInputs, storedPackagePoliciesToAgentInputs, fullAgentPolicyToYaml, @@ -28,4 +29,5 @@ export { isValidNamespace, LicenseService, isAgentUpgradeable, + doesPackageHaveIntegrations, } from '../../../../common'; 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 7f2b9d93e2df7..5aa400d6443e6 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 @@ -24,7 +24,9 @@ jest.mock('../../services/package_policy', (): { } => { return { packagePolicyService: { - compilePackagePolicyInputs: jest.fn((packageInfo, dataInputs) => Promise.resolve(dataInputs)), + compilePackagePolicyInputs: jest.fn((packageInfo, vars, dataInputs) => + Promise.resolve(dataInputs) + ), buildPackagePolicyFromPackage: jest.fn(), bulkCreate: jest.fn(), create: jest.fn((soClient, esClient, newData) => diff --git a/x-pack/plugins/fleet/server/saved_objects/index.ts b/x-pack/plugins/fleet/server/saved_objects/index.ts index 4331baef11001..10e5a6ac57f57 100644 --- a/x-pack/plugins/fleet/server/saved_objects/index.ts +++ b/x-pack/plugins/fleet/server/saved_objects/index.ts @@ -229,6 +229,7 @@ const getSavedObjectTypes = ( version: { type: 'keyword' }, }, }, + vars: { type: 'flattened' }, inputs: { type: 'nested', enabled: false, diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/ingest_pipeline/ingest_pipelines.test.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/ingest_pipeline/ingest_pipelines.test.ts index 097f9ce28c7d1..f915e871b98f7 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/ingest_pipeline/ingest_pipelines.test.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/ingest_pipeline/ingest_pipelines.test.ts @@ -121,7 +121,7 @@ test('getPipelineNameForInstallation gets correct name', () => { const packageVersion = '1.0.1'; const pipelineRefName = 'pipeline-json'; const pipelineEntryNameForInstallation = getPipelineNameForInstallation({ - pipelineName: dataStream.ingest_pipeline, + pipelineName: dataStream.ingest_pipeline!, dataStream, packageVersion, }); diff --git a/x-pack/plugins/fleet/server/services/epm/packages/get.ts b/x-pack/plugins/fleet/server/services/epm/packages/get.ts index 706b2679ed2eb..e4e4f9c55fd2b 100644 --- a/x-pack/plugins/fleet/server/services/epm/packages/get.ts +++ b/x-pack/plugins/fleet/server/services/epm/packages/get.ts @@ -18,6 +18,7 @@ import type { ArchivePackage, RegistryPackage, EpmPackageAdditions, + GetCategoriesRequest, } from '../../../../common/types'; import type { Installation, PackageInfo } from '../../../types'; import { IngestManagerError } from '../../../errors'; @@ -35,7 +36,7 @@ function nameAsTitle(name: string) { return name.charAt(0).toUpperCase() + name.substr(1).toLowerCase(); } -export async function getCategories(options: Registry.CategoriesParams) { +export async function getCategories(options: GetCategoriesRequest['query']) { return Registry.fetchCategories(options); } @@ -47,7 +48,7 @@ export async function getPackages( const { savedObjectsClient, experimental, category } = options; const registryItems = await Registry.fetchList({ category, experimental }).then((items) => { return items.map((item) => - Object.assign({}, item, { title: item.title || nameAsTitle(item.name) }) + Object.assign({}, item, { title: item.title || nameAsTitle(item.name) }, { id: item.name }) ); }); // get the installed packages diff --git a/x-pack/plugins/fleet/server/services/epm/registry/index.ts b/x-pack/plugins/fleet/server/services/epm/registry/index.ts index 9e04d75f36a16..5ee7e198555c5 100644 --- a/x-pack/plugins/fleet/server/services/epm/registry/index.ts +++ b/x-pack/plugins/fleet/server/services/epm/registry/index.ts @@ -20,6 +20,7 @@ import type { RegistryPackage, RegistrySearchResults, RegistrySearchResult, + GetCategoriesRequest, } from '../../../types'; import { getArchiveFilelist, @@ -45,10 +46,6 @@ export interface SearchParams { experimental?: boolean; } -export interface CategoriesParams { - experimental?: boolean; -} - /** * Extract the package name and package version from a string. * @@ -150,13 +147,18 @@ function setKibanaVersion(url: URL) { } } -export async function fetchCategories(params?: CategoriesParams): Promise { +export async function fetchCategories( + params?: GetCategoriesRequest['query'] +): Promise { const registryUrl = getRegistryUrl(); const url = new URL(`${registryUrl}/categories`); if (params) { if (params.experimental) { url.searchParams.set('experimental', params.experimental.toString()); } + if (params.include_policy_templates) { + url.searchParams.set('include_policy_templates', params.include_policy_templates.toString()); + } } setKibanaVersion(url); diff --git a/x-pack/plugins/fleet/server/services/package_policy.test.ts b/x-pack/plugins/fleet/server/services/package_policy.test.ts index ab2bc944a1932..46e5db3a95864 100644 --- a/x-pack/plugins/fleet/server/services/package_policy.test.ts +++ b/x-pack/plugins/fleet/server/services/package_policy.test.ts @@ -34,6 +34,12 @@ paths: {{#each paths}} - {{this}} {{/each}} +{{#if hosts}} +hosts: +{{#each hosts}} +- {{this}} +{{/each}} +{{/if}} `), }, ]; @@ -118,6 +124,7 @@ describe('Package policy service', () => { }, ], } as unknown) as PackageInfo, + {}, [ { type: 'log', @@ -180,6 +187,7 @@ describe('Package policy service', () => { }, ], } as unknown) as PackageInfo, + {}, [ { type: 'log', @@ -231,6 +239,74 @@ describe('Package policy service', () => { }, ], } as unknown) as PackageInfo, + {}, + [ + { + type: 'log', + enabled: true, + vars: { + paths: { + value: ['/var/log/set.log'], + }, + }, + streams: [ + { + id: 'datastream01', + data_stream: { dataset: 'package.dataset1', type: 'logs' }, + enabled: true, + }, + ], + }, + ] + ); + + expect(inputs).toEqual([ + { + type: 'log', + enabled: true, + vars: { + paths: { + value: ['/var/log/set.log'], + }, + }, + streams: [ + { + id: 'datastream01', + data_stream: { dataset: 'package.dataset1', type: 'logs' }, + enabled: true, + compiled_stream: { + metricset: ['dataset1'], + paths: ['/var/log/set.log'], + type: 'log', + }, + }, + ], + }, + ]); + }); + + it('should work with config variables at the package level', async () => { + const inputs = await packagePolicyService.compilePackagePolicyInputs( + ({ + data_streams: [ + { + dataset: 'package.dataset1', + type: 'logs', + streams: [{ input: 'log', template_path: 'some_template_path.yml' }], + path: 'dataset1', + }, + ], + policy_templates: [ + { + inputs: [{ type: 'log' }], + }, + ], + } as unknown) as PackageInfo, + { + hosts: { + value: ['localhost'], + }, + }, [ { type: 'log', @@ -269,6 +345,7 @@ describe('Package policy service', () => { metricset: ['dataset1'], paths: ['/var/log/set.log'], type: 'log', + hosts: ['localhost'], }, }, ], @@ -286,6 +363,7 @@ describe('Package policy service', () => { }, ], } as unknown) as PackageInfo, + {}, [ { type: 'log', @@ -334,6 +412,7 @@ describe('Package policy service', () => { }, ], } as unknown) as PackageInfo, + {}, [ { type: 'log', @@ -380,6 +459,7 @@ describe('Package policy service', () => { compiled_stream: { metricset: ['dataset1'], paths: ['/var/log/set.log'], + hosts: ['localhost'], type: 'log', }, }, @@ -397,6 +477,7 @@ describe('Package policy service', () => { }, ], } as unknown) as PackageInfo, + {}, [] ); @@ -412,6 +493,7 @@ describe('Package policy service', () => { }, ], } as unknown) as PackageInfo, + {}, [] ); diff --git a/x-pack/plugins/fleet/server/services/package_policy.ts b/x-pack/plugins/fleet/server/services/package_policy.ts index 7c870415bc521..19ff55fbf2e73 100644 --- a/x-pack/plugins/fleet/server/services/package_policy.ts +++ b/x-pack/plugins/fleet/server/services/package_policy.ts @@ -128,7 +128,7 @@ class PackagePolicyService { } } - inputs = await this.compilePackagePolicyInputs(pkgInfo, inputs); + inputs = await this.compilePackagePolicyInputs(pkgInfo, packagePolicy.vars || {}, inputs); } const isoDate = new Date().toISOString(); @@ -356,7 +356,7 @@ class PackagePolicyService { pkgVersion: packagePolicy.package.version, }); - inputs = await this.compilePackagePolicyInputs(pkgInfo, inputs); + inputs = await this.compilePackagePolicyInputs(pkgInfo, packagePolicy.vars || {}, inputs); } await soClient.update( @@ -432,7 +432,7 @@ class PackagePolicyService { ): Promise { const pkgInstall = await getInstallation({ savedObjectsClient: soClient, pkgName }); if (pkgInstall) { - const [pkgInfo, defaultOutputId] = await Promise.all([ + const [packageInfo, defaultOutputId] = await Promise.all([ getPackageInfo({ savedObjectsClient: soClient, pkgName: pkgInstall.name, @@ -440,23 +440,24 @@ class PackagePolicyService { }), outputService.getDefaultOutputId(soClient), ]); - if (pkgInfo) { + if (packageInfo) { if (!defaultOutputId) { throw new Error('Default output is not set'); } - return packageToPackagePolicy(pkgInfo, '', defaultOutputId); + return packageToPackagePolicy(packageInfo, '', defaultOutputId); } } } public async compilePackagePolicyInputs( pkgInfo: PackageInfo, + vars: PackagePolicy['vars'], inputs: PackagePolicyInput[] ): Promise { const registryPkgInfo = await Registry.fetchInfo(pkgInfo.name, pkgInfo.version); const inputsPromises = inputs.map(async (input) => { - const compiledInput = await _compilePackagePolicyInput(registryPkgInfo, pkgInfo, input); - const compiledStreams = await _compilePackageStreams(registryPkgInfo, pkgInfo, input); + const compiledInput = await _compilePackagePolicyInput(registryPkgInfo, pkgInfo, vars, input); + const compiledStreams = await _compilePackageStreams(registryPkgInfo, pkgInfo, vars, input); return { ...input, compiled_input: compiledInput, @@ -506,6 +507,7 @@ function assignStreamIdToInput(packagePolicyId: string, input: NewPackagePolicyI async function _compilePackagePolicyInput( registryPkgInfo: RegistryPackage, pkgInfo: PackageInfo, + vars: PackagePolicy['vars'], input: PackagePolicyInput ) { if ((!input.enabled || !pkgInfo.policy_templates?.[0]?.inputs?.length) ?? 0 > 0) { @@ -531,8 +533,8 @@ async function _compilePackagePolicyInput( } return compileTemplate( - // Populate template variables from input vars - Object.assign({}, input.vars), + // Populate template variables from package- and input-level vars + Object.assign({}, vars, input.vars), pkgInputTemplate.buffer.toString() ); } @@ -540,10 +542,11 @@ async function _compilePackagePolicyInput( async function _compilePackageStreams( registryPkgInfo: RegistryPackage, pkgInfo: PackageInfo, + vars: PackagePolicy['vars'], input: PackagePolicyInput ) { const streamsPromises = input.streams.map((stream) => - _compilePackageStream(registryPkgInfo, pkgInfo, input, stream) + _compilePackageStream(registryPkgInfo, pkgInfo, vars, input, stream) ); return await Promise.all(streamsPromises); @@ -552,6 +555,7 @@ async function _compilePackageStreams( async function _compilePackageStream( registryPkgInfo: RegistryPackage, pkgInfo: PackageInfo, + vars: PackagePolicy['vars'], input: PackagePolicyInput, stream: PackagePolicyInputStream ) { @@ -600,8 +604,8 @@ async function _compilePackageStream( } const yaml = compileTemplate( - // Populate template variables from input vars and stream vars - Object.assign({}, input.vars, stream.vars), + // Populate template variables from package-, input-, and stream-level vars + Object.assign({}, vars, input.vars, stream.vars), pkgStreamTemplate.buffer.toString() ); diff --git a/x-pack/plugins/fleet/server/types/index.tsx b/x-pack/plugins/fleet/server/types/index.tsx index 886b4a26b833b..a48a389ae689e 100644 --- a/x-pack/plugins/fleet/server/types/index.tsx +++ b/x-pack/plugins/fleet/server/types/index.tsx @@ -71,6 +71,7 @@ export { InstallType, InstallSource, InstallResult, + GetCategoriesRequest, DataType, dataTypes, // Fleet Server types diff --git a/x-pack/plugins/fleet/server/types/models/package_policy.ts b/x-pack/plugins/fleet/server/types/models/package_policy.ts index fa467a4185bd4..cbf311cac4e3b 100644 --- a/x-pack/plugins/fleet/server/types/models/package_policy.ts +++ b/x-pack/plugins/fleet/server/types/models/package_policy.ts @@ -77,6 +77,7 @@ const PackagePolicyBaseSchema = { ), }) ), + vars: schema.maybe(ConfigRecordSchema), }; export const NewPackagePolicySchema = schema.object({ diff --git a/x-pack/plugins/fleet/server/types/rest_spec/epm.ts b/x-pack/plugins/fleet/server/types/rest_spec/epm.ts index f7e3ed906e24b..25f1e766a7476 100644 --- a/x-pack/plugins/fleet/server/types/rest_spec/epm.ts +++ b/x-pack/plugins/fleet/server/types/rest_spec/epm.ts @@ -10,6 +10,7 @@ import { schema } from '@kbn/config-schema'; export const GetCategoriesRequestSchema = { query: schema.object({ experimental: schema.maybe(schema.boolean()), + include_policy_templates: schema.maybe(schema.boolean()), }), }; 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 4a86d7fd4de77..fa7ee84441a9b 100644 --- a/x-pack/plugins/security_solution/common/endpoint/generate_data.ts +++ b/x-pack/plugins/security_solution/common/endpoint/generate_data.ts @@ -1302,6 +1302,7 @@ export class EndpointDocGenerator extends BaseDataGenerator { */ public generateEpmPackage(): GetPackagesResponse['response'][0] { return { + id: this.seededUUIDv4(), name: 'endpoint', title: 'Elastic Endpoint', version: '0.5.0', From 507da3ee8bbfb0d987154b32363b9cc2ac2245ec Mon Sep 17 00:00:00 2001 From: Jonathan Budzenski Date: Wed, 26 May 2021 13:03:21 -0500 Subject: [PATCH 03/77] [docker] Set server.shutdownTimeout to match default docker stop timeout (#100494) --- .../docker_generator/templates/kibana_yml.template.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/dev/build/tasks/os_packages/docker_generator/templates/kibana_yml.template.ts b/src/dev/build/tasks/os_packages/docker_generator/templates/kibana_yml.template.ts index c8eb16530507f..e22d8ecdd4fd8 100644 --- a/src/dev/build/tasks/os_packages/docker_generator/templates/kibana_yml.template.ts +++ b/src/dev/build/tasks/os_packages/docker_generator/templates/kibana_yml.template.ts @@ -18,6 +18,7 @@ function generator({ imageFlavor }: TemplateContext) { # Default Kibana configuration for docker target server.host: "0.0.0.0" + server.shutdownTimeout: "5s" elasticsearch.hosts: [ "http://elasticsearch:9200" ] ${!imageFlavor ? 'monitoring.ui.container.elasticsearch.enabled: true' : ''} `); From 04a3620ec93df31c8e73cffd7e90f2c607c50769 Mon Sep 17 00:00:00 2001 From: spalger Date: Wed, 26 May 2021 11:24:20 -0700 Subject: [PATCH 04/77] enable es client renovate prs for 7.13 (#100645) --- renovate.json5 | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/renovate.json5 b/renovate.json5 index a72d4408478a2..e33a1108afef6 100644 --- a/renovate.json5 +++ b/renovate.json5 @@ -57,6 +57,14 @@ labels: ['release_note:skip', 'v7.14.0', 'Team:Operations', 'Team:Core', 'backport:skip'], enabled: true, }, + { + groupName: '@elastic/elasticsearch', + packageNames: ['@elastic/elasticsearch'], + reviewers: ['team:kibana-operations'], + matchBaseBranches: ['7.13'], + labels: ['release_note:skip', 'v7.13.0', 'Team:Operations', 'backport:skip'], + enabled: true, + }, { groupName: 'vega related modules', packageNames: ['vega', 'vega-lite', 'vega-schema-url-parser', 'vega-tooltip'], From 58f45eeeb3cf7eb2f89674bd614a54faf0172866 Mon Sep 17 00:00:00 2001 From: spalger Date: Wed, 26 May 2021 11:25:25 -0700 Subject: [PATCH 05/77] include 7.13 as a possible base branch of renovate prs --- renovate.json5 | 1 + 1 file changed, 1 insertion(+) diff --git a/renovate.json5 b/renovate.json5 index e33a1108afef6..f533eac479650 100644 --- a/renovate.json5 +++ b/renovate.json5 @@ -12,6 +12,7 @@ baseBranches: [ 'master', '7.x', + '7.13', ], prConcurrentLimit: 0, prHourlyLimit: 0, From e682b55c87358859fc1fddb9c5c754d10a70b428 Mon Sep 17 00:00:00 2001 From: Spencer Date: Wed, 26 May 2021 11:40:02 -0700 Subject: [PATCH 06/77] [ftr] migrate dashboard services to FtrService class (#100519) Co-authored-by: spalger --- .../services/dashboard/add_panel.ts | 452 +++++++------ .../services/dashboard/expectations.ts | 454 ++++++------- test/functional/services/dashboard/index.ts | 10 +- .../services/dashboard/panel_actions.ts | 596 +++++++++--------- .../services/dashboard/replace_panel.ts | 136 ++-- .../services/dashboard/visualizations.ts | 188 +++--- test/functional/services/index.ts | 20 +- 7 files changed, 928 insertions(+), 928 deletions(-) diff --git a/test/functional/services/dashboard/add_panel.ts b/test/functional/services/dashboard/add_panel.ts index a4e0c8b2647dd..98e947541b52d 100644 --- a/test/functional/services/dashboard/add_panel.ts +++ b/test/functional/services/dashboard/add_panel.ts @@ -6,235 +6,233 @@ * Side Public License, v 1. */ -import { FtrProviderContext } from '../../ftr_provider_context'; - -export function DashboardAddPanelProvider({ getService, getPageObjects }: FtrProviderContext) { - const log = getService('log'); - const retry = getService('retry'); - const testSubjects = getService('testSubjects'); - const flyout = getService('flyout'); - const PageObjects = getPageObjects(['header', 'common']); - - return new (class DashboardAddPanel { - async clickOpenAddPanel() { - log.debug('DashboardAddPanel.clickOpenAddPanel'); - await testSubjects.click('dashboardAddPanelButton'); - // Give some time for the animation to complete - await PageObjects.common.sleep(500); - } - - async clickCreateNewLink() { - log.debug('DashboardAddPanel.clickAddNewPanelButton'); - await testSubjects.click('dashboardAddNewPanelButton'); - // Give some time for the animation to complete - await PageObjects.common.sleep(500); - } - - async clickQuickButton(visType: string) { - log.debug(`DashboardAddPanel.clickQuickButton${visType}`); - await testSubjects.click(`dashboardQuickButton${visType}`); - } - - async clickMarkdownQuickButton() { - await this.clickQuickButton('markdown'); - } - - async clickMapQuickButton() { - await this.clickQuickButton('map'); - } - - async clickEditorMenuButton() { - log.debug('DashboardAddPanel.clickEditorMenuButton'); - await testSubjects.click('dashboardEditorMenuButton'); - } - - async clickAggBasedVisualizations() { - log.debug('DashboardAddPanel.clickEditorMenuAggBasedMenuItem'); - await testSubjects.click('dashboardEditorAggBasedMenuItem'); - } - - async clickVisType(visType: string) { - log.debug('DashboardAddPanel.clickVisType'); - await testSubjects.click(`visType-${visType}`); - } - - async clickEmbeddableFactoryGroupButton(groupId: string) { - log.debug('DashboardAddPanel.clickEmbeddableFactoryGroupButton'); - await testSubjects.click(`dashboardEditorMenu-${groupId}Group`); - } - - async clickAddNewEmbeddableLink(type: string) { - await testSubjects.click(`createNew-${type}`); - } - - async toggleFilterPopover() { - log.debug('DashboardAddPanel.toggleFilter'); - await testSubjects.click('savedObjectFinderFilterButton'); - } - - async toggleFilter(type: string) { - log.debug(`DashboardAddPanel.addToFilter(${type})`); - await this.waitForListLoading(); - await this.toggleFilterPopover(); - await testSubjects.click(`savedObjectFinderFilter-${type}`); - await this.toggleFilterPopover(); - } - - async addEveryEmbeddableOnCurrentPage() { - log.debug('addEveryEmbeddableOnCurrentPage'); - const itemList = await testSubjects.find('savedObjectFinderItemList'); - const embeddableList: string[] = []; - await retry.try(async () => { - const embeddableRows = await itemList.findAllByCssSelector('li'); - for (let i = 0; i < embeddableRows.length; i++) { - const name = await embeddableRows[i].getVisibleText(); - - if (embeddableList.includes(name)) { - // already added this one - continue; - } - - await embeddableRows[i].click(); - await PageObjects.common.closeToast(); - embeddableList.push(name); +import { FtrService } from '../../ftr_provider_context'; + +export class DashboardAddPanelService extends FtrService { + private readonly log = this.ctx.getService('log'); + private readonly retry = this.ctx.getService('retry'); + private readonly testSubjects = this.ctx.getService('testSubjects'); + private readonly flyout = this.ctx.getService('flyout'); + private readonly PageObjects = this.ctx.getPageObjects(['header', 'common']); + + async clickOpenAddPanel() { + this.log.debug('DashboardAddPanel.clickOpenAddPanel'); + await this.testSubjects.click('dashboardAddPanelButton'); + // Give some time for the animation to complete + await this.PageObjects.common.sleep(500); + } + + async clickCreateNewLink() { + this.log.debug('DashboardAddPanel.clickAddNewPanelButton'); + await this.testSubjects.click('dashboardAddNewPanelButton'); + // Give some time for the animation to complete + await this.PageObjects.common.sleep(500); + } + + async clickQuickButton(visType: string) { + this.log.debug(`DashboardAddPanel.clickQuickButton${visType}`); + await this.testSubjects.click(`dashboardQuickButton${visType}`); + } + + async clickMarkdownQuickButton() { + await this.clickQuickButton('markdown'); + } + + async clickMapQuickButton() { + await this.clickQuickButton('map'); + } + + async clickEditorMenuButton() { + this.log.debug('DashboardAddPanel.clickEditorMenuButton'); + await this.testSubjects.click('dashboardEditorMenuButton'); + } + + async clickAggBasedVisualizations() { + this.log.debug('DashboardAddPanel.clickEditorMenuAggBasedMenuItem'); + await this.testSubjects.click('dashboardEditorAggBasedMenuItem'); + } + + async clickVisType(visType: string) { + this.log.debug('DashboardAddPanel.clickVisType'); + await this.testSubjects.click(`visType-${visType}`); + } + + async clickEmbeddableFactoryGroupButton(groupId: string) { + this.log.debug('DashboardAddPanel.clickEmbeddableFactoryGroupButton'); + await this.testSubjects.click(`dashboardEditorMenu-${groupId}Group`); + } + + async clickAddNewEmbeddableLink(type: string) { + await this.testSubjects.click(`createNew-${type}`); + } + + async toggleFilterPopover() { + this.log.debug('DashboardAddPanel.toggleFilter'); + await this.testSubjects.click('savedObjectFinderFilterButton'); + } + + async toggleFilter(type: string) { + this.log.debug(`DashboardAddPanel.addToFilter(${type})`); + await this.waitForListLoading(); + await this.toggleFilterPopover(); + await this.testSubjects.click(`savedObjectFinderFilter-${type}`); + await this.toggleFilterPopover(); + } + + async addEveryEmbeddableOnCurrentPage() { + this.log.debug('addEveryEmbeddableOnCurrentPage'); + const itemList = await this.testSubjects.find('savedObjectFinderItemList'); + const embeddableList: string[] = []; + await this.retry.try(async () => { + const embeddableRows = await itemList.findAllByCssSelector('li'); + for (let i = 0; i < embeddableRows.length; i++) { + const name = await embeddableRows[i].getVisibleText(); + + if (embeddableList.includes(name)) { + // already added this one + continue; } - }); - log.debug(`Added ${embeddableList.length} embeddables`); - return embeddableList; - } - - async clickPagerNextButton() { - // Clear all toasts that could hide pagination controls - await PageObjects.common.clearAllToasts(); - - const isNext = await testSubjects.exists('pagination-button-next'); - if (!isNext) { - return false; - } - - const pagerNextButton = await testSubjects.find('pagination-button-next'); - - const isDisabled = await pagerNextButton.getAttribute('disabled'); - if (isDisabled != null) { - return false; - } - - await PageObjects.header.waitUntilLoadingHasFinished(); - await pagerNextButton.click(); - await PageObjects.header.waitUntilLoadingHasFinished(); - return true; - } - - async isAddPanelOpen() { - log.debug('DashboardAddPanel.isAddPanelOpen'); - return await testSubjects.exists('dashboardAddPanel'); - } - async ensureAddPanelIsShowing() { - log.debug('DashboardAddPanel.ensureAddPanelIsShowing'); - const isOpen = await this.isAddPanelOpen(); - if (!isOpen) { - await retry.try(async () => { - await this.clickOpenAddPanel(); - const isNowOpen = await this.isAddPanelOpen(); - if (!isNowOpen) { - throw new Error('Add panel still not open, trying again.'); - } - }); + await embeddableRows[i].click(); + await this.PageObjects.common.closeToast(); + embeddableList.push(name); } + }); + this.log.debug(`Added ${embeddableList.length} embeddables`); + return embeddableList; + } + + async clickPagerNextButton() { + // Clear all toasts that could hide pagination controls + await this.PageObjects.common.clearAllToasts(); + + const isNext = await this.testSubjects.exists('pagination-button-next'); + if (!isNext) { + return false; + } + + const pagerNextButton = await this.testSubjects.find('pagination-button-next'); + + const isDisabled = await pagerNextButton.getAttribute('disabled'); + if (isDisabled != null) { + return false; + } + + await this.PageObjects.header.waitUntilLoadingHasFinished(); + await pagerNextButton.click(); + await this.PageObjects.header.waitUntilLoadingHasFinished(); + return true; + } + + async isAddPanelOpen() { + this.log.debug('DashboardAddPanel.isAddPanelOpen'); + return await this.testSubjects.exists('dashboardAddPanel'); + } + + async ensureAddPanelIsShowing() { + this.log.debug('DashboardAddPanel.ensureAddPanelIsShowing'); + const isOpen = await this.isAddPanelOpen(); + if (!isOpen) { + await this.retry.try(async () => { + await this.clickOpenAddPanel(); + const isNowOpen = await this.isAddPanelOpen(); + if (!isNowOpen) { + throw new Error('Add panel still not open, trying again.'); + } + }); } - - async waitForListLoading() { - await testSubjects.waitForDeleted('savedObjectFinderLoadingIndicator'); - } - - async closeAddPanel() { - await flyout.ensureClosed('dashboardAddPanel'); - } - - async addEveryVisualization(filter: string) { - log.debug('DashboardAddPanel.addEveryVisualization'); - await this.ensureAddPanelIsShowing(); - await this.toggleFilter('visualization'); - if (filter) { - await this.filterEmbeddableNames(filter.replace('-', ' ')); - } - let morePages = true; - const vizList: string[][] = []; - while (morePages) { - vizList.push(await this.addEveryEmbeddableOnCurrentPage()); - morePages = await this.clickPagerNextButton(); - } - await this.closeAddPanel(); - return vizList.reduce((acc, list) => [...acc, ...list], []); - } - - async addEverySavedSearch(filter: string) { - log.debug('DashboardAddPanel.addEverySavedSearch'); - await this.ensureAddPanelIsShowing(); - await this.toggleFilter('search'); - const searchList = []; - if (filter) { - await this.filterEmbeddableNames(filter.replace('-', ' ')); - } - let morePages = true; - while (morePages) { - searchList.push(await this.addEveryEmbeddableOnCurrentPage()); - morePages = await this.clickPagerNextButton(); - } - await this.closeAddPanel(); - return searchList.reduce((acc, list) => [...acc, ...list], []); - } - - async addSavedSearch(searchName: string) { - return this.addEmbeddable(searchName, 'search'); - } - - async addSavedSearches(searches: string[]) { - for (const name of searches) { - await this.addSavedSearch(name); - } - } - - async addVisualizations(visualizations: string[]) { - log.debug('DashboardAddPanel.addVisualizations'); - const vizList = []; - for (const vizName of visualizations) { - await this.addVisualization(vizName); - vizList.push(vizName); - } - return vizList; - } - - async addVisualization(vizName: string) { - return this.addEmbeddable(vizName, 'visualization'); - } - - async addEmbeddable(embeddableName: string, embeddableType: string) { - log.debug( - `DashboardAddPanel.addEmbeddable, name: ${embeddableName}, type: ${embeddableType}` - ); - await this.ensureAddPanelIsShowing(); - await this.toggleFilter(embeddableType); - await this.filterEmbeddableNames(`"${embeddableName.replace('-', ' ')}"`); - await testSubjects.click(`savedObjectTitle${embeddableName.split(' ').join('-')}`); - await testSubjects.exists('addObjectToDashboardSuccess'); - await this.closeAddPanel(); - return embeddableName; - } - - async filterEmbeddableNames(name: string) { - // The search input field may be disabled while the table is loading so wait for it - await this.waitForListLoading(); - await testSubjects.setValue('savedObjectFinderSearchInput', name); - await this.waitForListLoading(); - } - - async panelAddLinkExists(name: string) { - log.debug(`DashboardAddPanel.panelAddLinkExists(${name})`); - await this.ensureAddPanelIsShowing(); - await this.filterEmbeddableNames(`"${name}"`); - return await testSubjects.exists(`savedObjectTitle${name.split(' ').join('-')}`); - } - })(); + } + + async waitForListLoading() { + await this.testSubjects.waitForDeleted('savedObjectFinderLoadingIndicator'); + } + + async closeAddPanel() { + await this.flyout.ensureClosed('dashboardAddPanel'); + } + + async addEveryVisualization(filter: string) { + this.log.debug('DashboardAddPanel.addEveryVisualization'); + await this.ensureAddPanelIsShowing(); + await this.toggleFilter('visualization'); + if (filter) { + await this.filterEmbeddableNames(filter.replace('-', ' ')); + } + let morePages = true; + const vizList: string[][] = []; + while (morePages) { + vizList.push(await this.addEveryEmbeddableOnCurrentPage()); + morePages = await this.clickPagerNextButton(); + } + await this.closeAddPanel(); + return vizList.reduce((acc, list) => [...acc, ...list], []); + } + + async addEverySavedSearch(filter: string) { + this.log.debug('DashboardAddPanel.addEverySavedSearch'); + await this.ensureAddPanelIsShowing(); + await this.toggleFilter('search'); + const searchList = []; + if (filter) { + await this.filterEmbeddableNames(filter.replace('-', ' ')); + } + let morePages = true; + while (morePages) { + searchList.push(await this.addEveryEmbeddableOnCurrentPage()); + morePages = await this.clickPagerNextButton(); + } + await this.closeAddPanel(); + return searchList.reduce((acc, list) => [...acc, ...list], []); + } + + async addSavedSearch(searchName: string) { + return this.addEmbeddable(searchName, 'search'); + } + + async addSavedSearches(searches: string[]) { + for (const name of searches) { + await this.addSavedSearch(name); + } + } + + async addVisualizations(visualizations: string[]) { + this.log.debug('DashboardAddPanel.addVisualizations'); + const vizList = []; + for (const vizName of visualizations) { + await this.addVisualization(vizName); + vizList.push(vizName); + } + return vizList; + } + + async addVisualization(vizName: string) { + return this.addEmbeddable(vizName, 'visualization'); + } + + async addEmbeddable(embeddableName: string, embeddableType: string) { + this.log.debug( + `DashboardAddPanel.addEmbeddable, name: ${embeddableName}, type: ${embeddableType}` + ); + await this.ensureAddPanelIsShowing(); + await this.toggleFilter(embeddableType); + await this.filterEmbeddableNames(`"${embeddableName.replace('-', ' ')}"`); + await this.testSubjects.click(`savedObjectTitle${embeddableName.split(' ').join('-')}`); + await this.testSubjects.exists('addObjectToDashboardSuccess'); + await this.closeAddPanel(); + return embeddableName; + } + + async filterEmbeddableNames(name: string) { + // The search input field may be disabled while the table is loading so wait for it + await this.waitForListLoading(); + await this.testSubjects.setValue('savedObjectFinderSearchInput', name); + await this.waitForListLoading(); + } + + async panelAddLinkExists(name: string) { + this.log.debug(`DashboardAddPanel.panelAddLinkExists(${name})`); + await this.ensureAddPanelIsShowing(); + await this.filterEmbeddableNames(`"${name}"`); + return await this.testSubjects.exists(`savedObjectTitle${name.split(' ').join('-')}`); + } } diff --git a/test/functional/services/dashboard/expectations.ts b/test/functional/services/dashboard/expectations.ts index c58fdd4d0305b..34a4a9de7899a 100644 --- a/test/functional/services/dashboard/expectations.ts +++ b/test/functional/services/dashboard/expectations.ts @@ -7,263 +7,271 @@ */ import expect from '@kbn/expect'; -import { FtrProviderContext } from '../../ftr_provider_context'; +import { FtrService } from '../../ftr_provider_context'; import { WebElementWrapper } from '../lib/web_element_wrapper'; -export function DashboardExpectProvider({ getService, getPageObjects }: FtrProviderContext) { - const log = getService('log'); - const retry = getService('retry'); - const testSubjects = getService('testSubjects'); - const find = getService('find'); - const filterBar = getService('filterBar'); - const PageObjects = getPageObjects(['dashboard', 'visualize', 'visChart']); - const findTimeout = 2500; +export class DashboardExpectService extends FtrService { + private readonly log = this.ctx.getService('log'); + private readonly retry = this.ctx.getService('retry'); + private readonly testSubjects = this.ctx.getService('testSubjects'); + private readonly find = this.ctx.getService('find'); + private readonly filterBar = this.ctx.getService('filterBar'); + private readonly PageObjects = this.ctx.getPageObjects(['dashboard', 'visualize', 'visChart']); + private readonly findTimeout = 2500; - return new (class DashboardExpect { - async panelCount(expectedCount: number) { - log.debug(`DashboardExpect.panelCount(${expectedCount})`); - await retry.try(async () => { - const panelCount = await PageObjects.dashboard.getPanelCount(); - expect(panelCount).to.be(expectedCount); - }); - } + async panelCount(expectedCount: number) { + this.log.debug(`DashboardExpect.panelCount(${expectedCount})`); + await this.retry.try(async () => { + const panelCount = await this.PageObjects.dashboard.getPanelCount(); + expect(panelCount).to.be(expectedCount); + }); + } - async visualizationsArePresent(vizList: string[]) { - log.debug('Checking all visualisations are present on dashsboard'); - let notLoaded = await PageObjects.dashboard.getNotLoadedVisualizations(vizList); - // TODO: Determine issue occasionally preventing 'geo map' from loading - notLoaded = notLoaded.filter((x) => x !== 'Rendering Test: geo map'); - expect(notLoaded).to.be.empty(); - } + async visualizationsArePresent(vizList: string[]) { + this.log.debug('Checking all visualisations are present on dashsboard'); + let notLoaded = await this.PageObjects.dashboard.getNotLoadedVisualizations(vizList); + // TODO: Determine issue occasionally preventing 'geo map' from loading + notLoaded = notLoaded.filter((x) => x !== 'Rendering Test: geo map'); + expect(notLoaded).to.be.empty(); + } - async selectedLegendColorCount(color: string, expectedCount: number) { - log.debug(`DashboardExpect.selectedLegendColorCount(${color}, ${expectedCount})`); - await retry.try(async () => { - const selectedLegendColor = await testSubjects.findAll( - `legendSelectedColor-${color}`, - findTimeout - ); - expect(selectedLegendColor.length).to.be(expectedCount); - }); - } + async selectedLegendColorCount(color: string, expectedCount: number) { + this.log.debug(`DashboardExpect.selectedLegendColorCount(${color}, ${expectedCount})`); + await this.retry.try(async () => { + const selectedLegendColor = await this.testSubjects.findAll( + `legendSelectedColor-${color}`, + this.findTimeout + ); + expect(selectedLegendColor.length).to.be(expectedCount); + }); + } - async docTableFieldCount(expectedCount: number) { - log.debug(`DashboardExpect.docTableFieldCount(${expectedCount})`); - await retry.try(async () => { - const docTableCells = await testSubjects.findAll('docTableField', findTimeout); - expect(docTableCells.length).to.be(expectedCount); - }); - } + async docTableFieldCount(expectedCount: number) { + this.log.debug(`DashboardExpect.docTableFieldCount(${expectedCount})`); + await this.retry.try(async () => { + const docTableCells = await this.testSubjects.findAll('docTableField', this.findTimeout); + expect(docTableCells.length).to.be(expectedCount); + }); + } - async fieldSuggestions(expectedFields: string[]) { - log.debug(`DashboardExpect.fieldSuggestions(${expectedFields})`); - const fields = await filterBar.getFilterEditorFields(); - expectedFields.forEach((expectedField) => { - expect(fields).to.contain(expectedField); - }); - } + async fieldSuggestions(expectedFields: string[]) { + this.log.debug(`DashboardExpect.fieldSuggestions(${expectedFields})`); + const fields = await this.filterBar.getFilterEditorFields(); + expectedFields.forEach((expectedField) => { + expect(fields).to.contain(expectedField); + }); + } + + async legendValuesToExist(legendValues: string[]) { + this.log.debug(`DashboardExpect.legendValuesToExist(${legendValues})`); + await Promise.all( + legendValues.map(async (legend) => { + await this.retry.try(async () => { + const legendValueExists = await this.testSubjects.exists(`legend-${legend}`); + expect(legendValueExists).to.be(true); + }); + }) + ); + } - async legendValuesToExist(legendValues: string[]) { - log.debug(`DashboardExpect.legendValuesToExist(${legendValues})`); + async textWithinElementsExists(texts: string[], getElementsFn: Function) { + this.log.debug(`DashboardExpect.textWithinElementsExists(${texts})`); + await this.retry.try(async () => { + const elements: WebElementWrapper[] = await getElementsFn(); + const elementTexts: string[] = []; await Promise.all( - legendValues.map(async (legend) => { - await retry.try(async () => { - const legendValueExists = await testSubjects.exists(`legend-${legend}`); - expect(legendValueExists).to.be(true); - }); + elements.map(async (element) => { + elementTexts.push(await element.getVisibleText()); }) ); - } - - async textWithinElementsExists(texts: string[], getElementsFn: Function) { - log.debug(`DashboardExpect.textWithinElementsExists(${texts})`); - await retry.try(async () => { - const elements: WebElementWrapper[] = await getElementsFn(); - const elementTexts: string[] = []; - await Promise.all( - elements.map(async (element) => { - elementTexts.push(await element.getVisibleText()); - }) - ); - log.debug(`Found ${elements.length} elements with values: ${JSON.stringify(elementTexts)}`); - texts.forEach((value) => { - const indexOfValue = elementTexts.indexOf(value); - expect(indexOfValue).to.be.greaterThan(-1); - elementTexts.splice(indexOfValue, 1); - }); + this.log.debug( + `Found ${elements.length} elements with values: ${JSON.stringify(elementTexts)}` + ); + texts.forEach((value) => { + const indexOfValue = elementTexts.indexOf(value); + expect(indexOfValue).to.be.greaterThan(-1); + elementTexts.splice(indexOfValue, 1); }); - } + }); + } - async textWithinTestSubjectsExists(texts: string[], selector: string) { - log.debug(`DashboardExpect.textWithinTestSubjectsExists(${texts})`); - log.debug(`textWithinTestSubjectsExists:(${JSON.stringify(texts)},${selector})`); - await this.textWithinElementsExists(texts, async () => await testSubjects.findAll(selector)); - } + async textWithinTestSubjectsExists(texts: string[], selector: string) { + this.log.debug(`DashboardExpect.textWithinTestSubjectsExists(${texts})`); + this.log.debug(`textWithinTestSubjectsExists:(${JSON.stringify(texts)},${selector})`); + await this.textWithinElementsExists( + texts, + async () => await this.testSubjects.findAll(selector) + ); + } - async textWithinCssElementExists(texts: string[], selector: string) { - log.debug(`DashboardExpect.textWithinCssElementExists(${texts})`); - log.debug(`textWithinCssElementExists:(${JSON.stringify(texts)},${selector})`); - await this.textWithinElementsExists(texts, async () => await find.allByCssSelector(selector)); - } + async textWithinCssElementExists(texts: string[], selector: string) { + this.log.debug(`DashboardExpect.textWithinCssElementExists(${texts})`); + this.log.debug(`textWithinCssElementExists:(${JSON.stringify(texts)},${selector})`); + await this.textWithinElementsExists( + texts, + async () => await this.find.allByCssSelector(selector) + ); + } - async textWithinElementsDoNotExist(texts: string[], getElementsFn: Function) { - log.debug(`DashboardExpect.textWithinElementsDoNotExist(${texts})`); - await retry.try(async () => { - const elements: WebElementWrapper[] = await getElementsFn(); - const elementTexts: string[] = []; - await Promise.all( - elements.map(async (element) => { - elementTexts.push(await element.getVisibleText()); - }) - ); - log.debug(`Found ${elements.length} elements with values: ${JSON.stringify(elementTexts)}`); - texts.forEach((value) => { - const indexOfValue = elementTexts.indexOf(value); - expect(indexOfValue).to.be(-1); - }); + async textWithinElementsDoNotExist(texts: string[], getElementsFn: Function) { + this.log.debug(`DashboardExpect.textWithinElementsDoNotExist(${texts})`); + await this.retry.try(async () => { + const elements: WebElementWrapper[] = await getElementsFn(); + const elementTexts: string[] = []; + await Promise.all( + elements.map(async (element) => { + elementTexts.push(await element.getVisibleText()); + }) + ); + this.log.debug( + `Found ${elements.length} elements with values: ${JSON.stringify(elementTexts)}` + ); + texts.forEach((value) => { + const indexOfValue = elementTexts.indexOf(value); + expect(indexOfValue).to.be(-1); }); - } + }); + } - async textWithinCssElementDoNotExist(texts: string[], selector: string) { - log.debug(`textWithinCssElementExists:(${JSON.stringify(texts)},${selector})`); - await this.textWithinElementsDoNotExist( - texts, - async () => await find.allByCssSelector(selector) - ); - } + async textWithinCssElementDoNotExist(texts: string[], selector: string) { + this.log.debug(`textWithinCssElementExists:(${JSON.stringify(texts)},${selector})`); + await this.textWithinElementsDoNotExist( + texts, + async () => await this.find.allByCssSelector(selector) + ); + } - async timelionLegendCount(expectedCount: number) { - log.debug(`DashboardExpect.timelionLegendCount(${expectedCount})`); - await retry.try(async () => { - const flotLegendLabels = await testSubjects.findAll('flotLegendLabel', findTimeout); - expect(flotLegendLabels.length).to.be(expectedCount); - }); - } + async timelionLegendCount(expectedCount: number) { + this.log.debug(`DashboardExpect.timelionLegendCount(${expectedCount})`); + await this.retry.try(async () => { + const flotLegendLabels = await this.testSubjects.findAll('flotLegendLabel', this.findTimeout); + expect(flotLegendLabels.length).to.be(expectedCount); + }); + } - async emptyTagCloudFound() { - log.debug(`DashboardExpect.emptyTagCloudFound()`); - const tagCloudVisualizations = await testSubjects.findAll('tagCloudVisualization'); - const tagCloudsHaveContent = await Promise.all( - tagCloudVisualizations.map(async (tagCloud) => { - return await find.descendantExistsByCssSelector('text', tagCloud); - }) - ); - expect(tagCloudsHaveContent.indexOf(false)).to.be.greaterThan(-1); - } + async emptyTagCloudFound() { + this.log.debug(`DashboardExpect.emptyTagCloudFound()`); + const tagCloudVisualizations = await this.testSubjects.findAll('tagCloudVisualization'); + const tagCloudsHaveContent = await Promise.all( + tagCloudVisualizations.map(async (tagCloud) => { + return await this.find.descendantExistsByCssSelector('text', tagCloud); + }) + ); + expect(tagCloudsHaveContent.indexOf(false)).to.be.greaterThan(-1); + } - async tagCloudWithValuesFound(values: string[]) { - log.debug(`DashboardExpect.tagCloudWithValuesFound(${values})`); - const tagCloudVisualizations = await testSubjects.findAll('tagCloudVisualization'); - const matches = await Promise.all( - tagCloudVisualizations.map(async (tagCloud) => { - for (let i = 0; i < values.length; i++) { - const valueExists = await testSubjects.descendantExists(values[i], tagCloud); - if (!valueExists) { - return false; - } + async tagCloudWithValuesFound(values: string[]) { + this.log.debug(`DashboardExpect.tagCloudWithValuesFound(${values})`); + const tagCloudVisualizations = await this.testSubjects.findAll('tagCloudVisualization'); + const matches = await Promise.all( + tagCloudVisualizations.map(async (tagCloud) => { + for (let i = 0; i < values.length; i++) { + const valueExists = await this.testSubjects.descendantExists(values[i], tagCloud); + if (!valueExists) { + return false; } - return true; - }) - ); - expect(matches.indexOf(true)).to.be.greaterThan(-1); - } + } + return true; + }) + ); + expect(matches.indexOf(true)).to.be.greaterThan(-1); + } - async goalAndGuageLabelsExist(labels: string[]) { - log.debug(`DashboardExpect.goalAndGuageLabelsExist(${labels})`); - await this.textWithinCssElementExists(labels, '.chart-label'); - } + async goalAndGuageLabelsExist(labels: string[]) { + this.log.debug(`DashboardExpect.goalAndGuageLabelsExist(${labels})`); + await this.textWithinCssElementExists(labels, '.chart-label'); + } - async metricValuesExist(values: string[]) { - log.debug(`DashboardExpect.metricValuesExist(${values})`); - await this.textWithinCssElementExists(values, '.mtrVis__value'); - } + async metricValuesExist(values: string[]) { + this.log.debug(`DashboardExpect.metricValuesExist(${values})`); + await this.textWithinCssElementExists(values, '.mtrVis__value'); + } - async tsvbMetricValuesExist(values: string[]) { - log.debug(`DashboardExpect.tsvbMetricValuesExist(${values})`); - await this.textWithinTestSubjectsExists(values, 'tsvbMetricValue'); - } + async tsvbMetricValuesExist(values: string[]) { + this.log.debug(`DashboardExpect.tsvbMetricValuesExist(${values})`); + await this.textWithinTestSubjectsExists(values, 'tsvbMetricValue'); + } - async tsvbTopNValuesExist(values: string[]) { - log.debug(`DashboardExpect.tsvbTopNValuesExist(${values})`); - await this.textWithinTestSubjectsExists(values, 'tsvbTopNValue'); - } + async tsvbTopNValuesExist(values: string[]) { + this.log.debug(`DashboardExpect.tsvbTopNValuesExist(${values})`); + await this.textWithinTestSubjectsExists(values, 'tsvbTopNValue'); + } - async vegaTextsExist(values: string[]) { - log.debug(`DashboardExpect.vegaTextsExist(${values})`); - await this.textWithinCssElementExists(values, '.vgaVis__view text'); - } + async vegaTextsExist(values: string[]) { + this.log.debug(`DashboardExpect.vegaTextsExist(${values})`); + await this.textWithinCssElementExists(values, '.vgaVis__view text'); + } - async vegaTextsDoNotExist(values: string[]) { - log.debug(`DashboardExpect.vegaTextsDoNotExist(${values})`); - await this.textWithinCssElementDoNotExist(values, '.vgaVis__view text'); - } + async vegaTextsDoNotExist(values: string[]) { + this.log.debug(`DashboardExpect.vegaTextsDoNotExist(${values})`); + await this.textWithinCssElementDoNotExist(values, '.vgaVis__view text'); + } - async tsvbMarkdownWithValuesExists(values: string[]) { - log.debug(`DashboardExpect.tsvbMarkdownWithValuesExists(${values})`); - await this.textWithinTestSubjectsExists(values, 'tsvbMarkdown'); - } + async tsvbMarkdownWithValuesExists(values: string[]) { + this.log.debug(`DashboardExpect.tsvbMarkdownWithValuesExists(${values})`); + await this.textWithinTestSubjectsExists(values, 'tsvbMarkdown'); + } - async markdownWithValuesExists(values: string[]) { - log.debug(`DashboardExpect.markdownWithValuesExists(${values})`); - await this.textWithinTestSubjectsExists(values, 'markdownBody'); - } + async markdownWithValuesExists(values: string[]) { + this.log.debug(`DashboardExpect.markdownWithValuesExists(${values})`); + await this.textWithinTestSubjectsExists(values, 'markdownBody'); + } - async savedSearchRowCount(expectedMinCount: number) { - log.debug(`DashboardExpect.savedSearchRowCount(${expectedMinCount})`); - await retry.try(async () => { - const savedSearchRows = await testSubjects.findAll( - 'docTableExpandToggleColumn', - findTimeout - ); - expect(savedSearchRows.length).to.be.above(expectedMinCount); - }); - } + async savedSearchRowCount(expectedMinCount: number) { + this.log.debug(`DashboardExpect.savedSearchRowCount(${expectedMinCount})`); + await this.retry.try(async () => { + const savedSearchRows = await this.testSubjects.findAll( + 'docTableExpandToggleColumn', + this.findTimeout + ); + expect(savedSearchRows.length).to.be.above(expectedMinCount); + }); + } - async dataTableRowCount(expectedCount: number) { - log.debug(`DashboardExpect.dataTableRowCount(${expectedCount})`); - await retry.try(async () => { - const dataTableRows = await PageObjects.visChart.getTableVisContent(); - expect(dataTableRows.length).to.be(expectedCount); - }); - } + async dataTableRowCount(expectedCount: number) { + this.log.debug(`DashboardExpect.dataTableRowCount(${expectedCount})`); + await this.retry.try(async () => { + const dataTableRows = await this.PageObjects.visChart.getTableVisContent(); + expect(dataTableRows.length).to.be(expectedCount); + }); + } - async dataTableNoResult() { - log.debug(`DashboardExpect.dataTableNoResult`); - await retry.try(async () => { - await PageObjects.visChart.getTableVisNoResult(); - }); - } + async dataTableNoResult() { + this.log.debug(`DashboardExpect.dataTableNoResult`); + await this.retry.try(async () => { + await this.PageObjects.visChart.getTableVisNoResult(); + }); + } - async seriesElementCount(expectedCount: number) { - log.debug(`DashboardExpect.seriesElementCount(${expectedCount})`); - await retry.try(async () => { - const seriesElements = await find.allByCssSelector('.series', findTimeout); - expect(seriesElements.length).to.be(expectedCount); - }); - } + async seriesElementCount(expectedCount: number) { + this.log.debug(`DashboardExpect.seriesElementCount(${expectedCount})`); + await this.retry.try(async () => { + const seriesElements = await this.find.allByCssSelector('.series', this.findTimeout); + expect(seriesElements.length).to.be(expectedCount); + }); + } - async inputControlItemCount(expectedCount: number) { - log.debug(`DashboardExpect.inputControlItemCount(${expectedCount})`); - await retry.try(async () => { - const inputControlItems = await testSubjects.findAll('inputControlItem'); - expect(inputControlItems.length).to.be(expectedCount); - }); - } + async inputControlItemCount(expectedCount: number) { + this.log.debug(`DashboardExpect.inputControlItemCount(${expectedCount})`); + await this.retry.try(async () => { + const inputControlItems = await this.testSubjects.findAll('inputControlItem'); + expect(inputControlItems.length).to.be(expectedCount); + }); + } - async lineChartPointsCount(expectedCount: number) { - log.debug(`DashboardExpect.lineChartPointsCount(${expectedCount})`); - await retry.try(async () => { - const points = await find.allByCssSelector('.points', findTimeout); - expect(points.length).to.be(expectedCount); - }); - } + async lineChartPointsCount(expectedCount: number) { + this.log.debug(`DashboardExpect.lineChartPointsCount(${expectedCount})`); + await this.retry.try(async () => { + const points = await this.find.allByCssSelector('.points', this.findTimeout); + expect(points.length).to.be(expectedCount); + }); + } - async tsvbTableCellCount(expectedCount: number) { - log.debug(`DashboardExpect.tsvbTableCellCount(${expectedCount})`); - await retry.try(async () => { - const tableCells = await testSubjects.findAll('tvbTableVis__value', findTimeout); - expect(tableCells.length).to.be(expectedCount); - }); - } - })(); + async tsvbTableCellCount(expectedCount: number) { + this.log.debug(`DashboardExpect.tsvbTableCellCount(${expectedCount})`); + await this.retry.try(async () => { + const tableCells = await this.testSubjects.findAll('tvbTableVis__value', this.findTimeout); + expect(tableCells.length).to.be(expectedCount); + }); + } } diff --git a/test/functional/services/dashboard/index.ts b/test/functional/services/dashboard/index.ts index 2746718892cf0..0423b66d04102 100644 --- a/test/functional/services/dashboard/index.ts +++ b/test/functional/services/dashboard/index.ts @@ -6,8 +6,8 @@ * Side Public License, v 1. */ -export { DashboardVisualizationProvider } from './visualizations'; -export { DashboardExpectProvider } from './expectations'; -export { DashboardAddPanelProvider } from './add_panel'; -export { DashboardReplacePanelProvider } from './replace_panel'; -export { DashboardPanelActionsProvider } from './panel_actions'; +export { DashboardVisualizationsService } from './visualizations'; +export { DashboardExpectService } from './expectations'; +export { DashboardAddPanelService } from './add_panel'; +export { DashboardReplacePanelService } from './replace_panel'; +export { DashboardPanelActionsService } from './panel_actions'; diff --git a/test/functional/services/dashboard/panel_actions.ts b/test/functional/services/dashboard/panel_actions.ts index 89790b19f426a..e7c028acc0e1b 100644 --- a/test/functional/services/dashboard/panel_actions.ts +++ b/test/functional/services/dashboard/panel_actions.ts @@ -6,8 +6,8 @@ * Side Public License, v 1. */ -import { FtrProviderContext } from '../../ftr_provider_context'; import { WebElementWrapper } from '../lib/web_element_wrapper'; +import { FtrService } from '../../ftr_provider_context'; const REMOVE_PANEL_DATA_TEST_SUBJ = 'embeddablePanelAction-deletePanel'; const EDIT_PANEL_DATA_TEST_SUBJ = 'embeddablePanelAction-editPanel'; @@ -21,320 +21,318 @@ const COPY_PANEL_TO_DATA_TEST_SUBJ = 'embeddablePanelAction-copyToDashboard'; const LIBRARY_NOTIFICATION_TEST_SUBJ = 'embeddablePanelNotification-ACTION_LIBRARY_NOTIFICATION'; const SAVE_TO_LIBRARY_TEST_SUBJ = 'embeddablePanelAction-saveToLibrary'; -export function DashboardPanelActionsProvider({ getService, getPageObjects }: FtrProviderContext) { - const log = getService('log'); - const testSubjects = getService('testSubjects'); - const PageObjects = getPageObjects(['header', 'common', 'dashboard']); - const inspector = getService('inspector'); - - return new (class DashboardPanelActions { - async findContextMenu(parent?: WebElementWrapper) { - return parent - ? await testSubjects.findDescendant(OPEN_CONTEXT_MENU_ICON_DATA_TEST_SUBJ, parent) - : await testSubjects.find(OPEN_CONTEXT_MENU_ICON_DATA_TEST_SUBJ); - } - - async isContextMenuIconVisible() { - log.debug('isContextMenuIconVisible'); - return await testSubjects.exists(OPEN_CONTEXT_MENU_ICON_DATA_TEST_SUBJ); - } - - async toggleContextMenu(parent?: WebElementWrapper) { - log.debug('toggleContextMenu'); - await (parent ? parent.moveMouseTo() : testSubjects.moveMouseTo('dashboardPanelTitle')); - const toggleMenuItem = await this.findContextMenu(parent); - await toggleMenuItem.click(); - } - - async expectContextMenuToBeOpen() { - await testSubjects.existOrFail('embeddablePanelContextMenuOpen'); - } - - async openContextMenu(parent?: WebElementWrapper) { - log.debug(`openContextMenu(${parent}`); - if (await testSubjects.exists('embeddablePanelContextMenuOpen')) return; - await this.toggleContextMenu(parent); - await this.expectContextMenuToBeOpen(); - } - - async hasContextMenuMoreItem() { - return await testSubjects.exists('embeddablePanelMore-mainMenu'); - } - - async clickContextMenuMoreItem() { - const hasMoreSubPanel = await testSubjects.exists('embeddablePanelMore-mainMenu'); - if (hasMoreSubPanel) { - await testSubjects.click('embeddablePanelMore-mainMenu'); - } - } - - async openContextMenuMorePanel(parent?: WebElementWrapper) { - await this.openContextMenu(parent); - await this.clickContextMenuMoreItem(); - } - - async clickEdit() { - log.debug('clickEdit'); +export class DashboardPanelActionsService extends FtrService { + private readonly log = this.ctx.getService('log'); + private readonly testSubjects = this.ctx.getService('testSubjects'); + private readonly inspector = this.ctx.getService('inspector'); + private readonly PageObjects = this.ctx.getPageObjects(['header', 'common', 'dashboard']); + + async findContextMenu(parent?: WebElementWrapper) { + return parent + ? await this.testSubjects.findDescendant(OPEN_CONTEXT_MENU_ICON_DATA_TEST_SUBJ, parent) + : await this.testSubjects.find(OPEN_CONTEXT_MENU_ICON_DATA_TEST_SUBJ); + } + + async isContextMenuIconVisible() { + this.log.debug('isContextMenuIconVisible'); + return await this.testSubjects.exists(OPEN_CONTEXT_MENU_ICON_DATA_TEST_SUBJ); + } + + async toggleContextMenu(parent?: WebElementWrapper) { + this.log.debug('toggleContextMenu'); + await (parent ? parent.moveMouseTo() : this.testSubjects.moveMouseTo('dashboardPanelTitle')); + const toggleMenuItem = await this.findContextMenu(parent); + await toggleMenuItem.click(); + } + + async expectContextMenuToBeOpen() { + await this.testSubjects.existOrFail('embeddablePanelContextMenuOpen'); + } + + async openContextMenu(parent?: WebElementWrapper) { + this.log.debug(`openContextMenu(${parent}`); + if (await this.testSubjects.exists('embeddablePanelContextMenuOpen')) return; + await this.toggleContextMenu(parent); + await this.expectContextMenuToBeOpen(); + } + + async hasContextMenuMoreItem() { + return await this.testSubjects.exists('embeddablePanelMore-mainMenu'); + } + + async clickContextMenuMoreItem() { + const hasMoreSubPanel = await this.testSubjects.exists('embeddablePanelMore-mainMenu'); + if (hasMoreSubPanel) { + await this.testSubjects.click('embeddablePanelMore-mainMenu'); + } + } + + async openContextMenuMorePanel(parent?: WebElementWrapper) { + await this.openContextMenu(parent); + await this.clickContextMenuMoreItem(); + } + + async clickEdit() { + this.log.debug('clickEdit'); + await this.openContextMenu(); + const isActionVisible = await this.testSubjects.exists(EDIT_PANEL_DATA_TEST_SUBJ); + if (!isActionVisible) await this.clickContextMenuMoreItem(); + await this.testSubjects.clickWhenNotDisabled(EDIT_PANEL_DATA_TEST_SUBJ); + await this.PageObjects.header.waitUntilLoadingHasFinished(); + await this.PageObjects.common.waitForTopNavToBeVisible(); + } + + async editPanelByTitle(title?: string) { + this.log.debug(`editPanelByTitle(${title})`); + if (title) { + const panelOptions = await this.getPanelHeading(title); + await this.openContextMenu(panelOptions); + } else { await this.openContextMenu(); - const isActionVisible = await testSubjects.exists(EDIT_PANEL_DATA_TEST_SUBJ); - if (!isActionVisible) await this.clickContextMenuMoreItem(); - await testSubjects.clickWhenNotDisabled(EDIT_PANEL_DATA_TEST_SUBJ); - await PageObjects.header.waitUntilLoadingHasFinished(); - await PageObjects.common.waitForTopNavToBeVisible(); - } - - async editPanelByTitle(title?: string) { - log.debug(`editPanelByTitle(${title})`); - if (title) { - const panelOptions = await this.getPanelHeading(title); - await this.openContextMenu(panelOptions); - } else { - await this.openContextMenu(); - } - await testSubjects.clickWhenNotDisabled(EDIT_PANEL_DATA_TEST_SUBJ); } - - async clickExpandPanelToggle() { - log.debug(`clickExpandPanelToggle`); + await this.testSubjects.clickWhenNotDisabled(EDIT_PANEL_DATA_TEST_SUBJ); + } + + async clickExpandPanelToggle() { + this.log.debug(`clickExpandPanelToggle`); + await this.openContextMenu(); + const isActionVisible = await this.testSubjects.exists(TOGGLE_EXPAND_PANEL_DATA_TEST_SUBJ); + if (!isActionVisible) await this.clickContextMenuMoreItem(); + await this.testSubjects.click(TOGGLE_EXPAND_PANEL_DATA_TEST_SUBJ); + } + + async removePanel(parent?: WebElementWrapper) { + this.log.debug('removePanel'); + await this.openContextMenu(parent); + const isActionVisible = await this.testSubjects.exists(REMOVE_PANEL_DATA_TEST_SUBJ); + if (!isActionVisible) await this.clickContextMenuMoreItem(); + const isPanelActionVisible = await this.testSubjects.exists(REMOVE_PANEL_DATA_TEST_SUBJ); + if (!isPanelActionVisible) await this.clickContextMenuMoreItem(); + await this.testSubjects.click(REMOVE_PANEL_DATA_TEST_SUBJ); + } + + async removePanelByTitle(title: string) { + const header = await this.getPanelHeading(title); + this.log.debug('found header? ', Boolean(header)); + await this.removePanel(header); + } + + async customizePanel(parent?: WebElementWrapper) { + await this.openContextMenu(parent); + await this.testSubjects.click(CUSTOMIZE_PANEL_DATA_TEST_SUBJ); + } + + async replacePanelByTitle(title?: string) { + this.log.debug(`replacePanel(${title})`); + if (title) { + const panelOptions = await this.getPanelHeading(title); + await this.openContextMenu(panelOptions); + } else { await this.openContextMenu(); - const isActionVisible = await testSubjects.exists(TOGGLE_EXPAND_PANEL_DATA_TEST_SUBJ); - if (!isActionVisible) await this.clickContextMenuMoreItem(); - await testSubjects.click(TOGGLE_EXPAND_PANEL_DATA_TEST_SUBJ); - } - - async removePanel(parent?: WebElementWrapper) { - log.debug('removePanel'); - await this.openContextMenu(parent); - const isActionVisible = await testSubjects.exists(REMOVE_PANEL_DATA_TEST_SUBJ); - if (!isActionVisible) await this.clickContextMenuMoreItem(); - const isPanelActionVisible = await testSubjects.exists(REMOVE_PANEL_DATA_TEST_SUBJ); - if (!isPanelActionVisible) await this.clickContextMenuMoreItem(); - await testSubjects.click(REMOVE_PANEL_DATA_TEST_SUBJ); - } - - async removePanelByTitle(title: string) { - const header = await this.getPanelHeading(title); - log.debug('found header? ', Boolean(header)); - await this.removePanel(header); - } - - async customizePanel(parent?: WebElementWrapper) { - await this.openContextMenu(parent); - await testSubjects.click(CUSTOMIZE_PANEL_DATA_TEST_SUBJ); - } - - async replacePanelByTitle(title?: string) { - log.debug(`replacePanel(${title})`); - if (title) { - const panelOptions = await this.getPanelHeading(title); - await this.openContextMenu(panelOptions); - } else { - await this.openContextMenu(); - } - const actionExists = await testSubjects.exists(REPLACE_PANEL_DATA_TEST_SUBJ); - if (!actionExists) { - await this.clickContextMenuMoreItem(); - } - await testSubjects.click(REPLACE_PANEL_DATA_TEST_SUBJ); - } - - async clonePanelByTitle(title?: string) { - log.debug(`clonePanel(${title})`); - if (title) { - const panelOptions = await this.getPanelHeading(title); - await this.openContextMenu(panelOptions); - } else { - await this.openContextMenu(); - } - await testSubjects.click(CLONE_PANEL_DATA_TEST_SUBJ); - await PageObjects.dashboard.waitForRenderComplete(); - } - - async openCopyToModalByTitle(title?: string) { - log.debug(`copyPanelTo(${title})`); - if (title) { - const panelOptions = await this.getPanelHeading(title); - await this.openContextMenu(panelOptions); - } else { - await this.openContextMenu(); - } - const isActionVisible = await testSubjects.exists(COPY_PANEL_TO_DATA_TEST_SUBJ); - if (!isActionVisible) await this.clickContextMenuMoreItem(); - await testSubjects.click(COPY_PANEL_TO_DATA_TEST_SUBJ); - } - - async openInspectorByTitle(title: string) { - const header = await this.getPanelHeading(title); - await this.openInspector(header); - } - - async getSearchSessionIdByTitle(title: string) { - await this.openInspectorByTitle(title); - await inspector.openInspectorRequestsView(); - const searchSessionId = await ( - await testSubjects.find('inspectorRequestSearchSessionId') - ).getAttribute('data-search-session-id'); - await inspector.close(); - return searchSessionId; } - - async openInspector(parent?: WebElementWrapper) { - await this.openContextMenu(parent); - const exists = await testSubjects.exists(OPEN_INSPECTOR_TEST_SUBJ); - if (!exists) { - await this.clickContextMenuMoreItem(); - } - await testSubjects.click(OPEN_INSPECTOR_TEST_SUBJ); - } - - async unlinkFromLibary(parent?: WebElementWrapper) { - log.debug('unlinkFromLibrary'); - const libraryNotification = parent - ? await testSubjects.findDescendant(LIBRARY_NOTIFICATION_TEST_SUBJ, parent) - : await testSubjects.find(LIBRARY_NOTIFICATION_TEST_SUBJ); - await libraryNotification.click(); - await testSubjects.click('libraryNotificationUnlinkButton'); - } - - async saveToLibrary(newTitle: string, parent?: WebElementWrapper) { - log.debug('saveToLibrary'); - await this.openContextMenu(parent); - const exists = await testSubjects.exists(SAVE_TO_LIBRARY_TEST_SUBJ); - if (!exists) { - await this.clickContextMenuMoreItem(); - } - await testSubjects.click(SAVE_TO_LIBRARY_TEST_SUBJ); - await testSubjects.setValue('savedObjectTitle', newTitle, { - clearWithKeyboard: true, - }); - await testSubjects.click('confirmSaveSavedObjectButton'); - } - - async expectExistsRemovePanelAction() { - log.debug('expectExistsRemovePanelAction'); - await this.expectExistsPanelAction(REMOVE_PANEL_DATA_TEST_SUBJ); + const actionExists = await this.testSubjects.exists(REPLACE_PANEL_DATA_TEST_SUBJ); + if (!actionExists) { + await this.clickContextMenuMoreItem(); } + await this.testSubjects.click(REPLACE_PANEL_DATA_TEST_SUBJ); + } - async expectExistsPanelAction(testSubject: string) { - log.debug('expectExistsPanelAction', testSubject); + async clonePanelByTitle(title?: string) { + this.log.debug(`clonePanel(${title})`); + if (title) { + const panelOptions = await this.getPanelHeading(title); + await this.openContextMenu(panelOptions); + } else { await this.openContextMenu(); - if (await testSubjects.exists(CLONE_PANEL_DATA_TEST_SUBJ)) return; - if (await this.hasContextMenuMoreItem()) { - await this.clickContextMenuMoreItem(); - } - await testSubjects.existOrFail(CLONE_PANEL_DATA_TEST_SUBJ); - await this.toggleContextMenu(); } + await this.testSubjects.click(CLONE_PANEL_DATA_TEST_SUBJ); + await this.PageObjects.dashboard.waitForRenderComplete(); + } - async expectMissingPanelAction(testSubject: string) { - log.debug('expectMissingPanelAction', testSubject); + async openCopyToModalByTitle(title?: string) { + this.log.debug(`copyPanelTo(${title})`); + if (title) { + const panelOptions = await this.getPanelHeading(title); + await this.openContextMenu(panelOptions); + } else { await this.openContextMenu(); - await testSubjects.missingOrFail(testSubject); - if (await this.hasContextMenuMoreItem()) { - await this.clickContextMenuMoreItem(); - await testSubjects.missingOrFail(testSubject); - } - await this.toggleContextMenu(); - } - - async expectExistsEditPanelAction() { - log.debug('expectExistsEditPanelAction'); - await this.expectExistsPanelAction(EDIT_PANEL_DATA_TEST_SUBJ); - } - - async expectExistsReplacePanelAction() { - log.debug('expectExistsReplacePanelAction'); - await this.expectExistsPanelAction(REPLACE_PANEL_DATA_TEST_SUBJ); } - - async expectExistsClonePanelAction() { - log.debug('expectExistsClonePanelAction'); - await this.expectExistsPanelAction(CLONE_PANEL_DATA_TEST_SUBJ); - } - - async expectMissingEditPanelAction() { - log.debug('expectMissingEditPanelAction'); - await this.expectMissingPanelAction(EDIT_PANEL_DATA_TEST_SUBJ); - } - - async expectMissingReplacePanelAction() { - log.debug('expectMissingReplacePanelAction'); - await this.expectMissingPanelAction(REPLACE_PANEL_DATA_TEST_SUBJ); - } - - async expectMissingDuplicatePanelAction() { - log.debug('expectMissingDuplicatePanelAction'); - await this.expectMissingPanelAction(CLONE_PANEL_DATA_TEST_SUBJ); - } - - async expectMissingRemovePanelAction() { - log.debug('expectMissingRemovePanelAction'); - await this.expectMissingPanelAction(REMOVE_PANEL_DATA_TEST_SUBJ); - } - - async expectExistsToggleExpandAction() { - log.debug('expectExistsToggleExpandAction'); - await this.expectExistsPanelAction(TOGGLE_EXPAND_PANEL_DATA_TEST_SUBJ); - } - - async getPanelHeading(title: string) { - return await testSubjects.find(`embeddablePanelHeading-${title.replace(/\s/g, '')}`); + const isActionVisible = await this.testSubjects.exists(COPY_PANEL_TO_DATA_TEST_SUBJ); + if (!isActionVisible) await this.clickContextMenuMoreItem(); + await this.testSubjects.click(COPY_PANEL_TO_DATA_TEST_SUBJ); + } + + async openInspectorByTitle(title: string) { + const header = await this.getPanelHeading(title); + await this.openInspector(header); + } + + async getSearchSessionIdByTitle(title: string) { + await this.openInspectorByTitle(title); + await this.inspector.openInspectorRequestsView(); + const searchSessionId = await ( + await this.testSubjects.find('inspectorRequestSearchSessionId') + ).getAttribute('data-search-session-id'); + await this.inspector.close(); + return searchSessionId; + } + + async openInspector(parent?: WebElementWrapper) { + await this.openContextMenu(parent); + const exists = await this.testSubjects.exists(OPEN_INSPECTOR_TEST_SUBJ); + if (!exists) { + await this.clickContextMenuMoreItem(); } - - async clickHidePanelTitleToggle() { - await testSubjects.click('customizePanelHideTitle'); + await this.testSubjects.click(OPEN_INSPECTOR_TEST_SUBJ); + } + + async unlinkFromLibary(parent?: WebElementWrapper) { + this.log.debug('unlinkFromLibrary'); + const libraryNotification = parent + ? await this.testSubjects.findDescendant(LIBRARY_NOTIFICATION_TEST_SUBJ, parent) + : await this.testSubjects.find(LIBRARY_NOTIFICATION_TEST_SUBJ); + await libraryNotification.click(); + await this.testSubjects.click('libraryNotificationUnlinkButton'); + } + + async saveToLibrary(newTitle: string, parent?: WebElementWrapper) { + this.log.debug('saveToLibrary'); + await this.openContextMenu(parent); + const exists = await this.testSubjects.exists(SAVE_TO_LIBRARY_TEST_SUBJ); + if (!exists) { + await this.clickContextMenuMoreItem(); } - - async toggleHidePanelTitle(originalTitle?: string) { - log.debug(`hidePanelTitle(${originalTitle})`); - if (originalTitle) { - const panelOptions = await this.getPanelHeading(originalTitle); - await this.customizePanel(panelOptions); - } else { - await this.customizePanel(); - } - await this.clickHidePanelTitleToggle(); - await testSubjects.click('saveNewTitleButton'); + await this.testSubjects.click(SAVE_TO_LIBRARY_TEST_SUBJ); + await this.testSubjects.setValue('savedObjectTitle', newTitle, { + clearWithKeyboard: true, + }); + await this.testSubjects.click('confirmSaveSavedObjectButton'); + } + + async expectExistsRemovePanelAction() { + this.log.debug('expectExistsRemovePanelAction'); + await this.expectExistsPanelAction(REMOVE_PANEL_DATA_TEST_SUBJ); + } + + async expectExistsPanelAction(testSubject: string) { + this.log.debug('expectExistsPanelAction', testSubject); + await this.openContextMenu(); + if (await this.testSubjects.exists(CLONE_PANEL_DATA_TEST_SUBJ)) return; + if (await this.hasContextMenuMoreItem()) { + await this.clickContextMenuMoreItem(); } + await this.testSubjects.existOrFail(CLONE_PANEL_DATA_TEST_SUBJ); + await this.toggleContextMenu(); + } - /** - * - * @param customTitle - * @param originalTitle - optional to specify which panel to change the title on. - * @return {Promise} - */ - async setCustomPanelTitle(customTitle: string, originalTitle?: string) { - log.debug(`setCustomPanelTitle(${customTitle}, ${originalTitle})`); - if (originalTitle) { - const panelOptions = await this.getPanelHeading(originalTitle); - await this.customizePanel(panelOptions); - } else { - await this.customizePanel(); + async expectMissingPanelAction(testSubject: string) { + this.log.debug('expectMissingPanelAction', testSubject); + await this.openContextMenu(); + await this.testSubjects.missingOrFail(testSubject); + if (await this.hasContextMenuMoreItem()) { + await this.clickContextMenuMoreItem(); + await this.testSubjects.missingOrFail(testSubject); + } + await this.toggleContextMenu(); + } + + async expectExistsEditPanelAction() { + this.log.debug('expectExistsEditPanelAction'); + await this.expectExistsPanelAction(EDIT_PANEL_DATA_TEST_SUBJ); + } + + async expectExistsReplacePanelAction() { + this.log.debug('expectExistsReplacePanelAction'); + await this.expectExistsPanelAction(REPLACE_PANEL_DATA_TEST_SUBJ); + } + + async expectExistsClonePanelAction() { + this.log.debug('expectExistsClonePanelAction'); + await this.expectExistsPanelAction(CLONE_PANEL_DATA_TEST_SUBJ); + } + + async expectMissingEditPanelAction() { + this.log.debug('expectMissingEditPanelAction'); + await this.expectMissingPanelAction(EDIT_PANEL_DATA_TEST_SUBJ); + } + + async expectMissingReplacePanelAction() { + this.log.debug('expectMissingReplacePanelAction'); + await this.expectMissingPanelAction(REPLACE_PANEL_DATA_TEST_SUBJ); + } + + async expectMissingDuplicatePanelAction() { + this.log.debug('expectMissingDuplicatePanelAction'); + await this.expectMissingPanelAction(CLONE_PANEL_DATA_TEST_SUBJ); + } + + async expectMissingRemovePanelAction() { + this.log.debug('expectMissingRemovePanelAction'); + await this.expectMissingPanelAction(REMOVE_PANEL_DATA_TEST_SUBJ); + } + + async expectExistsToggleExpandAction() { + this.log.debug('expectExistsToggleExpandAction'); + await this.expectExistsPanelAction(TOGGLE_EXPAND_PANEL_DATA_TEST_SUBJ); + } + + async getPanelHeading(title: string) { + return await this.testSubjects.find(`embeddablePanelHeading-${title.replace(/\s/g, '')}`); + } + + async clickHidePanelTitleToggle() { + await this.testSubjects.click('customizePanelHideTitle'); + } + + async toggleHidePanelTitle(originalTitle?: string) { + this.log.debug(`hidePanelTitle(${originalTitle})`); + if (originalTitle) { + const panelOptions = await this.getPanelHeading(originalTitle); + await this.customizePanel(panelOptions); + } else { + await this.customizePanel(); + } + await this.clickHidePanelTitleToggle(); + await this.testSubjects.click('saveNewTitleButton'); + } + + /** + * + * @param customTitle + * @param originalTitle - optional to specify which panel to change the title on. + * @return {Promise} + */ + async setCustomPanelTitle(customTitle: string, originalTitle?: string) { + this.log.debug(`setCustomPanelTitle(${customTitle}, ${originalTitle})`); + if (originalTitle) { + const panelOptions = await this.getPanelHeading(originalTitle); + await this.customizePanel(panelOptions); + } else { + await this.customizePanel(); + } + await this.testSubjects.setValue('customEmbeddablePanelTitleInput', customTitle); + await this.testSubjects.click('saveNewTitleButton'); + } + + async resetCustomPanelTitle(panel?: WebElementWrapper) { + this.log.debug('resetCustomPanelTitle'); + await this.customizePanel(panel); + await this.testSubjects.click('resetCustomEmbeddablePanelTitle'); + await this.testSubjects.click('saveNewTitleButton'); + await this.toggleContextMenu(panel); + } + + async getActionWebElementByText(text: string): Promise { + this.log.debug(`getActionWebElement: "${text}"`); + const menu = await this.testSubjects.find('multipleActionsContextMenu'); + const items = await menu.findAllByCssSelector('[data-test-subj*="embeddablePanelAction-"]'); + for (const item of items) { + const currentText = await item.getVisibleText(); + if (currentText === text) { + return item; } - await testSubjects.setValue('customEmbeddablePanelTitleInput', customTitle); - await testSubjects.click('saveNewTitleButton'); } - async resetCustomPanelTitle(panel?: WebElementWrapper) { - log.debug('resetCustomPanelTitle'); - await this.customizePanel(panel); - await testSubjects.click('resetCustomEmbeddablePanelTitle'); - await testSubjects.click('saveNewTitleButton'); - await this.toggleContextMenu(panel); - } - - async getActionWebElementByText(text: string): Promise { - log.debug(`getActionWebElement: "${text}"`); - const menu = await testSubjects.find('multipleActionsContextMenu'); - const items = await menu.findAllByCssSelector('[data-test-subj*="embeddablePanelAction-"]'); - for (const item of items) { - const currentText = await item.getVisibleText(); - if (currentText === text) { - return item; - } - } - - throw new Error(`No action matching text "${text}"`); - } - })(); + throw new Error(`No action matching text "${text}"`); + } } diff --git a/test/functional/services/dashboard/replace_panel.ts b/test/functional/services/dashboard/replace_panel.ts index 3b33b5cd4f6a6..8f8f680b839bf 100644 --- a/test/functional/services/dashboard/replace_panel.ts +++ b/test/functional/services/dashboard/replace_panel.ts @@ -6,89 +6,87 @@ * Side Public License, v 1. */ -import { FtrProviderContext } from '../../ftr_provider_context'; +import { FtrService } from '../../ftr_provider_context'; -export function DashboardReplacePanelProvider({ getService }: FtrProviderContext) { - const log = getService('log'); - const testSubjects = getService('testSubjects'); - const flyout = getService('flyout'); +export class DashboardReplacePanelService extends FtrService { + private readonly log = this.ctx.getService('log'); + private readonly testSubjects = this.ctx.getService('testSubjects'); + private readonly flyout = this.ctx.getService('flyout'); - return new (class DashboardReplacePanel { - async toggleFilterPopover() { - log.debug('DashboardReplacePanel.toggleFilter'); - await testSubjects.click('savedObjectFinderFilterButton'); - } + async toggleFilterPopover() { + this.log.debug('DashboardReplacePanel.toggleFilter'); + await this.testSubjects.click('savedObjectFinderFilterButton'); + } - async toggleFilter(type: string) { - log.debug(`DashboardReplacePanel.replaceToFilter(${type})`); - await this.waitForListLoading(); - await this.toggleFilterPopover(); - await testSubjects.click(`savedObjectFinderFilter-${type}`); - await this.toggleFilterPopover(); - } + async toggleFilter(type: string) { + this.log.debug(`DashboardReplacePanel.replaceToFilter(${type})`); + await this.waitForListLoading(); + await this.toggleFilterPopover(); + await this.testSubjects.click(`savedObjectFinderFilter-${type}`); + await this.toggleFilterPopover(); + } - async isReplacePanelOpen() { - log.debug('DashboardReplacePanel.isReplacePanelOpen'); - return await testSubjects.exists('dashboardReplacePanel'); - } + async isReplacePanelOpen() { + this.log.debug('DashboardReplacePanel.isReplacePanelOpen'); + return await this.testSubjects.exists('dashboardReplacePanel'); + } - async ensureReplacePanelIsShowing() { - log.debug('DashboardReplacePanel.ensureReplacePanelIsShowing'); - const isOpen = await this.isReplacePanelOpen(); - if (!isOpen) { - throw new Error('Replace panel is not open, trying again.'); - } + async ensureReplacePanelIsShowing() { + this.log.debug('DashboardReplacePanel.ensureReplacePanelIsShowing'); + const isOpen = await this.isReplacePanelOpen(); + if (!isOpen) { + throw new Error('Replace panel is not open, trying again.'); } + } - async waitForListLoading() { - await testSubjects.waitForDeleted('savedObjectFinderLoadingIndicator'); - } + async waitForListLoading() { + await this.testSubjects.waitForDeleted('savedObjectFinderLoadingIndicator'); + } - async closeReplacePanel() { - await flyout.ensureClosed('dashboardReplacePanel'); - } + async closeReplacePanel() { + await this.flyout.ensureClosed('dashboardReplacePanel'); + } - async replaceSavedSearch(searchName: string) { - return this.replaceEmbeddable(searchName, 'search'); - } + async replaceSavedSearch(searchName: string) { + return this.replaceEmbeddable(searchName, 'search'); + } - async replaceSavedSearches(searches: string[]) { - for (const name of searches) { - await this.replaceSavedSearch(name); - } + async replaceSavedSearches(searches: string[]) { + for (const name of searches) { + await this.replaceSavedSearch(name); } + } - async replaceVisualization(vizName: string) { - return this.replaceEmbeddable(vizName, 'visualization'); - } + async replaceVisualization(vizName: string) { + return this.replaceEmbeddable(vizName, 'visualization'); + } - async replaceEmbeddable(embeddableName: string, embeddableType?: string) { - log.debug( - `DashboardReplacePanel.replaceEmbeddable, name: ${embeddableName}, type: ${embeddableType}` - ); - await this.ensureReplacePanelIsShowing(); - if (embeddableType) { - await this.toggleFilter(embeddableType); - } - await this.filterEmbeddableNames(`"${embeddableName.replace('-', ' ')}"`); - await testSubjects.click(`savedObjectTitle${embeddableName.split(' ').join('-')}`); - await testSubjects.exists('addObjectToDashboardSuccess'); - await this.closeReplacePanel(); - return embeddableName; + async replaceEmbeddable(embeddableName: string, embeddableType?: string) { + this.log.debug( + `DashboardReplacePanel.replaceEmbeddable, name: ${embeddableName}, type: ${embeddableType}` + ); + await this.ensureReplacePanelIsShowing(); + if (embeddableType) { + await this.toggleFilter(embeddableType); } + await this.filterEmbeddableNames(`"${embeddableName.replace('-', ' ')}"`); + await this.testSubjects.click(`savedObjectTitle${embeddableName.split(' ').join('-')}`); + await this.testSubjects.exists('addObjectToDashboardSuccess'); + await this.closeReplacePanel(); + return embeddableName; + } - async filterEmbeddableNames(name: string) { - // The search input field may be disabled while the table is loading so wait for it - await this.waitForListLoading(); - await testSubjects.setValue('savedObjectFinderSearchInput', name); - await this.waitForListLoading(); - } + async filterEmbeddableNames(name: string) { + // The search input field may be disabled while the table is loading so wait for it + await this.waitForListLoading(); + await this.testSubjects.setValue('savedObjectFinderSearchInput', name); + await this.waitForListLoading(); + } - async panelReplaceLinkExists(name: string) { - log.debug(`DashboardReplacePanel.panelReplaceLinkExists(${name})`); - await this.ensureReplacePanelIsShowing(); - await this.filterEmbeddableNames(`"${name}"`); - return await testSubjects.exists(`savedObjectTitle${name.split(' ').join('-')}`); - } - })(); + async panelReplaceLinkExists(name: string) { + this.log.debug(`DashboardReplacePanel.panelReplaceLinkExists(${name})`); + await this.ensureReplacePanelIsShowing(); + await this.filterEmbeddableNames(`"${name}"`); + return await this.testSubjects.exists(`savedObjectTitle${name.split(' ').join('-')}`); + } } diff --git a/test/functional/services/dashboard/visualizations.ts b/test/functional/services/dashboard/visualizations.ts index 2bf7458ff9c5f..a6b88802d7b81 100644 --- a/test/functional/services/dashboard/visualizations.ts +++ b/test/functional/services/dashboard/visualizations.ts @@ -6,14 +6,14 @@ * Side Public License, v 1. */ -import { FtrProviderContext } from '../../ftr_provider_context'; +import { FtrService } from '../../ftr_provider_context'; -export function DashboardVisualizationProvider({ getService, getPageObjects }: FtrProviderContext) { - const log = getService('log'); - const queryBar = getService('queryBar'); - const testSubjects = getService('testSubjects'); - const dashboardAddPanel = getService('dashboardAddPanel'); - const PageObjects = getPageObjects([ +export class DashboardVisualizationsService extends FtrService { + private readonly log = this.ctx.getService('log'); + private readonly queryBar = this.ctx.getService('queryBar'); + private readonly testSubjects = this.ctx.getService('testSubjects'); + private readonly dashboardAddPanel = this.ctx.getService('dashboardAddPanel'); + private readonly PageObjects = this.ctx.getPageObjects([ 'dashboard', 'visualize', 'visEditor', @@ -22,108 +22,106 @@ export function DashboardVisualizationProvider({ getService, getPageObjects }: F 'timePicker', ]); - return new (class DashboardVisualizations { - async createAndAddTSVBVisualization(name: string) { - log.debug(`createAndAddTSVBVisualization(${name})`); - const inViewMode = await PageObjects.dashboard.getIsInViewMode(); - if (inViewMode) { - await PageObjects.dashboard.switchToEditMode(); - } - await dashboardAddPanel.clickEditorMenuButton(); - await dashboardAddPanel.clickAddNewEmbeddableLink('metrics'); - await PageObjects.visualize.clickVisualBuilder(); - await PageObjects.visualize.saveVisualizationExpectSuccess(name); + async createAndAddTSVBVisualization(name: string) { + this.log.debug(`createAndAddTSVBVisualization(${name})`); + const inViewMode = await this.PageObjects.dashboard.getIsInViewMode(); + if (inViewMode) { + await this.PageObjects.dashboard.switchToEditMode(); } + await this.dashboardAddPanel.clickEditorMenuButton(); + await this.dashboardAddPanel.clickAddNewEmbeddableLink('metrics'); + await this.PageObjects.visualize.clickVisualBuilder(); + await this.PageObjects.visualize.saveVisualizationExpectSuccess(name); + } - async createSavedSearch({ - name, - query, - fields, - }: { - name: string; - query?: string; - fields?: string[]; - }) { - log.debug(`createSavedSearch(${name})`); - await PageObjects.header.clickDiscover(true); - await PageObjects.timePicker.setHistoricalDataRange(); + async createSavedSearch({ + name, + query, + fields, + }: { + name: string; + query?: string; + fields?: string[]; + }) { + this.log.debug(`createSavedSearch(${name})`); + await this.PageObjects.header.clickDiscover(true); + await this.PageObjects.timePicker.setHistoricalDataRange(); - if (query) { - await queryBar.setQuery(query); - await queryBar.submitQuery(); - } + if (query) { + await this.queryBar.setQuery(query); + await this.queryBar.submitQuery(); + } - if (fields) { - for (let i = 0; i < fields.length; i++) { - await PageObjects.discover.clickFieldListItemAdd(fields[i]); - } + if (fields) { + for (let i = 0; i < fields.length; i++) { + await this.PageObjects.discover.clickFieldListItemAdd(fields[i]); } - - await PageObjects.discover.saveSearch(name); - await PageObjects.header.waitUntilLoadingHasFinished(); - await testSubjects.exists('saveSearchSuccess'); } - async createAndAddSavedSearch({ - name, - query, - fields, - }: { - name: string; - query?: string; - fields?: string[]; - }) { - log.debug(`createAndAddSavedSearch(${name})`); - await this.createSavedSearch({ name, query, fields }); + await this.PageObjects.discover.saveSearch(name); + await this.PageObjects.header.waitUntilLoadingHasFinished(); + await this.testSubjects.exists('saveSearchSuccess'); + } - await PageObjects.header.clickDashboard(); + async createAndAddSavedSearch({ + name, + query, + fields, + }: { + name: string; + query?: string; + fields?: string[]; + }) { + this.log.debug(`createAndAddSavedSearch(${name})`); + await this.createSavedSearch({ name, query, fields }); - const inViewMode = await PageObjects.dashboard.getIsInViewMode(); - if (inViewMode) { - await PageObjects.dashboard.switchToEditMode(); - } - await dashboardAddPanel.addSavedSearch(name); + await this.PageObjects.header.clickDashboard(); + + const inViewMode = await this.PageObjects.dashboard.getIsInViewMode(); + if (inViewMode) { + await this.PageObjects.dashboard.switchToEditMode(); } + await this.dashboardAddPanel.addSavedSearch(name); + } - async createAndAddMarkdown({ name, markdown }: { name: string; markdown: string }) { - log.debug(`createAndAddMarkdown(${markdown})`); - const inViewMode = await PageObjects.dashboard.getIsInViewMode(); - if (inViewMode) { - await PageObjects.dashboard.switchToEditMode(); - } - await dashboardAddPanel.clickMarkdownQuickButton(); - await PageObjects.visEditor.setMarkdownTxt(markdown); - await PageObjects.visEditor.clickGo(); - await PageObjects.visualize.saveVisualizationExpectSuccess(name, { - saveAsNew: false, - redirectToOrigin: true, - }); + async createAndAddMarkdown({ name, markdown }: { name: string; markdown: string }) { + this.log.debug(`createAndAddMarkdown(${markdown})`); + const inViewMode = await this.PageObjects.dashboard.getIsInViewMode(); + if (inViewMode) { + await this.PageObjects.dashboard.switchToEditMode(); } + await this.dashboardAddPanel.clickMarkdownQuickButton(); + await this.PageObjects.visEditor.setMarkdownTxt(markdown); + await this.PageObjects.visEditor.clickGo(); + await this.PageObjects.visualize.saveVisualizationExpectSuccess(name, { + saveAsNew: false, + redirectToOrigin: true, + }); + } - async createAndEmbedMetric(name: string) { - log.debug(`createAndEmbedMetric(${name})`); - const inViewMode = await PageObjects.dashboard.getIsInViewMode(); - if (inViewMode) { - await PageObjects.dashboard.switchToEditMode(); - } - await dashboardAddPanel.clickEditorMenuButton(); - await dashboardAddPanel.clickAggBasedVisualizations(); - await dashboardAddPanel.clickVisType('metric'); - await testSubjects.click('savedObjectTitlelogstash-*'); - await testSubjects.exists('visualizesaveAndReturnButton'); - await testSubjects.click('visualizesaveAndReturnButton'); + async createAndEmbedMetric(name: string) { + this.log.debug(`createAndEmbedMetric(${name})`); + const inViewMode = await this.PageObjects.dashboard.getIsInViewMode(); + if (inViewMode) { + await this.PageObjects.dashboard.switchToEditMode(); } + await this.dashboardAddPanel.clickEditorMenuButton(); + await this.dashboardAddPanel.clickAggBasedVisualizations(); + await this.dashboardAddPanel.clickVisType('metric'); + await this.testSubjects.click('savedObjectTitlelogstash-*'); + await this.testSubjects.exists('visualizesaveAndReturnButton'); + await this.testSubjects.click('visualizesaveAndReturnButton'); + } - async createAndEmbedMarkdown({ name, markdown }: { name: string; markdown: string }) { - log.debug(`createAndEmbedMarkdown(${markdown})`); - const inViewMode = await PageObjects.dashboard.getIsInViewMode(); - if (inViewMode) { - await PageObjects.dashboard.switchToEditMode(); - } - await dashboardAddPanel.clickMarkdownQuickButton(); - await PageObjects.visEditor.setMarkdownTxt(markdown); - await PageObjects.visEditor.clickGo(); - await testSubjects.click('visualizesaveAndReturnButton'); + async createAndEmbedMarkdown({ name, markdown }: { name: string; markdown: string }) { + this.log.debug(`createAndEmbedMarkdown(${markdown})`); + const inViewMode = await this.PageObjects.dashboard.getIsInViewMode(); + if (inViewMode) { + await this.PageObjects.dashboard.switchToEditMode(); } - })(); + await this.dashboardAddPanel.clickMarkdownQuickButton(); + await this.PageObjects.visEditor.setMarkdownTxt(markdown); + await this.PageObjects.visEditor.clickGo(); + await this.testSubjects.click('visualizesaveAndReturnButton'); + } } diff --git a/test/functional/services/index.ts b/test/functional/services/index.ts index 819b8a3981e26..d9cadb1169a66 100644 --- a/test/functional/services/index.ts +++ b/test/functional/services/index.ts @@ -19,11 +19,11 @@ import { } from './common'; import { ComboBoxProvider } from './combo_box'; import { - DashboardAddPanelProvider, - DashboardReplacePanelProvider, - DashboardExpectProvider, - DashboardPanelActionsProvider, - DashboardVisualizationProvider, + DashboardAddPanelService, + DashboardReplacePanelService, + DashboardExpectService, + DashboardPanelActionsService, + DashboardVisualizationsService, } from './dashboard'; import { DocTableService } from './doc_table'; import { EmbeddingProvider } from './embedding'; @@ -60,13 +60,13 @@ export const services = { docTable: DocTableService, screenshots: ScreenshotsService, snapshots: SnapshotsService, - dashboardVisualizations: DashboardVisualizationProvider, - dashboardExpect: DashboardExpectProvider, failureDebugging: FailureDebuggingProvider, listingTable: ListingTableService, - dashboardAddPanel: DashboardAddPanelProvider, - dashboardReplacePanel: DashboardReplacePanelProvider, - dashboardPanelActions: DashboardPanelActionsProvider, + dashboardVisualizations: DashboardVisualizationsService, + dashboardExpect: DashboardExpectService, + dashboardAddPanel: DashboardAddPanelService, + dashboardReplacePanel: DashboardReplacePanelService, + dashboardPanelActions: DashboardPanelActionsService, flyout: FlyoutProvider, comboBox: ComboBoxProvider, dataGrid: DataGridService, From c166dae31e4fde7e1ba83413b3fbc2fa6e3e3f99 Mon Sep 17 00:00:00 2001 From: Spencer Date: Wed, 26 May 2021 12:01:31 -0700 Subject: [PATCH 07/77] [ftr] migrate visualizations service to FtrService classes (#100522) Co-authored-by: spalger --- test/functional/apps/visualize/_vega_chart.ts | 20 +- test/functional/services/index.ts | 12 +- .../services/visualizations/elastic_chart.ts | 186 ++++++++-------- .../services/visualizations/index.ts | 6 +- .../services/visualizations/pie_chart.ts | 208 +++++++++--------- .../visualizations/vega_debug_inspector.ts | 72 +++--- 6 files changed, 248 insertions(+), 256 deletions(-) diff --git a/test/functional/apps/visualize/_vega_chart.ts b/test/functional/apps/visualize/_vega_chart.ts index da33b390925a4..b2692c2a00d78 100644 --- a/test/functional/apps/visualize/_vega_chart.ts +++ b/test/functional/apps/visualize/_vega_chart.ts @@ -118,12 +118,12 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { await inspector.openInspectorRequestsView(); for (const getFn of [ - inspector.getOpenRequestDetailRequestButton, - inspector.getOpenRequestDetailResponseButton, - inspector.getOpenRequestStatisticButton, - ]) { + 'getOpenRequestDetailRequestButton', + 'getOpenRequestDetailResponseButton', + 'getOpenRequestStatisticButton', + ] as const) { await retry.try(async () => { - const requestStatisticTab = await getFn(); + const requestStatisticTab = await inspector[getFn](); expect(await requestStatisticTab.isEnabled()).to.be(true); }); @@ -159,12 +159,12 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { await vegaDebugInspectorView.openVegaDebugInspectorView(); for (const getFn of [ - vegaDebugInspectorView.getOpenDataViewerButton, - vegaDebugInspectorView.getOpenSignalViewerButton, - vegaDebugInspectorView.getOpenSpecViewerButton, - ]) { + 'getOpenDataViewerButton', + 'getOpenSignalViewerButton', + 'getOpenSpecViewerButton', + ] as const) { await retry.try(async () => { - const requestStatisticTab = await getFn(); + const requestStatisticTab = await vegaDebugInspectorView[getFn](); expect(await requestStatisticTab.isEnabled()).to.be(true); }); diff --git a/test/functional/services/index.ts b/test/functional/services/index.ts index d9cadb1169a66..a483dd4f21ba9 100644 --- a/test/functional/services/index.ts +++ b/test/functional/services/index.ts @@ -39,9 +39,9 @@ import { RenderableProvider } from './renderable'; import { ToastsProvider } from './toasts'; import { DataGridService } from './data_grid'; import { - PieChartProvider, - ElasticChartProvider, - VegaDebugInspectorViewProvider, + PieChartService, + ElasticChartService, + VegaDebugInspectorViewService, } from './visualizations'; import { ListingTableService } from './listing_table'; import { SavedQueryManagementComponentProvider } from './saved_query_management_component'; @@ -73,15 +73,15 @@ export const services = { embedding: EmbeddingProvider, renderable: RenderableProvider, browser: BrowserProvider, - pieChart: PieChartProvider, + pieChart: PieChartService, inspector: InspectorProvider, fieldEditor: FieldEditorService, - vegaDebugInspector: VegaDebugInspectorViewProvider, + vegaDebugInspector: VegaDebugInspectorViewService, appsMenu: AppsMenuProvider, globalNav: GlobalNavService, toasts: ToastsProvider, savedQueryManagementComponent: SavedQueryManagementComponentProvider, - elasticChart: ElasticChartProvider, + elasticChart: ElasticChartService, supertest: KibanaSupertestProvider, managementMenu: ManagementMenuProvider, monacoEditor: MonacoEditorProvider, diff --git a/test/functional/services/visualizations/elastic_chart.ts b/test/functional/services/visualizations/elastic_chart.ts index 80483100a06dd..b954b4ba03616 100644 --- a/test/functional/services/visualizations/elastic_chart.ts +++ b/test/functional/services/visualizations/elastic_chart.ts @@ -9,7 +9,7 @@ import { DebugState } from '@elastic/charts'; import expect from '@kbn/expect'; -import { FtrProviderContext } from '../../ftr_provider_context'; +import { FtrService } from '../../ftr_provider_context'; import { WebElementWrapper } from '../lib/web_element_wrapper'; declare global { @@ -21,115 +21,111 @@ declare global { } } -export function ElasticChartProvider({ getService }: FtrProviderContext) { - const testSubjects = getService('testSubjects'); - const find = getService('find'); - const retry = getService('retry'); - const log = getService('log'); - const browser = getService('browser'); - - class ElasticChart { - public async getCanvas(dataTestSubj?: string) { - if (dataTestSubj) { - const chart = await this.getChart(dataTestSubj); - return await chart.findByClassName('echCanvasRenderer'); - } - return await find.byCssSelector('.echChart canvas:last-of-type'); - } +export class ElasticChartService extends FtrService { + private readonly testSubjects = this.ctx.getService('testSubjects'); + private readonly find = this.ctx.getService('find'); + private readonly retry = this.ctx.getService('retry'); + private readonly log = this.ctx.getService('log'); + private readonly browser = this.ctx.getService('browser'); - public async canvasExists() { - return await find.existsByCssSelector('.echChart canvas:last-of-type'); - } - - public async waitForRenderComplete(dataTestSubj?: string) { + public async getCanvas(dataTestSubj?: string) { + if (dataTestSubj) { const chart = await this.getChart(dataTestSubj); - const rendered = await chart.findAllByCssSelector( - '.echChartStatus[data-ech-render-complete=true]' - ); - expect(rendered.length).to.equal(1); + return await chart.findByClassName('echCanvasRenderer'); } + return await this.find.byCssSelector('.echChart canvas:last-of-type'); + } - public async getVisualizationRenderingCount(dataTestSubj?: string) { - const chart = await this.getChart(dataTestSubj); - const visContainer = await chart.findByCssSelector('.echChartStatus'); - const renderingCount = await visContainer.getAttribute('data-ech-render-count'); - return Number(renderingCount); - } + public async canvasExists() { + return await this.find.existsByCssSelector('.echChart canvas:last-of-type'); + } - public async waitForRenderingCount(minimumCount: number, dataTestSubj?: string) { - await retry.waitFor(`rendering count to be equal to [${minimumCount}]`, async () => { - const currentRenderingCount = await this.getVisualizationRenderingCount(dataTestSubj); - log.debug(`-- currentRenderingCount=${currentRenderingCount}`); - return currentRenderingCount >= minimumCount; - }); - } + public async waitForRenderComplete(dataTestSubj?: string) { + const chart = await this.getChart(dataTestSubj); + const rendered = await chart.findAllByCssSelector( + '.echChartStatus[data-ech-render-complete=true]' + ); + expect(rendered.length).to.equal(1); + } - public async hasChart(dataTestSubj?: string, timeout?: number): Promise { - if (dataTestSubj) { - return await testSubjects.exists(dataTestSubj, { timeout }); - } else { - const charts = await this.getAllCharts(timeout); + public async getVisualizationRenderingCount(dataTestSubj?: string) { + const chart = await this.getChart(dataTestSubj); + const visContainer = await chart.findByCssSelector('.echChartStatus'); + const renderingCount = await visContainer.getAttribute('data-ech-render-count'); + return Number(renderingCount); + } - return charts.length > 0; - } - } + public async waitForRenderingCount(minimumCount: number, dataTestSubj?: string) { + await this.retry.waitFor(`rendering count to be equal to [${minimumCount}]`, async () => { + const currentRenderingCount = await this.getVisualizationRenderingCount(dataTestSubj); + this.log.debug(`-- currentRenderingCount=${currentRenderingCount}`); + return currentRenderingCount >= minimumCount; + }); + } - private async getChart( - dataTestSubj?: string, - timeout?: number, - match: number = 0 - ): Promise { - if (dataTestSubj) { - if (!(await testSubjects.exists(dataTestSubj, { timeout }))) { - throw Error(`Failed to find an elastic-chart with testSubject '${dataTestSubj}'`); - } - - return (await testSubjects.findAll(dataTestSubj))[match]; - } else { - const charts = await this.getAllCharts(timeout); - if (charts.length === 0) { - throw Error(`Failed to find any elastic-charts on the page`); - } else { - return charts[match]; - } - } - } + public async hasChart(dataTestSubj?: string, timeout?: number): Promise { + if (dataTestSubj) { + return await this.testSubjects.exists(dataTestSubj, { timeout }); + } else { + const charts = await this.getAllCharts(timeout); - private async getAllCharts(timeout?: number) { - return await find.allByCssSelector('.echChart', timeout); + return charts.length > 0; } + } - /** - * used to get chart data from `@elastic/charts` - * requires `window._echDebugStateFlag` to be true - */ - public async getChartDebugData( - dataTestSubj?: string, - match: number = 0 - ): Promise { - const chart = await this.getChart(dataTestSubj, undefined, match); - - try { - const visContainer = await chart.findByCssSelector('.echChartStatus'); - const debugDataString: string | undefined = await visContainer.getAttribute( - 'data-ech-debug-state' - ); - return debugDataString ? JSON.parse(debugDataString) : null; - } catch (error) { - throw Error('Elastic charts debugState not found'); + private async getChart( + dataTestSubj?: string, + timeout?: number, + match: number = 0 + ): Promise { + if (dataTestSubj) { + if (!(await this.testSubjects.exists(dataTestSubj, { timeout }))) { + throw Error(`Failed to find an elastic-chart with testSubject '${dataTestSubj}'`); + } + + return (await this.testSubjects.findAll(dataTestSubj))[match]; + } else { + const charts = await this.getAllCharts(timeout); + if (charts.length === 0) { + throw Error(`Failed to find any elastic-charts on the page`); + } else { + return charts[match]; } } + } - /** - * Used to set a flag on the window to trigger debug state on elastic charts - * @param value - */ - public async setNewChartUiDebugFlag(value = true) { - await browser.execute<[boolean], void>((v) => { - window._echDebugStateFlag = v; - }, value); + private async getAllCharts(timeout?: number) { + return await this.find.allByCssSelector('.echChart', timeout); + } + + /** + * used to get chart data from `@elastic/charts` + * requires `window._echDebugStateFlag` to be true + */ + public async getChartDebugData( + dataTestSubj?: string, + match: number = 0 + ): Promise { + const chart = await this.getChart(dataTestSubj, undefined, match); + + try { + const visContainer = await chart.findByCssSelector('.echChartStatus'); + const debugDataString: string | undefined = await visContainer.getAttribute( + 'data-ech-debug-state' + ); + return debugDataString ? JSON.parse(debugDataString) : null; + } catch (error) { + throw Error('Elastic charts debugState not found'); } } - return new ElasticChart(); + /** + * Used to set a flag on the window to trigger debug state on elastic charts + * @param value + */ + public async setNewChartUiDebugFlag(value = true) { + await this.browser.execute<[boolean], void>((v) => { + window._echDebugStateFlag = v; + }, value); + } } diff --git a/test/functional/services/visualizations/index.ts b/test/functional/services/visualizations/index.ts index 9c43a1be83de8..22c06f3821a30 100644 --- a/test/functional/services/visualizations/index.ts +++ b/test/functional/services/visualizations/index.ts @@ -6,6 +6,6 @@ * Side Public License, v 1. */ -export { PieChartProvider } from './pie_chart'; -export { ElasticChartProvider } from './elastic_chart'; -export { VegaDebugInspectorViewProvider } from './vega_debug_inspector'; +export { PieChartService } from './pie_chart'; +export { ElasticChartService } from './elastic_chart'; +export { VegaDebugInspectorViewService } from './vega_debug_inspector'; diff --git a/test/functional/services/visualizations/pie_chart.ts b/test/functional/services/visualizations/pie_chart.ts index bdf26ab8a5b44..cac4e8fe64c5e 100644 --- a/test/functional/services/visualizations/pie_chart.ts +++ b/test/functional/services/visualizations/pie_chart.ts @@ -7,111 +7,111 @@ */ import expect from '@kbn/expect'; -import { FtrProviderContext } from '../../ftr_provider_context'; - -export function PieChartProvider({ getService }: FtrProviderContext) { - const log = getService('log'); - const retry = getService('retry'); - const config = getService('config'); - const inspector = getService('inspector'); - const testSubjects = getService('testSubjects'); - const find = getService('find'); - const defaultFindTimeout = config.get('timeouts.find'); - const panelActions = getService('dashboardPanelActions'); - - return new (class PieChart { - private readonly filterActionText = 'Apply filter to current view'; - - async clickOnPieSlice(name?: string) { - log.debug(`PieChart.clickOnPieSlice(${name})`); - if (name) { - await testSubjects.click(`pieSlice-${name.split(' ').join('-')}`); - } else { - // If no pie slice has been provided, find the first one available. - await retry.try(async () => { - const slices = await find.allByCssSelector('svg > g > g.arcs > path.slice'); - log.debug('Slices found:' + slices.length); - return slices[0].click(); - }); - } - } - - async filterOnPieSlice(name?: string) { - log.debug(`PieChart.filterOnPieSlice(${name})`); - await this.clickOnPieSlice(name); - const hasUiActionsPopup = await testSubjects.exists('multipleActionsContextMenu'); - if (hasUiActionsPopup) { - const actionElement = await panelActions.getActionWebElementByText(this.filterActionText); - await actionElement.click(); - } - } - - async filterByLegendItem(label: string) { - log.debug(`PieChart.filterByLegendItem(${label})`); - await testSubjects.click(`legend-${label}`); - await testSubjects.click(`legend-${label}-filterIn`); - } - - async getPieSlice(name: string) { - return await testSubjects.find(`pieSlice-${name.split(' ').join('-')}`); - } - - async getAllPieSlices(name: string) { - return await testSubjects.findAll(`pieSlice-${name.split(' ').join('-')}`); - } - - async getPieSliceStyle(name: string) { - log.debug(`VisualizePage.getPieSliceStyle(${name})`); - const pieSlice = await this.getPieSlice(name); - return await pieSlice.getAttribute('style'); - } - - async getAllPieSliceStyles(name: string) { - log.debug(`VisualizePage.getAllPieSliceStyles(${name})`); - const pieSlices = await this.getAllPieSlices(name); - return await Promise.all( - pieSlices.map(async (pieSlice) => await pieSlice.getAttribute('style')) - ); - } - - async getPieChartData() { - const chartTypes = await find.allByCssSelector('path.slice', defaultFindTimeout * 2); - return await Promise.all(chartTypes.map(async (chart) => await chart.getAttribute('d'))); - } - - async expectPieChartTableData(expectedTableData: Array<[]>) { - await inspector.open(); - await inspector.setTablePageSize(50); - await inspector.expectTableData(expectedTableData); - } - - async getPieChartLabels() { - const chartTypes = await find.allByCssSelector('path.slice', defaultFindTimeout * 2); - return await Promise.all( - chartTypes.map(async (chart) => await chart.getAttribute('data-label')) - ); - } - - async getPieSliceCount() { - log.debug('PieChart.getPieSliceCount'); - const slices = await find.allByCssSelector('svg > g > g.arcs > path.slice'); - return slices.length; - } - - async expectPieSliceCount(expectedCount: number) { - log.debug(`PieChart.expectPieSliceCount(${expectedCount})`); - await retry.try(async () => { - const slicesCount = await this.getPieSliceCount(); - expect(slicesCount).to.be(expectedCount); +import { FtrService } from '../../ftr_provider_context'; + +export class PieChartService extends FtrService { + private readonly log = this.ctx.getService('log'); + private readonly retry = this.ctx.getService('retry'); + private readonly config = this.ctx.getService('config'); + private readonly inspector = this.ctx.getService('inspector'); + private readonly testSubjects = this.ctx.getService('testSubjects'); + private readonly find = this.ctx.getService('find'); + private readonly panelActions = this.ctx.getService('dashboardPanelActions'); + private readonly defaultFindTimeout = this.config.get('timeouts.find'); + + private readonly filterActionText = 'Apply filter to current view'; + + async clickOnPieSlice(name?: string) { + this.log.debug(`PieChart.clickOnPieSlice(${name})`); + if (name) { + await this.testSubjects.click(`pieSlice-${name.split(' ').join('-')}`); + } else { + // If no pie slice has been provided, find the first one available. + await this.retry.try(async () => { + const slices = await this.find.allByCssSelector('svg > g > g.arcs > path.slice'); + this.log.debug('Slices found:' + slices.length); + return slices[0].click(); }); } - - async expectPieChartLabels(expectedLabels: string[]) { - log.debug(`PieChart.expectPieChartLabels(${expectedLabels.join(',')})`); - await retry.try(async () => { - const pieData = await this.getPieChartLabels(); - expect(pieData).to.eql(expectedLabels); - }); + } + + async filterOnPieSlice(name?: string) { + this.log.debug(`PieChart.filterOnPieSlice(${name})`); + await this.clickOnPieSlice(name); + const hasUiActionsPopup = await this.testSubjects.exists('multipleActionsContextMenu'); + if (hasUiActionsPopup) { + const actionElement = await this.panelActions.getActionWebElementByText( + this.filterActionText + ); + await actionElement.click(); } - })(); + } + + async filterByLegendItem(label: string) { + this.log.debug(`PieChart.filterByLegendItem(${label})`); + await this.testSubjects.click(`legend-${label}`); + await this.testSubjects.click(`legend-${label}-filterIn`); + } + + async getPieSlice(name: string) { + return await this.testSubjects.find(`pieSlice-${name.split(' ').join('-')}`); + } + + async getAllPieSlices(name: string) { + return await this.testSubjects.findAll(`pieSlice-${name.split(' ').join('-')}`); + } + + async getPieSliceStyle(name: string) { + this.log.debug(`VisualizePage.getPieSliceStyle(${name})`); + const pieSlice = await this.getPieSlice(name); + return await pieSlice.getAttribute('style'); + } + + async getAllPieSliceStyles(name: string) { + this.log.debug(`VisualizePage.getAllPieSliceStyles(${name})`); + const pieSlices = await this.getAllPieSlices(name); + return await Promise.all( + pieSlices.map(async (pieSlice) => await pieSlice.getAttribute('style')) + ); + } + + async getPieChartData() { + const chartTypes = await this.find.allByCssSelector('path.slice', this.defaultFindTimeout * 2); + return await Promise.all(chartTypes.map(async (chart) => await chart.getAttribute('d'))); + } + + async expectPieChartTableData(expectedTableData: Array<[]>) { + await this.inspector.open(); + await this.inspector.setTablePageSize(50); + await this.inspector.expectTableData(expectedTableData); + } + + async getPieChartLabels() { + const chartTypes = await this.find.allByCssSelector('path.slice', this.defaultFindTimeout * 2); + return await Promise.all( + chartTypes.map(async (chart) => await chart.getAttribute('data-label')) + ); + } + + async getPieSliceCount() { + this.log.debug('PieChart.getPieSliceCount'); + const slices = await this.find.allByCssSelector('svg > g > g.arcs > path.slice'); + return slices.length; + } + + async expectPieSliceCount(expectedCount: number) { + this.log.debug(`PieChart.expectPieSliceCount(${expectedCount})`); + await this.retry.try(async () => { + const slicesCount = await this.getPieSliceCount(); + expect(slicesCount).to.be(expectedCount); + }); + } + + async expectPieChartLabels(expectedLabels: string[]) { + this.log.debug(`PieChart.expectPieChartLabels(${expectedLabels.join(',')})`); + await this.retry.try(async () => { + const pieData = await this.getPieChartLabels(); + expect(pieData).to.eql(expectedLabels); + }); + } } diff --git a/test/functional/services/visualizations/vega_debug_inspector.ts b/test/functional/services/visualizations/vega_debug_inspector.ts index af61a5aee4dea..f85d1d51107eb 100644 --- a/test/functional/services/visualizations/vega_debug_inspector.ts +++ b/test/functional/services/visualizations/vega_debug_inspector.ts @@ -6,53 +6,49 @@ * Side Public License, v 1. */ -import { FtrProviderContext } from '../../ftr_provider_context'; +import { FtrService } from '../../ftr_provider_context'; -export function VegaDebugInspectorViewProvider({ getService }: FtrProviderContext) { - const testSubjects = getService('testSubjects'); - const inspector = getService('inspector'); - const dataGrid = getService('dataGrid'); +export class VegaDebugInspectorViewService extends FtrService { + private readonly testSubjects = this.ctx.getService('testSubjects'); + private readonly inspector = this.ctx.getService('inspector'); + private readonly dataGrid = this.ctx.getService('dataGrid'); - class VegaDebugInspectorView { - async openVegaDebugInspectorView() { - await inspector.openInspectorView('inspectorViewChooserVega debug'); - } - - public getOpenDataViewerButton() { - return testSubjects.find('vegaDataInspectorDataViewerButton'); - } + async openVegaDebugInspectorView() { + await this.inspector.openInspectorView('inspectorViewChooserVega debug'); + } - public getOpenSignalViewerButton() { - return testSubjects.find('vegaDataInspectorSignalViewerButton'); - } + public getOpenDataViewerButton() { + return this.testSubjects.find('vegaDataInspectorDataViewerButton'); + } - public getOpenSpecViewerButton() { - return testSubjects.find('vegaDataInspectorSpecViewerButton'); - } + public getOpenSignalViewerButton() { + return this.testSubjects.find('vegaDataInspectorSignalViewerButton'); + } - public getCopyClipboardButton() { - return testSubjects.find('vegaDataInspectorCopyClipboardButton'); - } + public getOpenSpecViewerButton() { + return this.testSubjects.find('vegaDataInspectorSpecViewerButton'); + } - public getGridTableData() { - return dataGrid.getDataGridTableData(); - } + public getCopyClipboardButton() { + return this.testSubjects.find('vegaDataInspectorCopyClipboardButton'); + } - public async navigateToDataViewerTab() { - const dataViewerButton = await this.getOpenDataViewerButton(); - await dataViewerButton.click(); - } + public getGridTableData() { + return this.dataGrid.getDataGridTableData(); + } - public async navigateToSignalViewerTab() { - const signalViewerButton = await this.getOpenSignalViewerButton(); - await signalViewerButton.click(); - } + public async navigateToDataViewerTab() { + const dataViewerButton = await this.getOpenDataViewerButton(); + await dataViewerButton.click(); + } - public async navigateToSpecViewerTab() { - const specViewerButton = await this.getOpenSpecViewerButton(); - await specViewerButton.click(); - } + public async navigateToSignalViewerTab() { + const signalViewerButton = await this.getOpenSignalViewerButton(); + await signalViewerButton.click(); } - return new VegaDebugInspectorView(); + public async navigateToSpecViewerTab() { + const specViewerButton = await this.getOpenSpecViewerButton(); + await specViewerButton.click(); + } } From 7270c3bf40b1c1c5f302de8fb910a61aa0979321 Mon Sep 17 00:00:00 2001 From: Spencer Date: Wed, 26 May 2021 12:10:14 -0700 Subject: [PATCH 08/77] [ftr] migrate management services to FtrService class (#100521) Co-authored-by: spalger --- test/functional/services/index.ts | 4 +- test/functional/services/management/index.ts | 2 +- .../services/management/management_menu.ts | 44 +++++++++---------- 3 files changed, 23 insertions(+), 27 deletions(-) diff --git a/test/functional/services/index.ts b/test/functional/services/index.ts index a483dd4f21ba9..b2e0a3e0f473e 100644 --- a/test/functional/services/index.ts +++ b/test/functional/services/index.ts @@ -32,7 +32,7 @@ import { FlyoutProvider } from './flyout'; import { GlobalNavService } from './global_nav'; import { InspectorProvider } from './inspector'; import { FieldEditorService } from './field_editor'; -import { ManagementMenuProvider } from './management'; +import { ManagementMenuService } from './management'; import { QueryBarProvider } from './query_bar'; import { RemoteProvider } from './remote'; import { RenderableProvider } from './renderable'; @@ -83,7 +83,7 @@ export const services = { savedQueryManagementComponent: SavedQueryManagementComponentProvider, elasticChart: ElasticChartService, supertest: KibanaSupertestProvider, - managementMenu: ManagementMenuProvider, + managementMenu: ManagementMenuService, monacoEditor: MonacoEditorProvider, MenuToggle: MenuToggleProvider, }; diff --git a/test/functional/services/management/index.ts b/test/functional/services/management/index.ts index 988ac06f1ca18..8fc1a88ee5892 100644 --- a/test/functional/services/management/index.ts +++ b/test/functional/services/management/index.ts @@ -6,4 +6,4 @@ * Side Public License, v 1. */ -export { ManagementMenuProvider } from './management_menu'; +export { ManagementMenuService } from './management_menu'; diff --git a/test/functional/services/management/management_menu.ts b/test/functional/services/management/management_menu.ts index eb8c6901ffa66..738a8d55439ec 100644 --- a/test/functional/services/management/management_menu.ts +++ b/test/functional/services/management/management_menu.ts @@ -6,35 +6,31 @@ * Side Public License, v 1. */ -import { FtrProviderContext } from 'test/functional/ftr_provider_context'; +import { FtrService } from '../../ftr_provider_context'; -export function ManagementMenuProvider({ getService }: FtrProviderContext) { - const find = getService('find'); +export class ManagementMenuService extends FtrService { + private readonly find = this.ctx.getService('find'); - class ManagementMenu { - public async getSections() { - const sectionsElements = await find.allByCssSelector( - '.mgtSideBarNav > .euiSideNav__content > .euiSideNavItem' - ); - - const sections = []; + public async getSections() { + const sectionsElements = await this.find.allByCssSelector( + '.mgtSideBarNav > .euiSideNav__content > .euiSideNavItem' + ); - for (const el of sectionsElements) { - const sectionId = await (await el.findByClassName('euiSideNavItemButton')).getAttribute( - 'data-test-subj' - ); - const sectionLinks = await Promise.all( - (await el.findAllByCssSelector('.euiSideNavItem > a.euiSideNavItemButton')).map((item) => - item.getAttribute('data-test-subj') - ) - ); + const sections = []; - sections.push({ sectionId, sectionLinks }); - } + for (const el of sectionsElements) { + const sectionId = await (await el.findByClassName('euiSideNavItemButton')).getAttribute( + 'data-test-subj' + ); + const sectionLinks = await Promise.all( + (await el.findAllByCssSelector('.euiSideNavItem > a.euiSideNavItemButton')).map((item) => + item.getAttribute('data-test-subj') + ) + ); - return sections; + sections.push({ sectionId, sectionLinks }); } - } - return new ManagementMenu(); + return sections; + } } From b189d05bc3304ad6180787b8e48f78a352814ffc Mon Sep 17 00:00:00 2001 From: Justin Kambic Date: Wed, 26 May 2021 15:31:15 -0400 Subject: [PATCH 09/77] [Uptime] Move uptime actions to Header Actions Menu (#100298) * Move uptime actions to Kibana's HeaderActionsMenu. * Delete a comment. * Extract ActionMenu content to dedicated component to make testing easier. * Add tests. * Use `EuiHeaderLinks` instead of `EuiFlexItem`. * Clean up tests. * Prefer `getByRole` for a test. * Fix copy mistake. * Fix a test broken by the previous commit. * Prefer `EuiHeaderSectionItem` over `EuiHeaderSectionLink` to avoid nesting `button`s within `buttons`. * Reverse "Settings" and "Alerts" menu options to make them uniform with APM. Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../components/common/header/action_menu.tsx | 72 ++----------- .../header/action_menu_content.test.tsx | 55 ++++++++++ .../common/header/action_menu_content.tsx | 101 ++++++++++++++++++ .../components/common/header/page_header.tsx | 4 - .../common/header/page_tabs.test.tsx | 5 - .../components/common/header/page_tabs.tsx | 17 +-- 6 files changed, 166 insertions(+), 88 deletions(-) create mode 100644 x-pack/plugins/uptime/public/components/common/header/action_menu_content.test.tsx create mode 100644 x-pack/plugins/uptime/public/components/common/header/action_menu_content.tsx diff --git a/x-pack/plugins/uptime/public/components/common/header/action_menu.tsx b/x-pack/plugins/uptime/public/components/common/header/action_menu.tsx index 1d5a375acedee..6186d6f38b968 100644 --- a/x-pack/plugins/uptime/public/components/common/header/action_menu.tsx +++ b/x-pack/plugins/uptime/public/components/common/header/action_menu.tsx @@ -6,70 +6,12 @@ */ import React from 'react'; -import { EuiButtonEmpty, EuiFlexGroup, EuiFlexItem, EuiToolTip } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import { useKibana } from '../../../../../../../src/plugins/kibana_react/public'; -import { - createExploratoryViewUrl, - HeaderMenuPortal, - SeriesUrl, -} from '../../../../../observability/public'; +import { HeaderMenuPortal } from '../../../../../observability/public'; import { AppMountParameters } from '../../../../../../../src/core/public'; -import { useUptimeSettingsContext } from '../../../contexts/uptime_settings_context'; -import { useGetUrlParams } from '../../../hooks'; +import { ActionMenuContent } from './action_menu_content'; -const ADD_DATA_LABEL = i18n.translate('xpack.uptime.addDataButtonLabel', { - defaultMessage: 'Add data', -}); - -const ANALYZE_DATA = i18n.translate('xpack.uptime.analyzeDataButtonLabel', { - defaultMessage: 'Analyze data', -}); - -const ANALYZE_MESSAGE = i18n.translate('xpack.uptime.analyzeDataButtonLabel.message', { - defaultMessage: - 'EXPERIMENTAL - Analyze Data allows you to select and filter result data in any dimension and look for the cause or impact of performance problems.', -}); - -export const ActionMenu = ({ appMountParameters }: { appMountParameters: AppMountParameters }) => { - const kibana = useKibana(); - const { basePath } = useUptimeSettingsContext(); - const { dateRangeStart, dateRangeEnd } = useGetUrlParams(); - - const syntheticExploratoryViewLink = createExploratoryViewUrl( - { - 'synthetics-series': { - dataType: 'synthetics', - time: { from: dateRangeStart, to: dateRangeEnd }, - } as SeriesUrl, - }, - basePath - ); - - return ( - - - - {ANALYZE_MESSAGE}

}> - - {ANALYZE_DATA} - -
-
- - - {ADD_DATA_LABEL} - - -
-
- ); -}; +export const ActionMenu = ({ appMountParameters }: { appMountParameters: AppMountParameters }) => ( + + + +); diff --git a/x-pack/plugins/uptime/public/components/common/header/action_menu_content.test.tsx b/x-pack/plugins/uptime/public/components/common/header/action_menu_content.test.tsx new file mode 100644 index 0000000000000..bc5eab6f92111 --- /dev/null +++ b/x-pack/plugins/uptime/public/components/common/header/action_menu_content.test.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 { fireEvent, waitFor } from '@testing-library/react'; +import { render } from '../../../lib/helper/rtl_helpers'; +import { ActionMenuContent } from './action_menu_content'; + +describe('ActionMenuContent', () => { + it('renders alerts dropdown', async () => { + const { getByLabelText, getByText } = render(); + + const alertsDropdown = getByLabelText('Open alert context menu'); + fireEvent.click(alertsDropdown); + + await waitFor(() => { + expect(getByText('Create alert')); + expect(getByText('Manage alerts')); + }); + }); + + it('renders settings link', () => { + const { getByRole, getByText } = render(); + + const settingsAnchor = getByRole('link', { name: 'Navigate to the Uptime settings page' }); + expect(settingsAnchor.getAttribute('href')).toBe('/settings'); + expect(getByText('Settings')); + }); + + it('renders exploratory view link', () => { + const { getByLabelText, getByText } = render(); + + const analyzeAnchor = getByLabelText( + 'Navigate to the "Analyze Data" view to visualize Synthetics/User data' + ); + + expect(analyzeAnchor.getAttribute('href')).toContain('/app/observability/exploratory-view'); + expect(getByText('Analyze data')); + }); + + it('renders Add Data link', () => { + const { getByLabelText, getByText } = render(); + + const addDataAnchor = getByLabelText('Navigate to a tutorial about adding Uptime data'); + + // this href value is mocked, so it doesn't correspond to the real link + // that Kibana core services will provide + expect(addDataAnchor.getAttribute('href')).toBe('/app/uptime'); + expect(getByText('Add data')); + }); +}); diff --git a/x-pack/plugins/uptime/public/components/common/header/action_menu_content.tsx b/x-pack/plugins/uptime/public/components/common/header/action_menu_content.tsx new file mode 100644 index 0000000000000..ac7c8ae0a95c6 --- /dev/null +++ b/x-pack/plugins/uptime/public/components/common/header/action_menu_content.tsx @@ -0,0 +1,101 @@ +/* + * 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 { EuiButtonEmpty, EuiHeaderLinks, EuiHeaderSectionItem, EuiToolTip } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { useHistory } from 'react-router-dom'; +import { createExploratoryViewUrl, SeriesUrl } from '../../../../../observability/public'; +import { useKibana } from '../../../../../../../src/plugins/kibana_react/public'; +import { useUptimeSettingsContext } from '../../../contexts/uptime_settings_context'; +import { useGetUrlParams } from '../../../hooks'; +import { ToggleAlertFlyoutButton } from '../../overview/alerts/alerts_containers'; +import { SETTINGS_ROUTE } from '../../../../common/constants'; +import { stringifyUrlParams } from '../../../lib/helper/stringify_url_params'; + +const ADD_DATA_LABEL = i18n.translate('xpack.uptime.addDataButtonLabel', { + defaultMessage: 'Add data', +}); + +const ANALYZE_DATA = i18n.translate('xpack.uptime.analyzeDataButtonLabel', { + defaultMessage: 'Analyze data', +}); + +const ANALYZE_MESSAGE = i18n.translate('xpack.uptime.analyzeDataButtonLabel.message', { + defaultMessage: + 'EXPERIMENTAL - Analyze Data allows you to select and filter result data in any dimension and look for the cause or impact of performance problems.', +}); + +export function ActionMenuContent(): React.ReactElement { + const kibana = useKibana(); + const { basePath } = useUptimeSettingsContext(); + const params = useGetUrlParams(); + const { dateRangeStart, dateRangeEnd } = params; + const history = useHistory(); + + const syntheticExploratoryViewLink = createExploratoryViewUrl( + { + 'synthetics-series': { + dataType: 'synthetics', + time: { from: dateRangeStart, to: dateRangeEnd }, + } as SeriesUrl, + }, + basePath + ); + + return ( + + + + + + + + + + + {ANALYZE_MESSAGE}

}> + + {ANALYZE_DATA} + +
+
+ + + {ADD_DATA_LABEL} + + +
+ ); +} diff --git a/x-pack/plugins/uptime/public/components/common/header/page_header.tsx b/x-pack/plugins/uptime/public/components/common/header/page_header.tsx index 753ce267d141c..28a133698ae8b 100644 --- a/x-pack/plugins/uptime/public/components/common/header/page_header.tsx +++ b/x-pack/plugins/uptime/public/components/common/header/page_header.tsx @@ -12,7 +12,6 @@ import { UptimeDatePicker } from '../uptime_date_picker'; import { SyntheticsCallout } from '../../overview/synthetics_callout'; import { PageTabs } from './page_tabs'; import { CertRefreshBtn } from '../../certificates/cert_refresh_btn'; -import { ToggleAlertFlyoutButton } from '../../overview/alerts/alerts_containers'; import { MonitorPageTitle } from '../../monitor/monitor_title'; export interface Props { @@ -52,9 +51,6 @@ export const PageHeader = ({ {showMonitorTitle && } {showTabs && } - - - {showCertificateRefreshBtn && } {showDatePicker && ( diff --git a/x-pack/plugins/uptime/public/components/common/header/page_tabs.test.tsx b/x-pack/plugins/uptime/public/components/common/header/page_tabs.test.tsx index edb1b56668b15..2870006dc20be 100644 --- a/x-pack/plugins/uptime/public/components/common/header/page_tabs.test.tsx +++ b/x-pack/plugins/uptime/public/components/common/header/page_tabs.test.tsx @@ -15,7 +15,6 @@ describe('PageTabs', () => { const { getByText } = render(); expect(getByText('Overview')).toBeInTheDocument(); expect(getByText('Certificates')).toBeInTheDocument(); - expect(getByText('Settings')).toBeInTheDocument(); }); it('it keep params while switching', () => { @@ -32,10 +31,6 @@ describe('PageTabs', () => { 'href', '/certificates?dateRangeStart=now-10m' ); - expect(getByTestId('settings-page-link')).toHaveAttribute( - 'href', - '/settings?dateRangeStart=now-10m' - ); }); it('it resets params on overview if already on overview', () => { diff --git a/x-pack/plugins/uptime/public/components/common/header/page_tabs.tsx b/x-pack/plugins/uptime/public/components/common/header/page_tabs.tsx index 263351d4ea4d0..74b037971c126 100644 --- a/x-pack/plugins/uptime/public/components/common/header/page_tabs.tsx +++ b/x-pack/plugins/uptime/public/components/common/header/page_tabs.tsx @@ -10,7 +10,7 @@ import React, { useEffect, useState } from 'react'; import { EuiTabs, EuiTab } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { useHistory, useRouteMatch } from 'react-router-dom'; -import { CERTIFICATES_ROUTE, OVERVIEW_ROUTE, SETTINGS_ROUTE } from '../../../../common/constants'; +import { CERTIFICATES_ROUTE, OVERVIEW_ROUTE } from '../../../../common/constants'; import { useGetUrlParams } from '../../../hooks'; import { stringifyUrlParams } from '../../../lib/helper/stringify_url_params'; @@ -28,13 +28,6 @@ const tabs = [ name: 'Certificates', dataTestSubj: 'uptimeCertificatesLink', }, - { - id: SETTINGS_ROUTE, - dataTestSubj: 'settings-page-link', - name: i18n.translate('xpack.uptime.page_header.settingsLink', { - defaultMessage: 'Settings', - }), - }, ]; export const PageTabs = () => { @@ -45,7 +38,6 @@ export const PageTabs = () => { const params = useGetUrlParams(); const isOverView = useRouteMatch(OVERVIEW_ROUTE); - const isSettings = useRouteMatch(SETTINGS_ROUTE); const isCerts = useRouteMatch(CERTIFICATES_ROUTE); useEffect(() => { @@ -55,13 +47,10 @@ export const PageTabs = () => { if (isCerts) { setSelectedTabId(CERTIFICATES_ROUTE); } - if (isSettings) { - setSelectedTabId(SETTINGS_ROUTE); - } - if (!isOverView?.isExact && !isCerts && !isSettings) { + if (!isOverView?.isExact && !isCerts) { setSelectedTabId(null); } - }, [isCerts, isSettings, isOverView]); + }, [isCerts, isOverView]); const createHrefForTab = (id: string) => { if (selectedTabId === OVERVIEW_ROUTE && id === OVERVIEW_ROUTE) { From dbd0ce761ad8f06cc8494827ef69df0a621cf5a6 Mon Sep 17 00:00:00 2001 From: Spencer Date: Wed, 26 May 2021 12:41:05 -0700 Subject: [PATCH 10/77] [ftr] migrate "toasts" service to FtrService class (#100613) Co-authored-by: spalger --- test/functional/services/index.ts | 4 +- test/functional/services/toasts.ts | 116 ++++++++++++++--------------- 2 files changed, 58 insertions(+), 62 deletions(-) diff --git a/test/functional/services/index.ts b/test/functional/services/index.ts index b2e0a3e0f473e..93026af6766bd 100644 --- a/test/functional/services/index.ts +++ b/test/functional/services/index.ts @@ -36,7 +36,7 @@ import { ManagementMenuService } from './management'; import { QueryBarProvider } from './query_bar'; import { RemoteProvider } from './remote'; import { RenderableProvider } from './renderable'; -import { ToastsProvider } from './toasts'; +import { ToastsService } from './toasts'; import { DataGridService } from './data_grid'; import { PieChartService, @@ -79,7 +79,7 @@ export const services = { vegaDebugInspector: VegaDebugInspectorViewService, appsMenu: AppsMenuProvider, globalNav: GlobalNavService, - toasts: ToastsProvider, + toasts: ToastsService, savedQueryManagementComponent: SavedQueryManagementComponentProvider, elasticChart: ElasticChartService, supertest: KibanaSupertestProvider, diff --git a/test/functional/services/toasts.ts b/test/functional/services/toasts.ts index aeaf79e75574a..d71d66e399785 100644 --- a/test/functional/services/toasts.ts +++ b/test/functional/services/toasts.ts @@ -6,78 +6,74 @@ * Side Public License, v 1. */ -import { FtrProviderContext } from '../ftr_provider_context'; +import { FtrService } from '../ftr_provider_context'; -export function ToastsProvider({ getService }: FtrProviderContext) { - const testSubjects = getService('testSubjects'); +export class ToastsService extends FtrService { + private readonly testSubjects = this.ctx.getService('testSubjects'); - class Toasts { - /** - * Returns the title and message of a specific error toast. - * This method is specific to toasts created via `.addError` since they contain - * an additional button, that should not be part of the message. - * - * @param index The index of the toast (1-based, NOT 0-based!) of the toast. Use first by default. - * @returns The title and message of the specified error toast.https://github.com/elastic/kibana/issues/17087 - */ - public async getErrorToast(index: number = 1) { - const toast = await this.getToastElement(index); - const titleElement = await testSubjects.findDescendant('euiToastHeader', toast); - const title: string = await titleElement.getVisibleText(); - const messageElement = await testSubjects.findDescendant('errorToastMessage', toast); - const message: string = await messageElement.getVisibleText(); - return { title, message }; - } + /** + * Returns the title and message of a specific error toast. + * This method is specific to toasts created via `.addError` since they contain + * an additional button, that should not be part of the message. + * + * @param index The index of the toast (1-based, NOT 0-based!) of the toast. Use first by default. + * @returns The title and message of the specified error toast.https://github.com/elastic/kibana/issues/17087 + */ + public async getErrorToast(index: number = 1) { + const toast = await this.getToastElement(index); + const titleElement = await this.testSubjects.findDescendant('euiToastHeader', toast); + const title: string = await titleElement.getVisibleText(); + const messageElement = await this.testSubjects.findDescendant('errorToastMessage', toast); + const message: string = await messageElement.getVisibleText(); + return { title, message }; + } - /** - * Dismiss a specific toast from the toast list. Since toasts usually should time out themselves, - * you only need to call this for permanent toasts (e.g. error toasts). - * - * @param index The 1-based index of the toast to dismiss. Use first by default. - */ - public async dismissToast(index: number = 1) { - const toast = await this.getToastElement(index); - await toast.moveMouseTo(); - const dismissButton = await testSubjects.findDescendant('toastCloseButton', toast); - await dismissButton.click(); - } + /** + * Dismiss a specific toast from the toast list. Since toasts usually should time out themselves, + * you only need to call this for permanent toasts (e.g. error toasts). + * + * @param index The 1-based index of the toast to dismiss. Use first by default. + */ + public async dismissToast(index: number = 1) { + const toast = await this.getToastElement(index); + await toast.moveMouseTo(); + const dismissButton = await this.testSubjects.findDescendant('toastCloseButton', toast); + await dismissButton.click(); + } - public async dismissAllToasts() { - const list = await this.getGlobalToastList(); - const toasts = await list.findAllByCssSelector(`.euiToast`); + public async dismissAllToasts() { + const list = await this.getGlobalToastList(); + const toasts = await list.findAllByCssSelector(`.euiToast`); - if (toasts.length === 0) return; + if (toasts.length === 0) return; - for (const toast of toasts) { - await toast.moveMouseTo(); + for (const toast of toasts) { + await toast.moveMouseTo(); - if (await testSubjects.descendantExists('toastCloseButton', toast)) { - try { - const dismissButton = await testSubjects.findDescendant('toastCloseButton', toast); - await dismissButton.click(); - } catch (err) { - // ignore errors - // toasts are finnicky because they can dismiss themselves right before you close them - } + if (await this.testSubjects.descendantExists('toastCloseButton', toast)) { + try { + const dismissButton = await this.testSubjects.findDescendant('toastCloseButton', toast); + await dismissButton.click(); + } catch (err) { + // ignore errors + // toasts are finnicky because they can dismiss themselves right before you close them } } } + } - public async getToastElement(index: number) { - const list = await this.getGlobalToastList(); - return await list.findByCssSelector(`.euiToast:nth-child(${index})`); - } - - private async getGlobalToastList() { - return await testSubjects.find('globalToastList'); - } + public async getToastElement(index: number) { + const list = await this.getGlobalToastList(); + return await list.findByCssSelector(`.euiToast:nth-child(${index})`); + } - public async getToastCount() { - const list = await this.getGlobalToastList(); - const toasts = await list.findAllByCssSelector(`.euiToast`); - return toasts.length; - } + private async getGlobalToastList() { + return await this.testSubjects.find('globalToastList'); } - return new Toasts(); + public async getToastCount() { + const list = await this.getGlobalToastList(); + const toasts = await list.findAllByCssSelector(`.euiToast`); + return toasts.length; + } } From 881d89fba7cc8b7f963fcd5230a60b1f23ac8259 Mon Sep 17 00:00:00 2001 From: Mikhail Shustov Date: Wed, 26 May 2021 22:01:33 +0200 Subject: [PATCH 11/77] remove src/legacy and src/optimizer from configs (#100538) * cleanup removed dirs * delete removed folders from other places in the repo Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .i18nrc.json | 2 -- packages/kbn-test/src/jest/run_check_jest_configs_cli.ts | 2 +- src/dev/precommit_hook/casing_check_config.js | 1 - tsconfig.json | 2 -- x-pack/plugins/canvas/shareable_runtime/webpack.config.js | 1 - x-pack/plugins/canvas/storybook/webpack.dll.config.js | 7 ------- 6 files changed, 1 insertion(+), 14 deletions(-) diff --git a/.i18nrc.json b/.i18nrc.json index 1e07d662c057a..dc01a10b6a686 100644 --- a/.i18nrc.json +++ b/.i18nrc.json @@ -1,6 +1,5 @@ { "paths": { - "common.ui": "src/legacy/ui", "console": "src/plugins/console", "core": "src/core", "discover": "src/plugins/discover", @@ -61,6 +60,5 @@ "apmOss": "src/plugins/apm_oss", "usageCollection": "src/plugins/usage_collection" }, - "exclude": ["src/legacy/ui/ui_render/ui_render_mixin.js"], "translations": [] } diff --git a/packages/kbn-test/src/jest/run_check_jest_configs_cli.ts b/packages/kbn-test/src/jest/run_check_jest_configs_cli.ts index 3ce38733dfd24..5895ef193fbfe 100644 --- a/packages/kbn-test/src/jest/run_check_jest_configs_cli.ts +++ b/packages/kbn-test/src/jest/run_check_jest_configs_cli.ts @@ -26,7 +26,7 @@ const template: string = `module.exports = { }; `; -const roots: string[] = ['x-pack/plugins', 'packages', 'src/legacy', 'src/plugins', 'test', 'src']; +const roots: string[] = ['x-pack/plugins', 'packages', 'src/plugins', 'test', 'src']; export async function runCheckJestConfigsCli() { run( diff --git a/src/dev/precommit_hook/casing_check_config.js b/src/dev/precommit_hook/casing_check_config.js index 3aed49b5015bb..0d5ecab40fbc4 100644 --- a/src/dev/precommit_hook/casing_check_config.js +++ b/src/dev/precommit_hook/casing_check_config.js @@ -94,7 +94,6 @@ export const IGNORE_DIRECTORY_GLOBS = [ ...KEBAB_CASE_DIRECTORY_GLOBS, 'src/babel-*', 'packages/*', - 'src/legacy/ui/public/flot-charts', 'test/functional/fixtures/es_archiver/visualize_source-filters', 'packages/kbn-pm/src/utils/__fixtures__/*', 'x-pack/dev-tools', diff --git a/tsconfig.json b/tsconfig.json index c56d4c6b8dc32..ceb03107076c2 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -10,8 +10,6 @@ "src/cli/**/*", "src/dev/**/*", "src/fixtures/**/*", - "src/legacy/**/*", - "src/optimize/**/*", "x-pack/tasks/**/*", ], diff --git a/x-pack/plugins/canvas/shareable_runtime/webpack.config.js b/x-pack/plugins/canvas/shareable_runtime/webpack.config.js index 34fade58ffc8d..e85840e873430 100644 --- a/x-pack/plugins/canvas/shareable_runtime/webpack.config.js +++ b/x-pack/plugins/canvas/shareable_runtime/webpack.config.js @@ -33,7 +33,6 @@ module.exports = { // Include a require alias for legacy UI code and styles resolve: { alias: { - ui: path.resolve(KIBANA_ROOT, 'src/legacy/ui/public'), 'data/interpreter': path.resolve( KIBANA_ROOT, 'src/plugins/data/public/expressions/interpreter' diff --git a/x-pack/plugins/canvas/storybook/webpack.dll.config.js b/x-pack/plugins/canvas/storybook/webpack.dll.config.js index 3051bbebdaf0c..c13fabe998921 100644 --- a/x-pack/plugins/canvas/storybook/webpack.dll.config.js +++ b/x-pack/plugins/canvas/storybook/webpack.dll.config.js @@ -77,13 +77,6 @@ module.exports = { filename: 'dll.js', library: DLL_NAME, }, - // Include a require alias for legacy UI code and styles - resolve: { - alias: { - ui: path.resolve(KIBANA_ROOT, 'src/legacy/ui/public'), - }, - symlinks: false, - }, module: { rules: [ { From af59f68e8ba60d0919742f9a5fb0fb052295dcc7 Mon Sep 17 00:00:00 2001 From: Spencer Date: Wed, 26 May 2021 13:55:04 -0700 Subject: [PATCH 12/77] [ftr] migrate "flyout" and "inspector" services to FtrService class (#100602) Co-authored-by: spalger --- test/functional/services/flyout.ts | 74 +++-- test/functional/services/index.ts | 8 +- test/functional/services/inspector.ts | 414 +++++++++++++------------- 3 files changed, 244 insertions(+), 252 deletions(-) diff --git a/test/functional/services/flyout.ts b/test/functional/services/flyout.ts index 2e10bf757ac7a..e7b57dc0fb66b 100644 --- a/test/functional/services/flyout.ts +++ b/test/functional/services/flyout.ts @@ -6,50 +6,46 @@ * Side Public License, v 1. */ -import { FtrProviderContext } from '../ftr_provider_context'; - -export function FlyoutProvider({ getService }: FtrProviderContext) { - const testSubjects = getService('testSubjects'); - const find = getService('find'); - const log = getService('log'); - const retry = getService('retry'); - - class Flyout { - public async close(dataTestSubj: string): Promise { - log.debug('Closing flyout', dataTestSubj); - const flyoutElement = await testSubjects.find(dataTestSubj); - const closeBtn = await flyoutElement.findByCssSelector('[aria-label*="Close"]'); - await closeBtn.click(); - await retry.waitFor( - 'flyout closed', - async () => !(await testSubjects.exists(dataTestSubj, { timeout: 1000 })) - ); - } +import { FtrService } from '../ftr_provider_context'; + +export class FlyoutService extends FtrService { + private readonly testSubjects = this.ctx.getService('testSubjects'); + private readonly find = this.ctx.getService('find'); + private readonly log = this.ctx.getService('log'); + private readonly retry = this.ctx.getService('retry'); + + public async close(dataTestSubj: string): Promise { + this.log.debug('Closing flyout', dataTestSubj); + const flyoutElement = await this.testSubjects.find(dataTestSubj); + const closeBtn = await flyoutElement.findByCssSelector('[aria-label*="Close"]'); + await closeBtn.click(); + await this.retry.waitFor( + 'flyout closed', + async () => !(await this.testSubjects.exists(dataTestSubj, { timeout: 1000 })) + ); + } - public async ensureClosed(dataTestSubj: string): Promise { - if (await testSubjects.exists(dataTestSubj, { timeout: 1000 })) { - await this.close(dataTestSubj); - } + public async ensureClosed(dataTestSubj: string): Promise { + if (await this.testSubjects.exists(dataTestSubj, { timeout: 1000 })) { + await this.close(dataTestSubj); } + } - public async ensureAllClosed(): Promise { - const flyoutElements = await find.allByCssSelector('.euiFlyout'); - - if (!flyoutElements.length) { - return; - } + public async ensureAllClosed(): Promise { + const flyoutElements = await this.find.allByCssSelector('.euiFlyout'); - for (let i = 0; i < flyoutElements.length; i++) { - const closeBtn = await flyoutElements[i].findByCssSelector('[aria-label*="Close"]'); - await closeBtn.click(); - } + if (!flyoutElements.length) { + return; + } - await retry.waitFor( - 'all flyouts to be closed', - async () => (await find.allByCssSelector('.euiFlyout')).length === 0 - ); + for (let i = 0; i < flyoutElements.length; i++) { + const closeBtn = await flyoutElements[i].findByCssSelector('[aria-label*="Close"]'); + await closeBtn.click(); } - } - return new Flyout(); + await this.retry.waitFor( + 'all flyouts to be closed', + async () => (await this.find.allByCssSelector('.euiFlyout')).length === 0 + ); + } } diff --git a/test/functional/services/index.ts b/test/functional/services/index.ts index 93026af6766bd..8dcefcba55d6d 100644 --- a/test/functional/services/index.ts +++ b/test/functional/services/index.ts @@ -28,9 +28,9 @@ import { import { DocTableService } from './doc_table'; import { EmbeddingProvider } from './embedding'; import { FilterBarService } from './filter_bar'; -import { FlyoutProvider } from './flyout'; +import { FlyoutService } from './flyout'; import { GlobalNavService } from './global_nav'; -import { InspectorProvider } from './inspector'; +import { InspectorService } from './inspector'; import { FieldEditorService } from './field_editor'; import { ManagementMenuService } from './management'; import { QueryBarProvider } from './query_bar'; @@ -67,14 +67,14 @@ export const services = { dashboardAddPanel: DashboardAddPanelService, dashboardReplacePanel: DashboardReplacePanelService, dashboardPanelActions: DashboardPanelActionsService, - flyout: FlyoutProvider, + flyout: FlyoutService, comboBox: ComboBoxProvider, dataGrid: DataGridService, embedding: EmbeddingProvider, renderable: RenderableProvider, browser: BrowserProvider, pieChart: PieChartService, - inspector: InspectorProvider, + inspector: InspectorService, fieldEditor: FieldEditorService, vegaDebugInspector: VegaDebugInspectorViewService, appsMenu: AppsMenuProvider, diff --git a/test/functional/services/inspector.ts b/test/functional/services/inspector.ts index c9cf159d0d38e..dc46db458501b 100644 --- a/test/functional/services/inspector.ts +++ b/test/functional/services/inspector.ts @@ -7,234 +7,230 @@ */ import expect from '@kbn/expect'; -import { FtrProviderContext } from '../ftr_provider_context'; - -export function InspectorProvider({ getService }: FtrProviderContext) { - const log = getService('log'); - const retry = getService('retry'); - const renderable = getService('renderable'); - const flyout = getService('flyout'); - const testSubjects = getService('testSubjects'); - const find = getService('find'); - - class Inspector { - private async getIsEnabled(): Promise { - const ariaDisabled = await testSubjects.getAttribute('openInspectorButton', 'disabled'); - return ariaDisabled !== 'true'; - } - - /** - * Asserts that inspector is enabled - */ - public async expectIsEnabled(): Promise { - await retry.try(async () => { - const isEnabled = await this.getIsEnabled(); - expect(isEnabled).to.be(true); - }); - } +import { FtrService } from '../ftr_provider_context'; + +export class InspectorService extends FtrService { + private readonly log = this.ctx.getService('log'); + private readonly retry = this.ctx.getService('retry'); + private readonly renderable = this.ctx.getService('renderable'); + private readonly flyout = this.ctx.getService('flyout'); + private readonly testSubjects = this.ctx.getService('testSubjects'); + private readonly find = this.ctx.getService('find'); + + private async getIsEnabled(): Promise { + const ariaDisabled = await this.testSubjects.getAttribute('openInspectorButton', 'disabled'); + return ariaDisabled !== 'true'; + } - /** - * Asserts that inspector is disabled - */ - public async expectIsNotEnabled(): Promise { - await retry.try(async () => { - const isEnabled = await this.getIsEnabled(); - expect(isEnabled).to.be(false); - }); - } + /** + * Asserts that inspector is enabled + */ + public async expectIsEnabled(): Promise { + await this.retry.try(async () => { + const isEnabled = await this.getIsEnabled(); + expect(isEnabled).to.be(true); + }); + } - /** - * Opens inspector panel - */ - public async open(): Promise { - log.debug('Inspector.open'); - const isOpen = await testSubjects.exists('inspectorPanel'); - if (!isOpen) { - await retry.try(async () => { - await testSubjects.click('openInspectorButton'); - await testSubjects.exists('inspectorPanel'); - }); - } - } + /** + * Asserts that inspector is disabled + */ + public async expectIsNotEnabled(): Promise { + await this.retry.try(async () => { + const isEnabled = await this.getIsEnabled(); + expect(isEnabled).to.be(false); + }); + } - /** - * Closes inspector panel - */ - public async close(): Promise { - log.debug('Close Inspector'); - let isOpen = await testSubjects.exists('inspectorPanel'); - if (isOpen) { - await retry.try(async () => { - await flyout.close('inspectorPanel'); - isOpen = await testSubjects.exists('inspectorPanel'); - if (isOpen) { - throw new Error('Failed to close inspector'); - } - }); - } + /** + * Opens inspector panel + */ + public async open(): Promise { + this.log.debug('Inspector.open'); + const isOpen = await this.testSubjects.exists('inspectorPanel'); + if (!isOpen) { + await this.retry.try(async () => { + await this.testSubjects.click('openInspectorButton'); + await this.testSubjects.exists('inspectorPanel'); + }); } + } - /** - * Asserts data on inspector panel - * @param expectedData - */ - public async expectTableData(expectedData: string[][]): Promise { - log.debug(`Inspector.expectTableData(${expectedData.join(',')})`); - const data = await this.getTableData(); - expect(data).to.eql(expectedData); + /** + * Closes inspector panel + */ + public async close(): Promise { + this.log.debug('Close Inspector'); + let isOpen = await this.testSubjects.exists('inspectorPanel'); + if (isOpen) { + await this.retry.try(async () => { + await this.flyout.close('inspectorPanel'); + isOpen = await this.testSubjects.exists('inspectorPanel'); + if (isOpen) { + throw new Error('Failed to close inspector'); + } + }); } + } - /** - * Sets table page size - * @param size rows count - */ - public async setTablePageSize(size: number): Promise { - const panel = await testSubjects.find('inspectorPanel'); - await find.clickByButtonText('Rows per page: 20', panel); - // The buttons for setting table page size are in a popover element. This popover - // element appears as if it's part of the inspectorPanel but it's really attached - // to the body element by a portal. - const tableSizesPopover = await find.byCssSelector('.euiPanel .euiContextMenuPanel'); - await find.clickByButtonText(`${size} rows`, tableSizesPopover); - } + /** + * Asserts data on inspector panel + * @param expectedData + */ + public async expectTableData(expectedData: string[][]): Promise { + this.log.debug(`Inspector.expectTableData(${expectedData.join(',')})`); + const data = await this.getTableData(); + expect(data).to.eql(expectedData); + } - /** - * Returns table data in nested array format - */ - public async getTableData(): Promise { - // TODO: we should use datat-test-subj=inspectorTable as soon as EUI supports it - const inspectorPanel = await testSubjects.find('inspectorPanel'); - const tableBody = await retry.try(async () => inspectorPanel.findByTagName('tbody')); - const $ = await tableBody.parseDomContent(); - return $('tr') - .toArray() - .map((tr) => { - return $(tr) - .find('td') - .toArray() - .map((cell) => { - // if this is an EUI table, filter down to the specific cell content - // otherwise this will include mobile-specific header information - const euiTableCellContent = $(cell).find('.euiTableCellContent'); - - if (euiTableCellContent.length > 0) { - return $(cell).find('.euiTableCellContent').text().trim(); - } else { - return $(cell).text().trim(); - } - }); - }); - } + /** + * Sets table page size + * @param size rows count + */ + public async setTablePageSize(size: number): Promise { + const panel = await this.testSubjects.find('inspectorPanel'); + await this.find.clickByButtonText('Rows per page: 20', panel); + // The buttons for setting table page size are in a popover element. This popover + // element appears as if it's part of the inspectorPanel but it's really attached + // to the body element by a portal. + const tableSizesPopover = await this.find.byCssSelector('.euiPanel .euiContextMenuPanel'); + await this.find.clickByButtonText(`${size} rows`, tableSizesPopover); + } - /** - * Returns table headers - */ - public async getTableHeaders(): Promise { - log.debug('Inspector.getTableHeaders'); - // TODO: we should use datat-test-subj=inspectorTable as soon as EUI supports it - const dataTableHeader = await retry.try(async () => { - const inspectorPanel = await testSubjects.find('inspectorPanel'); - return await inspectorPanel.findByTagName('thead'); + /** + * Returns table data in nested array format + */ + public async getTableData(): Promise { + // TODO: we should use datat-test-subj=inspectorTable as soon as EUI supports it + const inspectorPanel = await this.testSubjects.find('inspectorPanel'); + const tableBody = await this.retry.try(async () => inspectorPanel.findByTagName('tbody')); + const $ = await tableBody.parseDomContent(); + return $('tr') + .toArray() + .map((tr) => { + return $(tr) + .find('td') + .toArray() + .map((cell) => { + // if this is an EUI table, filter down to the specific cell content + // otherwise this will include mobile-specific header information + const euiTableCellContent = $(cell).find('.euiTableCellContent'); + + if (euiTableCellContent.length > 0) { + return $(cell).find('.euiTableCellContent').text().trim(); + } else { + return $(cell).text().trim(); + } + }); }); - const $ = await dataTableHeader.parseDomContent(); - return $('th span.euiTableCellContent__text') - .toArray() - .map((cell) => $(cell).text().trim()); - } + } - /** - * Asserts table headers - * @param expected expected headers - */ - public async expectTableHeaders(expected: string[]): Promise { - await retry.try(async () => { - const headers = await this.getTableHeaders(); - expect(headers).to.eql(expected); - }); - } + /** + * Returns table headers + */ + public async getTableHeaders(): Promise { + this.log.debug('Inspector.getTableHeaders'); + // TODO: we should use datat-test-subj=inspectorTable as soon as EUI supports it + const dataTableHeader = await this.retry.try(async () => { + const inspectorPanel = await this.testSubjects.find('inspectorPanel'); + return await inspectorPanel.findByTagName('thead'); + }); + const $ = await dataTableHeader.parseDomContent(); + return $('th span.euiTableCellContent__text') + .toArray() + .map((cell) => $(cell).text().trim()); + } - /** - * Filters table for value by clicking specified cell - * @param column column index - * @param row row index - */ - public async filterForTableCell(column: string | number, row: string | number): Promise { - await retry.try(async () => { - const table = await testSubjects.find('inspectorTable'); - const cell = await table.findByCssSelector( - `tbody tr:nth-child(${row}) td:nth-child(${column})` - ); - await cell.moveMouseTo(); - const filterBtn = await testSubjects.findDescendant('filterForInspectorCellValue', cell); - await filterBtn.click(); - }); - await renderable.waitForRender(); - } + /** + * Asserts table headers + * @param expected expected headers + */ + public async expectTableHeaders(expected: string[]): Promise { + await this.retry.try(async () => { + const headers = await this.getTableHeaders(); + expect(headers).to.eql(expected); + }); + } - /** - * Filters out table by clicking specified cell - * @param column column index - * @param row row index - */ - public async filterOutTableCell(column: string | number, row: string | number): Promise { - await retry.try(async () => { - const table = await testSubjects.find('inspectorTable'); - const cell = await table.findByCssSelector( - `tbody tr:nth-child(${row}) td:nth-child(${column})` - ); - await cell.moveMouseTo(); - const filterBtn = await testSubjects.findDescendant('filterOutInspectorCellValue', cell); - await filterBtn.click(); - }); - await renderable.waitForRender(); - } + /** + * Filters table for value by clicking specified cell + * @param column column index + * @param row row index + */ + public async filterForTableCell(column: string | number, row: string | number): Promise { + await this.retry.try(async () => { + const table = await this.testSubjects.find('inspectorTable'); + const cell = await table.findByCssSelector( + `tbody tr:nth-child(${row}) td:nth-child(${column})` + ); + await cell.moveMouseTo(); + const filterBtn = await this.testSubjects.findDescendant('filterForInspectorCellValue', cell); + await filterBtn.click(); + }); + await this.renderable.waitForRender(); + } - /** - * Opens inspector view - * @param viewId - */ - public async openInspectorView(viewId: string): Promise { - log.debug(`Open Inspector view ${viewId}`); - await testSubjects.click('inspectorViewChooser'); - await testSubjects.click(viewId); - } + /** + * Filters out table by clicking specified cell + * @param column column index + * @param row row index + */ + public async filterOutTableCell(column: string | number, row: string | number): Promise { + await this.retry.try(async () => { + const table = await this.testSubjects.find('inspectorTable'); + const cell = await table.findByCssSelector( + `tbody tr:nth-child(${row}) td:nth-child(${column})` + ); + await cell.moveMouseTo(); + const filterBtn = await this.testSubjects.findDescendant('filterOutInspectorCellValue', cell); + await filterBtn.click(); + }); + await this.renderable.waitForRender(); + } - /** - * Opens inspector requests view - */ - public async openInspectorRequestsView(): Promise { - await this.openInspectorView('inspectorViewChooserRequests'); - } + /** + * Opens inspector view + * @param viewId + */ + public async openInspectorView(viewId: string): Promise { + this.log.debug(`Open Inspector view ${viewId}`); + await this.testSubjects.click('inspectorViewChooser'); + await this.testSubjects.click(viewId); + } - /** - * Returns request name as the comma-separated string - */ - public async getRequestNames(): Promise { - await this.openInspectorRequestsView(); - const requestChooserExists = await testSubjects.exists('inspectorRequestChooser'); - if (requestChooserExists) { - await testSubjects.click('inspectorRequestChooser'); - const menu = await testSubjects.find('inspectorRequestChooserMenuPanel'); - const requestNames = await menu.getVisibleText(); - return requestNames.trim().split('\n').join(','); - } - - const singleRequest = await testSubjects.find('inspectorRequestName'); - return await singleRequest.getVisibleText(); - } + /** + * Opens inspector requests view + */ + public async openInspectorRequestsView(): Promise { + await this.openInspectorView('inspectorViewChooserRequests'); + } - public getOpenRequestStatisticButton() { - return testSubjects.find('inspectorRequestDetailStatistics'); - } + /** + * Returns request name as the comma-separated string + */ + public async getRequestNames(): Promise { + await this.openInspectorRequestsView(); + const requestChooserExists = await this.testSubjects.exists('inspectorRequestChooser'); + if (requestChooserExists) { + await this.testSubjects.click('inspectorRequestChooser'); + const menu = await this.testSubjects.find('inspectorRequestChooserMenuPanel'); + const requestNames = await menu.getVisibleText(); + return requestNames.trim().split('\n').join(','); + } + + const singleRequest = await this.testSubjects.find('inspectorRequestName'); + return await singleRequest.getVisibleText(); + } - public getOpenRequestDetailRequestButton() { - return testSubjects.find('inspectorRequestDetailRequest'); - } + public getOpenRequestStatisticButton() { + return this.testSubjects.find('inspectorRequestDetailStatistics'); + } - public getOpenRequestDetailResponseButton() { - return testSubjects.find('inspectorRequestDetailResponse'); - } + public getOpenRequestDetailRequestButton() { + return this.testSubjects.find('inspectorRequestDetailRequest'); } - return new Inspector(); + public getOpenRequestDetailResponseButton() { + return this.testSubjects.find('inspectorRequestDetailResponse'); + } } From b6d595268eab40d0184eb0ec0193974f2b8d46c1 Mon Sep 17 00:00:00 2001 From: Joe Portner <5295965+jportner@users.noreply.github.com> Date: Wed, 26 May 2021 17:10:55 -0400 Subject: [PATCH 13/77] Bump dependencies (#100724) --- packages/kbn-pm/dist/index.js | 52 ++++++++++++----------------------- yarn.lock | 6 ++-- 2 files changed, 20 insertions(+), 38 deletions(-) diff --git a/packages/kbn-pm/dist/index.js b/packages/kbn-pm/dist/index.js index c0afb92b859cd..29c0457c316f0 100644 --- a/packages/kbn-pm/dist/index.js +++ b/packages/kbn-pm/dist/index.js @@ -30541,29 +30541,14 @@ module.exports = function nodeModulesPaths(start, opts, request) { var isWindows = process.platform === 'win32'; -// Regex to split a windows path into three parts: [*, device, slash, -// tail] windows-only -var splitDeviceRe = - /^([a-zA-Z]:|[\\\/]{2}[^\\\/]+[\\\/]+[^\\\/]+)?([\\\/])?([\s\S]*?)$/; - -// Regex to split the tail part of the above into [*, dir, basename, ext] -var splitTailRe = - /^([\s\S]*?)((?:\.{1,2}|[^\\\/]+?|)(\.[^.\/\\]*|))(?:[\\\/]*)$/; +// Regex to split a windows path into into [dir, root, basename, name, ext] +var splitWindowsRe = + /^(((?:[a-zA-Z]:|[\\\/]{2}[^\\\/]+[\\\/]+[^\\\/]+)?[\\\/]?)(?:[^\\\/]*[\\\/])*)((\.{1,2}|[^\\\/]+?|)(\.[^.\/\\]*|))[\\\/]*$/; var win32 = {}; -// Function to split a filename into [root, dir, basename, ext] function win32SplitPath(filename) { - // Separate device+slash from tail - var result = splitDeviceRe.exec(filename), - device = (result[1] || '') + (result[2] || ''), - tail = result[3] || ''; - // Split the tail into dir, basename and extension - var result2 = splitTailRe.exec(tail), - dir = result2[1], - basename = result2[2], - ext = result2[3]; - return [device, dir, basename, ext]; + return splitWindowsRe.exec(filename).slice(1); } win32.parse = function(pathString) { @@ -30573,24 +30558,24 @@ win32.parse = function(pathString) { ); } var allParts = win32SplitPath(pathString); - if (!allParts || allParts.length !== 4) { + if (!allParts || allParts.length !== 5) { throw new TypeError("Invalid path '" + pathString + "'"); } return { - root: allParts[0], - dir: allParts[0] + allParts[1].slice(0, -1), + root: allParts[1], + dir: allParts[0] === allParts[1] ? allParts[0] : allParts[0].slice(0, -1), base: allParts[2], - ext: allParts[3], - name: allParts[2].slice(0, allParts[2].length - allParts[3].length) + ext: allParts[4], + name: allParts[3] }; }; -// Split a filename into [root, dir, basename, ext], unix version +// Split a filename into [dir, root, basename, name, ext], unix version // 'root' is just a slash, or nothing. var splitPathRe = - /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/; + /^((\/?)(?:[^\/]*\/)*)((\.{1,2}|[^\/]+?|)(\.[^.\/]*|))[\/]*$/; var posix = {}; @@ -30606,19 +30591,16 @@ posix.parse = function(pathString) { ); } var allParts = posixSplitPath(pathString); - if (!allParts || allParts.length !== 4) { + if (!allParts || allParts.length !== 5) { throw new TypeError("Invalid path '" + pathString + "'"); } - allParts[1] = allParts[1] || ''; - allParts[2] = allParts[2] || ''; - allParts[3] = allParts[3] || ''; - + return { - root: allParts[0], - dir: allParts[0] + allParts[1].slice(0, -1), + root: allParts[1], + dir: allParts[0].slice(0, -1), base: allParts[2], - ext: allParts[3], - name: allParts[2].slice(0, allParts[2].length - allParts[3].length) + ext: allParts[4], + name: allParts[3], }; }; diff --git a/yarn.lock b/yarn.lock index 1f09ede5e7900..9f7db552a3f53 100644 --- a/yarn.lock +++ b/yarn.lock @@ -21264,9 +21264,9 @@ path-key@^3.0.0, path-key@^3.1.0: integrity sha512-8cChqz0RP6SHJkMt48FW0A7+qUOn+OsnOsVtzI59tZ8m+5bCSk7hzwET0pulwOM2YMn9J1efb07KB9l9f30SGg== path-parse@^1.0.5, path-parse@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" - integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== path-platform@~0.11.15: version "0.11.15" From f3c846cc4fc7de58fc710a592f85923b6890b582 Mon Sep 17 00:00:00 2001 From: Spencer Date: Wed, 26 May 2021 14:39:10 -0700 Subject: [PATCH 14/77] [ftr] migrate AppsMenuService to FtrService class (#100588) Co-authored-by: spalger Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- test/functional/services/apps_menu.ts | 219 +++++++++++++------------- test/functional/services/index.ts | 4 +- 2 files changed, 111 insertions(+), 112 deletions(-) diff --git a/test/functional/services/apps_menu.ts b/test/functional/services/apps_menu.ts index f9c80a6450c2f..9fb8e36476f3e 100644 --- a/test/functional/services/apps_menu.ts +++ b/test/functional/services/apps_menu.ts @@ -6,133 +6,132 @@ * Side Public License, v 1. */ -import { FtrProviderContext } from '../ftr_provider_context'; +import { FtrService } from '../ftr_provider_context'; -export function AppsMenuProvider({ getService, getPageObjects }: FtrProviderContext) { - const testSubjects = getService('testSubjects'); - const log = getService('log'); - const config = getService('config'); - const defaultFindTimeout = config.get('timeouts.find'); - const find = getService('find'); +export class AppsMenuService extends FtrService { + private readonly testSubjects = this.ctx.getService('testSubjects'); + private readonly log = this.ctx.getService('log'); + private readonly config = this.ctx.getService('config'); + private readonly find = this.ctx.getService('find'); - return new (class AppsMenu { - private async waitUntilLoadingHasFinished() { - try { - await this.isGlobalLoadingIndicatorVisible(); - } catch (exception) { - if (exception.name === 'ElementNotVisible') { - // selenium might just have been too slow to catch it - } else { - throw exception; - } + private readonly defaultFindTimeout = this.config.get('timeouts.find'); + + private async waitUntilLoadingHasFinished() { + try { + await this.isGlobalLoadingIndicatorVisible(); + } catch (exception) { + if (exception.name === 'ElementNotVisible') { + // selenium might just have been too slow to catch it + } else { + throw exception; } - await this.awaitGlobalLoadingIndicatorHidden(); } + await this.awaitGlobalLoadingIndicatorHidden(); + } - private async isGlobalLoadingIndicatorVisible() { - log.debug('isGlobalLoadingIndicatorVisible'); - return await testSubjects.exists('globalLoadingIndicator', { timeout: 1500 }); - } + private async isGlobalLoadingIndicatorVisible() { + this.log.debug('isGlobalLoadingIndicatorVisible'); + return await this.testSubjects.exists('globalLoadingIndicator', { timeout: 1500 }); + } - private async awaitGlobalLoadingIndicatorHidden() { - await testSubjects.existOrFail('globalLoadingIndicator-hidden', { - allowHidden: true, - timeout: defaultFindTimeout * 10, - }); - } - /** - * Close the collapsible nav - * TODO #64541 can replace with a data-test-subj - */ - public async closeCollapsibleNav() { - const CLOSE_BUTTON = '[data-test-subj=collapsibleNav] > button'; - if (await find.existsByCssSelector(CLOSE_BUTTON)) { - // Close button is only visible when focused - const button = await find.byCssSelector(CLOSE_BUTTON); - await button.focus(); + private async awaitGlobalLoadingIndicatorHidden() { + await this.testSubjects.existOrFail('globalLoadingIndicator-hidden', { + allowHidden: true, + timeout: this.defaultFindTimeout * 10, + }); + } + /** + * Close the collapsible nav + * TODO #64541 can replace with a data-test-subj + */ + public async closeCollapsibleNav() { + const CLOSE_BUTTON = '[data-test-subj=collapsibleNav] > button'; + if (await this.find.existsByCssSelector(CLOSE_BUTTON)) { + // Close button is only visible when focused + const button = await this.find.byCssSelector(CLOSE_BUTTON); + await button.focus(); - await find.clickByCssSelector(CLOSE_BUTTON); - } + await this.find.clickByCssSelector(CLOSE_BUTTON); } + } - public async openCollapsibleNav() { - if (!(await testSubjects.exists('collapsibleNav'))) { - await testSubjects.click('toggleNavButton'); - } + public async openCollapsibleNav() { + if (!(await this.testSubjects.exists('collapsibleNav'))) { + await this.testSubjects.click('toggleNavButton'); } + } - /** - * Get the attributes from each of the links in the apps menu - */ - public async readLinks() { - // wait for the chrome to finish initializing - await this.waitUntilLoadingHasFinished(); - await this.openCollapsibleNav(); - const appMenu = await testSubjects.find('collapsibleNav'); - const $ = await appMenu.parseDomContent(); - const links = $.findTestSubjects('collapsibleNavAppLink') - .toArray() - .map((link) => { - return { - text: $(link).text(), - href: $(link).attr('href'), - disabled: $(link).attr('disabled') != null, - }; - }); + /** + * Get the attributes from each of the links in the apps menu + */ + public async readLinks() { + // wait for the chrome to finish initializing + await this.waitUntilLoadingHasFinished(); + await this.openCollapsibleNav(); + const appMenu = await this.testSubjects.find('collapsibleNav'); + const $ = await appMenu.parseDomContent(); + const links = $.findTestSubjects('collapsibleNavAppLink') + .toArray() + .map((link) => { + return { + text: $(link).text(), + href: $(link).attr('href'), + disabled: $(link).attr('disabled') != null, + }; + }); - await this.closeCollapsibleNav(); + await this.closeCollapsibleNav(); - return links; - } + return links; + } - /** - * Get the attributes from the link with the given name. - * @param name - */ - public async getLink(name: string) { - return (await this.readLinks()).find((nl) => nl.text === name); - } + /** + * Get the attributes from the link with the given name. + * @param name + */ + public async getLink(name: string) { + return (await this.readLinks()).find((nl) => nl.text === name); + } - /** - * Determine if an app link with the given name exists - * @param name - */ - public async linkExists(name: string) { - return (await this.readLinks()).some((nl) => nl.text === name); - } + /** + * Determine if an app link with the given name exists + * @param name + */ + public async linkExists(name: string) { + return (await this.readLinks()).some((nl) => nl.text === name); + } - /** - * Click the app link within the app menu that has the given name - * @param name - * @param options.closeCollapsibleNav - * @param options.category - optional field to ensure that a link is clicked in a particular category - * helpful when there may be a recent link with the same name as an app - */ - public async clickLink( - name: string, - { - closeCollapsibleNav = true, - category, - }: { closeCollapsibleNav?: boolean; category?: string } = {} - ) { - try { - log.debug(`click "${name}" app link`); - await this.openCollapsibleNav(); - let nav; - if (typeof category === 'string') { - nav = await testSubjects.find(`collapsibleNavGroup-${category}`); - } else { - nav = await testSubjects.find('collapsibleNav'); - } - const link = await nav.findByPartialLinkText(name); - await link.click(); + /** + * Click the app link within the app menu that has the given name + * @param name + * @param options.closeCollapsibleNav + * @param options.category - optional field to ensure that a link is clicked in a particular category + * helpful when there may be a recent link with the same name as an app + */ + public async clickLink( + name: string, + { + closeCollapsibleNav = true, + category, + }: { closeCollapsibleNav?: boolean; category?: string } = {} + ) { + try { + this.log.debug(`click "${name}" app link`); + await this.openCollapsibleNav(); + let nav; + if (typeof category === 'string') { + nav = await this.testSubjects.find(`collapsibleNavGroup-${category}`); + } else { + nav = await this.testSubjects.find('collapsibleNav'); + } + const link = await nav.findByPartialLinkText(name); + await link.click(); - if (closeCollapsibleNav) { - await this.closeCollapsibleNav(); - } - } finally { - // Intentionally empty + if (closeCollapsibleNav) { + await this.closeCollapsibleNav(); } + } finally { + // Intentionally empty } - })(); + } } diff --git a/test/functional/services/index.ts b/test/functional/services/index.ts index 8dcefcba55d6d..294b68c548865 100644 --- a/test/functional/services/index.ts +++ b/test/functional/services/index.ts @@ -8,7 +8,7 @@ import { services as commonServiceProviders } from '../../common/services'; -import { AppsMenuProvider } from './apps_menu'; +import { AppsMenuService } from './apps_menu'; import { BrowserProvider, FailureDebuggingProvider, @@ -77,7 +77,7 @@ export const services = { inspector: InspectorService, fieldEditor: FieldEditorService, vegaDebugInspector: VegaDebugInspectorViewService, - appsMenu: AppsMenuProvider, + appsMenu: AppsMenuService, globalNav: GlobalNavService, toasts: ToastsService, savedQueryManagementComponent: SavedQueryManagementComponentProvider, From 417c06b9a1e71a1a07feb158fb5082bd66b60f48 Mon Sep 17 00:00:00 2001 From: Tim Sullivan Date: Wed, 26 May 2021 17:31:55 -0700 Subject: [PATCH 15/77] [Reporting] Use the deprecations service to advise critical config changes (#100427) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../reporting/server/config/index.test.ts | 2 +- .../plugins/reporting/server/config/index.ts | 4 +- x-pack/plugins/reporting/server/core.ts | 14 +-- .../reporting/server/deprecations.test.ts | 107 ++++++++++++++++++ .../plugins/reporting/server/deprecations.ts | 52 +++++++++ x-pack/plugins/reporting/server/plugin.ts | 11 +- 6 files changed, 174 insertions(+), 16 deletions(-) create mode 100644 x-pack/plugins/reporting/server/deprecations.test.ts create mode 100644 x-pack/plugins/reporting/server/deprecations.ts diff --git a/x-pack/plugins/reporting/server/config/index.test.ts b/x-pack/plugins/reporting/server/config/index.test.ts index 8f13fe8b53810..327b03d679cae 100644 --- a/x-pack/plugins/reporting/server/config/index.test.ts +++ b/x-pack/plugins/reporting/server/config/index.test.ts @@ -45,7 +45,7 @@ describe('deprecations', () => { const { messages } = applyReportingDeprecations({ roles: { enabled: true } }); expect(messages).toMatchInlineSnapshot(` Array [ - "\\"xpack.reporting.roles\\" is deprecated. Granting reporting privilege through a \\"reporting_user\\" role will not be supported starting in 8.0. Please set 'xpack.reporting.roles.enabled' to 'false' and grant reporting privilege to users through feature controls in Management > Security > Roles", + "\\"xpack.reporting.roles\\" is deprecated. Granting reporting privilege through a \\"reporting_user\\" role will not be supported starting in 8.0. Please set 'xpack.reporting.roles.enabled' to 'false' and grant reporting privileges to users using Kibana application privileges **Management > Security > Roles**.", ] `); }); diff --git a/x-pack/plugins/reporting/server/config/index.ts b/x-pack/plugins/reporting/server/config/index.ts index 10d7ba5059f83..8927bd8ee94d5 100644 --- a/x-pack/plugins/reporting/server/config/index.ts +++ b/x-pack/plugins/reporting/server/config/index.ts @@ -35,8 +35,8 @@ export const config: PluginConfigDescriptor = { addDeprecation({ message: `"${fromPath}.roles" is deprecated. Granting reporting privilege through a "reporting_user" role will not be supported ` + - `starting in 8.0. Please set 'xpack.reporting.roles.enabled' to 'false' and grant reporting privilege to users ` + - `through feature controls in Management > Security > Roles`, + `starting in 8.0. Please set 'xpack.reporting.roles.enabled' to 'false' and grant reporting privileges to users ` + + `using Kibana application privileges **Management > Security > Roles**.`, }); } }, diff --git a/x-pack/plugins/reporting/server/core.ts b/x-pack/plugins/reporting/server/core.ts index 2d55a4aa7fa6d..b7f3ebe9dcfa8 100644 --- a/x-pack/plugins/reporting/server/core.ts +++ b/x-pack/plugins/reporting/server/core.ts @@ -25,14 +25,14 @@ import { SecurityPluginSetup } from '../../security/server'; import { DEFAULT_SPACE_ID } from '../../spaces/common/constants'; import { SpacesPluginSetup } from '../../spaces/server'; import { TaskManagerSetupContract, TaskManagerStartContract } from '../../task_manager/server'; -import { ReportingConfig } from './'; +import { ReportingConfig, ReportingSetup } from './'; import { HeadlessChromiumDriverFactory } from './browsers/chromium/driver_factory'; import { ReportingConfigType } from './config'; import { checkLicense, getExportTypesRegistry, LevelLogger } from './lib'; import { screenshotsObservableFactory, ScreenshotsObservableFn } from './lib/screenshots'; import { ReportingStore } from './lib/store'; import { ExecuteReportTask, MonitorReportsTask, ReportTaskParams } from './lib/tasks'; -import { ReportingPluginRouter, ReportingStart } from './types'; +import { ReportingPluginRouter } from './types'; export interface ReportingInternalSetup { basePath: Pick; @@ -69,7 +69,7 @@ export class ReportingCore { private config?: ReportingConfig; // final config, includes dynamic values based on OS type private executing: Set; - public getStartContract: () => ReportingStart; + public getContract: () => ReportingSetup; constructor(private logger: LevelLogger, context: PluginInitializerContext) { const syncConfig = context.config.get(); @@ -77,11 +77,9 @@ export class ReportingCore { this.executeTask = new ExecuteReportTask(this, syncConfig, this.logger); this.monitorTask = new MonitorReportsTask(this, syncConfig, this.logger); - this.getStartContract = (): ReportingStart => { - return { - usesUiCapabilities: () => syncConfig.roles.enabled === false, - }; - }; + this.getContract = () => ({ + usesUiCapabilities: () => syncConfig.roles.enabled === false, + }); this.executing = new Set(); } diff --git a/x-pack/plugins/reporting/server/deprecations.test.ts b/x-pack/plugins/reporting/server/deprecations.test.ts new file mode 100644 index 0000000000000..cce4721b941a0 --- /dev/null +++ b/x-pack/plugins/reporting/server/deprecations.test.ts @@ -0,0 +1,107 @@ +/* + * 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 { ReportingCore } from '.'; +import { registerDeprecations } from './deprecations'; +import { createMockConfigSchema, createMockReportingCore } from './test_helpers'; +import { coreMock, elasticsearchServiceMock } from 'src/core/server/mocks'; +import { GetDeprecationsContext, IScopedClusterClient } from 'kibana/server'; + +let reportingCore: ReportingCore; +let context: GetDeprecationsContext; +let esClient: jest.Mocked; + +beforeEach(async () => { + const mockReportingConfig = createMockConfigSchema({ roles: { enabled: false } }); + reportingCore = await createMockReportingCore(mockReportingConfig); + esClient = elasticsearchServiceMock.createScopedClusterClient(); + esClient.asCurrentUser.security.getUser = jest.fn().mockResolvedValue({ + body: { xyz: { username: 'normal_user', roles: ['data_analyst'] } }, + }); + context = ({ esClient } as unknown) as GetDeprecationsContext; +}); + +test('logs no deprecations when setup has no issues', async () => { + const { getDeprecations } = await registerDeprecations(reportingCore, coreMock.createSetup()); + expect(await getDeprecations(context)).toMatchInlineSnapshot(`Array []`); +}); + +test('logs a plain message when only a reporting_user role issue is found', async () => { + esClient.asCurrentUser.security.getUser = jest.fn().mockResolvedValue({ + body: { reportron: { username: 'reportron', roles: ['kibana_admin', 'reporting_user'] } }, + }); + + const { getDeprecations } = await registerDeprecations(reportingCore, coreMock.createSetup()); + expect(await getDeprecations(context)).toMatchInlineSnapshot(` + Array [ + Object { + "correctiveActions": Object { + "manualSteps": Array [ + "Create one or more custom roles that provide Kibana application privileges to reporting features in **Management > Security > Roles**.", + "Assign the custom role(s) as desired, and remove the \\"reporting_user\\" role from the user(s).", + ], + }, + "documentationUrl": "https://www.elastic.co/guide/en/kibana/current/secure-reporting.html", + "level": "critical", + "message": "The deprecated \\"reporting_user\\" role has been found for 1 user(s): \\"reportron\\"", + }, + ] + `); +}); + +test('logs multiple entries when multiple reporting_user role issues are found', async () => { + esClient.asCurrentUser.security.getUser = jest.fn().mockResolvedValue({ + body: { + reportron: { username: 'reportron', roles: ['kibana_admin', 'reporting_user'] }, + supercooluser: { username: 'supercooluser', roles: ['kibana_admin', 'reporting_user'] }, + }, + }); + + const { getDeprecations } = await registerDeprecations(reportingCore, coreMock.createSetup()); + expect(await getDeprecations(context)).toMatchInlineSnapshot(` + Array [ + Object { + "correctiveActions": Object { + "manualSteps": Array [ + "Create one or more custom roles that provide Kibana application privileges to reporting features in **Management > Security > Roles**.", + "Assign the custom role(s) as desired, and remove the \\"reporting_user\\" role from the user(s).", + ], + }, + "documentationUrl": "https://www.elastic.co/guide/en/kibana/current/secure-reporting.html", + "level": "critical", + "message": "The deprecated \\"reporting_user\\" role has been found for 2 user(s): \\"reportron\\", \\"supercooluser\\"", + }, + ] + `); +}); + +test('logs an expanded message when a config issue and a reporting_user role issue is found', async () => { + esClient.asCurrentUser.security.getUser = jest.fn().mockResolvedValue({ + body: { reportron: { username: 'reportron', roles: ['kibana_admin', 'reporting_user'] } }, + }); + + const mockReportingConfig = createMockConfigSchema({ roles: { enabled: true } }); + reportingCore = await createMockReportingCore(mockReportingConfig); + + const { getDeprecations } = await registerDeprecations(reportingCore, coreMock.createSetup()); + expect(await getDeprecations(context)).toMatchInlineSnapshot(` + Array [ + Object { + "correctiveActions": Object { + "manualSteps": Array [ + "Set \\"xpack.reporting.roles.enabled: false\\" in kibana.yml", + "Create one or more custom roles that provide Kibana application privileges to reporting features in **Management > Security > Roles**.", + "Assign the custom role(s) as desired, and remove the \\"reporting_user\\" role from the user(s).", + ], + }, + "documentationUrl": "https://www.elastic.co/guide/en/kibana/current/secure-reporting.html", + "level": "critical", + "message": "The deprecated \\"reporting_user\\" role has been found for 1 user(s): \\"reportron\\"", + }, + ] + `); +}); diff --git a/x-pack/plugins/reporting/server/deprecations.ts b/x-pack/plugins/reporting/server/deprecations.ts new file mode 100644 index 0000000000000..61074fff012a2 --- /dev/null +++ b/x-pack/plugins/reporting/server/deprecations.ts @@ -0,0 +1,52 @@ +/* + * 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 type { CoreSetup, DeprecationsDetails, RegisterDeprecationsConfig } from 'src/core/server'; +import { ReportingCore } from '.'; + +const deprecatedRole = 'reporting_user'; +const upgradableConfig = 'xpack.reporting.roles.enabled: false'; + +export async function registerDeprecations( + reporting: ReportingCore, + { deprecations: deprecationsService }: CoreSetup +) { + const deprecationsConfig: RegisterDeprecationsConfig = { + getDeprecations: async ({ esClient }) => { + const usingDeprecatedConfig = !reporting.getContract().usesUiCapabilities(); + const deprecations: DeprecationsDetails[] = []; + const { body: users } = await esClient.asCurrentUser.security.getUser(); + + const reportingUsers = Object.entries(users) + .filter(([username, user]) => user.roles.includes(deprecatedRole)) + .map(([, user]) => user.username); + const numReportingUsers = reportingUsers.length; + + if (numReportingUsers > 0) { + const usernames = reportingUsers.join('", "'); + deprecations.push({ + message: `The deprecated "${deprecatedRole}" role has been found for ${numReportingUsers} user(s): "${usernames}"`, + documentationUrl: 'https://www.elastic.co/guide/en/kibana/current/secure-reporting.html', + level: 'critical', + correctiveActions: { + manualSteps: [ + ...(usingDeprecatedConfig ? [`Set "${upgradableConfig}" in kibana.yml`] : []), + `Create one or more custom roles that provide Kibana application privileges to reporting features in **Management > Security > Roles**.`, + `Assign the custom role(s) as desired, and remove the "${deprecatedRole}" role from the user(s).`, + ], + }, + }); + } + + return deprecations; + }, + }; + + deprecationsService.registerDeprecations(deprecationsConfig); + + return deprecationsConfig; +} diff --git a/x-pack/plugins/reporting/server/plugin.ts b/x-pack/plugins/reporting/server/plugin.ts index efe1d9450bef3..dc0ddf27a53b3 100644 --- a/x-pack/plugins/reporting/server/plugin.ts +++ b/x-pack/plugins/reporting/server/plugin.ts @@ -10,6 +10,7 @@ import { PLUGIN_ID } from '../common/constants'; import { ReportingCore } from './'; import { initializeBrowserDriverFactory } from './browsers'; import { buildConfig, registerUiSettings, ReportingConfigType } from './config'; +import { registerDeprecations } from './deprecations'; import { LevelLogger, ReportingStore } from './lib'; import { registerRoutes } from './routes'; import { setFieldFormats } from './services'; @@ -38,15 +39,13 @@ export class ReportingPlugin // @ts-expect-error null is not assignable to object. use a boolean property to ensure reporting API is enabled. core.http.registerRouteHandlerContext(PLUGIN_ID, () => { if (reportingCore.pluginIsStarted()) { - return reportingCore.getStartContract(); + return reportingCore.getContract(); } else { this.logger.error(`Reporting features are not yet ready`); return null; } }); - registerUiSettings(core); - const { http } = core; const { screenshotMode, features, licensing, security, spaces, taskManager } = plugins; @@ -65,6 +64,8 @@ export class ReportingPlugin logger: this.logger, }); + registerUiSettings(core); + registerDeprecations(reportingCore, core); registerReportingUsageCollector(reportingCore, plugins); registerRoutes(reportingCore, this.logger); @@ -81,7 +82,7 @@ export class ReportingPlugin }); this.reportingCore = reportingCore; - return reportingCore.getStartContract(); + return reportingCore.getContract(); } public start(core: CoreStart, plugins: ReportingStartDeps) { @@ -116,6 +117,6 @@ export class ReportingPlugin this.logger.error(e); }); - return reportingCore.getStartContract(); + return reportingCore.getContract(); } } From aa32903440b58d1e7cd10199e7cac5cb0735552f Mon Sep 17 00:00:00 2001 From: ymao1 Date: Wed, 26 May 2021 20:57:40 -0400 Subject: [PATCH 16/77] [Alerting] Link to action config settings from connector docs (#100358) * wip * Adding section about connector networking config to all connectors * Updating wording * Changing header size * Updating links * Apply suggestions from code review Co-authored-by: gchaps <33642766+gchaps@users.noreply.github.com> Co-authored-by: gchaps <33642766+gchaps@users.noreply.github.com> Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- docs/management/action-types.asciidoc | 7 ++++++- docs/management/connectors/action-types/email.asciidoc | 6 ++++++ docs/management/connectors/action-types/jira.asciidoc | 6 ++++++ docs/management/connectors/action-types/pagerduty.asciidoc | 6 ++++++ docs/management/connectors/action-types/resilient.asciidoc | 6 ++++++ .../management/connectors/action-types/servicenow.asciidoc | 6 ++++++ docs/management/connectors/action-types/slack.asciidoc | 6 ++++++ docs/management/connectors/action-types/teams.asciidoc | 6 ++++++ docs/management/connectors/action-types/webhook.asciidoc | 6 ++++++ 9 files changed, 54 insertions(+), 1 deletion(-) diff --git a/docs/management/action-types.asciidoc b/docs/management/action-types.asciidoc index ec5677bd04a6e..65b600d4b7281 100644 --- a/docs/management/action-types.asciidoc +++ b/docs/management/action-types.asciidoc @@ -71,6 +71,11 @@ image::images/connector-listing.png[Example connector listing in the Rules and C Access to connectors is granted based on your privileges to alerting-enabled features. See <> for more information. +[float] +=== Connector networking configuration + +Use the <> to customize connector networking configurations, such as proxies, certificates, or TLS settings. You can set configurations that apply to all your connectors or use `xpack.actions.customHostSettings` to set per-host configurations. + [float] [[connectors-list]] === Connector list @@ -110,7 +115,7 @@ image::images/connector-select-type.png[Connector select type] [[importing-and-exporting-connectors]] === Importing and exporting connectors -To import and export rules, use the <>. +To import and export connectors, use the <>. After a successful import, the proper banner is displayed: [role="screenshot"] image::images/coonectors-import-banner.png[Connectors import banner, width=50%] diff --git a/docs/management/connectors/action-types/email.asciidoc b/docs/management/connectors/action-types/email.asciidoc index 1c2f9212b4887..719d00c16c932 100644 --- a/docs/management/connectors/action-types/email.asciidoc +++ b/docs/management/connectors/action-types/email.asciidoc @@ -24,6 +24,12 @@ Require authentication:: If true, a username and password for login type authent Username:: Username for login type authentication. Password:: Password for login type authentication. +[float] +[[email-connector-networking-configuration]] +==== Connector networking configuration + +Use the <> to customize connector networking configurations, such as proxies, certificates, or TLS settings. You can set configurations that apply to all your connectors or use `xpack.actions.customHostSettings` to set per-host configurations. + [float] [[preconfigured-email-configuration]] ==== Preconfigured connector type diff --git a/docs/management/connectors/action-types/jira.asciidoc b/docs/management/connectors/action-types/jira.asciidoc index a5e629887d5c6..368b11225654c 100644 --- a/docs/management/connectors/action-types/jira.asciidoc +++ b/docs/management/connectors/action-types/jira.asciidoc @@ -19,6 +19,12 @@ Project key:: Jira project key. Email (or username):: The account email (or username) for HTTP Basic authentication. API token (or password):: Jira API authentication token (or password) for HTTP Basic authentication. +[float] +[[jira-connector-networking-configuration]] +==== Connector networking configuration + +Use the <> to customize connector networking configurations, such as proxies, certificates, or TLS settings. You can set configurations that apply to all your connectors or use `xpack.actions.customHostSettings` to set per-host configurations. + [float] [[Preconfigured-jira-configuration]] ==== Preconfigured connector type diff --git a/docs/management/connectors/action-types/pagerduty.asciidoc b/docs/management/connectors/action-types/pagerduty.asciidoc index 25cba05010548..db1c4e3932d14 100644 --- a/docs/management/connectors/action-types/pagerduty.asciidoc +++ b/docs/management/connectors/action-types/pagerduty.asciidoc @@ -17,6 +17,12 @@ Name:: The name of the connector. The name is used to identify a connector API URL:: An optional PagerDuty event URL. Defaults to `https://events.pagerduty.com/v2/enqueue`. If you are using the <> setting, make sure the hostname is added to the allowed hosts. Integration Key:: A 32 character PagerDuty Integration Key for an integration on a service, also referred to as the routing key. +[float] +[[pagerduty-connector-networking-configuration]] +==== Connector networking configuration + +Use the <> to customize connector networking configurations, such as proxies, certificates, or TLS settings. You can set configurations that apply to all your connectors or use `xpack.actions.customHostSettings` to set per-host configurations. + [float] [[Preconfigured-pagerduty-configuration]] ==== Preconfigured connector type diff --git a/docs/management/connectors/action-types/resilient.asciidoc b/docs/management/connectors/action-types/resilient.asciidoc index 454ae145bbc57..ef8196bea0aab 100644 --- a/docs/management/connectors/action-types/resilient.asciidoc +++ b/docs/management/connectors/action-types/resilient.asciidoc @@ -19,6 +19,12 @@ Organization ID:: IBM Resilient organization ID. API key ID:: The authentication key ID for HTTP Basic authentication. API key secret:: The authentication key secret for HTTP Basic authentication. +[float] +[[resilient-connector-networking-configuration]] +==== Connector networking configuration + +Use the <> to customize connector networking configurations, such as proxies, certificates, or TLS settings. You can set configurations that apply to all your connectors or use `xpack.actions.customHostSettings` to set per-host configurations. + [float] [[Preconfigured-resilient-configuration]] ==== Preconfigured connector type diff --git a/docs/management/connectors/action-types/servicenow.asciidoc b/docs/management/connectors/action-types/servicenow.asciidoc index 24892c62e804b..dfac22cb23c6c 100644 --- a/docs/management/connectors/action-types/servicenow.asciidoc +++ b/docs/management/connectors/action-types/servicenow.asciidoc @@ -18,6 +18,12 @@ URL:: ServiceNow instance URL. Username:: Username for HTTP Basic authentication. Password:: Password for HTTP Basic authentication. +[float] +[[servicenow-connector-networking-configuration]] +==== Connector networking configuration + +Use the <> to customize connector networking configurations, such as proxies, certificates, or TLS settings. You can set configurations that apply to all your connectors or use `xpack.actions.customHostSettings` to set per-host configurations. + [float] [[Preconfigured-servicenow-configuration]] ==== Preconfigured connector type diff --git a/docs/management/connectors/action-types/slack.asciidoc b/docs/management/connectors/action-types/slack.asciidoc index da0bf321f9ade..6dffebd9d9354 100644 --- a/docs/management/connectors/action-types/slack.asciidoc +++ b/docs/management/connectors/action-types/slack.asciidoc @@ -16,6 +16,12 @@ Slack connectors have the following configuration properties. Name:: The name of the connector. The name is used to identify a connector in the management UI connector listing, or in the connector list when configuring an action. Webhook URL:: The URL of the incoming webhook. See https://api.slack.com/messaging/webhooks#getting_started[Slack Incoming Webhooks] for instructions on generating this URL. If you are using the <> setting, make sure the hostname is added to the allowed hosts. +[float] +[[slack-connector-networking-configuration]] +==== Connector networking configuration + +Use the <> to customize connector networking configurations, such as proxies, certificates, or TLS settings. You can set configurations that apply to all your connectors or use `xpack.actions.customHostSettings` to set per-host configurations. + [float] [[Preconfigured-slack-configuration]] ==== Preconfigured connector type diff --git a/docs/management/connectors/action-types/teams.asciidoc b/docs/management/connectors/action-types/teams.asciidoc index ba723a6f33c86..32cfaaf801d70 100644 --- a/docs/management/connectors/action-types/teams.asciidoc +++ b/docs/management/connectors/action-types/teams.asciidoc @@ -16,6 +16,12 @@ Microsoft Teams connectors have the following configuration properties. Name:: The name of the connector. The name is used to identify a connector in the management UI connector listing, or in the connector list when configuring an action. Webhook URL:: The URL of the incoming webhook. See https://docs.microsoft.com/en-us/microsoftteams/platform/webhooks-and-connectors/how-to/add-incoming-webhook#add-an-incoming-webhook-to-a-teams-channel[Add Incoming Webhooks] for instructions on generating this URL. If you are using the <> setting, make sure the hostname is added to the allowed hosts. +[float] +[[teams-connector-networking-configuration]] +==== Connector networking configuration + +Use the <> to customize connector networking configurations, such as proxies, certificates, or TLS settings. You can set configurations that apply to all your connectors or use `xpack.actions.customHostSettings` to set per-host configurations. + [float] [[Preconfigured-teams-configuration]] ==== Preconfigured connector type diff --git a/docs/management/connectors/action-types/webhook.asciidoc b/docs/management/connectors/action-types/webhook.asciidoc index a2024b9457a1c..aa52e8a3bdb43 100644 --- a/docs/management/connectors/action-types/webhook.asciidoc +++ b/docs/management/connectors/action-types/webhook.asciidoc @@ -21,6 +21,12 @@ Require authentication:: If true, a username and password for login type authent Username:: Username for HTTP basic authentication. Password:: Password for HTTP basic authentication. +[float] +[[webhook-connector-networking-configuration]] +==== Connector networking configuration + +Use the <> to customize connector networking configurations, such as proxies, certificates, or TLS settings. You can set configurations that apply to all your connectors or use `xpack.actions.customHostSettings` to set per-host configurations. + [float] [[Preconfigured-webhook-configuration]] ==== Preconfigured connector type From 5da329a809a9a57be9616ae263f747c19103ef3f Mon Sep 17 00:00:00 2001 From: Thomas Neirynck Date: Wed, 26 May 2021 21:09:38 -0400 Subject: [PATCH 17/77] [Maps] Isolate mapbox-gl types and align downstream package versions. (#100610) --- package.json | 8 +- packages/kbn-mapbox-gl/src/index.ts | 38 +++- .../vega_view/vega_map_view/constants.ts | 2 +- .../vega_view/vega_map_view/layers/types.ts | 2 +- .../vega_map_view/layers/vega_layer.ts | 2 +- .../public/vega_view/vega_map_view/view.ts | 2 +- .../layers/heatmap_layer/heatmap_layer.ts | 2 +- .../maps/public/classes/layers/layer.tsx | 2 +- .../tiled_vector_layer/tiled_vector_layer.tsx | 4 +- .../classes/layers/vector_layer/utils.tsx | 2 +- .../layers/vector_layer/vector_layer.tsx | 6 +- .../classes/styles/heatmap/heatmap_style.tsx | 2 +- .../properties/dynamic_color_property.tsx | 2 +- .../properties/dynamic_icon_property.tsx | 2 +- .../dynamic_orientation_property.ts | 2 +- .../properties/dynamic_size_property.test.tsx | 2 +- .../properties/dynamic_size_property.tsx | 2 +- .../properties/dynamic_style_property.tsx | 2 +- .../properties/dynamic_text_property.test.tsx | 2 +- .../properties/dynamic_text_property.ts | 2 +- .../properties/label_border_size_property.ts | 2 +- .../properties/static_color_property.ts | 2 +- .../vector/properties/static_icon_property.ts | 2 +- .../properties/static_orientation_property.ts | 2 +- .../vector/properties/static_size_property.ts | 2 +- .../properties/static_text_property.test.ts | 2 +- .../vector/properties/static_text_property.ts | 2 +- .../classes/styles/vector/vector_style.tsx | 2 +- .../mb_map/draw_control/draw_control.tsx | 2 +- .../draw_filter_control.tsx | 2 +- .../mb_map/draw_control/draw_tooltip.tsx | 2 +- .../connected_components/mb_map/mb_map.tsx | 2 +- .../scale_control/scale_control.test.tsx | 2 +- .../mb_map/scale_control/scale_control.tsx | 2 +- .../mb_map/sort_layers.test.ts | 2 +- .../mb_map/sort_layers.ts | 2 +- .../mb_map/tile_status_tracker.test.ts | 2 +- .../mb_map/tile_status_tracker.ts | 2 +- .../tooltip_control/tooltip_control.test.tsx | 2 +- .../tooltip_control/tooltip_control.tsx | 2 +- .../tooltip_control/tooltip_popover.test.tsx | 2 +- .../tooltip_control/tooltip_popover.tsx | 2 +- yarn.lock | 185 +++++------------- 43 files changed, 132 insertions(+), 185 deletions(-) diff --git a/package.json b/package.json index 3cdde5e52584a..936f985498ab1 100644 --- a/package.json +++ b/package.json @@ -158,8 +158,8 @@ "@loaders.gl/core": "^2.3.1", "@loaders.gl/json": "^2.3.1", "@mapbox/geojson-rewind": "^0.5.0", - "@mapbox/mapbox-gl-draw": "^1.2.0", - "@mapbox/mapbox-gl-rtl-text": "^0.2.3", + "@mapbox/mapbox-gl-draw": "1.3.0", + "@mapbox/mapbox-gl-rtl-text": "0.2.3", "@mapbox/vector-tile": "1.3.1", "@scant/router": "^0.1.1", "@slack/webhook": "^5.0.4", @@ -285,7 +285,7 @@ "lru-cache": "^4.1.5", "lz-string": "^1.4.4", "mapbox-gl": "1.13.1", - "mapbox-gl-draw-rectangle-mode": "^1.0.4", + "mapbox-gl-draw-rectangle-mode": "1.0.4", "markdown-it": "^10.0.0", "md5": "^2.1.0", "memoize-one": "^5.0.0", @@ -562,7 +562,7 @@ "@types/loader-utils": "^1.1.3", "@types/lodash": "^4.14.159", "@types/lru-cache": "^5.1.0", - "@types/mapbox-gl": "^1.9.1", + "@types/mapbox-gl": "1.13.1", "@types/markdown-it": "^0.0.7", "@types/md5": "^2.2.0", "@types/memoize-one": "^4.1.0", diff --git a/packages/kbn-mapbox-gl/src/index.ts b/packages/kbn-mapbox-gl/src/index.ts index 117b874a28ffb..404684af78031 100644 --- a/packages/kbn-mapbox-gl/src/index.ts +++ b/packages/kbn-mapbox-gl/src/index.ts @@ -7,6 +7,24 @@ */ import './typings'; +import type { + Map, + GeoJSONSource, + VectorSource, + Layer, + AnyLayer, + FeatureIdentifier, + Style, + MapboxOptions, + MapMouseEvent, + MapSourceDataEvent, + LngLat, + LngLatBounds, + PointLike, + MapboxGeoJSONFeature, + Point, + CustomLayerInterface, +} from 'mapbox-gl'; import mapboxgl from 'mapbox-gl/dist/mapbox-gl-csp'; // @ts-expect-error import mbRtlPlugin from '!!file-loader!@mapbox/mapbox-gl-rtl-text/mapbox-gl-rtl-text.min.js'; @@ -17,4 +35,22 @@ import 'mapbox-gl/dist/mapbox-gl.css'; mapboxgl.workerUrl = mbWorkerUrl; mapboxgl.setRTLTextPlugin(mbRtlPlugin); -export { mapboxgl }; +export { + mapboxgl, + Map, + GeoJSONSource, + VectorSource, + Layer, + AnyLayer, + FeatureIdentifier, + Style, + MapboxOptions, + MapMouseEvent, + MapSourceDataEvent, + LngLat, + LngLatBounds, + PointLike, + MapboxGeoJSONFeature, + Point, + CustomLayerInterface, +}; diff --git a/src/plugins/vis_type_vega/public/vega_view/vega_map_view/constants.ts b/src/plugins/vis_type_vega/public/vega_view/vega_map_view/constants.ts index 75e3b66a784b3..04957fda5b8ff 100644 --- a/src/plugins/vis_type_vega/public/vega_view/vega_map_view/constants.ts +++ b/src/plugins/vis_type_vega/public/vega_view/vega_map_view/constants.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import type { Style } from 'mapbox-gl'; +import type { Style } from '@kbn/mapbox-gl'; import { TMS_IN_YML_ID } from '../../../../maps_ems/public'; export const vegaLayerId = 'vega'; diff --git a/src/plugins/vis_type_vega/public/vega_view/vega_map_view/layers/types.ts b/src/plugins/vis_type_vega/public/vega_view/vega_map_view/layers/types.ts index d3e8bc3f5ab33..428910cbf2d38 100644 --- a/src/plugins/vis_type_vega/public/vega_view/vega_map_view/layers/types.ts +++ b/src/plugins/vis_type_vega/public/vega_view/vega_map_view/layers/types.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import type { Map } from 'mapbox-gl'; +import type { Map } from '@kbn/mapbox-gl'; export interface LayerParameters = {}> { id: string; diff --git a/src/plugins/vis_type_vega/public/vega_view/vega_map_view/layers/vega_layer.ts b/src/plugins/vis_type_vega/public/vega_view/vega_map_view/layers/vega_layer.ts index 8972b80cb99c5..b6bac1e842926 100644 --- a/src/plugins/vis_type_vega/public/vega_view/vega_map_view/layers/vega_layer.ts +++ b/src/plugins/vis_type_vega/public/vega_view/vega_map_view/layers/vega_layer.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import type { Map, CustomLayerInterface } from 'mapbox-gl'; +import type { Map, CustomLayerInterface } from '@kbn/mapbox-gl'; import type { View } from 'vega'; import type { LayerParameters } from './types'; diff --git a/src/plugins/vis_type_vega/public/vega_view/vega_map_view/view.ts b/src/plugins/vis_type_vega/public/vega_view/vega_map_view/view.ts index 835ac36ceee47..f4104a0f2457c 100644 --- a/src/plugins/vis_type_vega/public/vega_view/vega_map_view/view.ts +++ b/src/plugins/vis_type_vega/public/vega_view/vega_map_view/view.ts @@ -7,7 +7,7 @@ */ import { i18n } from '@kbn/i18n'; -import type { Map, Style, MapboxOptions } from 'mapbox-gl'; +import type { Map, Style, MapboxOptions } from '@kbn/mapbox-gl'; import { View, parse } from 'vega'; diff --git a/x-pack/plugins/maps/public/classes/layers/heatmap_layer/heatmap_layer.ts b/x-pack/plugins/maps/public/classes/layers/heatmap_layer/heatmap_layer.ts index 96c7fcedaf3d9..368ff8bebcdd1 100644 --- a/x-pack/plugins/maps/public/classes/layers/heatmap_layer/heatmap_layer.ts +++ b/x-pack/plugins/maps/public/classes/layers/heatmap_layer/heatmap_layer.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { Map as MbMap, GeoJSONSource as MbGeoJSONSource } from 'mapbox-gl'; +import type { Map as MbMap, GeoJSONSource as MbGeoJSONSource } from '@kbn/mapbox-gl'; import { FeatureCollection } from 'geojson'; import { AbstractLayer } from '../layer'; import { HeatmapStyle } from '../../styles/heatmap/heatmap_style'; diff --git a/x-pack/plugins/maps/public/classes/layers/layer.tsx b/x-pack/plugins/maps/public/classes/layers/layer.tsx index 1c1e29ca485ff..be113ab4cc2c9 100644 --- a/x-pack/plugins/maps/public/classes/layers/layer.tsx +++ b/x-pack/plugins/maps/public/classes/layers/layer.tsx @@ -7,7 +7,7 @@ /* eslint-disable @typescript-eslint/consistent-type-definitions */ -import { Map as MbMap } from 'mapbox-gl'; +import type { Map as MbMap } from '@kbn/mapbox-gl'; import { Query } from 'src/plugins/data/public'; import _ from 'lodash'; import React, { ReactElement, ReactNode } from 'react'; diff --git a/x-pack/plugins/maps/public/classes/layers/tiled_vector_layer/tiled_vector_layer.tsx b/x-pack/plugins/maps/public/classes/layers/tiled_vector_layer/tiled_vector_layer.tsx index d452096250576..6dba935ccc87d 100644 --- a/x-pack/plugins/maps/public/classes/layers/tiled_vector_layer/tiled_vector_layer.tsx +++ b/x-pack/plugins/maps/public/classes/layers/tiled_vector_layer/tiled_vector_layer.tsx @@ -6,11 +6,11 @@ */ import React from 'react'; -import { +import type { Map as MbMap, GeoJSONSource as MbGeoJSONSource, VectorSource as MbVectorSource, -} from 'mapbox-gl'; +} from '@kbn/mapbox-gl'; import { EuiIcon } from '@elastic/eui'; import { Feature } from 'geojson'; import uuid from 'uuid/v4'; diff --git a/x-pack/plugins/maps/public/classes/layers/vector_layer/utils.tsx b/x-pack/plugins/maps/public/classes/layers/vector_layer/utils.tsx index e49339b6250b4..a7ac9dd9cfb6a 100644 --- a/x-pack/plugins/maps/public/classes/layers/vector_layer/utils.tsx +++ b/x-pack/plugins/maps/public/classes/layers/vector_layer/utils.tsx @@ -6,7 +6,7 @@ */ import { FeatureCollection } from 'geojson'; -import { Map as MbMap } from 'mapbox-gl'; +import type { Map as MbMap } from '@kbn/mapbox-gl'; import { EMPTY_FEATURE_COLLECTION, SOURCE_BOUNDS_DATA_REQUEST_ID, diff --git a/x-pack/plugins/maps/public/classes/layers/vector_layer/vector_layer.tsx b/x-pack/plugins/maps/public/classes/layers/vector_layer/vector_layer.tsx index a4d913979cf1b..ca171f10207e1 100644 --- a/x-pack/plugins/maps/public/classes/layers/vector_layer/vector_layer.tsx +++ b/x-pack/plugins/maps/public/classes/layers/vector_layer/vector_layer.tsx @@ -6,7 +6,11 @@ */ import React from 'react'; -import { Map as MbMap, Layer as MbLayer, GeoJSONSource as MbGeoJSONSource } from 'mapbox-gl'; +import type { + Map as MbMap, + AnyLayer as MbLayer, + GeoJSONSource as MbGeoJSONSource, +} from '@kbn/mapbox-gl'; import { Feature, FeatureCollection, GeoJsonProperties } from 'geojson'; import _ from 'lodash'; import { EuiIcon } from '@elastic/eui'; diff --git a/x-pack/plugins/maps/public/classes/styles/heatmap/heatmap_style.tsx b/x-pack/plugins/maps/public/classes/styles/heatmap/heatmap_style.tsx index fe581a1807b28..723390ff23676 100644 --- a/x-pack/plugins/maps/public/classes/styles/heatmap/heatmap_style.tsx +++ b/x-pack/plugins/maps/public/classes/styles/heatmap/heatmap_style.tsx @@ -6,7 +6,7 @@ */ import React from 'react'; -import { Map as MbMap } from 'mapbox-gl'; +import type { Map as MbMap } from '@kbn/mapbox-gl'; import { i18n } from '@kbn/i18n'; import { EuiIcon } from '@elastic/eui'; import { IStyle } from '../style'; diff --git a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_color_property.tsx b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_color_property.tsx index d654cdc6bff51..73f8736750656 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_color_property.tsx +++ b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_color_property.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { Map as MbMap } from 'mapbox-gl'; +import type { Map as MbMap } from '@kbn/mapbox-gl'; import React from 'react'; import { EuiTextColor } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; diff --git a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_icon_property.tsx b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_icon_property.tsx index ad87b43c8e4a5..56d7c8597e151 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_icon_property.tsx +++ b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_icon_property.tsx @@ -8,7 +8,7 @@ import _ from 'lodash'; import React from 'react'; import { EuiTextColor } from '@elastic/eui'; -import { Map as MbMap } from 'mapbox-gl'; +import type { Map as MbMap } from '@kbn/mapbox-gl'; import { DynamicStyleProperty } from './dynamic_style_property'; // @ts-expect-error import { getIconPalette, getMakiIconId, getMakiSymbolAnchor } from '../symbol_utils'; diff --git a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_orientation_property.ts b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_orientation_property.ts index e72b411909e82..afa034b4d395c 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_orientation_property.ts +++ b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_orientation_property.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { Map as MbMap } from 'mapbox-gl'; +import type { Map as MbMap } from '@kbn/mapbox-gl'; import { DynamicStyleProperty, getNumericalMbFeatureStateValue } from './dynamic_style_property'; import { OrientationDynamicOptions } from '../../../../../common/descriptor_types'; import { RawValue } from '../../../../../common/constants'; diff --git a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_size_property.test.tsx b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_size_property.test.tsx index 64a3e0cf0e322..e1a92fdcad08a 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_size_property.test.tsx +++ b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_size_property.test.tsx @@ -18,7 +18,7 @@ import { shallow } from 'enzyme'; import { DynamicSizeProperty } from './dynamic_size_property'; import { RawValue, VECTOR_STYLES } from '../../../../../common/constants'; import { IField } from '../../../fields/field'; -import { Map as MbMap } from 'mapbox-gl'; +import type { Map as MbMap } from '@kbn/mapbox-gl'; import { SizeDynamicOptions } from '../../../../../common/descriptor_types'; import { mockField, MockLayer, MockStyle } from './test_helpers/test_util'; import { IVectorLayer } from '../../../layers/vector_layer'; diff --git a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_size_property.tsx b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_size_property.tsx index 7076775dcce31..8599adef33f01 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_size_property.tsx +++ b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_size_property.tsx @@ -7,7 +7,7 @@ import _ from 'lodash'; import React from 'react'; -import { Map as MbMap } from 'mapbox-gl'; +import type { Map as MbMap } from '@kbn/mapbox-gl'; import { DynamicStyleProperty } from './dynamic_style_property'; import { OrdinalLegend } from '../components/legend/ordinal_legend'; import { makeMbClampedNumberExpression } from '../style_util'; diff --git a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_style_property.tsx b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_style_property.tsx index 9ffd9a0f1b345..0841bb7546d9e 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_style_property.tsx +++ b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_style_property.tsx @@ -8,7 +8,7 @@ import _ from 'lodash'; import React from 'react'; import { Feature, FeatureCollection } from 'geojson'; -import { FeatureIdentifier, Map as MbMap } from 'mapbox-gl'; +import type { FeatureIdentifier, Map as MbMap } from '@kbn/mapbox-gl'; import { AbstractStyleProperty, IStyleProperty } from './style_property'; import { DEFAULT_SIGMA } from '../vector_style_defaults'; import { diff --git a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_text_property.test.tsx b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_text_property.test.tsx index 4550a27ac2d9a..b5872773fdce6 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_text_property.test.tsx +++ b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_text_property.test.tsx @@ -17,7 +17,7 @@ import React from 'react'; import { DynamicTextProperty } from './dynamic_text_property'; import { RawValue, VECTOR_STYLES } from '../../../../../common/constants'; import { IField } from '../../../fields/field'; -import { Map as MbMap } from 'mapbox-gl'; +import type { Map as MbMap } from '@kbn/mapbox-gl'; import { mockField, MockLayer, MockStyle } from './test_helpers/test_util'; import { IVectorLayer } from '../../../layers/vector_layer'; diff --git a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_text_property.ts b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_text_property.ts index e8612388a5ae1..c59d720798371 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_text_property.ts +++ b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_text_property.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { Map as MbMap } from 'mapbox-gl'; +import type { Map as MbMap } from '@kbn/mapbox-gl'; import { DynamicStyleProperty } from './dynamic_style_property'; import { LabelDynamicOptions } from '../../../../../common/descriptor_types'; import { RawValue } from '../../../../../common/constants'; diff --git a/x-pack/plugins/maps/public/classes/styles/vector/properties/label_border_size_property.ts b/x-pack/plugins/maps/public/classes/styles/vector/properties/label_border_size_property.ts index 4d9473a9adced..5d4425a9d4995 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/properties/label_border_size_property.ts +++ b/x-pack/plugins/maps/public/classes/styles/vector/properties/label_border_size_property.ts @@ -6,7 +6,7 @@ */ import _ from 'lodash'; -import { Map as MbMap } from 'mapbox-gl'; +import type { Map as MbMap } from '@kbn/mapbox-gl'; import { AbstractStyleProperty } from './style_property'; import { DEFAULT_LABEL_SIZE } from '../vector_style_defaults'; import { LABEL_BORDER_SIZES } from '../../../../../common/constants'; diff --git a/x-pack/plugins/maps/public/classes/styles/vector/properties/static_color_property.ts b/x-pack/plugins/maps/public/classes/styles/vector/properties/static_color_property.ts index dae983c4ae4fe..c8a80b5ee28dc 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/properties/static_color_property.ts +++ b/x-pack/plugins/maps/public/classes/styles/vector/properties/static_color_property.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { Map as MbMap } from 'mapbox-gl'; +import type { Map as MbMap } from '@kbn/mapbox-gl'; import { StaticStyleProperty } from './static_style_property'; import { ColorStaticOptions } from '../../../../../common/descriptor_types'; diff --git a/x-pack/plugins/maps/public/classes/styles/vector/properties/static_icon_property.ts b/x-pack/plugins/maps/public/classes/styles/vector/properties/static_icon_property.ts index 887f16a176048..3a61e1a074868 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/properties/static_icon_property.ts +++ b/x-pack/plugins/maps/public/classes/styles/vector/properties/static_icon_property.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { Map as MbMap } from 'mapbox-gl'; +import type { Map as MbMap } from '@kbn/mapbox-gl'; import { StaticStyleProperty } from './static_style_property'; // @ts-expect-error import { getMakiSymbolAnchor, getMakiIconId } from '../symbol_utils'; diff --git a/x-pack/plugins/maps/public/classes/styles/vector/properties/static_orientation_property.ts b/x-pack/plugins/maps/public/classes/styles/vector/properties/static_orientation_property.ts index 329088fdb160d..48a52f641dfc7 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/properties/static_orientation_property.ts +++ b/x-pack/plugins/maps/public/classes/styles/vector/properties/static_orientation_property.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { Map as MbMap } from 'mapbox-gl'; +import type { Map as MbMap } from '@kbn/mapbox-gl'; import { StaticStyleProperty } from './static_style_property'; import { VECTOR_STYLES } from '../../../../../common/constants'; import { OrientationStaticOptions } from '../../../../../common/descriptor_types'; diff --git a/x-pack/plugins/maps/public/classes/styles/vector/properties/static_size_property.ts b/x-pack/plugins/maps/public/classes/styles/vector/properties/static_size_property.ts index 3dd706043d158..de71d07aa7167 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/properties/static_size_property.ts +++ b/x-pack/plugins/maps/public/classes/styles/vector/properties/static_size_property.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { Map as MbMap } from 'mapbox-gl'; +import type { Map as MbMap } from '@kbn/mapbox-gl'; import { StaticStyleProperty } from './static_style_property'; import { VECTOR_STYLES } from '../../../../../common/constants'; import { diff --git a/x-pack/plugins/maps/public/classes/styles/vector/properties/static_text_property.test.ts b/x-pack/plugins/maps/public/classes/styles/vector/properties/static_text_property.test.ts index 70c7721e760b6..498ad2fc4ea17 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/properties/static_text_property.test.ts +++ b/x-pack/plugins/maps/public/classes/styles/vector/properties/static_text_property.test.ts @@ -7,7 +7,7 @@ import { StaticTextProperty } from './static_text_property'; import { VECTOR_STYLES } from '../../../../../common/constants'; -import { Map as MbMap } from 'mapbox-gl'; +import type { Map as MbMap } from '@kbn/mapbox-gl'; export class MockMbMap { _paintPropertyCalls: unknown[]; diff --git a/x-pack/plugins/maps/public/classes/styles/vector/properties/static_text_property.ts b/x-pack/plugins/maps/public/classes/styles/vector/properties/static_text_property.ts index fb05fa052db21..083d091aaefe5 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/properties/static_text_property.ts +++ b/x-pack/plugins/maps/public/classes/styles/vector/properties/static_text_property.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { Map as MbMap } from 'mapbox-gl'; +import type { Map as MbMap } from '@kbn/mapbox-gl'; import { StaticStyleProperty } from './static_style_property'; import { LabelStaticOptions } from '../../../../../common/descriptor_types'; diff --git a/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx b/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx index 692be08d07bc6..7578695d7ac6f 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx +++ b/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx @@ -7,7 +7,7 @@ import _ from 'lodash'; import React, { ReactElement } from 'react'; -import { FeatureIdentifier, Map as MbMap } from 'mapbox-gl'; +import { FeatureIdentifier, Map as MbMap } from '@kbn/mapbox-gl'; import { FeatureCollection } from 'geojson'; import { StyleProperties, VectorStyleEditor } from './components/vector_style_editor'; import { getDefaultStaticProperties, LINE_STYLES, POLYGON_STYLES } from './vector_style_defaults'; diff --git a/x-pack/plugins/maps/public/connected_components/mb_map/draw_control/draw_control.tsx b/x-pack/plugins/maps/public/connected_components/mb_map/draw_control/draw_control.tsx index a1bea4a8e93dc..4f8182963a185 100644 --- a/x-pack/plugins/maps/public/connected_components/mb_map/draw_control/draw_control.tsx +++ b/x-pack/plugins/maps/public/connected_components/mb_map/draw_control/draw_control.tsx @@ -11,7 +11,7 @@ import React, { Component } from 'react'; import MapboxDraw from '@mapbox/mapbox-gl-draw'; // @ts-expect-error import DrawRectangle from 'mapbox-gl-draw-rectangle-mode'; -import { Map as MbMap } from 'mapbox-gl'; +import type { Map as MbMap } from '@kbn/mapbox-gl'; import { Feature } from 'geojson'; import { DRAW_TYPE } from '../../../../common/constants'; import { DrawCircle } from './draw_circle'; diff --git a/x-pack/plugins/maps/public/connected_components/mb_map/draw_control/draw_filter_control/draw_filter_control.tsx b/x-pack/plugins/maps/public/connected_components/mb_map/draw_control/draw_filter_control/draw_filter_control.tsx index e6359394cd741..5fad291a5367f 100644 --- a/x-pack/plugins/maps/public/connected_components/mb_map/draw_control/draw_filter_control/draw_filter_control.tsx +++ b/x-pack/plugins/maps/public/connected_components/mb_map/draw_control/draw_filter_control/draw_filter_control.tsx @@ -7,7 +7,7 @@ import _ from 'lodash'; import React, { Component } from 'react'; -import { Map as MbMap } from 'mapbox-gl'; +import type { Map as MbMap } from '@kbn/mapbox-gl'; import { i18n } from '@kbn/i18n'; import { Filter } from 'src/plugins/data/public'; import { Feature, Polygon } from 'geojson'; diff --git a/x-pack/plugins/maps/public/connected_components/mb_map/draw_control/draw_tooltip.tsx b/x-pack/plugins/maps/public/connected_components/mb_map/draw_control/draw_tooltip.tsx index df650d5dfe410..38d3bab6cd129 100644 --- a/x-pack/plugins/maps/public/connected_components/mb_map/draw_control/draw_tooltip.tsx +++ b/x-pack/plugins/maps/public/connected_components/mb_map/draw_control/draw_tooltip.tsx @@ -9,7 +9,7 @@ import _ from 'lodash'; import React, { Component, RefObject } from 'react'; import { EuiPopover, EuiText } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { Map as MbMap } from 'mapbox-gl'; +import type { Map as MbMap } from '@kbn/mapbox-gl'; import { DRAW_TYPE } from '../../../../common/constants'; const noop = () => {}; diff --git a/x-pack/plugins/maps/public/connected_components/mb_map/mb_map.tsx b/x-pack/plugins/maps/public/connected_components/mb_map/mb_map.tsx index ce36ec811df40..877de10e11383 100644 --- a/x-pack/plugins/maps/public/connected_components/mb_map/mb_map.tsx +++ b/x-pack/plugins/maps/public/connected_components/mb_map/mb_map.tsx @@ -7,7 +7,7 @@ import _ from 'lodash'; import React, { Component } from 'react'; -import type { Map as MapboxMap, MapboxOptions, MapMouseEvent } from 'mapbox-gl'; +import type { Map as MapboxMap, MapboxOptions, MapMouseEvent } from '@kbn/mapbox-gl'; // @ts-expect-error import { spritesheet } from '@elastic/maki'; diff --git a/x-pack/plugins/maps/public/connected_components/mb_map/scale_control/scale_control.test.tsx b/x-pack/plugins/maps/public/connected_components/mb_map/scale_control/scale_control.test.tsx index bd735d5cd5183..0eb3ff2de16e8 100644 --- a/x-pack/plugins/maps/public/connected_components/mb_map/scale_control/scale_control.test.tsx +++ b/x-pack/plugins/maps/public/connected_components/mb_map/scale_control/scale_control.test.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { mount, shallow } from 'enzyme'; import { ScaleControl } from './scale_control'; -import { LngLat, LngLatBounds, Map as MapboxMap, PointLike } from 'mapbox-gl'; +import type { LngLat, LngLatBounds, Map as MapboxMap, PointLike } from '@kbn/mapbox-gl'; const CLIENT_HEIGHT_PIXELS = 1200; const DISTANCE_METERS = 87653; diff --git a/x-pack/plugins/maps/public/connected_components/mb_map/scale_control/scale_control.tsx b/x-pack/plugins/maps/public/connected_components/mb_map/scale_control/scale_control.tsx index 68f37721bdb1f..d762f17b9b898 100644 --- a/x-pack/plugins/maps/public/connected_components/mb_map/scale_control/scale_control.tsx +++ b/x-pack/plugins/maps/public/connected_components/mb_map/scale_control/scale_control.tsx @@ -8,7 +8,7 @@ import { i18n } from '@kbn/i18n'; import classNames from 'classnames'; import React, { Component } from 'react'; -import { Map as MapboxMap } from 'mapbox-gl'; +import type { Map as MapboxMap } from '@kbn/mapbox-gl'; const MAX_WIDTH = 110; interface Props { diff --git a/x-pack/plugins/maps/public/connected_components/mb_map/sort_layers.test.ts b/x-pack/plugins/maps/public/connected_components/mb_map/sort_layers.test.ts index 6be53cfb1349a..596ba793db708 100644 --- a/x-pack/plugins/maps/public/connected_components/mb_map/sort_layers.test.ts +++ b/x-pack/plugins/maps/public/connected_components/mb_map/sort_layers.test.ts @@ -8,7 +8,7 @@ /* eslint-disable max-classes-per-file */ import _ from 'lodash'; -import { Map as MbMap, Layer as MbLayer, Style as MbStyle } from 'mapbox-gl'; +import type { Map as MbMap, AnyLayer as MbLayer, Style as MbStyle } from '@kbn/mapbox-gl'; import { getIsTextLayer, syncLayerOrder } from './sort_layers'; import { SPATIAL_FILTERS_LAYER_ID } from '../../../common/constants'; import { ILayer } from '../../classes/layers/layer'; diff --git a/x-pack/plugins/maps/public/connected_components/mb_map/sort_layers.ts b/x-pack/plugins/maps/public/connected_components/mb_map/sort_layers.ts index 8c16c13bfcc90..927c6819351c2 100644 --- a/x-pack/plugins/maps/public/connected_components/mb_map/sort_layers.ts +++ b/x-pack/plugins/maps/public/connected_components/mb_map/sort_layers.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { Map as MbMap, Layer as MbLayer } from 'mapbox-gl'; +import type { Map as MbMap, Layer as MbLayer } from '@kbn/mapbox-gl'; import { ILayer } from '../../classes/layers/layer'; // "Layer" is overloaded and can mean the following diff --git a/x-pack/plugins/maps/public/connected_components/mb_map/tile_status_tracker.test.ts b/x-pack/plugins/maps/public/connected_components/mb_map/tile_status_tracker.test.ts index 223efae657601..6b47fe3e6e650 100644 --- a/x-pack/plugins/maps/public/connected_components/mb_map/tile_status_tracker.test.ts +++ b/x-pack/plugins/maps/public/connected_components/mb_map/tile_status_tracker.test.ts @@ -7,7 +7,7 @@ // eslint-disable-next-line max-classes-per-file import { TileStatusTracker } from './tile_status_tracker'; -import { Map as MbMap } from 'mapbox-gl'; +import type { Map as MbMap } from '@kbn/mapbox-gl'; import { ILayer } from '../../classes/layers/layer'; class MockMbMap { diff --git a/x-pack/plugins/maps/public/connected_components/mb_map/tile_status_tracker.ts b/x-pack/plugins/maps/public/connected_components/mb_map/tile_status_tracker.ts index be946a12fe225..fc99cd3067d0b 100644 --- a/x-pack/plugins/maps/public/connected_components/mb_map/tile_status_tracker.ts +++ b/x-pack/plugins/maps/public/connected_components/mb_map/tile_status_tracker.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { Map as MapboxMap, MapSourceDataEvent } from 'mapbox-gl'; +import type { Map as MapboxMap, MapSourceDataEvent } from '@kbn/mapbox-gl'; import _ from 'lodash'; import { ILayer } from '../../classes/layers/layer'; import { SPATIAL_FILTERS_LAYER_ID } from '../../../common/constants'; diff --git a/x-pack/plugins/maps/public/connected_components/mb_map/tooltip_control/tooltip_control.test.tsx b/x-pack/plugins/maps/public/connected_components/mb_map/tooltip_control/tooltip_control.test.tsx index 451150fabb064..ac6e3cfcccf4e 100644 --- a/x-pack/plugins/maps/public/connected_components/mb_map/tooltip_control/tooltip_control.test.tsx +++ b/x-pack/plugins/maps/public/connected_components/mb_map/tooltip_control/tooltip_control.test.tsx @@ -14,7 +14,7 @@ jest.mock('./tooltip_popover', () => ({ import sinon from 'sinon'; import React from 'react'; import { mount, shallow } from 'enzyme'; -import { Map as MbMap, MapMouseEvent, MapboxGeoJSONFeature } from 'mapbox-gl'; +import type { Map as MbMap, MapMouseEvent, MapboxGeoJSONFeature } from '@kbn/mapbox-gl'; import { TooltipControl } from './tooltip_control'; import { IVectorLayer } from '../../../classes/layers/vector_layer'; diff --git a/x-pack/plugins/maps/public/connected_components/mb_map/tooltip_control/tooltip_control.tsx b/x-pack/plugins/maps/public/connected_components/mb_map/tooltip_control/tooltip_control.tsx index e8c3a46430cb9..09dd9ee4f51d9 100644 --- a/x-pack/plugins/maps/public/connected_components/mb_map/tooltip_control/tooltip_control.tsx +++ b/x-pack/plugins/maps/public/connected_components/mb_map/tooltip_control/tooltip_control.tsx @@ -14,7 +14,7 @@ import { MapboxGeoJSONFeature, MapMouseEvent, Point as MbPoint, -} from 'mapbox-gl'; +} from '@kbn/mapbox-gl'; import uuid from 'uuid/v4'; import { Geometry } from 'geojson'; import { Filter } from 'src/plugins/data/public'; diff --git a/x-pack/plugins/maps/public/connected_components/mb_map/tooltip_control/tooltip_popover.test.tsx b/x-pack/plugins/maps/public/connected_components/mb_map/tooltip_control/tooltip_popover.test.tsx index 22223df366011..002ec09e68c2f 100644 --- a/x-pack/plugins/maps/public/connected_components/mb_map/tooltip_control/tooltip_popover.test.tsx +++ b/x-pack/plugins/maps/public/connected_components/mb_map/tooltip_control/tooltip_popover.test.tsx @@ -14,7 +14,7 @@ jest.mock('./features_tooltip/features_tooltip', () => ({ import sinon from 'sinon'; import React from 'react'; import { mount, shallow } from 'enzyme'; -import { Map as MbMap } from 'mapbox-gl'; +import type { Map as MbMap } from '@kbn/mapbox-gl'; import { TooltipPopover } from './tooltip_popover'; // mutable map state diff --git a/x-pack/plugins/maps/public/connected_components/mb_map/tooltip_control/tooltip_popover.tsx b/x-pack/plugins/maps/public/connected_components/mb_map/tooltip_control/tooltip_popover.tsx index a3fcc0ea6a07a..0b7ba3468d30c 100644 --- a/x-pack/plugins/maps/public/connected_components/mb_map/tooltip_control/tooltip_popover.tsx +++ b/x-pack/plugins/maps/public/connected_components/mb_map/tooltip_control/tooltip_popover.tsx @@ -7,7 +7,7 @@ import React, { Component, RefObject } from 'react'; import { EuiPopover, EuiText } from '@elastic/eui'; -import { Map as MbMap } from 'mapbox-gl'; +import type { Map as MbMap } from '@kbn/mapbox-gl'; import { GeoJsonProperties, Geometry } from 'geojson'; import { Filter } from 'src/plugins/data/public'; import { ActionExecutionContext, Action } from 'src/plugins/ui_actions/public'; diff --git a/yarn.lock b/yarn.lock index 9f7db552a3f53..24f80c7dcb7b5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2854,32 +2854,32 @@ resolved "https://registry.yarnpkg.com/@mapbox/extent/-/extent-0.4.0.tgz#3e591f32e1f0c3981c864239f7b0ac06e610f8a9" integrity sha1-PlkfMuHww5gchkI597CsBuYQ+Kk= -"@mapbox/geojson-area@^0.2.1": +"@mapbox/geojson-area@^0.2.2": version "0.2.2" resolved "https://registry.yarnpkg.com/@mapbox/geojson-area/-/geojson-area-0.2.2.tgz#18d7814aa36bf23fbbcc379f8e26a22927debf10" integrity sha1-GNeBSqNr8j+7zDefjiaiKSfevxA= dependencies: wgs84 "0.0.0" -"@mapbox/geojson-coords@0.0.0": - version "0.0.0" - resolved "https://registry.yarnpkg.com/@mapbox/geojson-coords/-/geojson-coords-0.0.0.tgz#4847a5b96059666e527a2139e75e35d84fd58f50" - integrity sha1-SEeluWBZZm5SeiE551412E/Vj1A= +"@mapbox/geojson-coords@0.0.1": + version "0.0.1" + resolved "https://registry.yarnpkg.com/@mapbox/geojson-coords/-/geojson-coords-0.0.1.tgz#31338ac5bc7b2e663409fb129643257ce715594f" + integrity sha512-cdMlqmDl1vzAl2E0XC2zIuqM74vdet0Dq2el49haJEVbGpC8se40j5UcsnBK/gsvZzrume30fon1u/aSYMXG4Q== dependencies: "@mapbox/geojson-normalize" "0.0.1" - geojson-flatten "~0.2.1" + geojson-flatten "^1.0.4" -"@mapbox/geojson-extent@^0.3.2": - version "0.3.2" - resolved "https://registry.yarnpkg.com/@mapbox/geojson-extent/-/geojson-extent-0.3.2.tgz#a1bdb2015afd0e031c18c3f29f7eb229e4e1950f" - integrity sha1-ob2yAVr9DgMcGMPyn36yKeThlQ8= +"@mapbox/geojson-extent@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@mapbox/geojson-extent/-/geojson-extent-1.0.0.tgz#cc1db1ca5f28e7a3a2d71dcfc86c9ef3486e1558" + integrity sha512-OWW/Tw7OkKHoogXjQJNILjLd2d4JZzO/elc5Qr08VNwFSIPpSnJgyaEGO2xRPqNuWDLr4RocuqmC0FcQWPgeOA== dependencies: "@mapbox/extent" "0.4.0" - "@mapbox/geojson-coords" "0.0.0" + "@mapbox/geojson-coords" "0.0.1" rw "~0.1.4" traverse "~0.6.6" -"@mapbox/geojson-normalize@0.0.1": +"@mapbox/geojson-normalize@0.0.1", "@mapbox/geojson-normalize@^0.0.1": version "0.0.1" resolved "https://registry.yarnpkg.com/@mapbox/geojson-normalize/-/geojson-normalize-0.0.1.tgz#1da1e6b3a7add3ad29909b30f438f60581b7cd80" integrity sha1-HaHms6et060pkJsw9Dj2BYG3zYA= @@ -2897,17 +2897,6 @@ resolved "https://registry.yarnpkg.com/@mapbox/geojson-types/-/geojson-types-1.0.2.tgz#9aecf642cb00eab1080a57c4f949a65b4a5846d6" integrity sha512-e9EBqHHv3EORHrSfbR9DqecPNn+AmuAoQxV6aL8Xu30bJMJR1o8PZLZzpk1Wq7/NfCbuhmakHTPYRhoqLsXRnw== -"@mapbox/geojsonhint@3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@mapbox/geojsonhint/-/geojsonhint-3.0.0.tgz#42448232ce4236cb89c1b69c36b0cadeac99e02e" - integrity sha512-zHcyh1rDHYnEBd6NvOWoeHLuvazlDkIjvz9MJx4cKwcKTlfrqgxVnTv1QLnVJnsSU5neJnhQJcgscR/Zl4uYgw== - dependencies: - concat-stream "^1.6.1" - jsonlint-lines "1.7.1" - minimist "1.2.0" - vfile "^4.0.0" - vfile-reporter "^5.1.1" - "@mapbox/hast-util-table-cell-style@^0.1.3": version "0.1.3" resolved "https://registry.yarnpkg.com/@mapbox/hast-util-table-cell-style/-/hast-util-table-cell-style-0.1.3.tgz#5b7166ae01297d72216932b245e4b2f0b642dca6" @@ -2920,22 +2909,20 @@ resolved "https://registry.yarnpkg.com/@mapbox/jsonlint-lines-primitives/-/jsonlint-lines-primitives-2.0.2.tgz#ce56e539f83552b58d10d672ea4d6fc9adc7b234" integrity sha1-zlblOfg1UrWNENZy6k1vya3HsjQ= -"@mapbox/mapbox-gl-draw@^1.2.0": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@mapbox/mapbox-gl-draw/-/mapbox-gl-draw-1.2.0.tgz#b6e5278afef65bd5d7d92366034997768e478ad9" - integrity sha512-gMrP2zn8PzDtrs72FMJTPytCumX5vUn9R7IK38qBOVy9UfqbdWr56KYuNA/2X+jKn4FIOpmWf8CWkKpOaQkv7w== +"@mapbox/mapbox-gl-draw@1.3.0": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@mapbox/mapbox-gl-draw/-/mapbox-gl-draw-1.3.0.tgz#7a30fb99488cb47a32c25e99c3c62413b04bbaed" + integrity sha512-B+KWK+dAgzLHMNyKVuuMRfjeSlQ77MhNLdfpQQpbp3pkhnrdmydDe3ixto1Ua78hktNut0WTrAaD8gYu4PVcjA== dependencies: - "@mapbox/geojson-area" "^0.2.1" - "@mapbox/geojson-extent" "^0.3.2" - "@mapbox/geojson-normalize" "0.0.1" - "@mapbox/geojsonhint" "3.0.0" - "@mapbox/point-geometry" "0.1.0" - eslint-plugin-import "^2.19.1" + "@mapbox/geojson-area" "^0.2.2" + "@mapbox/geojson-extent" "^1.0.0" + "@mapbox/geojson-normalize" "^0.0.1" + "@mapbox/point-geometry" "^0.1.0" hat "0.0.3" - lodash.isequal "^4.2.0" - xtend "^4.0.1" + lodash.isequal "^4.5.0" + xtend "^4.0.2" -"@mapbox/mapbox-gl-rtl-text@^0.2.3": +"@mapbox/mapbox-gl-rtl-text@0.2.3": version "0.2.3" resolved "https://registry.yarnpkg.com/@mapbox/mapbox-gl-rtl-text/-/mapbox-gl-rtl-text-0.2.3.tgz#a26ecfb3f0061456d93ee8570dd9587d226ea8bd" integrity sha512-RaCYfnxULUUUxNwcUimV9C/o2295ktTyLEUzD/+VWkqXqvaVfFcZ5slytGzb2Sd/Jj4MlbxD0DCZbfa6CzcmMw== @@ -5349,10 +5336,10 @@ resolved "https://registry.yarnpkg.com/@types/lru-cache/-/lru-cache-5.1.0.tgz#57f228f2b80c046b4a1bd5cac031f81f207f4f03" integrity sha512-RaE0B+14ToE4l6UqdarKPnXwVDuigfFv+5j9Dze/Nqr23yyuqdNvzcZi3xB+3Agvi5R4EOgAksfv3lXX4vBt9w== -"@types/mapbox-gl@^1.9.1": - version "1.9.1" - resolved "https://registry.yarnpkg.com/@types/mapbox-gl/-/mapbox-gl-1.9.1.tgz#78b62f8a1ead78bc525a4c1db84bb71fa0fcc579" - integrity sha512-5LS/fljbGjCPfjtOK5+pz8TT0PL4bBXTnN/PDbPtTQMqQdY/KWTWE4jRPuo0fL5wctd543DCptEUTydn+JK+gA== +"@types/mapbox-gl@1.13.1": + version "1.13.1" + resolved "https://registry.yarnpkg.com/@types/mapbox-gl/-/mapbox-gl-1.13.1.tgz#bd8108f912f32c895117e2970b6d4fbbecbe42a1" + integrity sha512-Yqv1eFAzG2gdecc94higNC8KE+BR6t8QhFgbQGGEpKr3OgSVVtr2qaBNBPaGlIAtCoKDF6JGB2haOhvijYC4Bg== dependencies: "@types/geojson" "*" @@ -6470,11 +6457,6 @@ JSONStream@1.3.5, JSONStream@^1.0.3: jsonparse "^1.2.0" through ">=2.2.7 <3" -"JSV@>= 4.0.x": - version "4.0.2" - resolved "https://registry.yarnpkg.com/JSV/-/JSV-4.0.2.tgz#d077f6825571f82132f9dffaed587b4029feff57" - integrity sha1-0Hf2glVx+CEy+d/67Vh7QCn+/1c= - abab@^2.0.0, abab@^2.0.3, abab@^2.0.4: version "2.0.5" resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.5.tgz#c0b678fb32d60fc1219c784d6a826fe385aeb79a" @@ -6871,11 +6853,6 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0: "@types/color-name" "^1.1.1" color-convert "^2.0.1" -ansi-styles@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-1.0.0.tgz#cb102df1c56f5123eab8b67cd7b98027a0279178" - integrity sha1-yxAt8cVvUSPquLZ817mAJ6AnkXg= - ansi-to-html@^0.6.11: version "0.6.13" resolved "https://registry.yarnpkg.com/ansi-to-html/-/ansi-to-html-0.6.13.tgz#c72eae8b63e5ca0643aab11bfc6e6f2217425833" @@ -9141,15 +9118,6 @@ chalk@^4.0.0, chalk@^4.1.0, chalk@~4.1.0: ansi-styles "^4.1.0" supports-color "^7.1.0" -chalk@~0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-0.4.0.tgz#5199a3ddcd0c1efe23bc08c1b027b06176e0c64f" - integrity sha1-UZmj3c0MHv4jvAjBsCewYXbgxk8= - dependencies: - ansi-styles "~1.0.0" - has-color "~0.1.0" - strip-ansi "~0.1.0" - chalk@~0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/chalk/-/chalk-0.5.1.tgz#663b3a648b68b55d04690d49167aa837858f2174" @@ -12649,7 +12617,7 @@ eslint-formatter-pretty@^4.0.0: string-width "^4.2.0" supports-hyperlinks "^2.0.0" -eslint-import-resolver-node@0.3.2, eslint-import-resolver-node@^0.3.2: +eslint-import-resolver-node@0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz#58f15fb839b8d0576ca980413476aab2472db66a" integrity sha512-sfmTqJfPSizWu4aymbPr4Iidp5yKm8yDkHp+Ir3YiTHiiDfxh69mOUsmiqW6RZ9zRXFaF64GtYmN7e+8GHBv6Q== @@ -12681,7 +12649,7 @@ eslint-import-resolver-webpack@0.11.1: resolve "^1.10.0" semver "^5.3.0" -eslint-module-utils@2.5.0, eslint-module-utils@^2.4.1: +eslint-module-utils@2.5.0: version "2.5.0" resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.5.0.tgz#cdf0b40d623032274ccd2abd7e64c4e524d6e19c" integrity sha512-kCo8pZaNz2dsAW7nCUjuVoI11EBXXpIzfNxmaoLhXoRDOnqXLC4iSGVRdZPhOitfbdEfMEfKOiENaK6wDPZEGw== @@ -12734,24 +12702,6 @@ eslint-plugin-eslint-comments@^3.2.0: escape-string-regexp "^1.0.5" ignore "^5.0.5" -eslint-plugin-import@^2.19.1: - version "2.19.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.19.1.tgz#5654e10b7839d064dd0d46cd1b88ec2133a11448" - integrity sha512-x68131aKoCZlCae7rDXKSAQmbT5DQuManyXo2sK6fJJ0aK5CWAkv6A6HJZGgqC8IhjQxYPgo6/IY4Oz8AFsbBw== - dependencies: - array-includes "^3.0.3" - array.prototype.flat "^1.2.1" - contains-path "^0.1.0" - debug "^2.6.9" - doctrine "1.5.0" - eslint-import-resolver-node "^0.3.2" - eslint-module-utils "^2.4.1" - has "^1.0.3" - minimatch "^3.0.4" - object.values "^1.1.0" - read-pkg-up "^2.0.0" - resolve "^1.12.0" - eslint-plugin-import@^2.22.1: version "2.22.1" resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.22.1.tgz#0896c7e6a0cf44109a2d97b95903c2bb689d7702" @@ -14232,13 +14182,13 @@ gensync@^1.0.0-beta.1: resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.1.tgz#58f4361ff987e5ff6e1e7a210827aa371eaac269" integrity sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg== -geojson-flatten@~0.2.1: - version "0.2.4" - resolved "https://registry.yarnpkg.com/geojson-flatten/-/geojson-flatten-0.2.4.tgz#8f3396f31a0f5b747e39c9e6a14088f43ba4ecfb" - integrity sha512-LiX6Jmot8adiIdZ/fthbcKKPOfWjTQchX/ggHnwMZ2e4b0I243N1ANUos0LvnzepTEsj0+D4fIJ5bKhBrWnAHA== +geojson-flatten@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/geojson-flatten/-/geojson-flatten-1.0.4.tgz#cdfef2e9042996fcaa14fe658db6d88c99c20930" + integrity sha512-PpscUXxO6dvvhZxtwuqiI5v+1C/IQYPJRMWoQeaF2oohJgfGYSHKVAe8L+yUqF34PH/hmq9JlwmO+juPw+95/Q== dependencies: - get-stdin "^6.0.0" - minimist "1.2.0" + get-stdin "^7.0.0" + minimist "^1.2.5" geojson-vt@^3.2.1: version "3.2.1" @@ -14311,6 +14261,11 @@ get-stdin@^6.0.0: resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-6.0.0.tgz#9e09bf712b360ab9225e812048f71fde9c89657b" integrity sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g== +get-stdin@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-7.0.0.tgz#8d5de98f15171a125c5e516643c7a6d0ea8a96f6" + integrity sha512-zRKcywvrXlXsA0v0i9Io4KDRaAw7+a1ZpjRwl9Wox8PFlVCCHra7E9c4kqXCoCM9nR5tBkaTTZRBoCm60bFqTQ== + get-stdin@^8.0.0: version "8.0.0" resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-8.0.0.tgz#cbad6a73feb75f6eeb22ba9e01f89aa28aa97a53" @@ -15056,11 +15011,6 @@ has-bigints@^1.0.1: resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.1.tgz#64fe6acb020673e3b78db035a5af69aa9d07b113" integrity sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA== -has-color@~0.1.0: - version "0.1.7" - resolved "https://registry.yarnpkg.com/has-color/-/has-color-0.1.7.tgz#67144a5260c34fc3cca677d041daf52fe7b78b2f" - integrity sha1-ZxRKUmDDT8PMpnfQQdr1L+e3iy8= - has-flag@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51" @@ -17749,14 +17699,6 @@ jsonify@~0.0.0: resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" integrity sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM= -jsonlint-lines@1.7.1: - version "1.7.1" - resolved "https://registry.yarnpkg.com/jsonlint-lines/-/jsonlint-lines-1.7.1.tgz#507de680d3fb8c4be1641cc57d6f679f29f178ff" - integrity sha1-UH3mgNP7jEvhZBzFfW9nnynxeP8= - dependencies: - JSV ">= 4.0.x" - nomnom ">= 1.5.x" - jsonparse@^1.2.0: version "1.3.1" resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" @@ -18452,7 +18394,7 @@ lodash.isempty@^4.4.0: resolved "https://registry.yarnpkg.com/lodash.isempty/-/lodash.isempty-4.4.0.tgz#6f86cbedd8be4ec987be9aaf33c9684db1b31e7e" integrity sha1-b4bL7di+TsmHvpqvM8loTbGzHn4= -lodash.isequal@^4.0.0, lodash.isequal@^4.1.1, lodash.isequal@^4.2.0, lodash.isequal@^4.5.0: +lodash.isequal@^4.0.0, lodash.isequal@^4.1.1, lodash.isequal@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" integrity sha1-QVxEePK8wwEgwizhDtMib30+GOA= @@ -18815,7 +18757,7 @@ map-visit@^1.0.0: dependencies: object-visit "^1.0.0" -mapbox-gl-draw-rectangle-mode@^1.0.4: +mapbox-gl-draw-rectangle-mode@1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/mapbox-gl-draw-rectangle-mode/-/mapbox-gl-draw-rectangle-mode-1.0.4.tgz#42987d68872a5fb5cc5d76d3375ee20cd8bab8f7" integrity sha512-BdF6nwEK2p8n9LQoMPzBO8LhddW1fe+d5vK8HQIei+4VcRnUbKNsEj7Z15FsJxCHzsc2BQKXbESx5GaE8x0imQ== @@ -19367,7 +19309,7 @@ minimist-options@4.1.0, minimist-options@^4.0.2: is-plain-obj "^1.1.0" kind-of "^6.0.3" -minimist@0.0.8, minimist@1.2.0, minimist@^1.1.0, minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0, minimist@^1.2.5, minimist@~1.2.0: +minimist@0.0.8, minimist@^1.1.0, minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0, minimist@^1.2.5, minimist@~1.2.0: version "1.2.5" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== @@ -20214,14 +20156,6 @@ nodemon@^2.0.4: undefsafe "^2.0.3" update-notifier "^4.1.0" -"nomnom@>= 1.5.x": - version "1.8.1" - resolved "https://registry.yarnpkg.com/nomnom/-/nomnom-1.8.1.tgz#2151f722472ba79e50a76fc125bb8c8f2e4dc2a7" - integrity sha1-IVH3Ikcrp55Qp2/BJbuMjy5Nwqc= - dependencies: - chalk "~0.4.0" - underscore "~1.6.0" - "nopt@2 || 3", nopt@~3.0.6: version "3.0.6" resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" @@ -24097,7 +24031,7 @@ repeat-element@^1.1.2: resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" integrity sha1-7wiaF40Ug7quTZPrmLT55OEdmQo= -repeat-string@^1.0.0, repeat-string@^1.5.0, repeat-string@^1.5.2, repeat-string@^1.5.4, repeat-string@^1.6.1: +repeat-string@^1.0.0, repeat-string@^1.5.2, repeat-string@^1.5.4, repeat-string@^1.6.1: version "1.6.1" resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= @@ -25879,7 +25813,7 @@ string-width@^1.0.1, string-width@^1.0.2: is-fullwidth-code-point "^1.0.0" strip-ansi "^3.0.0" -"string-width@^1.0.2 || 2", string-width@^2.0.0, string-width@^2.1.1: +"string-width@^1.0.2 || 2", string-width@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== @@ -26027,11 +25961,6 @@ strip-ansi@^4.0.0: dependencies: ansi-regex "^3.0.0" -strip-ansi@~0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-0.1.1.tgz#39e8a98d044d150660abe4a6808acf70bb7bc991" - integrity sha1-OeipjQRNFQZgq+SmgIrPcLt7yZE= - strip-bom-string@1.X: version "1.0.0" resolved "https://registry.yarnpkg.com/strip-bom-string/-/strip-bom-string-1.0.0.tgz#e5211e9224369fbb81d633a2f00044dc8cedad92" @@ -27486,7 +27415,7 @@ underscore.string@~3.3.5: sprintf-js "^1.0.3" util-deprecate "^1.0.2" -underscore@^1.13.1, underscore@^1.8.3, underscore@~1.6.0: +underscore@^1.13.1, underscore@^1.8.3: version "1.13.1" resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.13.1.tgz#0c1c6bd2df54b6b69f2314066d65b6cde6fcf9d1" integrity sha512-hzSoAVtJF+3ZtiFX0VgfFPHEDRm7Y/QPjGyNo4TVdnDTdft3tr8hEkD25a1jC+TjTuE7tkHGKkhwCgs9dgBB2g== @@ -28618,28 +28547,6 @@ vfile-message@^1.0.0: dependencies: unist-util-stringify-position "^1.1.1" -vfile-reporter@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/vfile-reporter/-/vfile-reporter-5.1.1.tgz#419688c7e9dcaf65ba81bfdb0ad443e9e0248e09" - integrity sha512-A/cfKvfVmeEmAKx1yyOWggCjC/k184Vkl5pVJAw5CEdppHd5FHBVcdyJ1JBSqIdJjJqyhZY4ZD3JycHr/uwmlA== - dependencies: - repeat-string "^1.5.0" - string-width "^2.0.0" - supports-color "^5.4.0" - unist-util-stringify-position "^1.0.0" - vfile-sort "^2.1.2" - vfile-statistics "^1.1.0" - -vfile-sort@^2.1.2: - version "2.2.0" - resolved "https://registry.yarnpkg.com/vfile-sort/-/vfile-sort-2.2.0.tgz#383a8727ec4c5daf37c05683684a5eb686366d39" - integrity sha512-RgxLXVWrJBWb2GuP8FsSkqK7HmbjXjnI8qx3nD6NTWhsWaelaKvJuxfh1F1d1lkCPD7imo4zzi8cf6IOMgaTnQ== - -vfile-statistics@^1.1.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/vfile-statistics/-/vfile-statistics-1.1.2.tgz#c50132627e4669a3afa07c64ff1e7aa7695e8151" - integrity sha512-16wAC9eEGXdsD35LX9m/iXCRIZyX5LIrDgDtAF92rbATSqsBRbC4n05e0Rj5vt3XRpcKu0UJeWnTxWsSyvNZ+w== - vfile@^2.0.0: version "2.3.0" resolved "https://registry.yarnpkg.com/vfile/-/vfile-2.3.0.tgz#e62d8e72b20e83c324bc6c67278ee272488bf84a" From 83e5b6c689a221fa92db1bbd1d71e7c8f19dd627 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Fern=C3=A1ndez=20G=C3=B3mez?= Date: Thu, 27 May 2021 11:30:15 +0200 Subject: [PATCH 18/77] [Fleet] Remove beats management plugin (#99789) --- .github/CODEOWNERS | 3 - api_docs/alerting.json | 22 +- api_docs/beats_management.json | 72 - api_docs/beats_management.mdx | 21 - api_docs/core.json | 338 ++- api_docs/core_application.json | 388 ++- api_docs/core_chrome.json | 144 +- api_docs/data.json | 2444 ++++++++--------- api_docs/data_index_patterns.json | 1730 ++++++------ api_docs/data_search.json | 81 +- api_docs/deprecations.mdx | 136 +- api_docs/features.json | 14 - api_docs/fleet.json | 24 +- api_docs/home.json | 14 +- api_docs/kibana_utils.json | 4 +- api_docs/licensing.json | 411 ++- api_docs/lists.json | 1359 +-------- api_docs/lists.mdx | 14 - api_docs/management.json | 53 +- api_docs/ml.json | 2 +- api_docs/saved_objects.json | 48 +- api_docs/security.json | 49 +- api_docs/spaces.json | 28 +- docs/developer/plugin-list.asciidoc | 5 - docs/management/managing-beats.asciidoc | 108 - docs/user/management.asciidoc | 6 - packages/kbn-optimizer/limits.yml | 1 - tsconfig.json | 1 - tsconfig.refs.json | 1 - x-pack/.i18nrc.json | 1 - .../beats_management/common/config_schemas.ts | 384 --- .../common/config_schemas_translations_map.ts | 243 -- .../common/constants/configuration_blocks.ts | 8 - .../common/constants/index.ts | 13 - .../common/constants/index_names.ts | 16 - .../common/constants/plugin.ts | 12 - .../common/constants/security.ts | 18 - .../common/constants/table.ts | 13 - .../beats_management/common/domain_types.ts | 136 - .../plugins/beats_management/common/index.ts | 23 - .../beats_management/common/io_ts_types.ts | 34 - .../beats_management/common/return_types.ts | 106 - .../plugins/beats_management/jest.config.js | 12 - x-pack/plugins/beats_management/kibana.json | 16 - .../beats_management/public/application.tsx | 89 - .../beats_management/public/bootstrap.tsx | 69 - .../components/autocomplete_field/index.tsx | 290 -- .../autocomplete_field/suggestion_item.tsx | 119 - .../public/components/config_list.tsx | 117 - .../public/components/enroll_beats.tsx | 292 -- .../public/components/inputs/code_editor.tsx | 114 - .../public/components/inputs/index.ts | 12 - .../public/components/inputs/input.tsx | 120 - .../public/components/inputs/multi_input.tsx | 122 - .../components/inputs/password_input.tsx | 114 - .../public/components/inputs/select.tsx | 125 - .../public/components/layouts/background.tsx | 12 - .../public/components/layouts/no_data.tsx | 31 - .../public/components/layouts/primary.tsx | 84 - .../public/components/layouts/walkthrough.tsx | 49 - .../public/components/loading.tsx | 17 - .../navigation/breadcrumb/breadcrumb.tsx | 64 - .../navigation/breadcrumb/consumer.tsx | 8 - .../navigation/breadcrumb/context.tsx | 19 - .../components/navigation/breadcrumb/index.ts | 10 - .../navigation/breadcrumb/provider.tsx | 73 - .../navigation/breadcrumb/types.d.ts | 16 - .../components/navigation/child_routes.tsx | 40 - .../components/navigation/connected_link.tsx | 46 - .../public/components/table/action_schema.ts | 101 - .../table/controls/action_control.tsx | 97 - .../public/components/table/controls/index.ts | 8 - .../table/controls/option_control.tsx | 58 - .../table/controls/tag_badge_list.tsx | 110 - .../public/components/table/index.ts | 16 - .../public/components/table/table.tsx | 160 -- .../components/table/table_type_configs.tsx | 345 --- .../tag/config_view/config_form.tsx | 216 -- .../components/tag/config_view/index.tsx | 189 -- .../public/components/tag/index.ts | 9 - .../public/components/tag/tag_badge.tsx | 48 - .../public/components/tag/tag_edit.tsx | 238 -- .../public/containers/beats.ts | 104 - .../public/containers/tags.ts | 54 - .../containers/with_kuery_autocompletion.tsx | 89 - .../public/containers/with_url_state.tsx | 101 - .../public/frontend_types.d.ts | 36 - .../plugins/beats_management/public/index.ts | 40 - .../beats_management/public/kbn_services.ts | 26 - .../lib/adapters/beats/adapter_types.ts | 38 - .../adapters/beats/memory_beats_adapter.ts | 109 - .../lib/adapters/beats/rest_beats_adapter.ts | 80 - .../configuration_blocks/adapter_types.ts | 15 - .../memory_config_blocks_adapter.ts | 42 - .../rest_config_blocks_adapter.ts | 36 - .../adapters/elasticsearch/adapter_types.ts | 14 - .../lib/adapters/elasticsearch/memory.ts | 27 - .../public/lib/adapters/elasticsearch/rest.ts | 66 - .../lib/adapters/framework/adapter_types.ts | 54 - .../framework/kibana_framework_adapter.ts | 160 -- .../framework/testing_framework_adapter.ts | 46 - .../lib/adapters/rest_api/adapter_types.ts | 15 - .../rest_api/axios_rest_api_adapter.ts | 79 - .../rest_api/node_axios_api_adapter.ts | 93 - .../public/lib/adapters/tags/adapter_types.ts | 16 - .../lib/adapters/tags/memory_tags_adapter.ts | 44 - .../lib/adapters/tags/rest_tags_adapter.ts | 66 - .../lib/adapters/tokens/adapter_types.ts | 10 - .../adapters/tokens/memory_tokens_adapter.ts | 14 - .../adapters/tokens/rest_tokens_adapter.ts | 23 - .../beats_management/public/lib/beats.ts | 66 - .../public/lib/compose/kibana.ts | 81 - .../public/lib/compose/scripts.ts | 79 - .../public/lib/config_blocks.test.ts | 149 - .../public/lib/configuration_blocks.ts | 123 - .../public/lib/elasticsearch.ts | 70 - .../beats_management/public/lib/framework.ts | 61 - .../beats_management/public/lib/tags.ts | 48 - .../beats_management/public/lib/types.ts | 60 - .../beats_management/public/pages/__404.tsx | 22 - .../public/pages/beat/details.tsx | 201 -- .../public/pages/beat/index.tsx | 201 -- .../public/pages/beat/tags.tsx | 76 - .../public/pages/error/enforce_security.tsx | 27 - .../public/pages/error/invalid_license.tsx | 28 - .../public/pages/error/no_access.tsx | 29 - .../beats_management/public/pages/index.ts | 56 - .../pages/overview/configuration_tags.tsx | 118 - .../public/pages/overview/enrolled_beats.tsx | 355 --- .../public/pages/overview/index.tsx | 110 - .../public/pages/tag/create.tsx | 160 -- .../public/pages/tag/edit.tsx | 203 -- .../public/pages/walkthrough/initial/beat.tsx | 65 - .../pages/walkthrough/initial/finish.tsx | 136 - .../pages/walkthrough/initial/index.tsx | 97 - .../public/pages/walkthrough/initial/tag.tsx | 137 - .../beats_management/public/router.tsx | 132 - .../public/utils/random_eui_color.ts | 26 - .../public/utils/typed_react.ts | 21 - x-pack/plugins/beats_management/readme.md | 39 - .../beats_management/scripts/enroll.js | 42 - .../beats_management/scripts/fake_env.ts | 158 -- .../plugins/beats_management/server/index.ts | 22 - .../index_templates/beats_template.json | 137 - .../index_templates/events_template.json | 45 - .../server/index_templates/index.ts | 11 - .../lib/adapters/beats/adapter_types.ts | 46 - .../beats/elasticsearch_beats_adapter.ts | 245 -- .../configuration_blocks/adapter_types.ts | 28 - ...asticsearch_configuration_block_adapter.ts | 168 -- .../lib/adapters/database/adapter_types.ts | 302 -- .../database/kibana_database_adapter.ts | 118 - .../lib/adapters/framework/adapter_types.ts | 115 - .../framework/kibana_framework_adapter.ts | 116 - .../server/lib/adapters/tags/adapter_types.ts | 17 - .../tags/elasticsearch_tags_adapter.ts | 180 -- .../lib/adapters/tokens/adapter_types.ts | 19 - .../tokens/elasticsearch_tokens_adapter.ts | 76 - .../server/lib/beat_events.ts | 59 - .../beats_management/server/lib/beats.ts | 260 -- .../server/lib/compose/kibana.ts | 85 - .../server/lib/configuration_blocks.ts | 77 - .../beats_management/server/lib/framework.ts | 54 - .../beats_management/server/lib/tags.ts | 62 - .../beats_management/server/lib/tokens.ts | 144 - .../beats_management/server/lib/types.ts | 61 - .../plugins/beats_management/server/plugin.ts | 89 - .../server/routes/beats/configuration.ts | 83 - .../server/routes/beats/enroll.ts | 90 - .../server/routes/beats/events.ts | 67 - .../server/routes/beats/get.ts | 60 - .../server/routes/beats/index.ts | 15 - .../server/routes/beats/list.ts | 70 - .../server/routes/beats/tag_assignment.ts | 69 - .../server/routes/beats/tag_removal.ts | 67 - .../server/routes/beats/update.ts | 105 - .../server/routes/configurations/delete.ts | 48 - .../server/routes/configurations/get.ts | 53 - .../server/routes/configurations/index.ts | 10 - .../server/routes/configurations/upsert.ts | 73 - .../beats_management/server/routes/index.ts | 55 - .../server/routes/tags/assignable.ts | 51 - .../server/routes/tags/delete.ts | 48 - .../server/routes/tags/get.ts | 46 - .../server/routes/tags/index.ts | 12 - .../server/routes/tags/list.ts | 53 - .../server/routes/tags/set.ts | 63 - .../server/routes/tokens/create.ts | 58 - .../server/routes/tokens/index.ts | 8 - .../server/routes/wrap_route_with_security.ts | 70 - x-pack/plugins/beats_management/tsconfig.json | 26 - .../beats_management/types/formsy.d.ts | 49 - .../translations/translations/ja-JP.json | 179 -- .../translations/translations/zh-CN.json | 183 -- .../apis/beats/assign_tags_to_beats.js | 254 -- .../api_integration/apis/beats/constants.js | 8 - .../apis/beats/create_enrollment_tokens.js | 88 - .../api_integration/apis/beats/enroll_beat.js | 184 -- .../api_integration/apis/beats/get_beat.js | 87 - .../test/api_integration/apis/beats/index.js | 31 - .../api_integration/apis/beats/list_beats.js | 39 - .../apis/beats/remove_tags_from_beats.js | 218 -- .../api_integration/apis/beats/set_config.js | 246 -- .../api_integration/apis/beats/set_tag.js | 67 - .../api_integration/apis/beats/update_beat.js | 122 - x-pack/test/api_integration/apis/index.ts | 1 - x-pack/test/tsconfig.json | 1 - 207 files changed, 2938 insertions(+), 19531 deletions(-) delete mode 100644 api_docs/beats_management.json delete mode 100644 api_docs/beats_management.mdx delete mode 100644 docs/management/managing-beats.asciidoc delete mode 100644 x-pack/plugins/beats_management/common/config_schemas.ts delete mode 100644 x-pack/plugins/beats_management/common/config_schemas_translations_map.ts delete mode 100644 x-pack/plugins/beats_management/common/constants/configuration_blocks.ts delete mode 100644 x-pack/plugins/beats_management/common/constants/index.ts delete mode 100644 x-pack/plugins/beats_management/common/constants/index_names.ts delete mode 100644 x-pack/plugins/beats_management/common/constants/plugin.ts delete mode 100644 x-pack/plugins/beats_management/common/constants/security.ts delete mode 100644 x-pack/plugins/beats_management/common/constants/table.ts delete mode 100644 x-pack/plugins/beats_management/common/domain_types.ts delete mode 100644 x-pack/plugins/beats_management/common/index.ts delete mode 100644 x-pack/plugins/beats_management/common/io_ts_types.ts delete mode 100644 x-pack/plugins/beats_management/common/return_types.ts delete mode 100644 x-pack/plugins/beats_management/jest.config.js delete mode 100644 x-pack/plugins/beats_management/kibana.json delete mode 100644 x-pack/plugins/beats_management/public/application.tsx delete mode 100644 x-pack/plugins/beats_management/public/bootstrap.tsx delete mode 100644 x-pack/plugins/beats_management/public/components/autocomplete_field/index.tsx delete mode 100644 x-pack/plugins/beats_management/public/components/autocomplete_field/suggestion_item.tsx delete mode 100644 x-pack/plugins/beats_management/public/components/config_list.tsx delete mode 100644 x-pack/plugins/beats_management/public/components/enroll_beats.tsx delete mode 100644 x-pack/plugins/beats_management/public/components/inputs/code_editor.tsx delete mode 100644 x-pack/plugins/beats_management/public/components/inputs/index.ts delete mode 100644 x-pack/plugins/beats_management/public/components/inputs/input.tsx delete mode 100644 x-pack/plugins/beats_management/public/components/inputs/multi_input.tsx delete mode 100644 x-pack/plugins/beats_management/public/components/inputs/password_input.tsx delete mode 100644 x-pack/plugins/beats_management/public/components/inputs/select.tsx delete mode 100644 x-pack/plugins/beats_management/public/components/layouts/background.tsx delete mode 100644 x-pack/plugins/beats_management/public/components/layouts/no_data.tsx delete mode 100644 x-pack/plugins/beats_management/public/components/layouts/primary.tsx delete mode 100644 x-pack/plugins/beats_management/public/components/layouts/walkthrough.tsx delete mode 100644 x-pack/plugins/beats_management/public/components/loading.tsx delete mode 100644 x-pack/plugins/beats_management/public/components/navigation/breadcrumb/breadcrumb.tsx delete mode 100644 x-pack/plugins/beats_management/public/components/navigation/breadcrumb/consumer.tsx delete mode 100644 x-pack/plugins/beats_management/public/components/navigation/breadcrumb/context.tsx delete mode 100644 x-pack/plugins/beats_management/public/components/navigation/breadcrumb/index.ts delete mode 100644 x-pack/plugins/beats_management/public/components/navigation/breadcrumb/provider.tsx delete mode 100644 x-pack/plugins/beats_management/public/components/navigation/breadcrumb/types.d.ts delete mode 100644 x-pack/plugins/beats_management/public/components/navigation/child_routes.tsx delete mode 100644 x-pack/plugins/beats_management/public/components/navigation/connected_link.tsx delete mode 100644 x-pack/plugins/beats_management/public/components/table/action_schema.ts delete mode 100644 x-pack/plugins/beats_management/public/components/table/controls/action_control.tsx delete mode 100644 x-pack/plugins/beats_management/public/components/table/controls/index.ts delete mode 100644 x-pack/plugins/beats_management/public/components/table/controls/option_control.tsx delete mode 100644 x-pack/plugins/beats_management/public/components/table/controls/tag_badge_list.tsx delete mode 100644 x-pack/plugins/beats_management/public/components/table/index.ts delete mode 100644 x-pack/plugins/beats_management/public/components/table/table.tsx delete mode 100644 x-pack/plugins/beats_management/public/components/table/table_type_configs.tsx delete mode 100644 x-pack/plugins/beats_management/public/components/tag/config_view/config_form.tsx delete mode 100644 x-pack/plugins/beats_management/public/components/tag/config_view/index.tsx delete mode 100644 x-pack/plugins/beats_management/public/components/tag/index.ts delete mode 100644 x-pack/plugins/beats_management/public/components/tag/tag_badge.tsx delete mode 100644 x-pack/plugins/beats_management/public/components/tag/tag_edit.tsx delete mode 100644 x-pack/plugins/beats_management/public/containers/beats.ts delete mode 100644 x-pack/plugins/beats_management/public/containers/tags.ts delete mode 100644 x-pack/plugins/beats_management/public/containers/with_kuery_autocompletion.tsx delete mode 100644 x-pack/plugins/beats_management/public/containers/with_url_state.tsx delete mode 100644 x-pack/plugins/beats_management/public/frontend_types.d.ts delete mode 100644 x-pack/plugins/beats_management/public/index.ts delete mode 100644 x-pack/plugins/beats_management/public/kbn_services.ts delete mode 100644 x-pack/plugins/beats_management/public/lib/adapters/beats/adapter_types.ts delete mode 100644 x-pack/plugins/beats_management/public/lib/adapters/beats/memory_beats_adapter.ts delete mode 100644 x-pack/plugins/beats_management/public/lib/adapters/beats/rest_beats_adapter.ts delete mode 100644 x-pack/plugins/beats_management/public/lib/adapters/configuration_blocks/adapter_types.ts delete mode 100644 x-pack/plugins/beats_management/public/lib/adapters/configuration_blocks/memory_config_blocks_adapter.ts delete mode 100644 x-pack/plugins/beats_management/public/lib/adapters/configuration_blocks/rest_config_blocks_adapter.ts delete mode 100644 x-pack/plugins/beats_management/public/lib/adapters/elasticsearch/adapter_types.ts delete mode 100644 x-pack/plugins/beats_management/public/lib/adapters/elasticsearch/memory.ts delete mode 100644 x-pack/plugins/beats_management/public/lib/adapters/elasticsearch/rest.ts delete mode 100644 x-pack/plugins/beats_management/public/lib/adapters/framework/adapter_types.ts delete mode 100644 x-pack/plugins/beats_management/public/lib/adapters/framework/kibana_framework_adapter.ts delete mode 100644 x-pack/plugins/beats_management/public/lib/adapters/framework/testing_framework_adapter.ts delete mode 100644 x-pack/plugins/beats_management/public/lib/adapters/rest_api/adapter_types.ts delete mode 100644 x-pack/plugins/beats_management/public/lib/adapters/rest_api/axios_rest_api_adapter.ts delete mode 100644 x-pack/plugins/beats_management/public/lib/adapters/rest_api/node_axios_api_adapter.ts delete mode 100644 x-pack/plugins/beats_management/public/lib/adapters/tags/adapter_types.ts delete mode 100644 x-pack/plugins/beats_management/public/lib/adapters/tags/memory_tags_adapter.ts delete mode 100644 x-pack/plugins/beats_management/public/lib/adapters/tags/rest_tags_adapter.ts delete mode 100644 x-pack/plugins/beats_management/public/lib/adapters/tokens/adapter_types.ts delete mode 100644 x-pack/plugins/beats_management/public/lib/adapters/tokens/memory_tokens_adapter.ts delete mode 100644 x-pack/plugins/beats_management/public/lib/adapters/tokens/rest_tokens_adapter.ts delete mode 100644 x-pack/plugins/beats_management/public/lib/beats.ts delete mode 100644 x-pack/plugins/beats_management/public/lib/compose/kibana.ts delete mode 100644 x-pack/plugins/beats_management/public/lib/compose/scripts.ts delete mode 100644 x-pack/plugins/beats_management/public/lib/config_blocks.test.ts delete mode 100644 x-pack/plugins/beats_management/public/lib/configuration_blocks.ts delete mode 100644 x-pack/plugins/beats_management/public/lib/elasticsearch.ts delete mode 100644 x-pack/plugins/beats_management/public/lib/framework.ts delete mode 100644 x-pack/plugins/beats_management/public/lib/tags.ts delete mode 100644 x-pack/plugins/beats_management/public/lib/types.ts delete mode 100644 x-pack/plugins/beats_management/public/pages/__404.tsx delete mode 100644 x-pack/plugins/beats_management/public/pages/beat/details.tsx delete mode 100644 x-pack/plugins/beats_management/public/pages/beat/index.tsx delete mode 100644 x-pack/plugins/beats_management/public/pages/beat/tags.tsx delete mode 100644 x-pack/plugins/beats_management/public/pages/error/enforce_security.tsx delete mode 100644 x-pack/plugins/beats_management/public/pages/error/invalid_license.tsx delete mode 100644 x-pack/plugins/beats_management/public/pages/error/no_access.tsx delete mode 100644 x-pack/plugins/beats_management/public/pages/index.ts delete mode 100644 x-pack/plugins/beats_management/public/pages/overview/configuration_tags.tsx delete mode 100644 x-pack/plugins/beats_management/public/pages/overview/enrolled_beats.tsx delete mode 100644 x-pack/plugins/beats_management/public/pages/overview/index.tsx delete mode 100644 x-pack/plugins/beats_management/public/pages/tag/create.tsx delete mode 100644 x-pack/plugins/beats_management/public/pages/tag/edit.tsx delete mode 100644 x-pack/plugins/beats_management/public/pages/walkthrough/initial/beat.tsx delete mode 100644 x-pack/plugins/beats_management/public/pages/walkthrough/initial/finish.tsx delete mode 100644 x-pack/plugins/beats_management/public/pages/walkthrough/initial/index.tsx delete mode 100644 x-pack/plugins/beats_management/public/pages/walkthrough/initial/tag.tsx delete mode 100644 x-pack/plugins/beats_management/public/router.tsx delete mode 100644 x-pack/plugins/beats_management/public/utils/random_eui_color.ts delete mode 100644 x-pack/plugins/beats_management/public/utils/typed_react.ts delete mode 100644 x-pack/plugins/beats_management/readme.md delete mode 100644 x-pack/plugins/beats_management/scripts/enroll.js delete mode 100644 x-pack/plugins/beats_management/scripts/fake_env.ts delete mode 100644 x-pack/plugins/beats_management/server/index.ts delete mode 100644 x-pack/plugins/beats_management/server/index_templates/beats_template.json delete mode 100644 x-pack/plugins/beats_management/server/index_templates/events_template.json delete mode 100644 x-pack/plugins/beats_management/server/index_templates/index.ts delete mode 100644 x-pack/plugins/beats_management/server/lib/adapters/beats/adapter_types.ts delete mode 100644 x-pack/plugins/beats_management/server/lib/adapters/beats/elasticsearch_beats_adapter.ts delete mode 100644 x-pack/plugins/beats_management/server/lib/adapters/configuration_blocks/adapter_types.ts delete mode 100644 x-pack/plugins/beats_management/server/lib/adapters/configuration_blocks/elasticsearch_configuration_block_adapter.ts delete mode 100644 x-pack/plugins/beats_management/server/lib/adapters/database/adapter_types.ts delete mode 100644 x-pack/plugins/beats_management/server/lib/adapters/database/kibana_database_adapter.ts delete mode 100644 x-pack/plugins/beats_management/server/lib/adapters/framework/adapter_types.ts delete mode 100644 x-pack/plugins/beats_management/server/lib/adapters/framework/kibana_framework_adapter.ts delete mode 100644 x-pack/plugins/beats_management/server/lib/adapters/tags/adapter_types.ts delete mode 100644 x-pack/plugins/beats_management/server/lib/adapters/tags/elasticsearch_tags_adapter.ts delete mode 100644 x-pack/plugins/beats_management/server/lib/adapters/tokens/adapter_types.ts delete mode 100644 x-pack/plugins/beats_management/server/lib/adapters/tokens/elasticsearch_tokens_adapter.ts delete mode 100644 x-pack/plugins/beats_management/server/lib/beat_events.ts delete mode 100644 x-pack/plugins/beats_management/server/lib/beats.ts delete mode 100644 x-pack/plugins/beats_management/server/lib/compose/kibana.ts delete mode 100644 x-pack/plugins/beats_management/server/lib/configuration_blocks.ts delete mode 100644 x-pack/plugins/beats_management/server/lib/framework.ts delete mode 100644 x-pack/plugins/beats_management/server/lib/tags.ts delete mode 100644 x-pack/plugins/beats_management/server/lib/tokens.ts delete mode 100644 x-pack/plugins/beats_management/server/lib/types.ts delete mode 100644 x-pack/plugins/beats_management/server/plugin.ts delete mode 100644 x-pack/plugins/beats_management/server/routes/beats/configuration.ts delete mode 100644 x-pack/plugins/beats_management/server/routes/beats/enroll.ts delete mode 100644 x-pack/plugins/beats_management/server/routes/beats/events.ts delete mode 100644 x-pack/plugins/beats_management/server/routes/beats/get.ts delete mode 100644 x-pack/plugins/beats_management/server/routes/beats/index.ts delete mode 100644 x-pack/plugins/beats_management/server/routes/beats/list.ts delete mode 100644 x-pack/plugins/beats_management/server/routes/beats/tag_assignment.ts delete mode 100644 x-pack/plugins/beats_management/server/routes/beats/tag_removal.ts delete mode 100644 x-pack/plugins/beats_management/server/routes/beats/update.ts delete mode 100644 x-pack/plugins/beats_management/server/routes/configurations/delete.ts delete mode 100644 x-pack/plugins/beats_management/server/routes/configurations/get.ts delete mode 100644 x-pack/plugins/beats_management/server/routes/configurations/index.ts delete mode 100644 x-pack/plugins/beats_management/server/routes/configurations/upsert.ts delete mode 100644 x-pack/plugins/beats_management/server/routes/index.ts delete mode 100644 x-pack/plugins/beats_management/server/routes/tags/assignable.ts delete mode 100644 x-pack/plugins/beats_management/server/routes/tags/delete.ts delete mode 100644 x-pack/plugins/beats_management/server/routes/tags/get.ts delete mode 100644 x-pack/plugins/beats_management/server/routes/tags/index.ts delete mode 100644 x-pack/plugins/beats_management/server/routes/tags/list.ts delete mode 100644 x-pack/plugins/beats_management/server/routes/tags/set.ts delete mode 100644 x-pack/plugins/beats_management/server/routes/tokens/create.ts delete mode 100644 x-pack/plugins/beats_management/server/routes/tokens/index.ts delete mode 100644 x-pack/plugins/beats_management/server/routes/wrap_route_with_security.ts delete mode 100644 x-pack/plugins/beats_management/tsconfig.json delete mode 100644 x-pack/plugins/beats_management/types/formsy.d.ts delete mode 100644 x-pack/test/api_integration/apis/beats/assign_tags_to_beats.js delete mode 100644 x-pack/test/api_integration/apis/beats/constants.js delete mode 100644 x-pack/test/api_integration/apis/beats/create_enrollment_tokens.js delete mode 100644 x-pack/test/api_integration/apis/beats/enroll_beat.js delete mode 100644 x-pack/test/api_integration/apis/beats/get_beat.js delete mode 100644 x-pack/test/api_integration/apis/beats/index.js delete mode 100644 x-pack/test/api_integration/apis/beats/list_beats.js delete mode 100644 x-pack/test/api_integration/apis/beats/remove_tags_from_beats.js delete mode 100644 x-pack/test/api_integration/apis/beats/set_config.js delete mode 100644 x-pack/test/api_integration/apis/beats/set_tag.js delete mode 100644 x-pack/test/api_integration/apis/beats/update_beat.js diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 39daa5780436f..df7dc1040907c 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -94,9 +94,6 @@ /x-pack/plugins/apm/server/projections/rum_page_load_transactions.ts @elastic/uptime /x-pack/test/apm_api_integration/tests/csm/ @elastic/uptime -# Beats -/x-pack/plugins/beats_management/ @elastic/beats -#CC# /x-pack/plugins/beats_management/ @elastic/beats # Presentation /src/plugins/dashboard/ @elastic/kibana-presentation diff --git a/api_docs/alerting.json b/api_docs/alerting.json index ddb92f5aff9bb..13a150d0af00d 100644 --- a/api_docs/alerting.json +++ b/api_docs/alerting.json @@ -516,13 +516,15 @@ "label": "rule", "description": [], "signature": [ + "Pick, \"enabled\" | \"id\" | \"name\" | \"params\" | \"actions\" | \"tags\" | \"alertTypeId\" | \"consumer\" | \"schedule\" | \"scheduledTaskId\" | \"createdBy\" | \"updatedBy\" | \"createdAt\" | \"updatedAt\" | \"apiKeyOwner\" | \"throttle\" | \"notifyWhen\" | \"muteAll\" | \"mutedInstanceIds\" | \"executionStatus\">, \"enabled\" | \"name\" | \"actions\" | \"tags\" | \"consumer\" | \"schedule\" | \"createdBy\" | \"updatedBy\" | \"createdAt\" | \"updatedAt\" | \"throttle\" | \"notifyWhen\"> & { producer: string; ruleTypeId: string; ruleTypeName: string; }" ], "source": { "path": "x-pack/plugins/alerting/server/types.ts", @@ -840,7 +842,7 @@ "description": [], "source": { "path": "x-pack/plugins/alerting/server/types.ts", - "lineNumber": 75 + "lineNumber": 76 }, "deprecated": false } @@ -1030,7 +1032,7 @@ ], "source": { "path": "x-pack/plugins/alerting/server/types.ts", - "lineNumber": 107 + "lineNumber": 109 }, "deprecated": false } @@ -3913,7 +3915,15 @@ "label": "SanitizedRuleConfig", "description": [], "signature": [ - "Pick, \"enabled\" | \"id\" | \"name\" | \"params\" | \"actions\" | \"tags\" | \"muteAll\" | \"alertTypeId\" | \"consumer\" | \"schedule\" | \"scheduledTaskId\" | \"createdBy\" | \"updatedBy\" | \"createdAt\" | \"updatedAt\" | \"apiKeyOwner\" | \"throttle\" | \"notifyWhen\" | \"mutedInstanceIds\" | \"executionStatus\">, \"enabled\" | \"name\" | \"actions\" | \"tags\" | \"consumer\" | \"schedule\" | \"createdBy\" | \"updatedBy\" | \"createdAt\" | \"updatedAt\" | \"throttle\" | \"notifyWhen\"> & { producer: string; ruleTypeId: string; ruleTypeName: string; }" + "Pick, \"enabled\" | \"id\" | \"name\" | \"params\" | \"actions\" | \"tags\" | \"alertTypeId\" | \"consumer\" | \"schedule\" | \"scheduledTaskId\" | \"createdBy\" | \"updatedBy\" | \"createdAt\" | \"updatedAt\" | \"apiKeyOwner\" | \"throttle\" | \"notifyWhen\" | \"muteAll\" | \"mutedInstanceIds\" | \"executionStatus\">, \"enabled\" | \"name\" | \"actions\" | \"tags\" | \"consumer\" | \"schedule\" | \"createdBy\" | \"updatedBy\" | \"createdAt\" | \"updatedAt\" | \"throttle\" | \"notifyWhen\"> & { producer: string; ruleTypeId: string; ruleTypeName: string; }" ], "source": { "path": "x-pack/plugins/alerting/common/alert.ts", diff --git a/api_docs/beats_management.json b/api_docs/beats_management.json deleted file mode 100644 index c8f0f6af96ce8..0000000000000 --- a/api_docs/beats_management.json +++ /dev/null @@ -1,72 +0,0 @@ -{ - "id": "beatsManagement", - "client": { - "classes": [], - "functions": [], - "interfaces": [], - "enums": [], - "misc": [], - "objects": [] - }, - "server": { - "classes": [], - "functions": [], - "interfaces": [], - "enums": [], - "misc": [], - "objects": [] - }, - "common": { - "classes": [], - "functions": [], - "interfaces": [], - "enums": [], - "misc": [ - { - "parentPluginId": "beatsManagement", - "id": "def-common.BeatsManagementConfigType", - "type": "Type", - "tags": [], - "label": "BeatsManagementConfigType", - "description": [], - "signature": [ - "{ readonly enabled: boolean; readonly defaultUserRoles: string[]; readonly encryptionKey: string; readonly enrollmentTokensTtlInSeconds: number; }" - ], - "source": { - "path": "x-pack/plugins/beats_management/common/index.ts", - "lineNumber": 23 - }, - "deprecated": false, - "initialIsOpen": false - } - ], - "objects": [ - { - "parentPluginId": "beatsManagement", - "id": "def-common.beatsManagementConfigSchema", - "type": "Object", - "tags": [], - "label": "beatsManagementConfigSchema", - "description": [], - "signature": [ - "ObjectType", - "<{ enabled: ", - "Type", - "; defaultUserRoles: ", - "Type", - "; encryptionKey: ", - "Type", - "; enrollmentTokensTtlInSeconds: ", - "Type", - "; }>" - ], - "source": { - "path": "x-pack/plugins/beats_management/common/index.ts", - "lineNumber": 12 - }, - "deprecated": false, - "initialIsOpen": false - } - ] - } -} \ No newline at end of file diff --git a/api_docs/beats_management.mdx b/api_docs/beats_management.mdx deleted file mode 100644 index 9d712c102a1a2..0000000000000 --- a/api_docs/beats_management.mdx +++ /dev/null @@ -1,21 +0,0 @@ ---- -id: kibBeatsManagementPluginApi -slug: /kibana-dev-docs/beatsManagementPluginApi -title: beatsManagement -image: https://source.unsplash.com/400x175/?github -summary: API docs for the beatsManagement plugin -date: 2020-11-16 -tags: ['contributor', 'dev', 'apidocs', 'kibana', 'beatsManagement'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. ---- - -import beatsManagementObj from './beats_management.json'; - -## Common - -### Objects - - -### Consts, variables and types - - diff --git a/api_docs/core.json b/api_docs/core.json index fbf766cad30b3..ee4fe9b10b145 100644 --- a/api_docs/core.json +++ b/api_docs/core.json @@ -1112,7 +1112,7 @@ ], "source": { "path": "src/core/public/index.ts", - "lineNumber": 206 + "lineNumber": 203 }, "deprecated": false, "children": [ @@ -1136,7 +1136,7 @@ ], "source": { "path": "src/core/public/index.ts", - "lineNumber": 208 + "lineNumber": 205 }, "deprecated": false }, @@ -1160,7 +1160,7 @@ ], "source": { "path": "src/core/public/index.ts", - "lineNumber": 210 + "lineNumber": 207 }, "deprecated": false }, @@ -1184,7 +1184,7 @@ ], "source": { "path": "src/core/public/index.ts", - "lineNumber": 212 + "lineNumber": 209 }, "deprecated": false }, @@ -1208,7 +1208,7 @@ ], "source": { "path": "src/core/public/index.ts", - "lineNumber": 214 + "lineNumber": 211 }, "deprecated": false }, @@ -1232,7 +1232,7 @@ ], "source": { "path": "src/core/public/index.ts", - "lineNumber": 216 + "lineNumber": 213 }, "deprecated": false }, @@ -1252,7 +1252,7 @@ ], "source": { "path": "src/core/public/index.ts", - "lineNumber": 223 + "lineNumber": 220 }, "deprecated": true, "references": [] @@ -1279,7 +1279,7 @@ ], "source": { "path": "src/core/public/index.ts", - "lineNumber": 227 + "lineNumber": 224 }, "deprecated": false, "returnComment": [], @@ -1299,7 +1299,7 @@ ], "source": { "path": "src/core/public/index.ts", - "lineNumber": 251 + "lineNumber": 248 }, "deprecated": false, "children": [ @@ -1323,7 +1323,7 @@ ], "source": { "path": "src/core/public/index.ts", - "lineNumber": 253 + "lineNumber": 250 }, "deprecated": false }, @@ -1347,7 +1347,7 @@ ], "source": { "path": "src/core/public/index.ts", - "lineNumber": 255 + "lineNumber": 252 }, "deprecated": false }, @@ -1371,7 +1371,7 @@ ], "source": { "path": "src/core/public/index.ts", - "lineNumber": 257 + "lineNumber": 254 }, "deprecated": false }, @@ -1395,7 +1395,7 @@ ], "source": { "path": "src/core/public/index.ts", - "lineNumber": 259 + "lineNumber": 256 }, "deprecated": false }, @@ -1419,7 +1419,7 @@ ], "source": { "path": "src/core/public/index.ts", - "lineNumber": 261 + "lineNumber": 258 }, "deprecated": false }, @@ -1443,7 +1443,7 @@ ], "source": { "path": "src/core/public/index.ts", - "lineNumber": 263 + "lineNumber": 260 }, "deprecated": false }, @@ -1467,7 +1467,7 @@ ], "source": { "path": "src/core/public/index.ts", - "lineNumber": 265 + "lineNumber": 262 }, "deprecated": false }, @@ -1491,7 +1491,7 @@ ], "source": { "path": "src/core/public/index.ts", - "lineNumber": 267 + "lineNumber": 264 }, "deprecated": false }, @@ -1515,7 +1515,7 @@ ], "source": { "path": "src/core/public/index.ts", - "lineNumber": 269 + "lineNumber": 266 }, "deprecated": false }, @@ -1539,7 +1539,7 @@ ], "source": { "path": "src/core/public/index.ts", - "lineNumber": 271 + "lineNumber": 268 }, "deprecated": false }, @@ -1563,7 +1563,7 @@ ], "source": { "path": "src/core/public/index.ts", - "lineNumber": 273 + "lineNumber": 270 }, "deprecated": false }, @@ -1583,7 +1583,7 @@ ], "source": { "path": "src/core/public/index.ts", - "lineNumber": 280 + "lineNumber": 277 }, "deprecated": true, "references": [ @@ -7427,7 +7427,7 @@ ], "source": { "path": "src/core/public/index.ts", - "lineNumber": 237 + "lineNumber": 234 }, "deprecated": false, "initialIsOpen": false @@ -8545,45 +8545,38 @@ } }, { - "plugin": "securitySolution", + "plugin": "monitoring", "link": { - "path": "x-pack/plugins/security_solution/server/lib/telemetry/sender.ts", - "lineNumber": 125 + "path": "x-pack/plugins/monitoring/server/kibana_monitoring/collectors/get_usage_collector.ts", + "lineNumber": 107 } }, { - "plugin": "securitySolution", + "plugin": "monitoring", "link": { - "path": "x-pack/plugins/security_solution/server/lib/telemetry/sender.ts", - "lineNumber": 218 + "path": "x-pack/plugins/monitoring/server/telemetry_collection/register_monitoring_telemetry_collection.ts", + "lineNumber": 148 } }, { "plugin": "securitySolution", "link": { "path": "x-pack/plugins/security_solution/server/lib/telemetry/sender.ts", - "lineNumber": 235 - } - }, - { - "plugin": "beatsManagement", - "link": { - "path": "x-pack/plugins/beats_management/server/lib/adapters/database/kibana_database_adapter.ts", - "lineNumber": 113 + "lineNumber": 125 } }, { - "plugin": "monitoring", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/monitoring/server/kibana_monitoring/collectors/get_usage_collector.ts", - "lineNumber": 107 + "path": "x-pack/plugins/security_solution/server/lib/telemetry/sender.ts", + "lineNumber": 218 } }, { - "plugin": "monitoring", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/monitoring/server/telemetry_collection/register_monitoring_telemetry_collection.ts", - "lineNumber": 148 + "path": "x-pack/plugins/security_solution/server/lib/telemetry/sender.ts", + "lineNumber": 235 } }, { @@ -9387,55 +9380,6 @@ "lineNumber": 67 } }, - { - "plugin": "lists", - "link": { - "path": "x-pack/plugins/lists/server/routes/read_privileges_route.ts", - "lineNumber": 31 - } - }, - { - "plugin": "lists", - "link": { - "path": "x-pack/plugins/lists/server/routes/read_privileges_route.ts", - "lineNumber": 35 - } - }, - { - "plugin": "securitySolution", - "link": { - "path": "x-pack/plugins/security_solution/server/lib/framework/kibana_framework_adapter.ts", - "lineNumber": 34 - } - }, - { - "plugin": "securitySolution", - "link": { - "path": "x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/query_signals_route.ts", - "lineNumber": 52 - } - }, - { - "plugin": "securitySolution", - "link": { - "path": "x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/open_close_signals_route.ts", - "lineNumber": 60 - } - }, - { - "plugin": "securitySolution", - "link": { - "path": "x-pack/plugins/security_solution/server/lib/detection_engine/routes/privileges/read_privileges_route.ts", - "lineNumber": 41 - } - }, - { - "plugin": "beatsManagement", - "link": { - "path": "x-pack/plugins/beats_management/server/lib/adapters/database/kibana_database_adapter.ts", - "lineNumber": 111 - } - }, { "plugin": "canvas", "link": { @@ -9821,6 +9765,20 @@ "lineNumber": 420 } }, + { + "plugin": "lists", + "link": { + "path": "x-pack/plugins/lists/server/routes/read_privileges_route.ts", + "lineNumber": 31 + } + }, + { + "plugin": "lists", + "link": { + "path": "x-pack/plugins/lists/server/routes/read_privileges_route.ts", + "lineNumber": 35 + } + }, { "plugin": "monitoring", "link": { @@ -9842,6 +9800,34 @@ "lineNumber": 356 } }, + { + "plugin": "securitySolution", + "link": { + "path": "x-pack/plugins/security_solution/server/lib/framework/kibana_framework_adapter.ts", + "lineNumber": 34 + } + }, + { + "plugin": "securitySolution", + "link": { + "path": "x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/query_signals_route.ts", + "lineNumber": 52 + } + }, + { + "plugin": "securitySolution", + "link": { + "path": "x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/open_close_signals_route.ts", + "lineNumber": 60 + } + }, + { + "plugin": "securitySolution", + "link": { + "path": "x-pack/plugins/security_solution/server/lib/detection_engine/routes/privileges/read_privileges_route.ts", + "lineNumber": 41 + } + }, { "plugin": "canvas", "link": { @@ -12712,34 +12698,6 @@ "lineNumber": 117 } }, - { - "plugin": "securitySolution", - "link": { - "path": "x-pack/plugins/security_solution/server/lib/telemetry/sender.ts", - "lineNumber": 125 - } - }, - { - "plugin": "securitySolution", - "link": { - "path": "x-pack/plugins/security_solution/server/lib/telemetry/sender.ts", - "lineNumber": 218 - } - }, - { - "plugin": "securitySolution", - "link": { - "path": "x-pack/plugins/security_solution/server/lib/telemetry/sender.ts", - "lineNumber": 235 - } - }, - { - "plugin": "beatsManagement", - "link": { - "path": "x-pack/plugins/beats_management/server/lib/adapters/database/kibana_database_adapter.ts", - "lineNumber": 31 - } - }, { "plugin": "indexManagement", "link": { @@ -12768,6 +12726,27 @@ "lineNumber": 41 } }, + { + "plugin": "securitySolution", + "link": { + "path": "x-pack/plugins/security_solution/server/lib/telemetry/sender.ts", + "lineNumber": 125 + } + }, + { + "plugin": "securitySolution", + "link": { + "path": "x-pack/plugins/security_solution/server/lib/telemetry/sender.ts", + "lineNumber": 218 + } + }, + { + "plugin": "securitySolution", + "link": { + "path": "x-pack/plugins/security_solution/server/lib/telemetry/sender.ts", + "lineNumber": 235 + } + }, { "plugin": "licensing", "link": { @@ -15940,48 +15919,6 @@ "deprecated": true, "removeBy": "7.16", "references": [ - { - "plugin": "lists", - "link": { - "path": "x-pack/plugins/lists/server/schemas/common/get_call_cluster.mock.ts", - "lineNumber": 9 - } - }, - { - "plugin": "lists", - "link": { - "path": "x-pack/plugins/lists/server/schemas/common/get_call_cluster.mock.ts", - "lineNumber": 27 - } - }, - { - "plugin": "lists", - "link": { - "path": "x-pack/plugins/lists/server/schemas/common/get_call_cluster.mock.ts", - "lineNumber": 31 - } - }, - { - "plugin": "securitySolution", - "link": { - "path": "x-pack/plugins/security_solution/server/lib/telemetry/sender.ts", - "lineNumber": 10 - } - }, - { - "plugin": "securitySolution", - "link": { - "path": "x-pack/plugins/security_solution/server/lib/telemetry/sender.ts", - "lineNumber": 447 - } - }, - { - "plugin": "securitySolution", - "link": { - "path": "x-pack/plugins/security_solution/server/lib/telemetry/sender.ts", - "lineNumber": 466 - } - }, { "plugin": "canvas", "link": { @@ -16269,6 +16206,48 @@ "lineNumber": 35 } }, + { + "plugin": "securitySolution", + "link": { + "path": "x-pack/plugins/security_solution/server/lib/telemetry/sender.ts", + "lineNumber": 10 + } + }, + { + "plugin": "securitySolution", + "link": { + "path": "x-pack/plugins/security_solution/server/lib/telemetry/sender.ts", + "lineNumber": 447 + } + }, + { + "plugin": "securitySolution", + "link": { + "path": "x-pack/plugins/security_solution/server/lib/telemetry/sender.ts", + "lineNumber": 466 + } + }, + { + "plugin": "lists", + "link": { + "path": "x-pack/plugins/lists/server/schemas/common/get_call_cluster.mock.ts", + "lineNumber": 9 + } + }, + { + "plugin": "lists", + "link": { + "path": "x-pack/plugins/lists/server/schemas/common/get_call_cluster.mock.ts", + "lineNumber": 27 + } + }, + { + "plugin": "lists", + "link": { + "path": "x-pack/plugins/lists/server/schemas/common/get_call_cluster.mock.ts", + "lineNumber": 31 + } + }, { "plugin": "monitoring", "link": { @@ -16458,6 +16437,27 @@ "lineNumber": 20 } }, + { + "plugin": "lists", + "link": { + "path": "x-pack/plugins/lists/target/types/server/schemas/common/get_call_cluster.mock.d.ts", + "lineNumber": 2 + } + }, + { + "plugin": "lists", + "link": { + "path": "x-pack/plugins/lists/target/types/server/schemas/common/get_call_cluster.mock.d.ts", + "lineNumber": 4 + } + }, + { + "plugin": "lists", + "link": { + "path": "x-pack/plugins/lists/target/types/server/schemas/common/get_call_cluster.mock.d.ts", + "lineNumber": 5 + } + }, { "plugin": "monitoring", "link": { @@ -19544,7 +19544,7 @@ "The os platform" ], "signature": [ - "\"linux\" | \"aix\" | \"android\" | \"darwin\" | \"freebsd\" | \"openbsd\" | \"sunos\" | \"win32\" | \"cygwin\" | \"netbsd\"" + "\"linux\" | \"aix\" | \"android\" | \"darwin\" | \"freebsd\" | \"openbsd\" | \"sunos\" | \"win32\" | \"cygwin\"" ], "source": { "path": "src/core/server/metrics/collectors/types.ts", @@ -23173,20 +23173,6 @@ "lineNumber": 180 } }, - { - "plugin": "beatsManagement", - "link": { - "path": "x-pack/plugins/beats_management/server/lib/adapters/database/kibana_database_adapter.ts", - "lineNumber": 8 - } - }, - { - "plugin": "beatsManagement", - "link": { - "path": "x-pack/plugins/beats_management/server/lib/adapters/database/kibana_database_adapter.ts", - "lineNumber": 28 - } - }, { "plugin": "licensing", "link": { diff --git a/api_docs/core_application.json b/api_docs/core_application.json index 3141bf16a9349..13b110900ab53 100644 --- a/api_docs/core_application.json +++ b/api_docs/core_application.json @@ -886,7 +886,7 @@ ], "source": { "path": "src/core/public/application/types.ts", - "lineNumber": 339 + "lineNumber": 326 }, "deprecated": false } @@ -930,26 +930,44 @@ }, { "parentPluginId": "core", - "id": "def-public.App.meta", - "type": "Object", + "id": "def-public.App.keywords", + "type": "Array", + "tags": [], + "label": "keywords", + "description": [ + "Optional keywords to match with in deep links search. Omit if this part of the hierarchy does not have a page URL." + ], + "signature": [ + "string[] | undefined" + ], + "source": { + "path": "src/core/public/application/types.ts", + "lineNumber": 215 + }, + "deprecated": false + }, + { + "parentPluginId": "core", + "id": "def-public.App.deepLinks", + "type": "Array", "tags": [], - "label": "meta", + "label": "deepLinks", "description": [ - "\nMeta data for an application that represent additional information for the app.\nSee {@link AppMeta}\n" + "\nInput type for registering secondary in-app locations for an application.\n\nDeep links must include at least one of `path` or `deepLinks`. A deep link that does not have a `path`\nrepresents a topological level in the application's hierarchy, but does not have a destination URL that is\nuser-accessible.\n" ], "signature": [ { "pluginId": "core", "scope": "public", "docId": "kibCoreApplicationPluginApi", - "section": "def-public.AppMeta", - "text": "AppMeta" + "section": "def-public.AppDeepLink", + "text": "AppDeepLink" }, - " | undefined" + "[] | undefined" ], "source": { "path": "src/core/public/application/types.ts", - "lineNumber": 244 + "lineNumber": 254 }, "deprecated": false } @@ -967,7 +985,7 @@ ], "source": { "path": "src/core/public/application/types.ts", - "lineNumber": 565 + "lineNumber": 552 }, "deprecated": false, "children": [ @@ -990,7 +1008,7 @@ ], "source": { "path": "src/core/public/application/types.ts", - "lineNumber": 566 + "lineNumber": 553 }, "deprecated": false }, @@ -1003,7 +1021,7 @@ "description": [], "source": { "path": "src/core/public/application/types.ts", - "lineNumber": 567 + "lineNumber": 554 }, "deprecated": false }, @@ -1019,7 +1037,7 @@ ], "source": { "path": "src/core/public/application/types.ts", - "lineNumber": 568 + "lineNumber": 555 }, "deprecated": false }, @@ -1035,7 +1053,7 @@ ], "source": { "path": "src/core/public/application/types.ts", - "lineNumber": 569 + "lineNumber": 556 }, "deprecated": false } @@ -1053,7 +1071,7 @@ ], "source": { "path": "src/core/public/application/types.ts", - "lineNumber": 553 + "lineNumber": 540 }, "deprecated": false, "children": [ @@ -1076,7 +1094,7 @@ ], "source": { "path": "src/core/public/application/types.ts", - "lineNumber": 554 + "lineNumber": 541 }, "deprecated": false } @@ -1092,7 +1110,7 @@ "description": [], "source": { "path": "src/core/public/application/types.ts", - "lineNumber": 620 + "lineNumber": 607 }, "deprecated": false, "children": [ @@ -1118,7 +1136,7 @@ ], "source": { "path": "src/core/public/application/types.ts", - "lineNumber": 626 + "lineNumber": 613 }, "deprecated": false, "children": [ @@ -1143,7 +1161,7 @@ ], "source": { "path": "src/core/public/application/types.ts", - "lineNumber": 626 + "lineNumber": 613 }, "deprecated": false, "isRequired": true @@ -1175,7 +1193,7 @@ ], "source": { "path": "src/core/public/application/types.ts", - "lineNumber": 655 + "lineNumber": 642 }, "deprecated": false, "children": [ @@ -1200,7 +1218,7 @@ ], "source": { "path": "src/core/public/application/types.ts", - "lineNumber": 655 + "lineNumber": 642 }, "deprecated": false, "isRequired": true @@ -1220,7 +1238,7 @@ "description": [], "source": { "path": "src/core/public/application/types.ts", - "lineNumber": 696 + "lineNumber": 683 }, "deprecated": false, "children": [ @@ -1238,7 +1256,7 @@ ], "source": { "path": "src/core/public/application/types.ts", - "lineNumber": 700 + "lineNumber": 687 }, "deprecated": false }, @@ -1265,7 +1283,7 @@ ], "source": { "path": "src/core/public/application/types.ts", - "lineNumber": 709 + "lineNumber": 696 }, "deprecated": false }, @@ -1291,7 +1309,7 @@ ], "source": { "path": "src/core/public/application/types.ts", - "lineNumber": 717 + "lineNumber": 704 }, "deprecated": false, "children": [ @@ -1307,7 +1325,7 @@ ], "source": { "path": "src/core/public/application/types.ts", - "lineNumber": 717 + "lineNumber": 704 }, "deprecated": false, "isRequired": true @@ -1333,7 +1351,7 @@ ], "source": { "path": "src/core/public/application/types.ts", - "lineNumber": 717 + "lineNumber": 704 }, "deprecated": false, "isRequired": false @@ -1355,7 +1373,7 @@ ], "source": { "path": "src/core/public/application/types.ts", - "lineNumber": 755 + "lineNumber": 742 }, "deprecated": false, "children": [ @@ -1373,7 +1391,7 @@ ], "source": { "path": "src/core/public/application/types.ts", - "lineNumber": 755 + "lineNumber": 742 }, "deprecated": false, "isRequired": true @@ -1395,7 +1413,7 @@ ], "source": { "path": "src/core/public/application/types.ts", - "lineNumber": 769 + "lineNumber": 756 }, "deprecated": false, "children": [ @@ -1411,7 +1429,7 @@ ], "source": { "path": "src/core/public/application/types.ts", - "lineNumber": 769 + "lineNumber": 756 }, "deprecated": false, "isRequired": true @@ -1425,7 +1443,7 @@ "description": [], "source": { "path": "src/core/public/application/types.ts", - "lineNumber": 769 + "lineNumber": 756 }, "deprecated": false, "children": [ @@ -1441,7 +1459,7 @@ ], "source": { "path": "src/core/public/application/types.ts", - "lineNumber": 769 + "lineNumber": 756 }, "deprecated": false }, @@ -1457,7 +1475,7 @@ ], "source": { "path": "src/core/public/application/types.ts", - "lineNumber": 769 + "lineNumber": 756 }, "deprecated": false } @@ -1481,68 +1499,7 @@ ], "source": { "path": "src/core/public/application/types.ts", - "lineNumber": 774 - }, - "deprecated": false - } - ], - "initialIsOpen": false - }, - { - "parentPluginId": "core", - "id": "def-public.AppMeta", - "type": "Interface", - "tags": [], - "label": "AppMeta", - "description": [ - "\nInput type for meta data for an application.\n\nMeta fields include `keywords` and `searchDeepLinks`\nKeywords is an array of string with which to associate the app, must include at least one unique string as an array.\n`searchDeepLinks` is an array of links that represent secondary in-app locations for the app." - ], - "source": { - "path": "src/core/public/application/types.ts", - "lineNumber": 255 - }, - "deprecated": false, - "children": [ - { - "parentPluginId": "core", - "id": "def-public.AppMeta.keywords", - "type": "Array", - "tags": [], - "label": "keywords", - "description": [ - "Keywords to represent this application" - ], - "signature": [ - "string[] | undefined" - ], - "source": { - "path": "src/core/public/application/types.ts", - "lineNumber": 257 - }, - "deprecated": false - }, - { - "parentPluginId": "core", - "id": "def-public.AppMeta.searchDeepLinks", - "type": "Array", - "tags": [], - "label": "searchDeepLinks", - "description": [ - "Array of links that represent secondary in-app locations for the app." - ], - "signature": [ - { - "pluginId": "core", - "scope": "public", - "docId": "kibCoreApplicationPluginApi", - "section": "def-public.AppSearchDeepLink", - "text": "AppSearchDeepLink" - }, - "[] | undefined" - ], - "source": { - "path": "src/core/public/application/types.ts", - "lineNumber": 259 + "lineNumber": 761 }, "deprecated": false } @@ -1568,7 +1525,7 @@ ], "source": { "path": "src/core/public/application/types.ts", - "lineNumber": 349 + "lineNumber": 336 }, "deprecated": false, "children": [ @@ -1586,7 +1543,7 @@ ], "source": { "path": "src/core/public/application/types.ts", - "lineNumber": 353 + "lineNumber": 340 }, "deprecated": false }, @@ -1611,7 +1568,7 @@ ], "source": { "path": "src/core/public/application/types.ts", - "lineNumber": 399 + "lineNumber": 386 }, "deprecated": false }, @@ -1628,7 +1585,7 @@ ], "source": { "path": "src/core/public/application/types.ts", - "lineNumber": 449 + "lineNumber": 436 }, "deprecated": true, "references": [ @@ -1721,7 +1678,7 @@ ], "source": { "path": "src/core/public/application/types.ts", - "lineNumber": 484 + "lineNumber": 471 }, "deprecated": true, "references": [ @@ -1746,20 +1703,6 @@ "lineNumber": 298 } }, - { - "plugin": "lens", - "link": { - "path": "x-pack/plugins/lens/public/app_plugin/types.ts", - "lineNumber": 71 - } - }, - { - "plugin": "lens", - "link": { - "path": "x-pack/plugins/lens/public/app_plugin/mounter.tsx", - "lineNumber": 171 - } - }, { "plugin": "maps", "link": { @@ -1781,6 +1724,20 @@ "lineNumber": 19 } }, + { + "plugin": "lens", + "link": { + "path": "x-pack/plugins/lens/public/app_plugin/types.ts", + "lineNumber": 71 + } + }, + { + "plugin": "lens", + "link": { + "path": "x-pack/plugins/lens/public/app_plugin/mounter.tsx", + "lineNumber": 171 + } + }, { "plugin": "ml", "link": { @@ -1882,7 +1839,7 @@ ], "source": { "path": "src/core/public/application/types.ts", - "lineNumber": 484 + "lineNumber": 471 }, "deprecated": false } @@ -1910,7 +1867,7 @@ ], "source": { "path": "src/core/public/application/types.ts", - "lineNumber": 515 + "lineNumber": 502 }, "deprecated": false, "returnComment": [], @@ -1934,7 +1891,7 @@ ], "source": { "path": "src/core/public/application/types.ts", - "lineNumber": 515 + "lineNumber": 502 }, "deprecated": false } @@ -1954,7 +1911,7 @@ ], "source": { "path": "src/core/public/application/types.ts", - "lineNumber": 674 + "lineNumber": 661 }, "deprecated": false, "children": [ @@ -1972,7 +1929,7 @@ ], "source": { "path": "src/core/public/application/types.ts", - "lineNumber": 679 + "lineNumber": 666 }, "deprecated": false }, @@ -1990,7 +1947,7 @@ ], "source": { "path": "src/core/public/application/types.ts", - "lineNumber": 683 + "lineNumber": 670 }, "deprecated": false }, @@ -2008,7 +1965,7 @@ ], "source": { "path": "src/core/public/application/types.ts", - "lineNumber": 687 + "lineNumber": 674 }, "deprecated": false }, @@ -2026,7 +1983,7 @@ ], "source": { "path": "src/core/public/application/types.ts", - "lineNumber": 692 + "lineNumber": 679 }, "deprecated": false } @@ -2046,7 +2003,7 @@ ], "source": { "path": "src/core/public/application/types.ts", - "lineNumber": 540 + "lineNumber": 527 }, "deprecated": false, "initialIsOpen": false @@ -2085,6 +2042,57 @@ } ], "misc": [ + { + "parentPluginId": "core", + "id": "def-public.AppDeepLink", + "type": "Type", + "tags": [], + "label": "AppDeepLink", + "description": [ + "\nInput type for registering secondary in-app locations for an application.\n\nDeep links must include at least one of `path` or `deepLinks`. A deep link that does not have a `path`\nrepresents a topological level in the application's hierarchy, but does not have a destination URL that is\nuser-accessible." + ], + "signature": [ + "({ id: string; title: string; keywords?: string[] | undefined; navLinkStatus?: ", + { + "pluginId": "core", + "scope": "public", + "docId": "kibCoreApplicationPluginApi", + "section": "def-public.AppNavLinkStatus", + "text": "AppNavLinkStatus" + }, + " | undefined; } & { path: string; deepLinks?: ", + { + "pluginId": "core", + "scope": "public", + "docId": "kibCoreApplicationPluginApi", + "section": "def-public.AppDeepLink", + "text": "AppDeepLink" + }, + "[] | undefined; }) | ({ id: string; title: string; keywords?: string[] | undefined; navLinkStatus?: ", + { + "pluginId": "core", + "scope": "public", + "docId": "kibCoreApplicationPluginApi", + "section": "def-public.AppNavLinkStatus", + "text": "AppNavLinkStatus" + }, + " | undefined; } & { path?: string | undefined; deepLinks: ", + { + "pluginId": "core", + "scope": "public", + "docId": "kibCoreApplicationPluginApi", + "section": "def-public.AppDeepLink", + "text": "AppDeepLink" + }, + "[]; })" + ], + "source": { + "path": "src/core/public/application/types.ts", + "lineNumber": 279 + }, + "deprecated": false, + "initialIsOpen": false + }, { "parentPluginId": "core", "id": "def-public.AppLeaveAction", @@ -2113,7 +2121,7 @@ ], "source": { "path": "src/core/public/application/types.ts", - "lineNumber": 579 + "lineNumber": 566 }, "deprecated": false, "initialIsOpen": false @@ -2143,7 +2151,7 @@ ], "source": { "path": "src/core/public/application/types.ts", - "lineNumber": 530 + "lineNumber": 517 }, "deprecated": true, "references": [ @@ -2251,42 +2259,7 @@ ], "source": { "path": "src/core/public/application/types.ts", - "lineNumber": 338 - }, - "deprecated": false, - "initialIsOpen": false - }, - { - "parentPluginId": "core", - "id": "def-public.AppSearchDeepLink", - "type": "Type", - "tags": [], - "label": "AppSearchDeepLink", - "description": [ - "\nInput type for registering secondary in-app locations for an application.\n\nDeep links must include at least one of `path` or `searchDeepLinks`. A deep link that does not have a `path`\nrepresents a topological level in the application's hierarchy, but does not have a destination URL that is\nuser-accessible." - ], - "signature": [ - "({ id: string; title: string; } & { path: string; searchDeepLinks?: ", - { - "pluginId": "core", - "scope": "public", - "docId": "kibCoreApplicationPluginApi", - "section": "def-public.AppSearchDeepLink", - "text": "AppSearchDeepLink" - }, - "[] | undefined; keywords?: string[] | undefined; }) | ({ id: string; title: string; } & { path?: string | undefined; searchDeepLinks: ", - { - "pluginId": "core", - "scope": "public", - "docId": "kibCoreApplicationPluginApi", - "section": "def-public.AppSearchDeepLink", - "text": "AppSearchDeepLink" - }, - "[]; keywords?: string[] | undefined; })" - ], - "source": { - "path": "src/core/public/application/types.ts", - "lineNumber": 293 + "lineNumber": 325 }, "deprecated": false, "initialIsOpen": false @@ -2305,7 +2278,7 @@ ], "source": { "path": "src/core/public/application/types.ts", - "lineNumber": 346 + "lineNumber": 333 }, "deprecated": false, "initialIsOpen": false @@ -2328,15 +2301,15 @@ "section": "def-public.AppStatus", "text": "AppStatus" }, - " | undefined; meta?: ", + " | undefined; deepLinks?: ", { "pluginId": "core", "scope": "public", "docId": "kibCoreApplicationPluginApi", - "section": "def-public.AppMeta", - "text": "AppMeta" + "section": "def-public.AppDeepLink", + "text": "AppDeepLink" }, - " | undefined; navLinkStatus?: ", + "[] | undefined; navLinkStatus?: ", { "pluginId": "core", "scope": "public", @@ -2379,7 +2352,7 @@ "section": "def-public.App", "text": "App" }, - ", \"status\" | \"meta\" | \"navLinkStatus\" | \"defaultPath\" | \"tooltip\">> | undefined" + ", \"status\" | \"deepLinks\" | \"navLinkStatus\" | \"defaultPath\" | \"tooltip\">> | undefined" ], "source": { "path": "src/core/public/application/types.ts", @@ -2390,12 +2363,12 @@ }, { "parentPluginId": "core", - "id": "def-public.PublicAppInfo", + "id": "def-public.PublicAppDeepLinkInfo", "type": "Type", "tags": [], - "label": "PublicAppInfo", + "label": "PublicAppDeepLinkInfo", "description": [ - "\nPublic information about a registered {@link App | application}\n" + "\nPublic information about a registered app's {@link AppDeepLink | deepLinks}\n" ], "signature": [ "Pick<", @@ -2403,18 +2376,18 @@ "pluginId": "core", "scope": "public", "docId": "kibCoreApplicationPluginApi", - "section": "def-public.App", - "text": "App" + "section": "def-public.AppDeepLink", + "text": "AppDeepLink" }, - ", \"status\" | \"title\" | \"id\" | \"order\" | \"category\" | \"navLinkStatus\" | \"defaultPath\" | \"tooltip\" | \"euiIconType\" | \"icon\" | \"capabilities\" | \"chromeless\" | \"appRoute\" | \"exactRoute\"> & { status: ", + ", \"title\" | \"id\" | \"path\"> & { deepLinks: ", { "pluginId": "core", "scope": "public", "docId": "kibCoreApplicationPluginApi", - "section": "def-public.AppStatus", - "text": "AppStatus" + "section": "def-public.PublicAppDeepLinkInfo", + "text": "PublicAppDeepLinkInfo" }, - "; navLinkStatus: ", + "[]; keywords: string[]; navLinkStatus: ", { "pluginId": "core", "scope": "public", @@ -2422,31 +2395,23 @@ "section": "def-public.AppNavLinkStatus", "text": "AppNavLinkStatus" }, - "; appRoute: string; meta: ", - { - "pluginId": "core", - "scope": "public", - "docId": "kibCoreApplicationPluginApi", - "section": "def-public.PublicAppMetaInfo", - "text": "PublicAppMetaInfo" - }, "; }" ], "source": { "path": "src/core/public/application/types.ts", - "lineNumber": 322 + "lineNumber": 262 }, "deprecated": false, "initialIsOpen": false }, { "parentPluginId": "core", - "id": "def-public.PublicAppMetaInfo", + "id": "def-public.PublicAppInfo", "type": "Type", "tags": [], - "label": "PublicAppMetaInfo", + "label": "PublicAppInfo", "description": [ - "\nPublic information about a registered app's {@link AppMeta | keywords }\n" + "\nPublic information about a registered {@link App | application}\n" ], "signature": [ "Pick<", @@ -2454,57 +2419,38 @@ "pluginId": "core", "scope": "public", "docId": "kibCoreApplicationPluginApi", - "section": "def-public.AppMeta", - "text": "AppMeta" + "section": "def-public.App", + "text": "App" }, - ", never> & { keywords: string[]; searchDeepLinks: ", + ", \"status\" | \"title\" | \"id\" | \"order\" | \"category\" | \"navLinkStatus\" | \"defaultPath\" | \"tooltip\" | \"euiIconType\" | \"icon\" | \"capabilities\" | \"chromeless\" | \"appRoute\" | \"exactRoute\"> & { status: ", { "pluginId": "core", "scope": "public", "docId": "kibCoreApplicationPluginApi", - "section": "def-public.PublicAppSearchDeepLinkInfo", - "text": "PublicAppSearchDeepLinkInfo" + "section": "def-public.AppStatus", + "text": "AppStatus" }, - "[]; }" - ], - "source": { - "path": "src/core/public/application/types.ts", - "lineNumber": 267 - }, - "deprecated": false, - "initialIsOpen": false - }, - { - "parentPluginId": "core", - "id": "def-public.PublicAppSearchDeepLinkInfo", - "type": "Type", - "tags": [], - "label": "PublicAppSearchDeepLinkInfo", - "description": [ - "\nPublic information about a registered app's {@link AppSearchDeepLink | searchDeepLinks}\n" - ], - "signature": [ - "Pick<", + "; navLinkStatus: ", { "pluginId": "core", "scope": "public", "docId": "kibCoreApplicationPluginApi", - "section": "def-public.AppSearchDeepLink", - "text": "AppSearchDeepLink" + "section": "def-public.AppNavLinkStatus", + "text": "AppNavLinkStatus" }, - ", \"title\" | \"id\" | \"path\"> & { searchDeepLinks: ", + "; appRoute: string; keywords: string[]; deepLinks: ", { "pluginId": "core", "scope": "public", "docId": "kibCoreApplicationPluginApi", - "section": "def-public.PublicAppSearchDeepLinkInfo", - "text": "PublicAppSearchDeepLinkInfo" + "section": "def-public.PublicAppDeepLinkInfo", + "text": "PublicAppDeepLinkInfo" }, - "[]; keywords: string[]; }" + "[]; }" ], "source": { "path": "src/core/public/application/types.ts", - "lineNumber": 277 + "lineNumber": 308 }, "deprecated": false, "initialIsOpen": false diff --git a/api_docs/core_chrome.json b/api_docs/core_chrome.json index d6ec4b0d3f640..fae65ff62c971 100644 --- a/api_docs/core_chrome.json +++ b/api_docs/core_chrome.json @@ -890,7 +890,7 @@ "description": [], "source": { "path": "src/core/public/chrome/nav_links/nav_link.ts", - "lineNumber": 15 + "lineNumber": 14 }, "deprecated": false, "children": [ @@ -905,7 +905,7 @@ ], "source": { "path": "src/core/public/chrome/nav_links/nav_link.ts", - "lineNumber": 19 + "lineNumber": 18 }, "deprecated": false }, @@ -920,7 +920,7 @@ ], "source": { "path": "src/core/public/chrome/nav_links/nav_link.ts", - "lineNumber": 24 + "lineNumber": 23 }, "deprecated": false }, @@ -939,7 +939,7 @@ ], "source": { "path": "src/core/public/chrome/nav_links/nav_link.ts", - "lineNumber": 29 + "lineNumber": 28 }, "deprecated": false }, @@ -954,7 +954,7 @@ ], "source": { "path": "src/core/public/chrome/nav_links/nav_link.ts", - "lineNumber": 34 + "lineNumber": 33 }, "deprecated": false }, @@ -972,7 +972,7 @@ ], "source": { "path": "src/core/public/chrome/nav_links/nav_link.ts", - "lineNumber": 40 + "lineNumber": 39 }, "deprecated": false }, @@ -990,7 +990,7 @@ ], "source": { "path": "src/core/public/chrome/nav_links/nav_link.ts", - "lineNumber": 45 + "lineNumber": 44 }, "deprecated": false }, @@ -1008,7 +1008,7 @@ ], "source": { "path": "src/core/public/chrome/nav_links/nav_link.ts", - "lineNumber": 50 + "lineNumber": 49 }, "deprecated": false }, @@ -1026,7 +1026,7 @@ ], "source": { "path": "src/core/public/chrome/nav_links/nav_link.ts", - "lineNumber": 56 + "lineNumber": 55 }, "deprecated": false }, @@ -1044,7 +1044,7 @@ ], "source": { "path": "src/core/public/chrome/nav_links/nav_link.ts", - "lineNumber": 62 + "lineNumber": 61 }, "deprecated": false }, @@ -1059,7 +1059,7 @@ ], "source": { "path": "src/core/public/chrome/nav_links/nav_link.ts", - "lineNumber": 67 + "lineNumber": 66 }, "deprecated": false }, @@ -1077,7 +1077,7 @@ ], "source": { "path": "src/core/public/chrome/nav_links/nav_link.ts", - "lineNumber": 76 + "lineNumber": 75 }, "deprecated": false }, @@ -1095,7 +1095,7 @@ ], "source": { "path": "src/core/public/chrome/nav_links/nav_link.ts", - "lineNumber": 81 + "lineNumber": 80 }, "deprecated": false } @@ -1297,103 +1297,6 @@ ], "returnComment": [] }, - { - "parentPluginId": "core", - "id": "def-public.ChromeNavLinks.update", - "type": "Function", - "tags": [ - "deprecated" - ], - "label": "update", - "description": [ - "\nUpdate the navlink for the given id with the updated attributes.\nReturns the updated navlink or `undefined` if it does not exist.\n" - ], - "signature": [ - "(id: string, values: Partial>) => ", - { - "pluginId": "core", - "scope": "public", - "docId": "kibCoreChromePluginApi", - "section": "def-public.ChromeNavLink", - "text": "ChromeNavLink" - }, - " | undefined" - ], - "source": { - "path": "src/core/public/chrome/nav_links/nav_links_service.ts", - "lineNumber": 71 - }, - "deprecated": true, - "references": [ - { - "plugin": "apm", - "link": { - "path": "x-pack/plugins/apm/public/toggleAppLinkInNav.ts", - "lineNumber": 13 - } - }, - { - "plugin": "graph", - "link": { - "path": "x-pack/plugins/graph/public/services/toggle_nav_link.ts", - "lineNumber": 26 - } - } - ], - "children": [ - { - "parentPluginId": "core", - "id": "def-public.ChromeNavLinks.update.$1", - "type": "string", - "tags": [], - "label": "id", - "description": [], - "signature": [ - "string" - ], - "source": { - "path": "src/core/public/chrome/nav_links/nav_links_service.ts", - "lineNumber": 71 - }, - "deprecated": false, - "isRequired": true - }, - { - "parentPluginId": "core", - "id": "def-public.ChromeNavLinks.update.$2", - "type": "Object", - "tags": [], - "label": "values", - "description": [], - "signature": [ - "Partial>" - ], - "source": { - "path": "src/core/public/chrome/nav_links/nav_links_service.ts", - "lineNumber": 71 - }, - "deprecated": false, - "isRequired": true - } - ], - "returnComment": [] - }, { "parentPluginId": "core", "id": "def-public.ChromeNavLinks.enableForcedAppSwitcherNavigation", @@ -1408,7 +1311,7 @@ ], "source": { "path": "src/core/public/chrome/nav_links/nav_links_service.ts", - "lineNumber": 85 + "lineNumber": 73 }, "deprecated": false, "children": [], @@ -1430,7 +1333,7 @@ ], "source": { "path": "src/core/public/chrome/nav_links/nav_links_service.ts", - "lineNumber": 90 + "lineNumber": 78 }, "deprecated": false, "children": [], @@ -2678,23 +2581,6 @@ "deprecated": false, "initialIsOpen": false }, - { - "parentPluginId": "core", - "id": "def-public.ChromeNavLinkUpdateableFields", - "type": "Type", - "tags": [], - "label": "ChromeNavLinkUpdateableFields", - "description": [], - "signature": [ - "{ readonly hidden?: boolean | undefined; readonly url?: string | undefined; readonly disabled?: boolean | undefined; readonly href?: string | undefined; }" - ], - "source": { - "path": "src/core/public/chrome/nav_links/nav_link.ts", - "lineNumber": 85 - }, - "deprecated": false, - "initialIsOpen": false - }, { "parentPluginId": "core", "id": "def-public.NavType", diff --git a/api_docs/data.json b/api_docs/data.json index 77d26811db5bf..ab5196934d855 100644 --- a/api_docs/data.json +++ b/api_docs/data.json @@ -11486,111 +11486,6 @@ "lineNumber": 58 } }, - { - "plugin": "fleet", - "link": { - "path": "x-pack/plugins/fleet/public/applications/fleet/components/search_bar.tsx", - "lineNumber": 10 - } - }, - { - "plugin": "fleet", - "link": { - "path": "x-pack/plugins/fleet/public/applications/fleet/components/search_bar.tsx", - "lineNumber": 33 - } - }, - { - "plugin": "fleet", - "link": { - "path": "x-pack/plugins/fleet/public/applications/fleet/components/search_bar.tsx", - "lineNumber": 51 - } - }, - { - "plugin": "indexPatternManagement", - "link": { - "path": "src/plugins/index_pattern_management/public/service/list/config.ts", - "lineNumber": 10 - } - }, - { - "plugin": "indexPatternManagement", - "link": { - "path": "src/plugins/index_pattern_management/public/service/list/config.ts", - "lineNumber": 42 - } - }, - { - "plugin": "indexPatternManagement", - "link": { - "path": "src/plugins/index_pattern_management/public/service/list/manager.ts", - "lineNumber": 9 - } - }, - { - "plugin": "indexPatternManagement", - "link": { - "path": "src/plugins/index_pattern_management/public/service/list/manager.ts", - "lineNumber": 43 - } - }, - { - "plugin": "indexPatternManagement", - "link": { - "path": "src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/lib/extract_time_fields.ts", - "lineNumber": 10 - } - }, - { - "plugin": "indexPatternManagement", - "link": { - "path": "src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/lib/extract_time_fields.ts", - "lineNumber": 12 - } - }, - { - "plugin": "indexPatternManagement", - "link": { - "path": "src/plugins/index_pattern_management/public/components/edit_index_pattern/indexed_fields_table/types.ts", - "lineNumber": 9 - } - }, - { - "plugin": "indexPatternManagement", - "link": { - "path": "src/plugins/index_pattern_management/public/components/edit_index_pattern/indexed_fields_table/types.ts", - "lineNumber": 11 - } - }, - { - "plugin": "indexPatternManagement", - "link": { - "path": "src/plugins/index_pattern_management/public/components/edit_index_pattern/indexed_fields_table/indexed_fields_table.tsx", - "lineNumber": 11 - } - }, - { - "plugin": "indexPatternManagement", - "link": { - "path": "src/plugins/index_pattern_management/public/components/edit_index_pattern/indexed_fields_table/indexed_fields_table.tsx", - "lineNumber": 23 - } - }, - { - "plugin": "indexPatternManagement", - "link": { - "path": "src/plugins/index_pattern_management/public/components/field_editor/field_editor.tsx", - "lineNumber": 45 - } - }, - { - "plugin": "indexPatternManagement", - "link": { - "path": "src/plugins/index_pattern_management/public/components/field_editor/field_editor.tsx", - "lineNumber": 148 - } - }, { "plugin": "maps", "link": { @@ -11955,6 +11850,90 @@ "lineNumber": 66 } }, + { + "plugin": "indexPatternManagement", + "link": { + "path": "src/plugins/index_pattern_management/public/service/list/config.ts", + "lineNumber": 10 + } + }, + { + "plugin": "indexPatternManagement", + "link": { + "path": "src/plugins/index_pattern_management/public/service/list/config.ts", + "lineNumber": 42 + } + }, + { + "plugin": "indexPatternManagement", + "link": { + "path": "src/plugins/index_pattern_management/public/service/list/manager.ts", + "lineNumber": 9 + } + }, + { + "plugin": "indexPatternManagement", + "link": { + "path": "src/plugins/index_pattern_management/public/service/list/manager.ts", + "lineNumber": 43 + } + }, + { + "plugin": "indexPatternManagement", + "link": { + "path": "src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/lib/extract_time_fields.ts", + "lineNumber": 10 + } + }, + { + "plugin": "indexPatternManagement", + "link": { + "path": "src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/lib/extract_time_fields.ts", + "lineNumber": 12 + } + }, + { + "plugin": "indexPatternManagement", + "link": { + "path": "src/plugins/index_pattern_management/public/components/edit_index_pattern/indexed_fields_table/types.ts", + "lineNumber": 9 + } + }, + { + "plugin": "indexPatternManagement", + "link": { + "path": "src/plugins/index_pattern_management/public/components/edit_index_pattern/indexed_fields_table/types.ts", + "lineNumber": 11 + } + }, + { + "plugin": "indexPatternManagement", + "link": { + "path": "src/plugins/index_pattern_management/public/components/edit_index_pattern/indexed_fields_table/indexed_fields_table.tsx", + "lineNumber": 11 + } + }, + { + "plugin": "indexPatternManagement", + "link": { + "path": "src/plugins/index_pattern_management/public/components/edit_index_pattern/indexed_fields_table/indexed_fields_table.tsx", + "lineNumber": 23 + } + }, + { + "plugin": "indexPatternManagement", + "link": { + "path": "src/plugins/index_pattern_management/public/components/field_editor/field_editor.tsx", + "lineNumber": 45 + } + }, + { + "plugin": "indexPatternManagement", + "link": { + "path": "src/plugins/index_pattern_management/public/components/field_editor/field_editor.tsx", + "lineNumber": 148 + } + }, { "plugin": "ml", "link": { @@ -12207,6 +12186,27 @@ "lineNumber": 21 } }, + { + "plugin": "fleet", + "link": { + "path": "x-pack/plugins/fleet/public/applications/fleet/components/search_bar.tsx", + "lineNumber": 10 + } + }, + { + "plugin": "fleet", + "link": { + "path": "x-pack/plugins/fleet/public/applications/fleet/components/search_bar.tsx", + "lineNumber": 33 + } + }, + { + "plugin": "fleet", + "link": { + "path": "x-pack/plugins/fleet/public/applications/fleet/components/search_bar.tsx", + "lineNumber": 51 + } + }, { "plugin": "fleet", "link": { @@ -12747,409 +12747,346 @@ } }, { - "plugin": "lists", + "plugin": "maps", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.ts", - "lineNumber": 19 + "path": "x-pack/plugins/maps/common/elasticsearch_util/es_agg_utils.ts", + "lineNumber": 10 } }, { - "plugin": "lists", + "plugin": "maps", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.ts", - "lineNumber": 30 + "path": "x-pack/plugins/maps/common/elasticsearch_util/es_agg_utils.ts", + "lineNumber": 16 } }, { - "plugin": "lists", + "plugin": "maps", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.ts", - "lineNumber": 54 + "path": "x-pack/plugins/maps/common/elasticsearch_util/es_agg_utils.ts", + "lineNumber": 29 } }, { - "plugin": "lists", + "plugin": "maps", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.ts", - "lineNumber": 84 + "path": "x-pack/plugins/maps/public/components/geo_field_select.tsx", + "lineNumber": 12 } }, { - "plugin": "lists", + "plugin": "maps", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.ts", - "lineNumber": 150 + "path": "x-pack/plugins/maps/public/components/geo_field_select.tsx", + "lineNumber": 16 } }, { - "plugin": "lists", + "plugin": "maps", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", - "lineNumber": 11 + "path": "x-pack/plugins/maps/public/classes/sources/es_search_source/top_hits/create_source_editor.tsx", + "lineNumber": 18 } }, { - "plugin": "lists", + "plugin": "maps", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", - "lineNumber": 26 + "path": "x-pack/plugins/maps/public/classes/sources/es_search_source/top_hits/create_source_editor.tsx", + "lineNumber": 30 } }, { - "plugin": "lists", + "plugin": "maps", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", - "lineNumber": 28 + "path": "x-pack/plugins/maps/public/classes/sources/es_search_source/top_hits/create_source_editor.tsx", + "lineNumber": 33 } }, { - "plugin": "lists", + "plugin": "maps", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", - "lineNumber": 57 + "path": "x-pack/plugins/maps/public/classes/sources/es_search_source/top_hits/create_source_editor.tsx", + "lineNumber": 35 } }, { - "plugin": "lists", + "plugin": "lens", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", - "lineNumber": 95 + "path": "x-pack/plugins/lens/public/indexpattern_datasource/types.ts", + "lineNumber": 8 } }, { - "plugin": "lists", + "plugin": "lens", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", - "lineNumber": 96 + "path": "x-pack/plugins/lens/public/indexpattern_datasource/types.ts", + "lineNumber": 57 } }, { - "plugin": "lists", + "plugin": "lens", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", - "lineNumber": 101 + "path": "x-pack/plugins/lens/server/routes/field_stats.ts", + "lineNumber": 11 } }, { - "plugin": "lists", + "plugin": "lens", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", - "lineNumber": 114 + "path": "x-pack/plugins/lens/server/routes/field_stats.ts", + "lineNumber": 139 } }, { - "plugin": "lists", + "plugin": "lens", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", - "lineNumber": 121 + "path": "x-pack/plugins/lens/server/routes/field_stats.ts", + "lineNumber": 248 } }, { - "plugin": "lists", + "plugin": "lens", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", - "lineNumber": 125 + "path": "x-pack/plugins/lens/server/routes/field_stats.ts", + "lineNumber": 287 } }, { - "plugin": "lists", + "plugin": "lens", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", - "lineNumber": 125 + "path": "x-pack/plugins/lens/server/routes/field_stats.ts", + "lineNumber": 329 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", - "lineNumber": 130 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.ts", + "lineNumber": 19 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", - "lineNumber": 131 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.ts", + "lineNumber": 30 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", - "lineNumber": 133 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.ts", + "lineNumber": 54 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", - "lineNumber": 134 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.ts", + "lineNumber": 84 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/operator.tsx", - "lineNumber": 11 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.ts", + "lineNumber": 150 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/operator.tsx", - "lineNumber": 27 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", + "lineNumber": 11 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/hooks/use_field_value_autocomplete.ts", - "lineNumber": 13 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", + "lineNumber": 26 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/hooks/use_field_value_autocomplete.ts", - "lineNumber": 16 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", + "lineNumber": 28 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/hooks/use_field_value_autocomplete.ts", - "lineNumber": 32 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", + "lineNumber": 57 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field_value_match.tsx", - "lineNumber": 19 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", + "lineNumber": 95 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field_value_match.tsx", - "lineNumber": 36 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", + "lineNumber": 96 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field_value_match_any.tsx", - "lineNumber": 13 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", + "lineNumber": 101 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field_value_match_any.tsx", - "lineNumber": 23 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", + "lineNumber": 114 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field_value_lists.tsx", - "lineNumber": 13 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", + "lineNumber": 121 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field_value_lists.tsx", - "lineNumber": 29 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", + "lineNumber": 125 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.tsx", - "lineNumber": 31 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", + "lineNumber": 125 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.tsx", - "lineNumber": 91 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", + "lineNumber": 130 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.test.ts", - "lineNumber": 19 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", + "lineNumber": 131 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.test.ts", - "lineNumber": 333 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", + "lineNumber": 133 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.test.ts", - "lineNumber": 339 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", + "lineNumber": 134 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.test.ts", - "lineNumber": 347 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/operator.tsx", + "lineNumber": 11 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.test.ts", - "lineNumber": 355 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/operator.tsx", + "lineNumber": 27 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.test.ts", - "lineNumber": 363 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/hooks/use_field_value_autocomplete.ts", + "lineNumber": 13 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.test.ts", - "lineNumber": 371 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/hooks/use_field_value_autocomplete.ts", + "lineNumber": 16 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.test.ts", - "lineNumber": 380 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/hooks/use_field_value_autocomplete.ts", + "lineNumber": 32 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", - "lineNumber": 62 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field_value_match.tsx", + "lineNumber": 19 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", - "lineNumber": 166 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field_value_match.tsx", + "lineNumber": 36 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", - "lineNumber": 167 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field_value_match_any.tsx", + "lineNumber": 13 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", - "lineNumber": 629 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field_value_match_any.tsx", + "lineNumber": 23 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", - "lineNumber": 666 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field_value_lists.tsx", + "lineNumber": 14 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", - "lineNumber": 691 - } - }, - { - "plugin": "lens", - "link": { - "path": "x-pack/plugins/lens/public/indexpattern_datasource/types.ts", - "lineNumber": 8 - } - }, - { - "plugin": "lens", - "link": { - "path": "x-pack/plugins/lens/public/indexpattern_datasource/types.ts", - "lineNumber": 57 - } - }, - { - "plugin": "maps", - "link": { - "path": "x-pack/plugins/maps/common/elasticsearch_util/es_agg_utils.ts", - "lineNumber": 10 - } - }, - { - "plugin": "maps", - "link": { - "path": "x-pack/plugins/maps/common/elasticsearch_util/es_agg_utils.ts", - "lineNumber": 16 - } - }, - { - "plugin": "maps", - "link": { - "path": "x-pack/plugins/maps/common/elasticsearch_util/es_agg_utils.ts", + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field_value_lists.tsx", "lineNumber": 29 } }, { - "plugin": "maps", - "link": { - "path": "x-pack/plugins/maps/public/components/geo_field_select.tsx", - "lineNumber": 12 - } - }, - { - "plugin": "maps", - "link": { - "path": "x-pack/plugins/maps/public/components/geo_field_select.tsx", - "lineNumber": 16 - } - }, - { - "plugin": "maps", - "link": { - "path": "x-pack/plugins/maps/public/classes/sources/es_search_source/top_hits/create_source_editor.tsx", - "lineNumber": 18 - } - }, - { - "plugin": "maps", - "link": { - "path": "x-pack/plugins/maps/public/classes/sources/es_search_source/top_hits/create_source_editor.tsx", - "lineNumber": 30 - } - }, - { - "plugin": "maps", + "plugin": "lists", "link": { - "path": "x-pack/plugins/maps/public/classes/sources/es_search_source/top_hits/create_source_editor.tsx", - "lineNumber": 33 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.tsx", + "lineNumber": 31 } }, { - "plugin": "maps", + "plugin": "lists", "link": { - "path": "x-pack/plugins/maps/public/classes/sources/es_search_source/top_hits/create_source_editor.tsx", - "lineNumber": 35 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.tsx", + "lineNumber": 91 } }, { @@ -13391,192 +13328,213 @@ } }, { - "plugin": "securitySolution", + "plugin": "lens", "link": { - "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/field_value_lists.tsx", - "lineNumber": 12 + "path": "x-pack/plugins/lens/target/types/public/indexpattern_datasource/types.d.ts", + "lineNumber": 1 } }, { - "plugin": "securitySolution", + "plugin": "lens", "link": { - "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/field_value_lists.tsx", - "lineNumber": 20 - } + "path": "x-pack/plugins/lens/target/types/public/indexpattern_datasource/types.d.ts", + "lineNumber": 22 + } }, { - "plugin": "securitySolution", + "plugin": "lens", "link": { - "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/field_value_match_any.tsx", - "lineNumber": 13 + "path": "x-pack/plugins/lens/target/types/server/routes/field_stats.d.ts", + "lineNumber": 3 } }, { - "plugin": "securitySolution", + "plugin": "lens", "link": { - "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/field_value_match_any.tsx", - "lineNumber": 22 + "path": "x-pack/plugins/lens/target/types/server/routes/field_stats.d.ts", + "lineNumber": 7 } }, { - "plugin": "securitySolution", + "plugin": "lens", "link": { - "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/helpers.test.ts", - "lineNumber": 11 + "path": "x-pack/plugins/lens/target/types/server/routes/field_stats.d.ts", + "lineNumber": 8 } }, { - "plugin": "securitySolution", + "plugin": "lens", "link": { - "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/helpers.test.ts", + "path": "x-pack/plugins/lens/target/types/server/routes/field_stats.d.ts", + "lineNumber": 9 + } + }, + { + "plugin": "lists", + "link": { + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.test.ts", + "lineNumber": 19 + } + }, + { + "plugin": "lists", + "link": { + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.test.ts", "lineNumber": 333 } }, { - "plugin": "securitySolution", + "plugin": "lists", "link": { - "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/helpers.test.ts", + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.test.ts", "lineNumber": 339 } }, { - "plugin": "securitySolution", + "plugin": "lists", "link": { - "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/helpers.test.ts", + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.test.ts", "lineNumber": 347 } }, { - "plugin": "securitySolution", + "plugin": "lists", "link": { - "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/helpers.test.ts", + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.test.ts", "lineNumber": 355 } }, { - "plugin": "securitySolution", + "plugin": "lists", "link": { - "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/helpers.test.ts", + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.test.ts", "lineNumber": 363 } }, { - "plugin": "securitySolution", + "plugin": "lists", "link": { - "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/helpers.test.ts", + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.test.ts", "lineNumber": 371 } }, { - "plugin": "securitySolution", + "plugin": "lists", "link": { - "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/helpers.test.ts", + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.test.ts", "lineNumber": 380 } }, { - "plugin": "securitySolution", + "plugin": "lists", "link": { - "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/operator.tsx", - "lineNumber": 11 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", + "lineNumber": 62 } }, { - "plugin": "securitySolution", + "plugin": "lists", "link": { - "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/operator.tsx", - "lineNumber": 17 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", + "lineNumber": 166 } }, { - "plugin": "securitySolution", + "plugin": "lists", "link": { - "path": "x-pack/plugins/security_solution/public/common/components/exceptions/helpers.test.tsx", - "lineNumber": 43 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", + "lineNumber": 167 } }, { - "plugin": "securitySolution", + "plugin": "lists", "link": { - "path": "x-pack/plugins/security_solution/public/common/components/exceptions/helpers.test.tsx", - "lineNumber": 104 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", + "lineNumber": 629 } }, { - "plugin": "lens", + "plugin": "lists", "link": { - "path": "x-pack/plugins/lens/server/routes/field_stats.ts", - "lineNumber": 11 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", + "lineNumber": 666 } }, { - "plugin": "lens", + "plugin": "lists", "link": { - "path": "x-pack/plugins/lens/server/routes/field_stats.ts", - "lineNumber": 139 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", + "lineNumber": 691 } }, { - "plugin": "lens", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/lens/server/routes/field_stats.ts", - "lineNumber": 248 + "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/helpers.test.ts", + "lineNumber": 11 } }, { - "plugin": "lens", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/lens/server/routes/field_stats.ts", - "lineNumber": 287 + "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/helpers.test.ts", + "lineNumber": 333 } }, { - "plugin": "lens", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/lens/server/routes/field_stats.ts", - "lineNumber": 329 + "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/helpers.test.ts", + "lineNumber": 339 } }, { - "plugin": "lens", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/lens/target/types/public/indexpattern_datasource/types.d.ts", - "lineNumber": 1 + "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/helpers.test.ts", + "lineNumber": 347 } }, { - "plugin": "lens", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/lens/target/types/public/indexpattern_datasource/types.d.ts", - "lineNumber": 22 + "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/helpers.test.ts", + "lineNumber": 355 } }, { - "plugin": "lens", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/lens/target/types/server/routes/field_stats.d.ts", - "lineNumber": 3 + "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/helpers.test.ts", + "lineNumber": 363 } }, { - "plugin": "lens", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/lens/target/types/server/routes/field_stats.d.ts", - "lineNumber": 7 + "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/helpers.test.ts", + "lineNumber": 371 } }, { - "plugin": "lens", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/lens/target/types/server/routes/field_stats.d.ts", - "lineNumber": 8 + "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/helpers.test.ts", + "lineNumber": 380 } }, { - "plugin": "lens", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/lens/target/types/server/routes/field_stats.d.ts", - "lineNumber": 9 + "path": "x-pack/plugins/security_solution/target/types/public/common/components/exceptions/helpers.test.d.ts", + "lineNumber": 1 + } + }, + { + "plugin": "securitySolution", + "link": { + "path": "x-pack/plugins/security_solution/target/types/public/common/components/exceptions/helpers.test.d.ts", + "lineNumber": 2 } }, { @@ -14103,48 +14061,6 @@ }, "deprecated": true, "references": [ - { - "plugin": "lists", - "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/exception_items_renderer.tsx", - "lineNumber": 34 - } - }, - { - "plugin": "lists", - "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/exception_items_renderer.tsx", - "lineNumber": 78 - } - }, - { - "plugin": "lists", - "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/exception_items_renderer.tsx", - "lineNumber": 86 - } - }, - { - "plugin": "lists", - "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/exception_items_renderer.tsx", - "lineNumber": 88 - } - }, - { - "plugin": "securitySolution", - "link": { - "path": "x-pack/plugins/security_solution/common/search_strategy/index_fields/index.ts", - "lineNumber": 8 - } - }, - { - "plugin": "securitySolution", - "link": { - "path": "x-pack/plugins/security_solution/common/search_strategy/index_fields/index.ts", - "lineNumber": 86 - } - }, { "plugin": "savedObjects", "link": { @@ -14237,206 +14153,178 @@ } }, { - "plugin": "savedObjectsManagement", + "plugin": "indexPatternManagement", "link": { - "path": "src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.tsx", - "lineNumber": 37 + "path": "src/plugins/index_pattern_management/public/service/list/config.ts", + "lineNumber": 10 } }, { - "plugin": "savedObjectsManagement", + "plugin": "indexPatternManagement", "link": { - "path": "src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.tsx", - "lineNumber": 89 + "path": "src/plugins/index_pattern_management/public/service/list/config.ts", + "lineNumber": 29 } }, { - "plugin": "infra", + "plugin": "indexPatternManagement", "link": { - "path": "x-pack/plugins/infra/public/containers/with_kuery_autocompletion.tsx", - "lineNumber": 9 + "path": "src/plugins/index_pattern_management/public/service/list/config.ts", + "lineNumber": 29 } }, { - "plugin": "infra", + "plugin": "indexPatternManagement", "link": { - "path": "x-pack/plugins/infra/public/containers/with_kuery_autocompletion.tsx", - "lineNumber": 24 + "path": "src/plugins/index_pattern_management/public/service/list/config.ts", + "lineNumber": 42 } }, { - "plugin": "infra", + "plugin": "indexPatternManagement", "link": { - "path": "x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/kuery_bar.tsx", - "lineNumber": 15 + "path": "src/plugins/index_pattern_management/public/service/list/config.ts", + "lineNumber": 46 } }, { - "plugin": "infra", + "plugin": "indexPatternManagement", "link": { - "path": "x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/kuery_bar.tsx", - "lineNumber": 28 + "path": "src/plugins/index_pattern_management/public/service/list/manager.ts", + "lineNumber": 9 } }, { - "plugin": "lens", + "plugin": "indexPatternManagement", "link": { - "path": "x-pack/plugins/lens/public/editor_frame_service/embeddable/embeddable.tsx", - "lineNumber": 14 + "path": "src/plugins/index_pattern_management/public/service/list/manager.ts", + "lineNumber": 32 } }, { - "plugin": "lens", + "plugin": "indexPatternManagement", "link": { - "path": "x-pack/plugins/lens/public/editor_frame_service/embeddable/embeddable.tsx", - "lineNumber": 85 + "path": "src/plugins/index_pattern_management/public/service/list/manager.ts", + "lineNumber": 32 } }, { - "plugin": "lens", + "plugin": "indexPatternManagement", "link": { - "path": "x-pack/plugins/lens/public/indexpattern_datasource/field_item.tsx", - "lineNumber": 47 + "path": "src/plugins/index_pattern_management/public/service/list/manager.ts", + "lineNumber": 43 } }, { - "plugin": "lens", + "plugin": "indexPatternManagement", "link": { - "path": "x-pack/plugins/lens/public/indexpattern_datasource/field_item.tsx", - "lineNumber": 172 + "path": "src/plugins/index_pattern_management/public/service/list/manager.ts", + "lineNumber": 50 } }, { - "plugin": "lens", + "plugin": "indexPatternManagement", "link": { - "path": "x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx", - "lineNumber": 42 - } - }, - { - "plugin": "lens", - "link": { - "path": "x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx", - "lineNumber": 96 - } - }, - { - "plugin": "lens", - "link": { - "path": "x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx", - "lineNumber": 166 - } - }, - { - "plugin": "indexPatternManagement", - "link": { - "path": "src/plugins/index_pattern_management/public/service/list/config.ts", - "lineNumber": 10 - } - }, - { - "plugin": "indexPatternManagement", - "link": { - "path": "src/plugins/index_pattern_management/public/service/list/config.ts", - "lineNumber": 29 + "path": "src/plugins/index_pattern_management/public/components/edit_index_pattern/indexed_fields_table/components/table/table.tsx", + "lineNumber": 22 } }, { "plugin": "indexPatternManagement", "link": { - "path": "src/plugins/index_pattern_management/public/service/list/config.ts", - "lineNumber": 29 + "path": "src/plugins/index_pattern_management/public/components/edit_index_pattern/indexed_fields_table/components/table/table.tsx", + "lineNumber": 171 } }, { "plugin": "indexPatternManagement", "link": { - "path": "src/plugins/index_pattern_management/public/service/list/config.ts", - "lineNumber": 42 + "path": "src/plugins/index_pattern_management/public/components/edit_index_pattern/scripted_fields_table/components/table/table.tsx", + "lineNumber": 15 } }, { "plugin": "indexPatternManagement", "link": { - "path": "src/plugins/index_pattern_management/public/service/list/config.ts", - "lineNumber": 46 + "path": "src/plugins/index_pattern_management/public/components/edit_index_pattern/scripted_fields_table/components/table/table.tsx", + "lineNumber": 18 } }, { "plugin": "indexPatternManagement", "link": { - "path": "src/plugins/index_pattern_management/public/service/list/manager.ts", - "lineNumber": 9 + "path": "src/plugins/index_pattern_management/public/components/edit_index_pattern/index_header/index_header.tsx", + "lineNumber": 12 } }, { "plugin": "indexPatternManagement", "link": { - "path": "src/plugins/index_pattern_management/public/service/list/manager.ts", - "lineNumber": 32 + "path": "src/plugins/index_pattern_management/public/components/edit_index_pattern/index_header/index_header.tsx", + "lineNumber": 15 } }, { - "plugin": "indexPatternManagement", + "plugin": "savedObjectsManagement", "link": { - "path": "src/plugins/index_pattern_management/public/service/list/manager.ts", - "lineNumber": 32 + "path": "src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.tsx", + "lineNumber": 37 } }, { - "plugin": "indexPatternManagement", + "plugin": "savedObjectsManagement", "link": { - "path": "src/plugins/index_pattern_management/public/service/list/manager.ts", - "lineNumber": 43 + "path": "src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.tsx", + "lineNumber": 89 } }, { - "plugin": "indexPatternManagement", + "plugin": "lens", "link": { - "path": "src/plugins/index_pattern_management/public/service/list/manager.ts", - "lineNumber": 50 + "path": "x-pack/plugins/lens/public/editor_frame_service/embeddable/embeddable.tsx", + "lineNumber": 14 } }, { - "plugin": "indexPatternManagement", + "plugin": "lens", "link": { - "path": "src/plugins/index_pattern_management/public/components/edit_index_pattern/indexed_fields_table/components/table/table.tsx", - "lineNumber": 22 + "path": "x-pack/plugins/lens/public/editor_frame_service/embeddable/embeddable.tsx", + "lineNumber": 85 } }, { - "plugin": "indexPatternManagement", + "plugin": "lens", "link": { - "path": "src/plugins/index_pattern_management/public/components/edit_index_pattern/indexed_fields_table/components/table/table.tsx", - "lineNumber": 171 + "path": "x-pack/plugins/lens/public/indexpattern_datasource/field_item.tsx", + "lineNumber": 47 } }, { - "plugin": "indexPatternManagement", + "plugin": "lens", "link": { - "path": "src/plugins/index_pattern_management/public/components/edit_index_pattern/scripted_fields_table/components/table/table.tsx", - "lineNumber": 15 + "path": "x-pack/plugins/lens/public/indexpattern_datasource/field_item.tsx", + "lineNumber": 172 } }, { - "plugin": "indexPatternManagement", + "plugin": "lens", "link": { - "path": "src/plugins/index_pattern_management/public/components/edit_index_pattern/scripted_fields_table/components/table/table.tsx", - "lineNumber": 18 + "path": "x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx", + "lineNumber": 42 } }, { - "plugin": "indexPatternManagement", + "plugin": "lens", "link": { - "path": "src/plugins/index_pattern_management/public/components/edit_index_pattern/index_header/index_header.tsx", - "lineNumber": 12 + "path": "x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx", + "lineNumber": 96 } }, { - "plugin": "indexPatternManagement", + "plugin": "lens", "link": { - "path": "src/plugins/index_pattern_management/public/components/edit_index_pattern/index_header/index_header.tsx", - "lineNumber": 15 + "path": "x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx", + "lineNumber": 166 } }, { @@ -14509,6 +14397,48 @@ "lineNumber": 30 } }, + { + "plugin": "apm", + "link": { + "path": "x-pack/plugins/apm/public/components/shared/KueryBar/index.tsx", + "lineNumber": 14 + } + }, + { + "plugin": "apm", + "link": { + "path": "x-pack/plugins/apm/public/components/shared/KueryBar/index.tsx", + "lineNumber": 31 + } + }, + { + "plugin": "infra", + "link": { + "path": "x-pack/plugins/infra/public/containers/with_kuery_autocompletion.tsx", + "lineNumber": 9 + } + }, + { + "plugin": "infra", + "link": { + "path": "x-pack/plugins/infra/public/containers/with_kuery_autocompletion.tsx", + "lineNumber": 24 + } + }, + { + "plugin": "infra", + "link": { + "path": "x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/kuery_bar.tsx", + "lineNumber": 15 + } + }, + { + "plugin": "infra", + "link": { + "path": "x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/kuery_bar.tsx", + "lineNumber": 28 + } + }, { "plugin": "infra", "link": { @@ -14649,32 +14579,74 @@ "lineNumber": 23 } }, + { + "plugin": "lists", + "link": { + "path": "x-pack/plugins/lists/public/exceptions/components/builder/exception_items_renderer.tsx", + "lineNumber": 34 + } + }, + { + "plugin": "lists", + "link": { + "path": "x-pack/plugins/lists/public/exceptions/components/builder/exception_items_renderer.tsx", + "lineNumber": 78 + } + }, + { + "plugin": "lists", + "link": { + "path": "x-pack/plugins/lists/public/exceptions/components/builder/exception_items_renderer.tsx", + "lineNumber": 86 + } + }, + { + "plugin": "lists", + "link": { + "path": "x-pack/plugins/lists/public/exceptions/components/builder/exception_items_renderer.tsx", + "lineNumber": 88 + } + }, { "plugin": "securitySolution", "link": { "path": "x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/types.ts", - "lineNumber": 20 + "lineNumber": 21 } }, { "plugin": "securitySolution", "link": { "path": "x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/types.ts", - "lineNumber": 64 + "lineNumber": 66 } }, { "plugin": "securitySolution", "link": { "path": "x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/action.ts", - "lineNumber": 17 + "lineNumber": 19 } }, { "plugin": "securitySolution", "link": { "path": "x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/action.ts", - "lineNumber": 98 + "lineNumber": 100 + } + }, + { + "plugin": "securitySolution", + "link": { + "path": "x-pack/plugins/security_solution/common/search_strategy/index_fields/index.ts", + "lineNumber": 8 + } + }, + { + "plugin": "securitySolution", + "link": { + "path": "x-pack/plugins/security_solution/common/search_strategy/index_fields/index.ts", + "lineNumber": 86 } }, { @@ -14912,21 +14884,21 @@ "plugin": "securitySolution", "link": { "path": "x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts", - "lineNumber": 32 + "lineNumber": 40 } }, { "plugin": "securitySolution", "link": { "path": "x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts", - "lineNumber": 38 + "lineNumber": 55 } }, { "plugin": "securitySolution", "link": { "path": "x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts", - "lineNumber": 43 + "lineNumber": 60 } }, { @@ -15013,34 +14985,6 @@ "lineNumber": 33 } }, - { - "plugin": "securitySolution", - "link": { - "path": "x-pack/plugins/security_solution/public/common/containers/kuery_autocompletion/index.tsx", - "lineNumber": 9 - } - }, - { - "plugin": "securitySolution", - "link": { - "path": "x-pack/plugins/security_solution/public/common/containers/kuery_autocompletion/index.tsx", - "lineNumber": 21 - } - }, - { - "plugin": "apm", - "link": { - "path": "x-pack/plugins/apm/public/components/shared/KueryBar/index.tsx", - "lineNumber": 14 - } - }, - { - "plugin": "apm", - "link": { - "path": "x-pack/plugins/apm/public/components/shared/KueryBar/index.tsx", - "lineNumber": 31 - } - }, { "plugin": "uptime", "link": { @@ -15083,6 +15027,20 @@ "lineNumber": 36 } }, + { + "plugin": "securitySolution", + "link": { + "path": "x-pack/plugins/security_solution/target/types/common/search_strategy/index_fields/index.d.ts", + "lineNumber": 1 + } + }, + { + "plugin": "securitySolution", + "link": { + "path": "x-pack/plugins/security_solution/target/types/common/search_strategy/index_fields/index.d.ts", + "lineNumber": 66 + } + }, { "plugin": "infra", "link": { @@ -15126,486 +15084,444 @@ } }, { - "plugin": "infra", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/infra/target/types/public/alerting/metric_threshold/components/expression_chart.d.ts", - "lineNumber": 2 + "path": "x-pack/plugins/security_solution/target/types/public/common/containers/source/index.d.ts", + "lineNumber": 1 } }, { - "plugin": "infra", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/infra/target/types/public/alerting/metric_threshold/components/expression_chart.d.ts", - "lineNumber": 7 + "path": "x-pack/plugins/security_solution/target/types/public/common/containers/source/index.d.ts", + "lineNumber": 10 } }, { - "plugin": "infra", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/infra/target/types/public/alerting/metric_threshold/hooks/use_metrics_explorer_chart_data.d.ts", - "lineNumber": 1 - } - }, - { - "plugin": "infra", - "link": { - "path": "x-pack/plugins/infra/target/types/public/alerting/metric_threshold/hooks/use_metrics_explorer_chart_data.d.ts", - "lineNumber": 4 + "path": "x-pack/plugins/security_solution/target/types/public/common/containers/source/index.d.ts", + "lineNumber": 23 } }, { "plugin": "infra", "link": { - "path": "x-pack/plugins/infra/target/types/public/pages/metrics/metrics_explorer/index.d.ts", - "lineNumber": 1 + "path": "x-pack/plugins/infra/target/types/public/alerting/metric_threshold/components/expression_chart.d.ts", + "lineNumber": 2 } }, { "plugin": "infra", "link": { - "path": "x-pack/plugins/infra/target/types/public/pages/metrics/metrics_explorer/index.d.ts", - "lineNumber": 5 + "path": "x-pack/plugins/infra/target/types/public/alerting/metric_threshold/components/expression_chart.d.ts", + "lineNumber": 7 } }, { "plugin": "infra", "link": { - "path": "x-pack/plugins/infra/target/types/public/pages/metrics/metrics_explorer/hooks/use_metric_explorer_state.d.ts", + "path": "x-pack/plugins/infra/target/types/public/alerting/metric_threshold/hooks/use_metrics_explorer_chart_data.d.ts", "lineNumber": 1 } }, { "plugin": "infra", "link": { - "path": "x-pack/plugins/infra/target/types/public/pages/metrics/metrics_explorer/hooks/use_metric_explorer_state.d.ts", - "lineNumber": 11 + "path": "x-pack/plugins/infra/target/types/public/alerting/metric_threshold/hooks/use_metrics_explorer_chart_data.d.ts", + "lineNumber": 4 } }, { "plugin": "infra", "link": { - "path": "x-pack/plugins/infra/target/types/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_data.d.ts", + "path": "x-pack/plugins/infra/target/types/public/pages/metrics/metrics_explorer/index.d.ts", "lineNumber": 1 } }, { "plugin": "infra", "link": { - "path": "x-pack/plugins/infra/target/types/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_data.d.ts", - "lineNumber": 4 + "path": "x-pack/plugins/infra/target/types/public/pages/metrics/metrics_explorer/index.d.ts", + "lineNumber": 5 } }, { - "plugin": "ml", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/ml/target/types/public/application/jobs/new_job/common/index_pattern_context.d.ts", - "lineNumber": 2 + "path": "x-pack/plugins/security_solution/target/types/public/common/components/url_state/types.d.ts", + "lineNumber": 3 } }, { - "plugin": "ml", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/ml/target/types/public/application/jobs/new_job/common/index_pattern_context.d.ts", - "lineNumber": 3 + "path": "x-pack/plugins/security_solution/target/types/public/common/components/url_state/types.d.ts", + "lineNumber": 25 } }, { - "plugin": "ml", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/ml/target/types/public/application/jobs/new_job/common/index_pattern_context.d.ts", - "lineNumber": 4 + "path": "x-pack/plugins/security_solution/target/types/public/common/components/url_state/types.d.ts", + "lineNumber": 55 } }, { - "plugin": "lists", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", - "lineNumber": 11 + "path": "x-pack/plugins/security_solution/target/types/public/network/components/network_top_countries_table/columns.d.ts", + "lineNumber": 1 } }, { - "plugin": "lists", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", - "lineNumber": 21 + "path": "x-pack/plugins/security_solution/target/types/public/network/components/network_top_countries_table/columns.d.ts", + "lineNumber": 20 } }, { - "plugin": "lists", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", - "lineNumber": 100 + "path": "x-pack/plugins/security_solution/target/types/public/network/components/network_top_countries_table/columns.d.ts", + "lineNumber": 21 } }, { - "plugin": "lists", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", - "lineNumber": 121 + "path": "x-pack/plugins/security_solution/target/types/public/common/components/search_bar/index.d.ts", + "lineNumber": 3 } }, { - "plugin": "lists", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/hooks/use_field_value_autocomplete.ts", - "lineNumber": 13 + "path": "x-pack/plugins/security_solution/target/types/public/common/components/search_bar/index.d.ts", + "lineNumber": 9 } }, { - "plugin": "lists", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/hooks/use_field_value_autocomplete.ts", - "lineNumber": 17 + "path": "x-pack/plugins/security_solution/target/types/public/hosts/pages/details/types.d.ts", + "lineNumber": 2 } }, { - "plugin": "lists", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/hooks/use_field_value_autocomplete.ts", - "lineNumber": 29 + "path": "x-pack/plugins/security_solution/target/types/public/hosts/pages/details/types.d.ts", + "lineNumber": 40 } }, { - "plugin": "lists", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field_value_match.tsx", - "lineNumber": 19 + "path": "x-pack/plugins/security_solution/target/types/public/network/components/network_top_countries_table/index.d.ts", + "lineNumber": 2 } }, { - "plugin": "lists", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field_value_match.tsx", - "lineNumber": 38 + "path": "x-pack/plugins/security_solution/target/types/public/network/components/network_top_countries_table/index.d.ts", + "lineNumber": 10 } }, { - "plugin": "lists", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field_value_match_any.tsx", - "lineNumber": 13 + "path": "x-pack/plugins/security_solution/target/types/public/network/pages/details/types.d.ts", + "lineNumber": 1 } }, { - "plugin": "lists", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field_value_match_any.tsx", + "path": "x-pack/plugins/security_solution/target/types/public/network/pages/details/types.d.ts", "lineNumber": 25 } }, { - "plugin": "lists", + "plugin": "infra", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.tsx", - "lineNumber": 31 + "path": "x-pack/plugins/infra/target/types/public/pages/metrics/metrics_explorer/hooks/use_metric_explorer_state.d.ts", + "lineNumber": 1 } }, { - "plugin": "lists", + "plugin": "infra", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.tsx", - "lineNumber": 53 + "path": "x-pack/plugins/infra/target/types/public/pages/metrics/metrics_explorer/hooks/use_metric_explorer_state.d.ts", + "lineNumber": 11 } }, { - "plugin": "lists", + "plugin": "infra", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.tsx", - "lineNumber": 58 + "path": "x-pack/plugins/infra/target/types/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_data.d.ts", + "lineNumber": 1 } }, { - "plugin": "lists", + "plugin": "infra", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.tsx", - "lineNumber": 61 + "path": "x-pack/plugins/infra/target/types/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_data.d.ts", + "lineNumber": 4 } }, { - "plugin": "lists", + "plugin": "ml", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/exception_item_renderer.tsx", - "lineNumber": 22 + "path": "x-pack/plugins/ml/target/types/public/application/jobs/new_job/common/index_pattern_context.d.ts", + "lineNumber": 2 } }, { - "plugin": "lists", + "plugin": "ml", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/exception_item_renderer.tsx", - "lineNumber": 50 + "path": "x-pack/plugins/ml/target/types/public/application/jobs/new_job/common/index_pattern_context.d.ts", + "lineNumber": 3 } }, { - "plugin": "lists", + "plugin": "ml", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/exception_item_renderer.tsx", - "lineNumber": 55 + "path": "x-pack/plugins/ml/target/types/public/application/jobs/new_job/common/index_pattern_context.d.ts", + "lineNumber": 4 } }, { - "plugin": "lists", + "plugin": "ml", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/exception_item_renderer.tsx", - "lineNumber": 58 + "path": "x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/action_clone/clone_action_name.tsx", + "lineNumber": 12 } }, { - "plugin": "lists", + "plugin": "ml", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", - "lineNumber": 62 + "path": "x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/action_clone/clone_action_name.tsx", + "lineNumber": 412 } }, { - "plugin": "lists", + "plugin": "ml", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", - "lineNumber": 96 + "path": "x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/action_delete/use_delete_action.tsx", + "lineNumber": 12 } }, { - "plugin": "lists", + "plugin": "ml", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", - "lineNumber": 169 + "path": "x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/action_delete/use_delete_action.tsx", + "lineNumber": 60 } }, { - "plugin": "lists", + "plugin": "ml", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", - "lineNumber": 169 + "path": "x-pack/plugins/ml/public/application/jobs/components/custom_url_editor/utils.d.ts", + "lineNumber": 8 } }, { - "plugin": "lists", + "plugin": "ml", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", - "lineNumber": 184 + "path": "x-pack/plugins/ml/public/application/jobs/components/custom_url_editor/utils.d.ts", + "lineNumber": 37 } }, { - "plugin": "lists", + "plugin": "ml", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", - "lineNumber": 187 + "path": "x-pack/plugins/ml/public/application/jobs/jobs_list/components/edit_job_flyout/edit_utils.d.ts", + "lineNumber": 8 } }, { - "plugin": "lists", + "plugin": "ml", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", - "lineNumber": 196 + "path": "x-pack/plugins/ml/public/application/jobs/jobs_list/components/edit_job_flyout/edit_utils.d.ts", + "lineNumber": 11 } }, { - "plugin": "lists", + "plugin": "ml", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", - "lineNumber": 199 + "path": "x-pack/plugins/ml/public/application/datavisualizer/index_based/components/actions_panel/actions_panel.tsx", + "lineNumber": 25 } }, { - "plugin": "lists", + "plugin": "ml", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", - "lineNumber": 208 + "path": "x-pack/plugins/ml/public/application/datavisualizer/index_based/components/actions_panel/actions_panel.tsx", + "lineNumber": 28 } }, { - "plugin": "lists", + "plugin": "infra", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", - "lineNumber": 214 + "path": "x-pack/plugins/infra/public/pages/metrics/index.tsx", + "lineNumber": 14 } }, { - "plugin": "lists", + "plugin": "infra", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", - "lineNumber": 226 + "path": "x-pack/plugins/infra/public/pages/metrics/index.tsx", + "lineNumber": 193 } }, { - "plugin": "lists", + "plugin": "visTypeTimeseries", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", - "lineNumber": 229 + "path": "src/plugins/vis_type_timeseries/common/index_patterns_utils.ts", + "lineNumber": 11 } }, { - "plugin": "lists", + "plugin": "visTypeTimeseries", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", - "lineNumber": 239 + "path": "src/plugins/vis_type_timeseries/common/index_patterns_utils.ts", + "lineNumber": 20 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", - "lineNumber": 267 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", + "lineNumber": 11 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", - "lineNumber": 285 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", + "lineNumber": 21 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", - "lineNumber": 320 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", + "lineNumber": 100 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", - "lineNumber": 336 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", + "lineNumber": 121 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", - "lineNumber": 1026 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/hooks/use_field_value_autocomplete.ts", + "lineNumber": 13 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", - "lineNumber": 1045 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/hooks/use_field_value_autocomplete.ts", + "lineNumber": 17 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", - "lineNumber": 1095 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/hooks/use_field_value_autocomplete.ts", + "lineNumber": 29 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", - "lineNumber": 1251 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field_value_match.tsx", + "lineNumber": 19 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", - "lineNumber": 1302 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field_value_match.tsx", + "lineNumber": 38 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", - "lineNumber": 1352 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field_value_match_any.tsx", + "lineNumber": 13 } }, { - "plugin": "securitySolution", + "plugin": "lists", "link": { - "path": "x-pack/plugins/security_solution/common/detection_engine/get_query_filter.ts", - "lineNumber": 15 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field_value_match_any.tsx", + "lineNumber": 25 } }, { - "plugin": "securitySolution", + "plugin": "lists", "link": { - "path": "x-pack/plugins/security_solution/common/detection_engine/get_query_filter.ts", + "path": "x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.tsx", "lineNumber": 31 } }, { - "plugin": "ml", - "link": { - "path": "x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/action_clone/clone_action_name.tsx", - "lineNumber": 12 - } - }, - { - "plugin": "ml", - "link": { - "path": "x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/action_clone/clone_action_name.tsx", - "lineNumber": 412 - } - }, - { - "plugin": "ml", - "link": { - "path": "x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/action_delete/use_delete_action.tsx", - "lineNumber": 12 - } - }, - { - "plugin": "ml", - "link": { - "path": "x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/action_delete/use_delete_action.tsx", - "lineNumber": 60 - } - }, - { - "plugin": "ml", - "link": { - "path": "x-pack/plugins/ml/public/application/jobs/components/custom_url_editor/utils.d.ts", - "lineNumber": 8 - } - }, - { - "plugin": "ml", + "plugin": "lists", "link": { - "path": "x-pack/plugins/ml/public/application/jobs/components/custom_url_editor/utils.d.ts", - "lineNumber": 37 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.tsx", + "lineNumber": 53 } }, { - "plugin": "ml", + "plugin": "lists", "link": { - "path": "x-pack/plugins/ml/public/application/jobs/jobs_list/components/edit_job_flyout/edit_utils.d.ts", - "lineNumber": 8 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.tsx", + "lineNumber": 58 } }, { - "plugin": "ml", + "plugin": "lists", "link": { - "path": "x-pack/plugins/ml/public/application/jobs/jobs_list/components/edit_job_flyout/edit_utils.d.ts", - "lineNumber": 11 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.tsx", + "lineNumber": 61 } }, { - "plugin": "ml", + "plugin": "lists", "link": { - "path": "x-pack/plugins/ml/public/application/datavisualizer/index_based/components/actions_panel/actions_panel.tsx", - "lineNumber": 25 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/exception_item_renderer.tsx", + "lineNumber": 22 } }, { - "plugin": "ml", + "plugin": "lists", "link": { - "path": "x-pack/plugins/ml/public/application/datavisualizer/index_based/components/actions_panel/actions_panel.tsx", - "lineNumber": 28 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/exception_item_renderer.tsx", + "lineNumber": 50 } }, { - "plugin": "infra", + "plugin": "lists", "link": { - "path": "x-pack/plugins/infra/public/pages/metrics/index.tsx", - "lineNumber": 14 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/exception_item_renderer.tsx", + "lineNumber": 55 } }, { - "plugin": "infra", + "plugin": "lists", "link": { - "path": "x-pack/plugins/infra/public/pages/metrics/index.tsx", - "lineNumber": 193 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/exception_item_renderer.tsx", + "lineNumber": 58 } }, { @@ -15629,6 +15545,20 @@ "lineNumber": 53 } }, + { + "plugin": "securitySolution", + "link": { + "path": "x-pack/plugins/security_solution/common/detection_engine/get_query_filter.ts", + "lineNumber": 16 + } + }, + { + "plugin": "securitySolution", + "link": { + "path": "x-pack/plugins/security_solution/common/detection_engine/get_query_filter.ts", + "lineNumber": 31 + } + }, { "plugin": "securitySolution", "link": { @@ -15756,164 +15686,220 @@ } }, { - "plugin": "securitySolution", + "plugin": "stackAlerts", "link": { - "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/field_value_match_any.tsx", + "path": "x-pack/plugins/stack_alerts/server/alert_types/geo_containment/es_query_builder.ts", "lineNumber": 13 } }, { - "plugin": "securitySolution", + "plugin": "stackAlerts", "link": { - "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/field_value_match_any.tsx", - "lineNumber": 24 + "path": "x-pack/plugins/stack_alerts/server/alert_types/geo_containment/es_query_builder.ts", + "lineNumber": 25 } }, { - "plugin": "securitySolution", + "plugin": "infra", "link": { - "path": "x-pack/plugins/security_solution/public/common/components/exceptions/helpers.test.tsx", - "lineNumber": 43 + "path": "x-pack/plugins/infra/common/dependency_mocks/index_patterns.ts", + "lineNumber": 13 } }, { - "plugin": "securitySolution", + "plugin": "infra", "link": { - "path": "x-pack/plugins/security_solution/public/common/components/exceptions/helpers.test.tsx", - "lineNumber": 49 + "path": "x-pack/plugins/infra/common/dependency_mocks/index_patterns.ts", + "lineNumber": 30 } }, { - "plugin": "securitySolution", + "plugin": "infra", "link": { - "path": "x-pack/plugins/security_solution/public/common/components/exceptions/helpers.test.tsx", - "lineNumber": 368 + "path": "x-pack/plugins/infra/target/types/common/dependency_mocks/index_patterns.d.ts", + "lineNumber": 1 } }, { - "plugin": "visTypeTimeseries", + "plugin": "infra", "link": { - "path": "src/plugins/vis_type_timeseries/common/index_patterns_utils.ts", - "lineNumber": 11 + "path": "x-pack/plugins/infra/target/types/common/dependency_mocks/index_patterns.d.ts", + "lineNumber": 3 } }, { - "plugin": "visTypeTimeseries", + "plugin": "lists", "link": { - "path": "src/plugins/vis_type_timeseries/common/index_patterns_utils.ts", - "lineNumber": 20 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", + "lineNumber": 62 } }, { - "plugin": "stackAlerts", + "plugin": "lists", "link": { - "path": "x-pack/plugins/stack_alerts/server/alert_types/geo_containment/es_query_builder.ts", - "lineNumber": 13 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", + "lineNumber": 96 } }, { - "plugin": "stackAlerts", + "plugin": "lists", "link": { - "path": "x-pack/plugins/stack_alerts/server/alert_types/geo_containment/es_query_builder.ts", - "lineNumber": 25 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", + "lineNumber": 169 } }, { - "plugin": "infra", + "plugin": "lists", "link": { - "path": "x-pack/plugins/infra/common/dependency_mocks/index_patterns.ts", - "lineNumber": 13 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", + "lineNumber": 169 } }, { - "plugin": "infra", + "plugin": "lists", "link": { - "path": "x-pack/plugins/infra/common/dependency_mocks/index_patterns.ts", - "lineNumber": 30 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", + "lineNumber": 184 } }, { - "plugin": "infra", + "plugin": "lists", "link": { - "path": "x-pack/plugins/infra/target/types/common/dependency_mocks/index_patterns.d.ts", - "lineNumber": 1 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", + "lineNumber": 187 } }, { - "plugin": "infra", + "plugin": "lists", "link": { - "path": "x-pack/plugins/infra/target/types/common/dependency_mocks/index_patterns.d.ts", - "lineNumber": 3 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", + "lineNumber": 196 } }, { - "plugin": "discover", + "plugin": "lists", "link": { - "path": "src/plugins/discover/public/application/components/context_app/context_app_legacy.tsx", - "lineNumber": 17 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", + "lineNumber": 199 } }, { - "plugin": "discover", + "plugin": "lists", "link": { - "path": "src/plugins/discover/public/application/components/context_app/context_app_legacy.tsx", - "lineNumber": 26 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", + "lineNumber": 208 } }, { - "plugin": "observability", + "plugin": "lists", "link": { - "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/types.ts", - "lineNumber": 18 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", + "lineNumber": 214 } }, { - "plugin": "observability", + "plugin": "lists", "link": { - "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/types.ts", - "lineNumber": 95 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", + "lineNumber": 226 } }, { - "plugin": "observability", + "plugin": "lists", "link": { - "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/utils.ts", - "lineNumber": 10 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", + "lineNumber": 229 } }, { - "plugin": "observability", + "plugin": "lists", "link": { - "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/utils.ts", - "lineNumber": 53 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", + "lineNumber": 239 } }, { - "plugin": "observability", + "plugin": "lists", "link": { - "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/utils.ts", - "lineNumber": 61 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", + "lineNumber": 267 } }, { - "plugin": "observability", + "plugin": "lists", "link": { - "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/utils.ts", - "lineNumber": 69 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", + "lineNumber": 285 } }, { - "plugin": "observability", + "plugin": "lists", "link": { - "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/default_configs.ts", - "lineNumber": 19 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", + "lineNumber": 320 } }, { - "plugin": "observability", + "plugin": "lists", "link": { - "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/default_configs.ts", - "lineNumber": 24 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", + "lineNumber": 336 + } + }, + { + "plugin": "lists", + "link": { + "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", + "lineNumber": 1026 + } + }, + { + "plugin": "lists", + "link": { + "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", + "lineNumber": 1045 + } + }, + { + "plugin": "lists", + "link": { + "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", + "lineNumber": 1095 + } + }, + { + "plugin": "lists", + "link": { + "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", + "lineNumber": 1251 + } + }, + { + "plugin": "lists", + "link": { + "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", + "lineNumber": 1302 + } + }, + { + "plugin": "lists", + "link": { + "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", + "lineNumber": 1352 + } + }, + { + "plugin": "discover", + "link": { + "path": "src/plugins/discover/public/application/components/context_app/context_app_legacy.tsx", + "lineNumber": 17 + } + }, + { + "plugin": "discover", + "link": { + "path": "src/plugins/discover/public/application/components/context_app/context_app_legacy.tsx", + "lineNumber": 26 } }, { @@ -15980,52 +15966,108 @@ } }, { - "plugin": "ml", + "plugin": "ml", + "link": { + "path": "x-pack/plugins/ml/public/application/jobs/jobs_list/components/edit_job_flyout/tabs/custom_urls.tsx", + "lineNumber": 57 + } + }, + { + "plugin": "ml", + "link": { + "path": "x-pack/plugins/ml/public/application/datavisualizer/index_based/components/field_data_row/action_menu/lens_utils.ts", + "lineNumber": 14 + } + }, + { + "plugin": "ml", + "link": { + "path": "x-pack/plugins/ml/public/application/datavisualizer/index_based/components/field_data_row/action_menu/lens_utils.ts", + "lineNumber": 27 + } + }, + { + "plugin": "ml", + "link": { + "path": "x-pack/plugins/ml/public/application/datavisualizer/index_based/components/field_data_row/action_menu/lens_utils.ts", + "lineNumber": 213 + } + }, + { + "plugin": "ml", + "link": { + "path": "x-pack/plugins/ml/public/application/datavisualizer/index_based/components/field_data_row/action_menu/lens_utils.ts", + "lineNumber": 234 + } + }, + { + "plugin": "ml", + "link": { + "path": "x-pack/plugins/ml/public/application/datavisualizer/index_based/components/field_data_row/action_menu/actions.ts", + "lineNumber": 12 + } + }, + { + "plugin": "ml", + "link": { + "path": "x-pack/plugins/ml/public/application/datavisualizer/index_based/components/field_data_row/action_menu/actions.ts", + "lineNumber": 17 + } + }, + { + "plugin": "observability", + "link": { + "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/types.ts", + "lineNumber": 18 + } + }, + { + "plugin": "observability", "link": { - "path": "x-pack/plugins/ml/public/application/jobs/jobs_list/components/edit_job_flyout/tabs/custom_urls.tsx", - "lineNumber": 57 + "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/types.ts", + "lineNumber": 95 } }, { - "plugin": "ml", + "plugin": "observability", "link": { - "path": "x-pack/plugins/ml/public/application/datavisualizer/index_based/components/field_data_row/action_menu/lens_utils.ts", - "lineNumber": 14 + "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/utils.ts", + "lineNumber": 10 } }, { - "plugin": "ml", + "plugin": "observability", "link": { - "path": "x-pack/plugins/ml/public/application/datavisualizer/index_based/components/field_data_row/action_menu/lens_utils.ts", - "lineNumber": 27 + "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/utils.ts", + "lineNumber": 53 } }, { - "plugin": "ml", + "plugin": "observability", "link": { - "path": "x-pack/plugins/ml/public/application/datavisualizer/index_based/components/field_data_row/action_menu/lens_utils.ts", - "lineNumber": 213 + "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/utils.ts", + "lineNumber": 61 } }, { - "plugin": "ml", + "plugin": "observability", "link": { - "path": "x-pack/plugins/ml/public/application/datavisualizer/index_based/components/field_data_row/action_menu/lens_utils.ts", - "lineNumber": 234 + "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/utils.ts", + "lineNumber": 69 } }, { - "plugin": "ml", + "plugin": "observability", "link": { - "path": "x-pack/plugins/ml/public/application/datavisualizer/index_based/components/field_data_row/action_menu/actions.ts", - "lineNumber": 12 + "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/default_configs.ts", + "lineNumber": 19 } }, { - "plugin": "ml", + "plugin": "observability", "link": { - "path": "x-pack/plugins/ml/public/application/datavisualizer/index_based/components/field_data_row/action_menu/actions.ts", - "lineNumber": 17 + "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/default_configs.ts", + "lineNumber": 24 } }, { @@ -16098,20 +16140,6 @@ "lineNumber": 19 } }, - { - "plugin": "securitySolution", - "link": { - "path": "x-pack/plugins/security_solution/public/common/mock/index_pattern.ts", - "lineNumber": 8 - } - }, - { - "plugin": "securitySolution", - "link": { - "path": "x-pack/plugins/security_solution/public/common/mock/index_pattern.ts", - "lineNumber": 10 - } - }, { "plugin": "stackAlerts", "link": { @@ -16231,6 +16259,20 @@ "lineNumber": 13 } }, + { + "plugin": "securitySolution", + "link": { + "path": "x-pack/plugins/security_solution/public/common/mock/index_pattern.ts", + "lineNumber": 8 + } + }, + { + "plugin": "securitySolution", + "link": { + "path": "x-pack/plugins/security_solution/public/common/mock/index_pattern.ts", + "lineNumber": 10 + } + }, { "plugin": "ml", "link": { @@ -33252,111 +33294,6 @@ "lineNumber": 58 } }, - { - "plugin": "fleet", - "link": { - "path": "x-pack/plugins/fleet/public/applications/fleet/components/search_bar.tsx", - "lineNumber": 10 - } - }, - { - "plugin": "fleet", - "link": { - "path": "x-pack/plugins/fleet/public/applications/fleet/components/search_bar.tsx", - "lineNumber": 33 - } - }, - { - "plugin": "fleet", - "link": { - "path": "x-pack/plugins/fleet/public/applications/fleet/components/search_bar.tsx", - "lineNumber": 51 - } - }, - { - "plugin": "indexPatternManagement", - "link": { - "path": "src/plugins/index_pattern_management/public/service/list/config.ts", - "lineNumber": 10 - } - }, - { - "plugin": "indexPatternManagement", - "link": { - "path": "src/plugins/index_pattern_management/public/service/list/config.ts", - "lineNumber": 42 - } - }, - { - "plugin": "indexPatternManagement", - "link": { - "path": "src/plugins/index_pattern_management/public/service/list/manager.ts", - "lineNumber": 9 - } - }, - { - "plugin": "indexPatternManagement", - "link": { - "path": "src/plugins/index_pattern_management/public/service/list/manager.ts", - "lineNumber": 43 - } - }, - { - "plugin": "indexPatternManagement", - "link": { - "path": "src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/lib/extract_time_fields.ts", - "lineNumber": 10 - } - }, - { - "plugin": "indexPatternManagement", - "link": { - "path": "src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/lib/extract_time_fields.ts", - "lineNumber": 12 - } - }, - { - "plugin": "indexPatternManagement", - "link": { - "path": "src/plugins/index_pattern_management/public/components/edit_index_pattern/indexed_fields_table/types.ts", - "lineNumber": 9 - } - }, - { - "plugin": "indexPatternManagement", - "link": { - "path": "src/plugins/index_pattern_management/public/components/edit_index_pattern/indexed_fields_table/types.ts", - "lineNumber": 11 - } - }, - { - "plugin": "indexPatternManagement", - "link": { - "path": "src/plugins/index_pattern_management/public/components/edit_index_pattern/indexed_fields_table/indexed_fields_table.tsx", - "lineNumber": 11 - } - }, - { - "plugin": "indexPatternManagement", - "link": { - "path": "src/plugins/index_pattern_management/public/components/edit_index_pattern/indexed_fields_table/indexed_fields_table.tsx", - "lineNumber": 23 - } - }, - { - "plugin": "indexPatternManagement", - "link": { - "path": "src/plugins/index_pattern_management/public/components/field_editor/field_editor.tsx", - "lineNumber": 45 - } - }, - { - "plugin": "indexPatternManagement", - "link": { - "path": "src/plugins/index_pattern_management/public/components/field_editor/field_editor.tsx", - "lineNumber": 148 - } - }, { "plugin": "maps", "link": { @@ -33701,24 +33638,108 @@ } }, { - "plugin": "maps", + "plugin": "maps", + "link": { + "path": "x-pack/plugins/maps/public/classes/layers/choropleth_layer_wizard/layer_template.tsx", + "lineNumber": 59 + } + }, + { + "plugin": "maps", + "link": { + "path": "x-pack/plugins/maps/public/classes/layers/choropleth_layer_wizard/layer_template.tsx", + "lineNumber": 60 + } + }, + { + "plugin": "maps", + "link": { + "path": "x-pack/plugins/maps/public/classes/layers/choropleth_layer_wizard/layer_template.tsx", + "lineNumber": 66 + } + }, + { + "plugin": "indexPatternManagement", + "link": { + "path": "src/plugins/index_pattern_management/public/service/list/config.ts", + "lineNumber": 10 + } + }, + { + "plugin": "indexPatternManagement", + "link": { + "path": "src/plugins/index_pattern_management/public/service/list/config.ts", + "lineNumber": 42 + } + }, + { + "plugin": "indexPatternManagement", + "link": { + "path": "src/plugins/index_pattern_management/public/service/list/manager.ts", + "lineNumber": 9 + } + }, + { + "plugin": "indexPatternManagement", + "link": { + "path": "src/plugins/index_pattern_management/public/service/list/manager.ts", + "lineNumber": 43 + } + }, + { + "plugin": "indexPatternManagement", + "link": { + "path": "src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/lib/extract_time_fields.ts", + "lineNumber": 10 + } + }, + { + "plugin": "indexPatternManagement", + "link": { + "path": "src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/lib/extract_time_fields.ts", + "lineNumber": 12 + } + }, + { + "plugin": "indexPatternManagement", + "link": { + "path": "src/plugins/index_pattern_management/public/components/edit_index_pattern/indexed_fields_table/types.ts", + "lineNumber": 9 + } + }, + { + "plugin": "indexPatternManagement", + "link": { + "path": "src/plugins/index_pattern_management/public/components/edit_index_pattern/indexed_fields_table/types.ts", + "lineNumber": 11 + } + }, + { + "plugin": "indexPatternManagement", + "link": { + "path": "src/plugins/index_pattern_management/public/components/edit_index_pattern/indexed_fields_table/indexed_fields_table.tsx", + "lineNumber": 11 + } + }, + { + "plugin": "indexPatternManagement", "link": { - "path": "x-pack/plugins/maps/public/classes/layers/choropleth_layer_wizard/layer_template.tsx", - "lineNumber": 59 + "path": "src/plugins/index_pattern_management/public/components/edit_index_pattern/indexed_fields_table/indexed_fields_table.tsx", + "lineNumber": 23 } }, { - "plugin": "maps", + "plugin": "indexPatternManagement", "link": { - "path": "x-pack/plugins/maps/public/classes/layers/choropleth_layer_wizard/layer_template.tsx", - "lineNumber": 60 + "path": "src/plugins/index_pattern_management/public/components/field_editor/field_editor.tsx", + "lineNumber": 45 } }, { - "plugin": "maps", + "plugin": "indexPatternManagement", "link": { - "path": "x-pack/plugins/maps/public/classes/layers/choropleth_layer_wizard/layer_template.tsx", - "lineNumber": 66 + "path": "src/plugins/index_pattern_management/public/components/field_editor/field_editor.tsx", + "lineNumber": 148 } }, { @@ -33973,6 +33994,27 @@ "lineNumber": 21 } }, + { + "plugin": "fleet", + "link": { + "path": "x-pack/plugins/fleet/public/applications/fleet/components/search_bar.tsx", + "lineNumber": 10 + } + }, + { + "plugin": "fleet", + "link": { + "path": "x-pack/plugins/fleet/public/applications/fleet/components/search_bar.tsx", + "lineNumber": 33 + } + }, + { + "plugin": "fleet", + "link": { + "path": "x-pack/plugins/fleet/public/applications/fleet/components/search_bar.tsx", + "lineNumber": 51 + } + }, { "plugin": "fleet", "link": { @@ -34513,409 +34555,346 @@ } }, { - "plugin": "lists", - "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.ts", - "lineNumber": 19 - } - }, - { - "plugin": "lists", - "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.ts", - "lineNumber": 30 - } - }, - { - "plugin": "lists", - "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.ts", - "lineNumber": 54 - } - }, - { - "plugin": "lists", - "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.ts", - "lineNumber": 84 - } - }, - { - "plugin": "lists", - "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.ts", - "lineNumber": 150 - } - }, - { - "plugin": "lists", - "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", - "lineNumber": 11 - } - }, - { - "plugin": "lists", - "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", - "lineNumber": 26 - } - }, - { - "plugin": "lists", - "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", - "lineNumber": 28 - } - }, - { - "plugin": "lists", - "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", - "lineNumber": 57 - } - }, - { - "plugin": "lists", + "plugin": "maps", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", - "lineNumber": 95 + "path": "x-pack/plugins/maps/common/elasticsearch_util/es_agg_utils.ts", + "lineNumber": 10 } }, { - "plugin": "lists", + "plugin": "maps", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", - "lineNumber": 96 + "path": "x-pack/plugins/maps/common/elasticsearch_util/es_agg_utils.ts", + "lineNumber": 16 } }, { - "plugin": "lists", + "plugin": "maps", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", - "lineNumber": 101 + "path": "x-pack/plugins/maps/common/elasticsearch_util/es_agg_utils.ts", + "lineNumber": 29 } }, { - "plugin": "lists", + "plugin": "maps", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", - "lineNumber": 114 + "path": "x-pack/plugins/maps/public/components/geo_field_select.tsx", + "lineNumber": 12 } }, { - "plugin": "lists", + "plugin": "maps", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", - "lineNumber": 121 + "path": "x-pack/plugins/maps/public/components/geo_field_select.tsx", + "lineNumber": 16 } }, { - "plugin": "lists", + "plugin": "maps", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", - "lineNumber": 125 + "path": "x-pack/plugins/maps/public/classes/sources/es_search_source/top_hits/create_source_editor.tsx", + "lineNumber": 18 } }, { - "plugin": "lists", + "plugin": "maps", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", - "lineNumber": 125 + "path": "x-pack/plugins/maps/public/classes/sources/es_search_source/top_hits/create_source_editor.tsx", + "lineNumber": 30 } }, { - "plugin": "lists", + "plugin": "maps", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", - "lineNumber": 130 + "path": "x-pack/plugins/maps/public/classes/sources/es_search_source/top_hits/create_source_editor.tsx", + "lineNumber": 33 } }, { - "plugin": "lists", + "plugin": "maps", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", - "lineNumber": 131 + "path": "x-pack/plugins/maps/public/classes/sources/es_search_source/top_hits/create_source_editor.tsx", + "lineNumber": 35 } }, { - "plugin": "lists", + "plugin": "lens", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", - "lineNumber": 133 + "path": "x-pack/plugins/lens/public/indexpattern_datasource/types.ts", + "lineNumber": 8 } }, { - "plugin": "lists", + "plugin": "lens", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", - "lineNumber": 134 + "path": "x-pack/plugins/lens/public/indexpattern_datasource/types.ts", + "lineNumber": 57 } }, { - "plugin": "lists", + "plugin": "lens", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/operator.tsx", + "path": "x-pack/plugins/lens/server/routes/field_stats.ts", "lineNumber": 11 } }, { - "plugin": "lists", + "plugin": "lens", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/operator.tsx", - "lineNumber": 27 + "path": "x-pack/plugins/lens/server/routes/field_stats.ts", + "lineNumber": 139 } }, { - "plugin": "lists", + "plugin": "lens", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/hooks/use_field_value_autocomplete.ts", - "lineNumber": 13 + "path": "x-pack/plugins/lens/server/routes/field_stats.ts", + "lineNumber": 248 } }, { - "plugin": "lists", + "plugin": "lens", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/hooks/use_field_value_autocomplete.ts", - "lineNumber": 16 + "path": "x-pack/plugins/lens/server/routes/field_stats.ts", + "lineNumber": 287 } }, { - "plugin": "lists", + "plugin": "lens", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/hooks/use_field_value_autocomplete.ts", - "lineNumber": 32 + "path": "x-pack/plugins/lens/server/routes/field_stats.ts", + "lineNumber": 329 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field_value_match.tsx", + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.ts", "lineNumber": 19 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field_value_match.tsx", - "lineNumber": 36 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.ts", + "lineNumber": 30 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field_value_match_any.tsx", - "lineNumber": 13 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.ts", + "lineNumber": 54 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field_value_match_any.tsx", - "lineNumber": 23 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.ts", + "lineNumber": 84 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field_value_lists.tsx", - "lineNumber": 13 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.ts", + "lineNumber": 150 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field_value_lists.tsx", - "lineNumber": 29 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", + "lineNumber": 11 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.tsx", - "lineNumber": 31 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", + "lineNumber": 26 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.tsx", - "lineNumber": 91 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", + "lineNumber": 28 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.test.ts", - "lineNumber": 19 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", + "lineNumber": 57 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.test.ts", - "lineNumber": 333 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", + "lineNumber": 95 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.test.ts", - "lineNumber": 339 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", + "lineNumber": 96 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.test.ts", - "lineNumber": 347 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", + "lineNumber": 101 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.test.ts", - "lineNumber": 355 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", + "lineNumber": 114 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.test.ts", - "lineNumber": 363 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", + "lineNumber": 121 } }, { "plugin": "lists", - "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.test.ts", - "lineNumber": 371 + "link": { + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", + "lineNumber": 125 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.test.ts", - "lineNumber": 380 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", + "lineNumber": 125 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", - "lineNumber": 62 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", + "lineNumber": 130 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", - "lineNumber": 166 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", + "lineNumber": 131 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", - "lineNumber": 167 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", + "lineNumber": 133 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", - "lineNumber": 629 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", + "lineNumber": 134 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", - "lineNumber": 666 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/operator.tsx", + "lineNumber": 11 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", - "lineNumber": 691 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/operator.tsx", + "lineNumber": 27 } }, { - "plugin": "lens", + "plugin": "lists", "link": { - "path": "x-pack/plugins/lens/public/indexpattern_datasource/types.ts", - "lineNumber": 8 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/hooks/use_field_value_autocomplete.ts", + "lineNumber": 13 } }, { - "plugin": "lens", + "plugin": "lists", "link": { - "path": "x-pack/plugins/lens/public/indexpattern_datasource/types.ts", - "lineNumber": 57 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/hooks/use_field_value_autocomplete.ts", + "lineNumber": 16 } }, { - "plugin": "maps", + "plugin": "lists", "link": { - "path": "x-pack/plugins/maps/common/elasticsearch_util/es_agg_utils.ts", - "lineNumber": 10 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/hooks/use_field_value_autocomplete.ts", + "lineNumber": 32 } }, { - "plugin": "maps", + "plugin": "lists", "link": { - "path": "x-pack/plugins/maps/common/elasticsearch_util/es_agg_utils.ts", - "lineNumber": 16 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field_value_match.tsx", + "lineNumber": 19 } }, { - "plugin": "maps", + "plugin": "lists", "link": { - "path": "x-pack/plugins/maps/common/elasticsearch_util/es_agg_utils.ts", - "lineNumber": 29 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field_value_match.tsx", + "lineNumber": 36 } }, { - "plugin": "maps", + "plugin": "lists", "link": { - "path": "x-pack/plugins/maps/public/components/geo_field_select.tsx", - "lineNumber": 12 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field_value_match_any.tsx", + "lineNumber": 13 } }, { - "plugin": "maps", + "plugin": "lists", "link": { - "path": "x-pack/plugins/maps/public/components/geo_field_select.tsx", - "lineNumber": 16 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field_value_match_any.tsx", + "lineNumber": 23 } }, { - "plugin": "maps", + "plugin": "lists", "link": { - "path": "x-pack/plugins/maps/public/classes/sources/es_search_source/top_hits/create_source_editor.tsx", - "lineNumber": 18 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field_value_lists.tsx", + "lineNumber": 14 } }, { - "plugin": "maps", + "plugin": "lists", "link": { - "path": "x-pack/plugins/maps/public/classes/sources/es_search_source/top_hits/create_source_editor.tsx", - "lineNumber": 30 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field_value_lists.tsx", + "lineNumber": 29 } }, { - "plugin": "maps", + "plugin": "lists", "link": { - "path": "x-pack/plugins/maps/public/classes/sources/es_search_source/top_hits/create_source_editor.tsx", - "lineNumber": 33 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.tsx", + "lineNumber": 31 } }, { - "plugin": "maps", + "plugin": "lists", "link": { - "path": "x-pack/plugins/maps/public/classes/sources/es_search_source/top_hits/create_source_editor.tsx", - "lineNumber": 35 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.tsx", + "lineNumber": 91 } }, { @@ -35157,192 +35136,213 @@ } }, { - "plugin": "securitySolution", + "plugin": "lens", "link": { - "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/field_value_lists.tsx", - "lineNumber": 12 + "path": "x-pack/plugins/lens/target/types/public/indexpattern_datasource/types.d.ts", + "lineNumber": 1 } }, { - "plugin": "securitySolution", + "plugin": "lens", "link": { - "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/field_value_lists.tsx", - "lineNumber": 20 + "path": "x-pack/plugins/lens/target/types/public/indexpattern_datasource/types.d.ts", + "lineNumber": 22 } }, { - "plugin": "securitySolution", + "plugin": "lens", "link": { - "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/field_value_match_any.tsx", - "lineNumber": 13 + "path": "x-pack/plugins/lens/target/types/server/routes/field_stats.d.ts", + "lineNumber": 3 } }, { - "plugin": "securitySolution", + "plugin": "lens", "link": { - "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/field_value_match_any.tsx", - "lineNumber": 22 + "path": "x-pack/plugins/lens/target/types/server/routes/field_stats.d.ts", + "lineNumber": 7 } }, { - "plugin": "securitySolution", + "plugin": "lens", "link": { - "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/helpers.test.ts", - "lineNumber": 11 + "path": "x-pack/plugins/lens/target/types/server/routes/field_stats.d.ts", + "lineNumber": 8 } }, { - "plugin": "securitySolution", + "plugin": "lens", "link": { - "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/helpers.test.ts", + "path": "x-pack/plugins/lens/target/types/server/routes/field_stats.d.ts", + "lineNumber": 9 + } + }, + { + "plugin": "lists", + "link": { + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.test.ts", + "lineNumber": 19 + } + }, + { + "plugin": "lists", + "link": { + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.test.ts", "lineNumber": 333 } }, { - "plugin": "securitySolution", + "plugin": "lists", "link": { - "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/helpers.test.ts", + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.test.ts", "lineNumber": 339 } }, { - "plugin": "securitySolution", + "plugin": "lists", "link": { - "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/helpers.test.ts", + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.test.ts", "lineNumber": 347 } }, { - "plugin": "securitySolution", + "plugin": "lists", "link": { - "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/helpers.test.ts", + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.test.ts", "lineNumber": 355 } }, { - "plugin": "securitySolution", + "plugin": "lists", "link": { - "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/helpers.test.ts", + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.test.ts", "lineNumber": 363 } }, { - "plugin": "securitySolution", + "plugin": "lists", "link": { - "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/helpers.test.ts", + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.test.ts", "lineNumber": 371 } }, { - "plugin": "securitySolution", + "plugin": "lists", "link": { - "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/helpers.test.ts", + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.test.ts", "lineNumber": 380 } }, { - "plugin": "securitySolution", + "plugin": "lists", "link": { - "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/operator.tsx", - "lineNumber": 11 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", + "lineNumber": 62 } }, { - "plugin": "securitySolution", + "plugin": "lists", "link": { - "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/operator.tsx", - "lineNumber": 17 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", + "lineNumber": 166 } }, { - "plugin": "securitySolution", + "plugin": "lists", "link": { - "path": "x-pack/plugins/security_solution/public/common/components/exceptions/helpers.test.tsx", - "lineNumber": 43 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", + "lineNumber": 167 } }, { - "plugin": "securitySolution", + "plugin": "lists", "link": { - "path": "x-pack/plugins/security_solution/public/common/components/exceptions/helpers.test.tsx", - "lineNumber": 104 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", + "lineNumber": 629 } }, { - "plugin": "lens", + "plugin": "lists", "link": { - "path": "x-pack/plugins/lens/server/routes/field_stats.ts", - "lineNumber": 11 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", + "lineNumber": 666 } }, { - "plugin": "lens", + "plugin": "lists", "link": { - "path": "x-pack/plugins/lens/server/routes/field_stats.ts", - "lineNumber": 139 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", + "lineNumber": 691 } }, { - "plugin": "lens", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/lens/server/routes/field_stats.ts", - "lineNumber": 248 + "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/helpers.test.ts", + "lineNumber": 11 } }, { - "plugin": "lens", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/lens/server/routes/field_stats.ts", - "lineNumber": 287 + "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/helpers.test.ts", + "lineNumber": 333 } }, { - "plugin": "lens", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/lens/server/routes/field_stats.ts", - "lineNumber": 329 + "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/helpers.test.ts", + "lineNumber": 339 } }, { - "plugin": "lens", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/lens/target/types/public/indexpattern_datasource/types.d.ts", - "lineNumber": 1 + "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/helpers.test.ts", + "lineNumber": 347 } }, { - "plugin": "lens", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/lens/target/types/public/indexpattern_datasource/types.d.ts", - "lineNumber": 22 + "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/helpers.test.ts", + "lineNumber": 355 } }, { - "plugin": "lens", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/lens/target/types/server/routes/field_stats.d.ts", - "lineNumber": 3 + "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/helpers.test.ts", + "lineNumber": 363 } }, { - "plugin": "lens", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/lens/target/types/server/routes/field_stats.d.ts", - "lineNumber": 7 + "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/helpers.test.ts", + "lineNumber": 371 } }, { - "plugin": "lens", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/lens/target/types/server/routes/field_stats.d.ts", - "lineNumber": 8 + "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/helpers.test.ts", + "lineNumber": 380 } }, { - "plugin": "lens", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/lens/target/types/server/routes/field_stats.d.ts", - "lineNumber": 9 + "path": "x-pack/plugins/security_solution/target/types/public/common/components/exceptions/helpers.test.d.ts", + "lineNumber": 1 + } + }, + { + "plugin": "securitySolution", + "link": { + "path": "x-pack/plugins/security_solution/target/types/public/common/components/exceptions/helpers.test.d.ts", + "lineNumber": 2 } }, { diff --git a/api_docs/data_index_patterns.json b/api_docs/data_index_patterns.json index 08c47437faa56..6d9230cfb6a87 100644 --- a/api_docs/data_index_patterns.json +++ b/api_docs/data_index_patterns.json @@ -5513,111 +5513,6 @@ "lineNumber": 58 } }, - { - "plugin": "fleet", - "link": { - "path": "x-pack/plugins/fleet/public/applications/fleet/components/search_bar.tsx", - "lineNumber": 10 - } - }, - { - "plugin": "fleet", - "link": { - "path": "x-pack/plugins/fleet/public/applications/fleet/components/search_bar.tsx", - "lineNumber": 33 - } - }, - { - "plugin": "fleet", - "link": { - "path": "x-pack/plugins/fleet/public/applications/fleet/components/search_bar.tsx", - "lineNumber": 51 - } - }, - { - "plugin": "indexPatternManagement", - "link": { - "path": "src/plugins/index_pattern_management/public/service/list/config.ts", - "lineNumber": 10 - } - }, - { - "plugin": "indexPatternManagement", - "link": { - "path": "src/plugins/index_pattern_management/public/service/list/config.ts", - "lineNumber": 42 - } - }, - { - "plugin": "indexPatternManagement", - "link": { - "path": "src/plugins/index_pattern_management/public/service/list/manager.ts", - "lineNumber": 9 - } - }, - { - "plugin": "indexPatternManagement", - "link": { - "path": "src/plugins/index_pattern_management/public/service/list/manager.ts", - "lineNumber": 43 - } - }, - { - "plugin": "indexPatternManagement", - "link": { - "path": "src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/lib/extract_time_fields.ts", - "lineNumber": 10 - } - }, - { - "plugin": "indexPatternManagement", - "link": { - "path": "src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/lib/extract_time_fields.ts", - "lineNumber": 12 - } - }, - { - "plugin": "indexPatternManagement", - "link": { - "path": "src/plugins/index_pattern_management/public/components/edit_index_pattern/indexed_fields_table/types.ts", - "lineNumber": 9 - } - }, - { - "plugin": "indexPatternManagement", - "link": { - "path": "src/plugins/index_pattern_management/public/components/edit_index_pattern/indexed_fields_table/types.ts", - "lineNumber": 11 - } - }, - { - "plugin": "indexPatternManagement", - "link": { - "path": "src/plugins/index_pattern_management/public/components/edit_index_pattern/indexed_fields_table/indexed_fields_table.tsx", - "lineNumber": 11 - } - }, - { - "plugin": "indexPatternManagement", - "link": { - "path": "src/plugins/index_pattern_management/public/components/edit_index_pattern/indexed_fields_table/indexed_fields_table.tsx", - "lineNumber": 23 - } - }, - { - "plugin": "indexPatternManagement", - "link": { - "path": "src/plugins/index_pattern_management/public/components/field_editor/field_editor.tsx", - "lineNumber": 45 - } - }, - { - "plugin": "indexPatternManagement", - "link": { - "path": "src/plugins/index_pattern_management/public/components/field_editor/field_editor.tsx", - "lineNumber": 148 - } - }, { "plugin": "maps", "link": { @@ -5982,6 +5877,90 @@ "lineNumber": 66 } }, + { + "plugin": "indexPatternManagement", + "link": { + "path": "src/plugins/index_pattern_management/public/service/list/config.ts", + "lineNumber": 10 + } + }, + { + "plugin": "indexPatternManagement", + "link": { + "path": "src/plugins/index_pattern_management/public/service/list/config.ts", + "lineNumber": 42 + } + }, + { + "plugin": "indexPatternManagement", + "link": { + "path": "src/plugins/index_pattern_management/public/service/list/manager.ts", + "lineNumber": 9 + } + }, + { + "plugin": "indexPatternManagement", + "link": { + "path": "src/plugins/index_pattern_management/public/service/list/manager.ts", + "lineNumber": 43 + } + }, + { + "plugin": "indexPatternManagement", + "link": { + "path": "src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/lib/extract_time_fields.ts", + "lineNumber": 10 + } + }, + { + "plugin": "indexPatternManagement", + "link": { + "path": "src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/lib/extract_time_fields.ts", + "lineNumber": 12 + } + }, + { + "plugin": "indexPatternManagement", + "link": { + "path": "src/plugins/index_pattern_management/public/components/edit_index_pattern/indexed_fields_table/types.ts", + "lineNumber": 9 + } + }, + { + "plugin": "indexPatternManagement", + "link": { + "path": "src/plugins/index_pattern_management/public/components/edit_index_pattern/indexed_fields_table/types.ts", + "lineNumber": 11 + } + }, + { + "plugin": "indexPatternManagement", + "link": { + "path": "src/plugins/index_pattern_management/public/components/edit_index_pattern/indexed_fields_table/indexed_fields_table.tsx", + "lineNumber": 11 + } + }, + { + "plugin": "indexPatternManagement", + "link": { + "path": "src/plugins/index_pattern_management/public/components/edit_index_pattern/indexed_fields_table/indexed_fields_table.tsx", + "lineNumber": 23 + } + }, + { + "plugin": "indexPatternManagement", + "link": { + "path": "src/plugins/index_pattern_management/public/components/field_editor/field_editor.tsx", + "lineNumber": 45 + } + }, + { + "plugin": "indexPatternManagement", + "link": { + "path": "src/plugins/index_pattern_management/public/components/field_editor/field_editor.tsx", + "lineNumber": 148 + } + }, { "plugin": "ml", "link": { @@ -6234,6 +6213,27 @@ "lineNumber": 21 } }, + { + "plugin": "fleet", + "link": { + "path": "x-pack/plugins/fleet/public/applications/fleet/components/search_bar.tsx", + "lineNumber": 10 + } + }, + { + "plugin": "fleet", + "link": { + "path": "x-pack/plugins/fleet/public/applications/fleet/components/search_bar.tsx", + "lineNumber": 33 + } + }, + { + "plugin": "fleet", + "link": { + "path": "x-pack/plugins/fleet/public/applications/fleet/components/search_bar.tsx", + "lineNumber": 51 + } + }, { "plugin": "fleet", "link": { @@ -6774,409 +6774,346 @@ } }, { - "plugin": "lists", + "plugin": "maps", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.ts", - "lineNumber": 19 + "path": "x-pack/plugins/maps/common/elasticsearch_util/es_agg_utils.ts", + "lineNumber": 10 } }, { - "plugin": "lists", + "plugin": "maps", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.ts", - "lineNumber": 30 + "path": "x-pack/plugins/maps/common/elasticsearch_util/es_agg_utils.ts", + "lineNumber": 16 } }, { - "plugin": "lists", + "plugin": "maps", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.ts", - "lineNumber": 54 + "path": "x-pack/plugins/maps/common/elasticsearch_util/es_agg_utils.ts", + "lineNumber": 29 } }, { - "plugin": "lists", + "plugin": "maps", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.ts", - "lineNumber": 84 + "path": "x-pack/plugins/maps/public/components/geo_field_select.tsx", + "lineNumber": 12 } }, { - "plugin": "lists", + "plugin": "maps", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.ts", - "lineNumber": 150 + "path": "x-pack/plugins/maps/public/components/geo_field_select.tsx", + "lineNumber": 16 } }, { - "plugin": "lists", + "plugin": "maps", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", - "lineNumber": 11 + "path": "x-pack/plugins/maps/public/classes/sources/es_search_source/top_hits/create_source_editor.tsx", + "lineNumber": 18 } }, { - "plugin": "lists", + "plugin": "maps", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", - "lineNumber": 26 + "path": "x-pack/plugins/maps/public/classes/sources/es_search_source/top_hits/create_source_editor.tsx", + "lineNumber": 30 } }, { - "plugin": "lists", + "plugin": "maps", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", - "lineNumber": 28 + "path": "x-pack/plugins/maps/public/classes/sources/es_search_source/top_hits/create_source_editor.tsx", + "lineNumber": 33 } }, { - "plugin": "lists", + "plugin": "maps", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", - "lineNumber": 57 + "path": "x-pack/plugins/maps/public/classes/sources/es_search_source/top_hits/create_source_editor.tsx", + "lineNumber": 35 } }, { - "plugin": "lists", + "plugin": "lens", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", - "lineNumber": 95 + "path": "x-pack/plugins/lens/public/indexpattern_datasource/types.ts", + "lineNumber": 8 } }, { - "plugin": "lists", + "plugin": "lens", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", - "lineNumber": 96 + "path": "x-pack/plugins/lens/public/indexpattern_datasource/types.ts", + "lineNumber": 57 } }, { - "plugin": "lists", + "plugin": "lens", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", - "lineNumber": 101 + "path": "x-pack/plugins/lens/server/routes/field_stats.ts", + "lineNumber": 11 } }, { - "plugin": "lists", + "plugin": "lens", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", - "lineNumber": 114 + "path": "x-pack/plugins/lens/server/routes/field_stats.ts", + "lineNumber": 139 } }, { - "plugin": "lists", + "plugin": "lens", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", - "lineNumber": 121 + "path": "x-pack/plugins/lens/server/routes/field_stats.ts", + "lineNumber": 248 } }, { - "plugin": "lists", + "plugin": "lens", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", - "lineNumber": 125 + "path": "x-pack/plugins/lens/server/routes/field_stats.ts", + "lineNumber": 287 } }, { - "plugin": "lists", + "plugin": "lens", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", - "lineNumber": 125 + "path": "x-pack/plugins/lens/server/routes/field_stats.ts", + "lineNumber": 329 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", - "lineNumber": 130 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.ts", + "lineNumber": 19 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", - "lineNumber": 131 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.ts", + "lineNumber": 30 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", - "lineNumber": 133 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.ts", + "lineNumber": 54 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", - "lineNumber": 134 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.ts", + "lineNumber": 84 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/operator.tsx", - "lineNumber": 11 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.ts", + "lineNumber": 150 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/operator.tsx", - "lineNumber": 27 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", + "lineNumber": 11 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/hooks/use_field_value_autocomplete.ts", - "lineNumber": 13 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", + "lineNumber": 26 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/hooks/use_field_value_autocomplete.ts", - "lineNumber": 16 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", + "lineNumber": 28 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/hooks/use_field_value_autocomplete.ts", - "lineNumber": 32 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", + "lineNumber": 57 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field_value_match.tsx", - "lineNumber": 19 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", + "lineNumber": 95 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field_value_match.tsx", - "lineNumber": 36 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", + "lineNumber": 96 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field_value_match_any.tsx", - "lineNumber": 13 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", + "lineNumber": 101 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field_value_match_any.tsx", - "lineNumber": 23 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", + "lineNumber": 114 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field_value_lists.tsx", - "lineNumber": 13 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", + "lineNumber": 121 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field_value_lists.tsx", - "lineNumber": 29 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", + "lineNumber": 125 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.tsx", - "lineNumber": 31 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", + "lineNumber": 125 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.tsx", - "lineNumber": 91 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", + "lineNumber": 130 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.test.ts", - "lineNumber": 19 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", + "lineNumber": 131 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.test.ts", - "lineNumber": 333 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", + "lineNumber": 133 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.test.ts", - "lineNumber": 339 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", + "lineNumber": 134 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.test.ts", - "lineNumber": 347 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/operator.tsx", + "lineNumber": 11 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.test.ts", - "lineNumber": 355 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/operator.tsx", + "lineNumber": 27 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.test.ts", - "lineNumber": 363 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/hooks/use_field_value_autocomplete.ts", + "lineNumber": 13 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.test.ts", - "lineNumber": 371 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/hooks/use_field_value_autocomplete.ts", + "lineNumber": 16 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.test.ts", - "lineNumber": 380 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/hooks/use_field_value_autocomplete.ts", + "lineNumber": 32 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", - "lineNumber": 62 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field_value_match.tsx", + "lineNumber": 19 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", - "lineNumber": 166 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field_value_match.tsx", + "lineNumber": 36 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", - "lineNumber": 167 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field_value_match_any.tsx", + "lineNumber": 13 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", - "lineNumber": 629 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field_value_match_any.tsx", + "lineNumber": 23 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", - "lineNumber": 666 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field_value_lists.tsx", + "lineNumber": 14 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", - "lineNumber": 691 - } - }, - { - "plugin": "lens", - "link": { - "path": "x-pack/plugins/lens/public/indexpattern_datasource/types.ts", - "lineNumber": 8 - } - }, - { - "plugin": "lens", - "link": { - "path": "x-pack/plugins/lens/public/indexpattern_datasource/types.ts", - "lineNumber": 57 - } - }, - { - "plugin": "maps", - "link": { - "path": "x-pack/plugins/maps/common/elasticsearch_util/es_agg_utils.ts", - "lineNumber": 10 - } - }, - { - "plugin": "maps", - "link": { - "path": "x-pack/plugins/maps/common/elasticsearch_util/es_agg_utils.ts", - "lineNumber": 16 - } - }, - { - "plugin": "maps", - "link": { - "path": "x-pack/plugins/maps/common/elasticsearch_util/es_agg_utils.ts", + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field_value_lists.tsx", "lineNumber": 29 } }, { - "plugin": "maps", - "link": { - "path": "x-pack/plugins/maps/public/components/geo_field_select.tsx", - "lineNumber": 12 - } - }, - { - "plugin": "maps", - "link": { - "path": "x-pack/plugins/maps/public/components/geo_field_select.tsx", - "lineNumber": 16 - } - }, - { - "plugin": "maps", - "link": { - "path": "x-pack/plugins/maps/public/classes/sources/es_search_source/top_hits/create_source_editor.tsx", - "lineNumber": 18 - } - }, - { - "plugin": "maps", - "link": { - "path": "x-pack/plugins/maps/public/classes/sources/es_search_source/top_hits/create_source_editor.tsx", - "lineNumber": 30 - } - }, - { - "plugin": "maps", + "plugin": "lists", "link": { - "path": "x-pack/plugins/maps/public/classes/sources/es_search_source/top_hits/create_source_editor.tsx", - "lineNumber": 33 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.tsx", + "lineNumber": 31 } }, { - "plugin": "maps", + "plugin": "lists", "link": { - "path": "x-pack/plugins/maps/public/classes/sources/es_search_source/top_hits/create_source_editor.tsx", - "lineNumber": 35 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.tsx", + "lineNumber": 91 } }, { @@ -7418,192 +7355,213 @@ } }, { - "plugin": "securitySolution", + "plugin": "lens", "link": { - "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/field_value_lists.tsx", - "lineNumber": 12 + "path": "x-pack/plugins/lens/target/types/public/indexpattern_datasource/types.d.ts", + "lineNumber": 1 } }, { - "plugin": "securitySolution", + "plugin": "lens", "link": { - "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/field_value_lists.tsx", - "lineNumber": 20 - } + "path": "x-pack/plugins/lens/target/types/public/indexpattern_datasource/types.d.ts", + "lineNumber": 22 + } }, { - "plugin": "securitySolution", + "plugin": "lens", "link": { - "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/field_value_match_any.tsx", - "lineNumber": 13 + "path": "x-pack/plugins/lens/target/types/server/routes/field_stats.d.ts", + "lineNumber": 3 } }, { - "plugin": "securitySolution", + "plugin": "lens", "link": { - "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/field_value_match_any.tsx", - "lineNumber": 22 + "path": "x-pack/plugins/lens/target/types/server/routes/field_stats.d.ts", + "lineNumber": 7 } }, { - "plugin": "securitySolution", + "plugin": "lens", "link": { - "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/helpers.test.ts", - "lineNumber": 11 + "path": "x-pack/plugins/lens/target/types/server/routes/field_stats.d.ts", + "lineNumber": 8 } }, { - "plugin": "securitySolution", + "plugin": "lens", "link": { - "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/helpers.test.ts", + "path": "x-pack/plugins/lens/target/types/server/routes/field_stats.d.ts", + "lineNumber": 9 + } + }, + { + "plugin": "lists", + "link": { + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.test.ts", + "lineNumber": 19 + } + }, + { + "plugin": "lists", + "link": { + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.test.ts", "lineNumber": 333 } }, { - "plugin": "securitySolution", + "plugin": "lists", "link": { - "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/helpers.test.ts", + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.test.ts", "lineNumber": 339 } }, { - "plugin": "securitySolution", + "plugin": "lists", "link": { - "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/helpers.test.ts", + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.test.ts", "lineNumber": 347 } }, { - "plugin": "securitySolution", + "plugin": "lists", "link": { - "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/helpers.test.ts", + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.test.ts", "lineNumber": 355 } }, { - "plugin": "securitySolution", + "plugin": "lists", "link": { - "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/helpers.test.ts", + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.test.ts", "lineNumber": 363 } }, { - "plugin": "securitySolution", + "plugin": "lists", "link": { - "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/helpers.test.ts", + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.test.ts", "lineNumber": 371 } }, { - "plugin": "securitySolution", + "plugin": "lists", "link": { - "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/helpers.test.ts", + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/helpers.test.ts", "lineNumber": 380 } }, { - "plugin": "securitySolution", + "plugin": "lists", "link": { - "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/operator.tsx", - "lineNumber": 11 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", + "lineNumber": 62 } }, { - "plugin": "securitySolution", + "plugin": "lists", "link": { - "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/operator.tsx", - "lineNumber": 17 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", + "lineNumber": 166 } }, { - "plugin": "securitySolution", + "plugin": "lists", "link": { - "path": "x-pack/plugins/security_solution/public/common/components/exceptions/helpers.test.tsx", - "lineNumber": 43 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", + "lineNumber": 167 } }, { - "plugin": "securitySolution", + "plugin": "lists", "link": { - "path": "x-pack/plugins/security_solution/public/common/components/exceptions/helpers.test.tsx", - "lineNumber": 104 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", + "lineNumber": 629 } }, { - "plugin": "lens", + "plugin": "lists", "link": { - "path": "x-pack/plugins/lens/server/routes/field_stats.ts", - "lineNumber": 11 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", + "lineNumber": 666 } }, { - "plugin": "lens", + "plugin": "lists", "link": { - "path": "x-pack/plugins/lens/server/routes/field_stats.ts", - "lineNumber": 139 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", + "lineNumber": 691 } }, { - "plugin": "lens", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/lens/server/routes/field_stats.ts", - "lineNumber": 248 + "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/helpers.test.ts", + "lineNumber": 11 } }, { - "plugin": "lens", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/lens/server/routes/field_stats.ts", - "lineNumber": 287 + "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/helpers.test.ts", + "lineNumber": 333 } }, { - "plugin": "lens", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/lens/server/routes/field_stats.ts", - "lineNumber": 329 + "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/helpers.test.ts", + "lineNumber": 339 } }, { - "plugin": "lens", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/lens/target/types/public/indexpattern_datasource/types.d.ts", - "lineNumber": 1 + "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/helpers.test.ts", + "lineNumber": 347 } }, { - "plugin": "lens", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/lens/target/types/public/indexpattern_datasource/types.d.ts", - "lineNumber": 22 + "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/helpers.test.ts", + "lineNumber": 355 } }, { - "plugin": "lens", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/lens/target/types/server/routes/field_stats.d.ts", - "lineNumber": 3 + "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/helpers.test.ts", + "lineNumber": 363 } }, { - "plugin": "lens", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/lens/target/types/server/routes/field_stats.d.ts", - "lineNumber": 7 + "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/helpers.test.ts", + "lineNumber": 371 } }, { - "plugin": "lens", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/lens/target/types/server/routes/field_stats.d.ts", - "lineNumber": 8 + "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/helpers.test.ts", + "lineNumber": 380 } }, { - "plugin": "lens", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/lens/target/types/server/routes/field_stats.d.ts", - "lineNumber": 9 + "path": "x-pack/plugins/security_solution/target/types/public/common/components/exceptions/helpers.test.d.ts", + "lineNumber": 1 + } + }, + { + "plugin": "securitySolution", + "link": { + "path": "x-pack/plugins/security_solution/target/types/public/common/components/exceptions/helpers.test.d.ts", + "lineNumber": 2 } }, { @@ -8130,48 +8088,6 @@ }, "deprecated": true, "references": [ - { - "plugin": "lists", - "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/exception_items_renderer.tsx", - "lineNumber": 34 - } - }, - { - "plugin": "lists", - "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/exception_items_renderer.tsx", - "lineNumber": 78 - } - }, - { - "plugin": "lists", - "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/exception_items_renderer.tsx", - "lineNumber": 86 - } - }, - { - "plugin": "lists", - "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/exception_items_renderer.tsx", - "lineNumber": 88 - } - }, - { - "plugin": "securitySolution", - "link": { - "path": "x-pack/plugins/security_solution/common/search_strategy/index_fields/index.ts", - "lineNumber": 8 - } - }, - { - "plugin": "securitySolution", - "link": { - "path": "x-pack/plugins/security_solution/common/search_strategy/index_fields/index.ts", - "lineNumber": 86 - } - }, { "plugin": "savedObjects", "link": { @@ -8264,206 +8180,178 @@ } }, { - "plugin": "savedObjectsManagement", + "plugin": "indexPatternManagement", "link": { - "path": "src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.tsx", - "lineNumber": 37 + "path": "src/plugins/index_pattern_management/public/service/list/config.ts", + "lineNumber": 10 } }, { - "plugin": "savedObjectsManagement", + "plugin": "indexPatternManagement", "link": { - "path": "src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.tsx", - "lineNumber": 89 + "path": "src/plugins/index_pattern_management/public/service/list/config.ts", + "lineNumber": 29 } }, { - "plugin": "infra", + "plugin": "indexPatternManagement", "link": { - "path": "x-pack/plugins/infra/public/containers/with_kuery_autocompletion.tsx", - "lineNumber": 9 + "path": "src/plugins/index_pattern_management/public/service/list/config.ts", + "lineNumber": 29 } }, { - "plugin": "infra", + "plugin": "indexPatternManagement", "link": { - "path": "x-pack/plugins/infra/public/containers/with_kuery_autocompletion.tsx", - "lineNumber": 24 + "path": "src/plugins/index_pattern_management/public/service/list/config.ts", + "lineNumber": 42 } }, { - "plugin": "infra", + "plugin": "indexPatternManagement", "link": { - "path": "x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/kuery_bar.tsx", - "lineNumber": 15 + "path": "src/plugins/index_pattern_management/public/service/list/config.ts", + "lineNumber": 46 } }, { - "plugin": "infra", + "plugin": "indexPatternManagement", "link": { - "path": "x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/kuery_bar.tsx", - "lineNumber": 28 + "path": "src/plugins/index_pattern_management/public/service/list/manager.ts", + "lineNumber": 9 } }, { - "plugin": "lens", + "plugin": "indexPatternManagement", "link": { - "path": "x-pack/plugins/lens/public/editor_frame_service/embeddable/embeddable.tsx", - "lineNumber": 14 + "path": "src/plugins/index_pattern_management/public/service/list/manager.ts", + "lineNumber": 32 } }, { - "plugin": "lens", + "plugin": "indexPatternManagement", "link": { - "path": "x-pack/plugins/lens/public/editor_frame_service/embeddable/embeddable.tsx", - "lineNumber": 85 + "path": "src/plugins/index_pattern_management/public/service/list/manager.ts", + "lineNumber": 32 } }, { - "plugin": "lens", + "plugin": "indexPatternManagement", "link": { - "path": "x-pack/plugins/lens/public/indexpattern_datasource/field_item.tsx", - "lineNumber": 47 + "path": "src/plugins/index_pattern_management/public/service/list/manager.ts", + "lineNumber": 43 } }, { - "plugin": "lens", + "plugin": "indexPatternManagement", "link": { - "path": "x-pack/plugins/lens/public/indexpattern_datasource/field_item.tsx", - "lineNumber": 172 + "path": "src/plugins/index_pattern_management/public/service/list/manager.ts", + "lineNumber": 50 } }, { - "plugin": "lens", + "plugin": "indexPatternManagement", "link": { - "path": "x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx", - "lineNumber": 42 - } - }, - { - "plugin": "lens", - "link": { - "path": "x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx", - "lineNumber": 96 - } - }, - { - "plugin": "lens", - "link": { - "path": "x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx", - "lineNumber": 166 - } - }, - { - "plugin": "indexPatternManagement", - "link": { - "path": "src/plugins/index_pattern_management/public/service/list/config.ts", - "lineNumber": 10 - } - }, - { - "plugin": "indexPatternManagement", - "link": { - "path": "src/plugins/index_pattern_management/public/service/list/config.ts", - "lineNumber": 29 + "path": "src/plugins/index_pattern_management/public/components/edit_index_pattern/indexed_fields_table/components/table/table.tsx", + "lineNumber": 22 } }, { "plugin": "indexPatternManagement", "link": { - "path": "src/plugins/index_pattern_management/public/service/list/config.ts", - "lineNumber": 29 + "path": "src/plugins/index_pattern_management/public/components/edit_index_pattern/indexed_fields_table/components/table/table.tsx", + "lineNumber": 171 } }, { "plugin": "indexPatternManagement", "link": { - "path": "src/plugins/index_pattern_management/public/service/list/config.ts", - "lineNumber": 42 + "path": "src/plugins/index_pattern_management/public/components/edit_index_pattern/scripted_fields_table/components/table/table.tsx", + "lineNumber": 15 } }, { "plugin": "indexPatternManagement", "link": { - "path": "src/plugins/index_pattern_management/public/service/list/config.ts", - "lineNumber": 46 + "path": "src/plugins/index_pattern_management/public/components/edit_index_pattern/scripted_fields_table/components/table/table.tsx", + "lineNumber": 18 } }, { "plugin": "indexPatternManagement", "link": { - "path": "src/plugins/index_pattern_management/public/service/list/manager.ts", - "lineNumber": 9 + "path": "src/plugins/index_pattern_management/public/components/edit_index_pattern/index_header/index_header.tsx", + "lineNumber": 12 } }, { "plugin": "indexPatternManagement", "link": { - "path": "src/plugins/index_pattern_management/public/service/list/manager.ts", - "lineNumber": 32 + "path": "src/plugins/index_pattern_management/public/components/edit_index_pattern/index_header/index_header.tsx", + "lineNumber": 15 } }, { - "plugin": "indexPatternManagement", + "plugin": "savedObjectsManagement", "link": { - "path": "src/plugins/index_pattern_management/public/service/list/manager.ts", - "lineNumber": 32 + "path": "src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.tsx", + "lineNumber": 37 } }, { - "plugin": "indexPatternManagement", + "plugin": "savedObjectsManagement", "link": { - "path": "src/plugins/index_pattern_management/public/service/list/manager.ts", - "lineNumber": 43 + "path": "src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.tsx", + "lineNumber": 89 } }, { - "plugin": "indexPatternManagement", + "plugin": "lens", "link": { - "path": "src/plugins/index_pattern_management/public/service/list/manager.ts", - "lineNumber": 50 + "path": "x-pack/plugins/lens/public/editor_frame_service/embeddable/embeddable.tsx", + "lineNumber": 14 } }, { - "plugin": "indexPatternManagement", + "plugin": "lens", "link": { - "path": "src/plugins/index_pattern_management/public/components/edit_index_pattern/indexed_fields_table/components/table/table.tsx", - "lineNumber": 22 + "path": "x-pack/plugins/lens/public/editor_frame_service/embeddable/embeddable.tsx", + "lineNumber": 85 } }, { - "plugin": "indexPatternManagement", + "plugin": "lens", "link": { - "path": "src/plugins/index_pattern_management/public/components/edit_index_pattern/indexed_fields_table/components/table/table.tsx", - "lineNumber": 171 + "path": "x-pack/plugins/lens/public/indexpattern_datasource/field_item.tsx", + "lineNumber": 47 } }, { - "plugin": "indexPatternManagement", + "plugin": "lens", "link": { - "path": "src/plugins/index_pattern_management/public/components/edit_index_pattern/scripted_fields_table/components/table/table.tsx", - "lineNumber": 15 + "path": "x-pack/plugins/lens/public/indexpattern_datasource/field_item.tsx", + "lineNumber": 172 } }, { - "plugin": "indexPatternManagement", + "plugin": "lens", "link": { - "path": "src/plugins/index_pattern_management/public/components/edit_index_pattern/scripted_fields_table/components/table/table.tsx", - "lineNumber": 18 + "path": "x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx", + "lineNumber": 42 } }, { - "plugin": "indexPatternManagement", + "plugin": "lens", "link": { - "path": "src/plugins/index_pattern_management/public/components/edit_index_pattern/index_header/index_header.tsx", - "lineNumber": 12 + "path": "x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx", + "lineNumber": 96 } }, { - "plugin": "indexPatternManagement", + "plugin": "lens", "link": { - "path": "src/plugins/index_pattern_management/public/components/edit_index_pattern/index_header/index_header.tsx", - "lineNumber": 15 + "path": "x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx", + "lineNumber": 166 } }, { @@ -8536,6 +8424,48 @@ "lineNumber": 30 } }, + { + "plugin": "apm", + "link": { + "path": "x-pack/plugins/apm/public/components/shared/KueryBar/index.tsx", + "lineNumber": 14 + } + }, + { + "plugin": "apm", + "link": { + "path": "x-pack/plugins/apm/public/components/shared/KueryBar/index.tsx", + "lineNumber": 31 + } + }, + { + "plugin": "infra", + "link": { + "path": "x-pack/plugins/infra/public/containers/with_kuery_autocompletion.tsx", + "lineNumber": 9 + } + }, + { + "plugin": "infra", + "link": { + "path": "x-pack/plugins/infra/public/containers/with_kuery_autocompletion.tsx", + "lineNumber": 24 + } + }, + { + "plugin": "infra", + "link": { + "path": "x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/kuery_bar.tsx", + "lineNumber": 15 + } + }, + { + "plugin": "infra", + "link": { + "path": "x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/kuery_bar.tsx", + "lineNumber": 28 + } + }, { "plugin": "infra", "link": { @@ -8676,32 +8606,74 @@ "lineNumber": 23 } }, + { + "plugin": "lists", + "link": { + "path": "x-pack/plugins/lists/public/exceptions/components/builder/exception_items_renderer.tsx", + "lineNumber": 34 + } + }, + { + "plugin": "lists", + "link": { + "path": "x-pack/plugins/lists/public/exceptions/components/builder/exception_items_renderer.tsx", + "lineNumber": 78 + } + }, + { + "plugin": "lists", + "link": { + "path": "x-pack/plugins/lists/public/exceptions/components/builder/exception_items_renderer.tsx", + "lineNumber": 86 + } + }, + { + "plugin": "lists", + "link": { + "path": "x-pack/plugins/lists/public/exceptions/components/builder/exception_items_renderer.tsx", + "lineNumber": 88 + } + }, { "plugin": "securitySolution", "link": { "path": "x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/types.ts", - "lineNumber": 20 + "lineNumber": 21 } }, { "plugin": "securitySolution", "link": { "path": "x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/types.ts", - "lineNumber": 64 + "lineNumber": 66 } }, { "plugin": "securitySolution", "link": { "path": "x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/action.ts", - "lineNumber": 17 + "lineNumber": 19 } }, { "plugin": "securitySolution", "link": { "path": "x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/action.ts", - "lineNumber": 98 + "lineNumber": 100 + } + }, + { + "plugin": "securitySolution", + "link": { + "path": "x-pack/plugins/security_solution/common/search_strategy/index_fields/index.ts", + "lineNumber": 8 + } + }, + { + "plugin": "securitySolution", + "link": { + "path": "x-pack/plugins/security_solution/common/search_strategy/index_fields/index.ts", + "lineNumber": 86 } }, { @@ -8939,21 +8911,21 @@ "plugin": "securitySolution", "link": { "path": "x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts", - "lineNumber": 32 + "lineNumber": 40 } }, { "plugin": "securitySolution", "link": { "path": "x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts", - "lineNumber": 38 + "lineNumber": 55 } }, { "plugin": "securitySolution", "link": { "path": "x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts", - "lineNumber": 43 + "lineNumber": 60 } }, { @@ -9040,34 +9012,6 @@ "lineNumber": 33 } }, - { - "plugin": "securitySolution", - "link": { - "path": "x-pack/plugins/security_solution/public/common/containers/kuery_autocompletion/index.tsx", - "lineNumber": 9 - } - }, - { - "plugin": "securitySolution", - "link": { - "path": "x-pack/plugins/security_solution/public/common/containers/kuery_autocompletion/index.tsx", - "lineNumber": 21 - } - }, - { - "plugin": "apm", - "link": { - "path": "x-pack/plugins/apm/public/components/shared/KueryBar/index.tsx", - "lineNumber": 14 - } - }, - { - "plugin": "apm", - "link": { - "path": "x-pack/plugins/apm/public/components/shared/KueryBar/index.tsx", - "lineNumber": 31 - } - }, { "plugin": "uptime", "link": { @@ -9110,6 +9054,20 @@ "lineNumber": 36 } }, + { + "plugin": "securitySolution", + "link": { + "path": "x-pack/plugins/security_solution/target/types/common/search_strategy/index_fields/index.d.ts", + "lineNumber": 1 + } + }, + { + "plugin": "securitySolution", + "link": { + "path": "x-pack/plugins/security_solution/target/types/common/search_strategy/index_fields/index.d.ts", + "lineNumber": 66 + } + }, { "plugin": "infra", "link": { @@ -9153,507 +9111,479 @@ } }, { - "plugin": "infra", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/infra/target/types/public/alerting/metric_threshold/components/expression_chart.d.ts", - "lineNumber": 2 + "path": "x-pack/plugins/security_solution/target/types/public/common/containers/source/index.d.ts", + "lineNumber": 1 } }, { - "plugin": "infra", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/infra/target/types/public/alerting/metric_threshold/components/expression_chart.d.ts", - "lineNumber": 7 + "path": "x-pack/plugins/security_solution/target/types/public/common/containers/source/index.d.ts", + "lineNumber": 10 } }, { - "plugin": "infra", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/infra/target/types/public/alerting/metric_threshold/hooks/use_metrics_explorer_chart_data.d.ts", - "lineNumber": 1 - } - }, - { - "plugin": "infra", - "link": { - "path": "x-pack/plugins/infra/target/types/public/alerting/metric_threshold/hooks/use_metrics_explorer_chart_data.d.ts", - "lineNumber": 4 + "path": "x-pack/plugins/security_solution/target/types/public/common/containers/source/index.d.ts", + "lineNumber": 23 } }, { "plugin": "infra", "link": { - "path": "x-pack/plugins/infra/target/types/public/pages/metrics/metrics_explorer/index.d.ts", - "lineNumber": 1 + "path": "x-pack/plugins/infra/target/types/public/alerting/metric_threshold/components/expression_chart.d.ts", + "lineNumber": 2 } }, { "plugin": "infra", "link": { - "path": "x-pack/plugins/infra/target/types/public/pages/metrics/metrics_explorer/index.d.ts", - "lineNumber": 5 + "path": "x-pack/plugins/infra/target/types/public/alerting/metric_threshold/components/expression_chart.d.ts", + "lineNumber": 7 } }, { "plugin": "infra", "link": { - "path": "x-pack/plugins/infra/target/types/public/pages/metrics/metrics_explorer/hooks/use_metric_explorer_state.d.ts", + "path": "x-pack/plugins/infra/target/types/public/alerting/metric_threshold/hooks/use_metrics_explorer_chart_data.d.ts", "lineNumber": 1 } }, { "plugin": "infra", "link": { - "path": "x-pack/plugins/infra/target/types/public/pages/metrics/metrics_explorer/hooks/use_metric_explorer_state.d.ts", - "lineNumber": 11 + "path": "x-pack/plugins/infra/target/types/public/alerting/metric_threshold/hooks/use_metrics_explorer_chart_data.d.ts", + "lineNumber": 4 } }, { "plugin": "infra", "link": { - "path": "x-pack/plugins/infra/target/types/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_data.d.ts", + "path": "x-pack/plugins/infra/target/types/public/pages/metrics/metrics_explorer/index.d.ts", "lineNumber": 1 } }, { "plugin": "infra", "link": { - "path": "x-pack/plugins/infra/target/types/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_data.d.ts", - "lineNumber": 4 + "path": "x-pack/plugins/infra/target/types/public/pages/metrics/metrics_explorer/index.d.ts", + "lineNumber": 5 } }, { - "plugin": "ml", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/ml/target/types/public/application/jobs/new_job/common/index_pattern_context.d.ts", - "lineNumber": 2 + "path": "x-pack/plugins/security_solution/target/types/public/common/components/url_state/types.d.ts", + "lineNumber": 3 } }, { - "plugin": "ml", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/ml/target/types/public/application/jobs/new_job/common/index_pattern_context.d.ts", - "lineNumber": 3 + "path": "x-pack/plugins/security_solution/target/types/public/common/components/url_state/types.d.ts", + "lineNumber": 25 } }, { - "plugin": "ml", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/ml/target/types/public/application/jobs/new_job/common/index_pattern_context.d.ts", - "lineNumber": 4 + "path": "x-pack/plugins/security_solution/target/types/public/common/components/url_state/types.d.ts", + "lineNumber": 55 } }, { - "plugin": "lists", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", - "lineNumber": 11 + "path": "x-pack/plugins/security_solution/target/types/public/network/components/network_top_countries_table/columns.d.ts", + "lineNumber": 1 } }, { - "plugin": "lists", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", - "lineNumber": 21 + "path": "x-pack/plugins/security_solution/target/types/public/network/components/network_top_countries_table/columns.d.ts", + "lineNumber": 20 } }, { - "plugin": "lists", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", - "lineNumber": 100 + "path": "x-pack/plugins/security_solution/target/types/public/network/components/network_top_countries_table/columns.d.ts", + "lineNumber": 21 } }, { - "plugin": "lists", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", - "lineNumber": 121 + "path": "x-pack/plugins/security_solution/target/types/public/common/components/search_bar/index.d.ts", + "lineNumber": 3 } }, { - "plugin": "lists", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/hooks/use_field_value_autocomplete.ts", - "lineNumber": 13 + "path": "x-pack/plugins/security_solution/target/types/public/common/components/search_bar/index.d.ts", + "lineNumber": 9 } }, { - "plugin": "lists", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/hooks/use_field_value_autocomplete.ts", - "lineNumber": 17 + "path": "x-pack/plugins/security_solution/target/types/public/hosts/pages/details/types.d.ts", + "lineNumber": 2 } }, { - "plugin": "lists", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/hooks/use_field_value_autocomplete.ts", - "lineNumber": 29 + "path": "x-pack/plugins/security_solution/target/types/public/hosts/pages/details/types.d.ts", + "lineNumber": 40 } }, { - "plugin": "lists", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field_value_match.tsx", - "lineNumber": 19 + "path": "x-pack/plugins/security_solution/target/types/public/network/components/network_top_countries_table/index.d.ts", + "lineNumber": 2 } }, { - "plugin": "lists", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field_value_match.tsx", - "lineNumber": 38 + "path": "x-pack/plugins/security_solution/target/types/public/network/components/network_top_countries_table/index.d.ts", + "lineNumber": 10 } }, { - "plugin": "lists", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field_value_match_any.tsx", - "lineNumber": 13 + "path": "x-pack/plugins/security_solution/target/types/public/network/pages/details/types.d.ts", + "lineNumber": 1 } }, { - "plugin": "lists", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field_value_match_any.tsx", + "path": "x-pack/plugins/security_solution/target/types/public/network/pages/details/types.d.ts", "lineNumber": 25 } }, { - "plugin": "lists", + "plugin": "infra", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.tsx", - "lineNumber": 31 + "path": "x-pack/plugins/infra/target/types/public/pages/metrics/metrics_explorer/hooks/use_metric_explorer_state.d.ts", + "lineNumber": 1 } }, { - "plugin": "lists", + "plugin": "infra", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.tsx", - "lineNumber": 53 + "path": "x-pack/plugins/infra/target/types/public/pages/metrics/metrics_explorer/hooks/use_metric_explorer_state.d.ts", + "lineNumber": 11 } }, { - "plugin": "lists", + "plugin": "infra", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.tsx", - "lineNumber": 58 + "path": "x-pack/plugins/infra/target/types/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_data.d.ts", + "lineNumber": 1 } }, { - "plugin": "lists", + "plugin": "infra", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.tsx", - "lineNumber": 61 + "path": "x-pack/plugins/infra/target/types/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_data.d.ts", + "lineNumber": 4 } }, { - "plugin": "lists", + "plugin": "ml", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/exception_item_renderer.tsx", - "lineNumber": 22 + "path": "x-pack/plugins/ml/target/types/public/application/jobs/new_job/common/index_pattern_context.d.ts", + "lineNumber": 2 } }, { - "plugin": "lists", + "plugin": "ml", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/exception_item_renderer.tsx", - "lineNumber": 50 + "path": "x-pack/plugins/ml/target/types/public/application/jobs/new_job/common/index_pattern_context.d.ts", + "lineNumber": 3 } }, { - "plugin": "lists", + "plugin": "ml", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/exception_item_renderer.tsx", - "lineNumber": 55 + "path": "x-pack/plugins/ml/target/types/public/application/jobs/new_job/common/index_pattern_context.d.ts", + "lineNumber": 4 } }, { - "plugin": "lists", + "plugin": "ml", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/exception_item_renderer.tsx", - "lineNumber": 58 + "path": "x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/action_clone/clone_action_name.tsx", + "lineNumber": 12 } }, { - "plugin": "lists", + "plugin": "ml", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", - "lineNumber": 62 + "path": "x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/action_clone/clone_action_name.tsx", + "lineNumber": 412 } }, { - "plugin": "lists", + "plugin": "ml", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", - "lineNumber": 96 + "path": "x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/action_delete/use_delete_action.tsx", + "lineNumber": 12 } }, { - "plugin": "lists", + "plugin": "ml", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", - "lineNumber": 169 + "path": "x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/action_delete/use_delete_action.tsx", + "lineNumber": 60 } }, { - "plugin": "lists", + "plugin": "ml", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", - "lineNumber": 169 + "path": "x-pack/plugins/ml/public/application/jobs/components/custom_url_editor/utils.d.ts", + "lineNumber": 8 } }, { - "plugin": "lists", + "plugin": "ml", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", - "lineNumber": 184 + "path": "x-pack/plugins/ml/public/application/jobs/components/custom_url_editor/utils.d.ts", + "lineNumber": 37 } }, { - "plugin": "lists", + "plugin": "ml", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", - "lineNumber": 187 + "path": "x-pack/plugins/ml/public/application/jobs/jobs_list/components/edit_job_flyout/edit_utils.d.ts", + "lineNumber": 8 } }, { - "plugin": "lists", + "plugin": "ml", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", - "lineNumber": 196 + "path": "x-pack/plugins/ml/public/application/jobs/jobs_list/components/edit_job_flyout/edit_utils.d.ts", + "lineNumber": 11 } }, { - "plugin": "lists", + "plugin": "ml", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", - "lineNumber": 199 + "path": "x-pack/plugins/ml/public/application/datavisualizer/index_based/components/actions_panel/actions_panel.tsx", + "lineNumber": 25 } }, { - "plugin": "lists", + "plugin": "ml", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", - "lineNumber": 208 + "path": "x-pack/plugins/ml/public/application/datavisualizer/index_based/components/actions_panel/actions_panel.tsx", + "lineNumber": 28 } }, { - "plugin": "lists", + "plugin": "infra", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", - "lineNumber": 214 + "path": "x-pack/plugins/infra/public/pages/metrics/index.tsx", + "lineNumber": 14 } }, { - "plugin": "lists", + "plugin": "infra", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", - "lineNumber": 226 + "path": "x-pack/plugins/infra/public/pages/metrics/index.tsx", + "lineNumber": 193 } }, { - "plugin": "lists", + "plugin": "visTypeTimeseries", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", - "lineNumber": 229 + "path": "src/plugins/vis_type_timeseries/common/index_patterns_utils.ts", + "lineNumber": 11 } }, { - "plugin": "lists", + "plugin": "visTypeTimeseries", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", - "lineNumber": 239 + "path": "src/plugins/vis_type_timeseries/common/index_patterns_utils.ts", + "lineNumber": 20 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", - "lineNumber": 267 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", + "lineNumber": 11 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", - "lineNumber": 285 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", + "lineNumber": 21 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", - "lineNumber": 320 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", + "lineNumber": 100 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", - "lineNumber": 336 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field.tsx", + "lineNumber": 121 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", - "lineNumber": 1026 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/hooks/use_field_value_autocomplete.ts", + "lineNumber": 13 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", - "lineNumber": 1045 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/hooks/use_field_value_autocomplete.ts", + "lineNumber": 17 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", - "lineNumber": 1095 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/hooks/use_field_value_autocomplete.ts", + "lineNumber": 29 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", - "lineNumber": 1251 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field_value_match.tsx", + "lineNumber": 19 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", - "lineNumber": 1302 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field_value_match.tsx", + "lineNumber": 38 } }, { "plugin": "lists", "link": { - "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", - "lineNumber": 1352 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field_value_match_any.tsx", + "lineNumber": 13 } }, { - "plugin": "securitySolution", + "plugin": "lists", "link": { - "path": "x-pack/plugins/security_solution/common/detection_engine/get_query_filter.ts", - "lineNumber": 15 + "path": "x-pack/plugins/lists/public/exceptions/components/autocomplete/field_value_match_any.tsx", + "lineNumber": 25 } }, { - "plugin": "securitySolution", + "plugin": "lists", "link": { - "path": "x-pack/plugins/security_solution/common/detection_engine/get_query_filter.ts", + "path": "x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.tsx", "lineNumber": 31 } }, { - "plugin": "ml", - "link": { - "path": "x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/action_clone/clone_action_name.tsx", - "lineNumber": 12 - } - }, - { - "plugin": "ml", - "link": { - "path": "x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/action_clone/clone_action_name.tsx", - "lineNumber": 412 - } - }, - { - "plugin": "ml", - "link": { - "path": "x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/action_delete/use_delete_action.tsx", - "lineNumber": 12 - } - }, - { - "plugin": "ml", + "plugin": "lists", "link": { - "path": "x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/action_delete/use_delete_action.tsx", - "lineNumber": 60 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.tsx", + "lineNumber": 53 } }, { - "plugin": "ml", + "plugin": "lists", "link": { - "path": "x-pack/plugins/ml/public/application/jobs/components/custom_url_editor/utils.d.ts", - "lineNumber": 8 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.tsx", + "lineNumber": 58 } }, { - "plugin": "ml", + "plugin": "lists", "link": { - "path": "x-pack/plugins/ml/public/application/jobs/components/custom_url_editor/utils.d.ts", - "lineNumber": 37 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.tsx", + "lineNumber": 61 } }, { - "plugin": "ml", + "plugin": "lists", "link": { - "path": "x-pack/plugins/ml/public/application/jobs/jobs_list/components/edit_job_flyout/edit_utils.d.ts", - "lineNumber": 8 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/exception_item_renderer.tsx", + "lineNumber": 22 } }, { - "plugin": "ml", + "plugin": "lists", "link": { - "path": "x-pack/plugins/ml/public/application/jobs/jobs_list/components/edit_job_flyout/edit_utils.d.ts", - "lineNumber": 11 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/exception_item_renderer.tsx", + "lineNumber": 50 } }, { - "plugin": "ml", + "plugin": "lists", "link": { - "path": "x-pack/plugins/ml/public/application/datavisualizer/index_based/components/actions_panel/actions_panel.tsx", - "lineNumber": 25 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/exception_item_renderer.tsx", + "lineNumber": 55 } }, { - "plugin": "ml", + "plugin": "lists", "link": { - "path": "x-pack/plugins/ml/public/application/datavisualizer/index_based/components/actions_panel/actions_panel.tsx", - "lineNumber": 28 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/exception_item_renderer.tsx", + "lineNumber": 58 } }, { - "plugin": "infra", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/infra/public/pages/metrics/index.tsx", - "lineNumber": 14 + "path": "x-pack/plugins/security_solution/public/network/pages/navigation/types.ts", + "lineNumber": 9 } }, { - "plugin": "infra", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/infra/public/pages/metrics/index.tsx", - "lineNumber": 193 + "path": "x-pack/plugins/security_solution/public/network/pages/navigation/types.ts", + "lineNumber": 35 } }, { "plugin": "securitySolution", "link": { "path": "x-pack/plugins/security_solution/public/network/pages/navigation/types.ts", - "lineNumber": 9 + "lineNumber": 53 } }, { "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/security_solution/public/network/pages/navigation/types.ts", - "lineNumber": 35 + "path": "x-pack/plugins/security_solution/common/detection_engine/get_query_filter.ts", + "lineNumber": 16 } }, { "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/security_solution/public/network/pages/navigation/types.ts", - "lineNumber": 53 + "path": "x-pack/plugins/security_solution/common/detection_engine/get_query_filter.ts", + "lineNumber": 31 } }, { @@ -9736,211 +9666,267 @@ { "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/field.tsx", - "lineNumber": 93 + "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/field.tsx", + "lineNumber": 93 + } + }, + { + "plugin": "securitySolution", + "link": { + "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/field.tsx", + "lineNumber": 114 + } + }, + { + "plugin": "securitySolution", + "link": { + "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/hooks/use_field_value_autocomplete.ts", + "lineNumber": 12 + } + }, + { + "plugin": "securitySolution", + "link": { + "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/hooks/use_field_value_autocomplete.ts", + "lineNumber": 19 + } + }, + { + "plugin": "securitySolution", + "link": { + "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/hooks/use_field_value_autocomplete.ts", + "lineNumber": 31 + } + }, + { + "plugin": "securitySolution", + "link": { + "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/field_value_match.tsx", + "lineNumber": 19 + } + }, + { + "plugin": "securitySolution", + "link": { + "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/field_value_match.tsx", + "lineNumber": 30 + } + }, + { + "plugin": "stackAlerts", + "link": { + "path": "x-pack/plugins/stack_alerts/server/alert_types/geo_containment/es_query_builder.ts", + "lineNumber": 13 + } + }, + { + "plugin": "stackAlerts", + "link": { + "path": "x-pack/plugins/stack_alerts/server/alert_types/geo_containment/es_query_builder.ts", + "lineNumber": 25 } }, { - "plugin": "securitySolution", + "plugin": "infra", "link": { - "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/field.tsx", - "lineNumber": 114 + "path": "x-pack/plugins/infra/common/dependency_mocks/index_patterns.ts", + "lineNumber": 13 } }, { - "plugin": "securitySolution", + "plugin": "infra", "link": { - "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/hooks/use_field_value_autocomplete.ts", - "lineNumber": 12 + "path": "x-pack/plugins/infra/common/dependency_mocks/index_patterns.ts", + "lineNumber": 30 } }, { - "plugin": "securitySolution", + "plugin": "infra", "link": { - "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/hooks/use_field_value_autocomplete.ts", - "lineNumber": 19 + "path": "x-pack/plugins/infra/target/types/common/dependency_mocks/index_patterns.d.ts", + "lineNumber": 1 } }, { - "plugin": "securitySolution", + "plugin": "infra", "link": { - "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/hooks/use_field_value_autocomplete.ts", - "lineNumber": 31 + "path": "x-pack/plugins/infra/target/types/common/dependency_mocks/index_patterns.d.ts", + "lineNumber": 3 } }, { - "plugin": "securitySolution", + "plugin": "lists", "link": { - "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/field_value_match.tsx", - "lineNumber": 19 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", + "lineNumber": 62 } }, { - "plugin": "securitySolution", + "plugin": "lists", "link": { - "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/field_value_match.tsx", - "lineNumber": 30 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", + "lineNumber": 96 } }, { - "plugin": "securitySolution", + "plugin": "lists", "link": { - "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/field_value_match_any.tsx", - "lineNumber": 13 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", + "lineNumber": 169 } }, { - "plugin": "securitySolution", + "plugin": "lists", "link": { - "path": "x-pack/plugins/security_solution/public/common/components/autocomplete/field_value_match_any.tsx", - "lineNumber": 24 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", + "lineNumber": 169 } }, { - "plugin": "securitySolution", + "plugin": "lists", "link": { - "path": "x-pack/plugins/security_solution/public/common/components/exceptions/helpers.test.tsx", - "lineNumber": 43 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", + "lineNumber": 184 } }, { - "plugin": "securitySolution", + "plugin": "lists", "link": { - "path": "x-pack/plugins/security_solution/public/common/components/exceptions/helpers.test.tsx", - "lineNumber": 49 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", + "lineNumber": 187 } }, { - "plugin": "securitySolution", + "plugin": "lists", "link": { - "path": "x-pack/plugins/security_solution/public/common/components/exceptions/helpers.test.tsx", - "lineNumber": 368 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", + "lineNumber": 196 } }, { - "plugin": "visTypeTimeseries", + "plugin": "lists", "link": { - "path": "src/plugins/vis_type_timeseries/common/index_patterns_utils.ts", - "lineNumber": 11 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", + "lineNumber": 199 } }, { - "plugin": "visTypeTimeseries", + "plugin": "lists", "link": { - "path": "src/plugins/vis_type_timeseries/common/index_patterns_utils.ts", - "lineNumber": 20 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", + "lineNumber": 208 } }, { - "plugin": "stackAlerts", + "plugin": "lists", "link": { - "path": "x-pack/plugins/stack_alerts/server/alert_types/geo_containment/es_query_builder.ts", - "lineNumber": 13 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", + "lineNumber": 214 } }, { - "plugin": "stackAlerts", + "plugin": "lists", "link": { - "path": "x-pack/plugins/stack_alerts/server/alert_types/geo_containment/es_query_builder.ts", - "lineNumber": 25 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", + "lineNumber": 226 } }, { - "plugin": "infra", + "plugin": "lists", "link": { - "path": "x-pack/plugins/infra/common/dependency_mocks/index_patterns.ts", - "lineNumber": 13 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", + "lineNumber": 229 } }, { - "plugin": "infra", + "plugin": "lists", "link": { - "path": "x-pack/plugins/infra/common/dependency_mocks/index_patterns.ts", - "lineNumber": 30 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", + "lineNumber": 239 } }, { - "plugin": "infra", + "plugin": "lists", "link": { - "path": "x-pack/plugins/infra/target/types/common/dependency_mocks/index_patterns.d.ts", - "lineNumber": 1 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", + "lineNumber": 267 } }, { - "plugin": "infra", + "plugin": "lists", "link": { - "path": "x-pack/plugins/infra/target/types/common/dependency_mocks/index_patterns.d.ts", - "lineNumber": 3 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", + "lineNumber": 285 } }, { - "plugin": "discover", + "plugin": "lists", "link": { - "path": "src/plugins/discover/public/application/components/context_app/context_app_legacy.tsx", - "lineNumber": 17 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", + "lineNumber": 320 } }, { - "plugin": "discover", + "plugin": "lists", "link": { - "path": "src/plugins/discover/public/application/components/context_app/context_app_legacy.tsx", - "lineNumber": 26 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", + "lineNumber": 336 } }, { - "plugin": "observability", + "plugin": "lists", "link": { - "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/types.ts", - "lineNumber": 18 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", + "lineNumber": 1026 } }, { - "plugin": "observability", + "plugin": "lists", "link": { - "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/types.ts", - "lineNumber": 95 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", + "lineNumber": 1045 } }, { - "plugin": "observability", + "plugin": "lists", "link": { - "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/utils.ts", - "lineNumber": 10 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", + "lineNumber": 1095 } }, { - "plugin": "observability", + "plugin": "lists", "link": { - "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/utils.ts", - "lineNumber": 53 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", + "lineNumber": 1251 } }, { - "plugin": "observability", + "plugin": "lists", "link": { - "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/utils.ts", - "lineNumber": 61 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", + "lineNumber": 1302 } }, { - "plugin": "observability", + "plugin": "lists", "link": { - "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/utils.ts", - "lineNumber": 69 + "path": "x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts", + "lineNumber": 1352 } }, { - "plugin": "observability", + "plugin": "discover", "link": { - "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/default_configs.ts", - "lineNumber": 19 + "path": "src/plugins/discover/public/application/components/context_app/context_app_legacy.tsx", + "lineNumber": 17 } }, { - "plugin": "observability", + "plugin": "discover", "link": { - "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/default_configs.ts", - "lineNumber": 24 + "path": "src/plugins/discover/public/application/components/context_app/context_app_legacy.tsx", + "lineNumber": 26 } }, { @@ -10055,6 +10041,62 @@ "lineNumber": 17 } }, + { + "plugin": "observability", + "link": { + "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/types.ts", + "lineNumber": 18 + } + }, + { + "plugin": "observability", + "link": { + "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/types.ts", + "lineNumber": 95 + } + }, + { + "plugin": "observability", + "link": { + "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/utils.ts", + "lineNumber": 10 + } + }, + { + "plugin": "observability", + "link": { + "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/utils.ts", + "lineNumber": 53 + } + }, + { + "plugin": "observability", + "link": { + "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/utils.ts", + "lineNumber": 61 + } + }, + { + "plugin": "observability", + "link": { + "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/utils.ts", + "lineNumber": 69 + } + }, + { + "plugin": "observability", + "link": { + "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/default_configs.ts", + "lineNumber": 19 + } + }, + { + "plugin": "observability", + "link": { + "path": "x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/default_configs.ts", + "lineNumber": 24 + } + }, { "plugin": "securitySolution", "link": { @@ -10125,20 +10167,6 @@ "lineNumber": 19 } }, - { - "plugin": "securitySolution", - "link": { - "path": "x-pack/plugins/security_solution/public/common/mock/index_pattern.ts", - "lineNumber": 8 - } - }, - { - "plugin": "securitySolution", - "link": { - "path": "x-pack/plugins/security_solution/public/common/mock/index_pattern.ts", - "lineNumber": 10 - } - }, { "plugin": "stackAlerts", "link": { @@ -10258,6 +10286,20 @@ "lineNumber": 13 } }, + { + "plugin": "securitySolution", + "link": { + "path": "x-pack/plugins/security_solution/public/common/mock/index_pattern.ts", + "lineNumber": 8 + } + }, + { + "plugin": "securitySolution", + "link": { + "path": "x-pack/plugins/security_solution/public/common/mock/index_pattern.ts", + "lineNumber": 10 + } + }, { "plugin": "ml", "link": { diff --git a/api_docs/data_search.json b/api_docs/data_search.json index a82a2ca24d899..082553e94dcf4 100644 --- a/api_docs/data_search.json +++ b/api_docs/data_search.json @@ -2690,7 +2690,7 @@ ], "source": { "path": "src/plugins/data/server/search/types.ts", - "lineNumber": 89 + "lineNumber": 90 }, "deprecated": false, "children": [ @@ -2708,7 +2708,7 @@ ], "source": { "path": "src/plugins/data/server/search/types.ts", - "lineNumber": 90 + "lineNumber": 91 }, "deprecated": false, "returnComment": [], @@ -2758,7 +2758,7 @@ ], "source": { "path": "src/plugins/data/server/search/types.ts", - "lineNumber": 91 + "lineNumber": 92 }, "deprecated": false, "returnComment": [], @@ -2806,7 +2806,7 @@ ], "source": { "path": "src/plugins/data/server/search/types.ts", - "lineNumber": 92 + "lineNumber": 93 }, "deprecated": false, "returnComment": [], @@ -2875,7 +2875,7 @@ ], "source": { "path": "src/plugins/data/server/search/types.ts", - "lineNumber": 93 + "lineNumber": 94 }, "deprecated": false, "returnComment": [], @@ -2923,7 +2923,7 @@ ], "source": { "path": "src/plugins/data/server/search/types.ts", - "lineNumber": 94 + "lineNumber": 95 }, "deprecated": false, "returnComment": [], @@ -2955,7 +2955,7 @@ ], "source": { "path": "src/plugins/data/server/search/types.ts", - "lineNumber": 95 + "lineNumber": 96 }, "deprecated": false, "returnComment": [], @@ -2995,7 +2995,7 @@ ], "source": { "path": "src/plugins/data/server/search/types.ts", - "lineNumber": 96 + "lineNumber": 97 }, "deprecated": false, "returnComment": [], @@ -3128,7 +3128,7 @@ "description": [], "source": { "path": "src/plugins/data/server/search/types.ts", - "lineNumber": 42 + "lineNumber": 43 }, "deprecated": false, "children": [ @@ -3144,7 +3144,7 @@ ], "source": { "path": "src/plugins/data/server/search/types.ts", - "lineNumber": 43 + "lineNumber": 44 }, "deprecated": false }, @@ -3202,7 +3202,7 @@ ], "source": { "path": "src/plugins/data/server/search/types.ts", - "lineNumber": 48 + "lineNumber": 49 }, "deprecated": false, "returnComment": [], @@ -3216,7 +3216,7 @@ "description": [], "source": { "path": "src/plugins/data/server/search/types.ts", - "lineNumber": 52 + "lineNumber": 53 }, "deprecated": false }, @@ -3239,7 +3239,7 @@ ], "source": { "path": "src/plugins/data/server/search/types.ts", - "lineNumber": 53 + "lineNumber": 54 }, "deprecated": false } @@ -3266,7 +3266,7 @@ ], "source": { "path": "src/plugins/data/server/search/types.ts", - "lineNumber": 59 + "lineNumber": 60 }, "deprecated": false } @@ -3292,7 +3292,7 @@ ], "source": { "path": "src/plugins/data/server/search/types.ts", - "lineNumber": 99 + "lineNumber": 100 }, "deprecated": false, "children": [ @@ -3308,7 +3308,7 @@ ], "source": { "path": "src/plugins/data/server/search/types.ts", - "lineNumber": 103 + "lineNumber": 104 }, "deprecated": false }, @@ -3334,7 +3334,7 @@ ], "source": { "path": "src/plugins/data/server/search/types.ts", - "lineNumber": 109 + "lineNumber": 110 }, "deprecated": false, "returnComment": [], @@ -3351,7 +3351,7 @@ ], "source": { "path": "src/plugins/data/server/search/types.ts", - "lineNumber": 110 + "lineNumber": 111 }, "deprecated": false } @@ -3384,7 +3384,7 @@ ], "source": { "path": "src/plugins/data/server/search/types.ts", - "lineNumber": 112 + "lineNumber": 113 }, "deprecated": false, "returnComment": [], @@ -3408,7 +3408,7 @@ ], "source": { "path": "src/plugins/data/server/search/types.ts", - "lineNumber": 112 + "lineNumber": 113 }, "deprecated": false } @@ -3442,7 +3442,7 @@ ], "source": { "path": "src/plugins/data/server/search/types.ts", - "lineNumber": 113 + "lineNumber": 114 }, "deprecated": false } @@ -3470,7 +3470,7 @@ ], "source": { "path": "src/plugins/data/server/search/types.ts", - "lineNumber": 71 + "lineNumber": 72 }, "deprecated": false, "children": [ @@ -3504,7 +3504,7 @@ ], "source": { "path": "src/plugins/data/server/search/types.ts", - "lineNumber": 75 + "lineNumber": 76 }, "deprecated": false, "returnComment": [], @@ -3521,7 +3521,7 @@ ], "source": { "path": "src/plugins/data/server/search/types.ts", - "lineNumber": 76 + "lineNumber": 77 }, "deprecated": false }, @@ -3543,7 +3543,7 @@ ], "source": { "path": "src/plugins/data/server/search/types.ts", - "lineNumber": 77 + "lineNumber": 78 }, "deprecated": false }, @@ -3565,7 +3565,7 @@ ], "source": { "path": "src/plugins/data/server/search/types.ts", - "lineNumber": 78 + "lineNumber": 79 }, "deprecated": false } @@ -3599,7 +3599,7 @@ ], "source": { "path": "src/plugins/data/server/search/types.ts", - "lineNumber": 80 + "lineNumber": 81 }, "deprecated": false }, @@ -3631,7 +3631,7 @@ ], "source": { "path": "src/plugins/data/server/search/types.ts", - "lineNumber": 81 + "lineNumber": 82 }, "deprecated": false } @@ -4027,6 +4027,29 @@ "lineNumber": 39 }, "deprecated": false + }, + { + "parentPluginId": "data", + "id": "def-server.SearchStrategyDependencies.request", + "type": "Object", + "tags": [], + "label": "request", + "description": [], + "signature": [ + { + "pluginId": "core", + "scope": "server", + "docId": "kibCoreHttpPluginApi", + "section": "def-server.KibanaRequest", + "text": "KibanaRequest" + }, + "" + ], + "source": { + "path": "src/plugins/data/server/search/types.ts", + "lineNumber": 40 + }, + "deprecated": false } ], "initialIsOpen": false @@ -4122,7 +4145,7 @@ ], "source": { "path": "src/plugins/data/server/search/types.ts", - "lineNumber": 118 + "lineNumber": 119 }, "deprecated": false, "initialIsOpen": false diff --git a/api_docs/deprecations.mdx b/api_docs/deprecations.mdx index 7d6df4965c712..9eee6d51d84ab 100644 --- a/api_docs/deprecations.mdx +++ b/api_docs/deprecations.mdx @@ -42,15 +42,6 @@ warning: This document is auto-generated and is meant to be viewed inside our ex -## beatsManagement - -| Deprecated API | Reference location | Remove By | -| ---------------|-----------|-----------| -| | [kibana_database_adapter.ts#L8](https://github.com/elastic/kibana/tree/master/x-pack/plugins/beats_management/server/lib/adapters/database/kibana_database_adapter.ts#L8) | 7.16 | -| | [kibana_database_adapter.ts#L28](https://github.com/elastic/kibana/tree/master/x-pack/plugins/beats_management/server/lib/adapters/database/kibana_database_adapter.ts#L28) | 7.16 | - - - ## canvas | Deprecated API | Reference location | Remove By | @@ -783,7 +774,7 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | | [field_value_match.tsx#L36](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lists/public/exceptions/components/autocomplete/field_value_match.tsx#L36) | - | | | [field_value_match_any.tsx#L13](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lists/public/exceptions/components/autocomplete/field_value_match_any.tsx#L13) | - | | | [field_value_match_any.tsx#L23](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lists/public/exceptions/components/autocomplete/field_value_match_any.tsx#L23) | - | -| | [field_value_lists.tsx#L13](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lists/public/exceptions/components/autocomplete/field_value_lists.tsx#L13) | - | +| | [field_value_lists.tsx#L14](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lists/public/exceptions/components/autocomplete/field_value_lists.tsx#L14) | - | | | [field_value_lists.tsx#L29](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lists/public/exceptions/components/autocomplete/field_value_lists.tsx#L29) | - | | | [entry_renderer.tsx#L31](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.tsx#L31) | - | | | [entry_renderer.tsx#L91](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.tsx#L91) | - | @@ -830,7 +821,7 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | | [field_value_match.tsx#L36](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lists/public/exceptions/components/autocomplete/field_value_match.tsx#L36) | - | | | [field_value_match_any.tsx#L13](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lists/public/exceptions/components/autocomplete/field_value_match_any.tsx#L13) | - | | | [field_value_match_any.tsx#L23](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lists/public/exceptions/components/autocomplete/field_value_match_any.tsx#L23) | - | -| | [field_value_lists.tsx#L13](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lists/public/exceptions/components/autocomplete/field_value_lists.tsx#L13) | - | +| | [field_value_lists.tsx#L14](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lists/public/exceptions/components/autocomplete/field_value_lists.tsx#L14) | - | | | [field_value_lists.tsx#L29](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lists/public/exceptions/components/autocomplete/field_value_lists.tsx#L29) | - | | | [entry_renderer.tsx#L31](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.tsx#L31) | - | | | [entry_renderer.tsx#L91](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.tsx#L91) | - | @@ -923,7 +914,7 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | | [field_value_match.tsx#L36](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lists/public/exceptions/components/autocomplete/field_value_match.tsx#L36) | - | | | [field_value_match_any.tsx#L13](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lists/public/exceptions/components/autocomplete/field_value_match_any.tsx#L13) | - | | | [field_value_match_any.tsx#L23](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lists/public/exceptions/components/autocomplete/field_value_match_any.tsx#L23) | - | -| | [field_value_lists.tsx#L13](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lists/public/exceptions/components/autocomplete/field_value_lists.tsx#L13) | - | +| | [field_value_lists.tsx#L14](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lists/public/exceptions/components/autocomplete/field_value_lists.tsx#L14) | - | | | [field_value_lists.tsx#L29](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lists/public/exceptions/components/autocomplete/field_value_lists.tsx#L29) | - | | | [entry_renderer.tsx#L31](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.tsx#L31) | - | | | [entry_renderer.tsx#L91](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.tsx#L91) | - | @@ -944,6 +935,9 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | | [get_call_cluster.mock.ts#L9](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lists/server/schemas/common/get_call_cluster.mock.ts#L9) | 7.16 | | | [get_call_cluster.mock.ts#L27](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lists/server/schemas/common/get_call_cluster.mock.ts#L27) | 7.16 | | | [get_call_cluster.mock.ts#L31](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lists/server/schemas/common/get_call_cluster.mock.ts#L31) | 7.16 | +| | [get_call_cluster.mock.d.ts#L2](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lists/target/types/server/schemas/common/get_call_cluster.mock.d.ts#L2) | 7.16 | +| | [get_call_cluster.mock.d.ts#L4](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lists/target/types/server/schemas/common/get_call_cluster.mock.d.ts#L4) | 7.16 | +| | [get_call_cluster.mock.d.ts#L5](https://github.com/elastic/kibana/tree/master/x-pack/plugins/lists/target/types/server/schemas/common/get_call_cluster.mock.d.ts#L5) | 7.16 | @@ -1579,12 +1573,12 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | Deprecated API | Reference location | Remove By | | ---------------|-----------|-----------| +| | [types.ts#L21](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/types.ts#L21) | - | +| | [types.ts#L66](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/types.ts#L66) | - | +| | [action.ts#L19](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/action.ts#L19) | - | +| | [action.ts#L100](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/action.ts#L100) | - | | | [index.ts#L8](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/common/search_strategy/index_fields/index.ts#L8) | - | | | [index.ts#L86](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/common/search_strategy/index_fields/index.ts#L86) | - | -| | [types.ts#L20](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/types.ts#L20) | - | -| | [types.ts#L64](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/types.ts#L64) | - | -| | [action.ts#L17](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/action.ts#L17) | - | -| | [action.ts#L98](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/action.ts#L98) | - | | | [index.tsx#L12](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/containers/source/index.tsx#L12) | - | | | [index.tsx#L48](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/containers/source/index.tsx#L48) | - | | | [index.tsx#L122](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/containers/source/index.tsx#L122) | - | @@ -1618,9 +1612,9 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | | [types.ts#L41](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/network/pages/details/types.ts#L41) | - | | | [index.tsx#L12](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/network/components/network_top_countries_table/index.tsx#L12) | - | | | [index.tsx#L34](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/network/components/network_top_countries_table/index.tsx#L34) | - | -| | [middleware.ts#L32](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts#L32) | - | -| | [middleware.ts#L38](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts#L38) | - | -| | [middleware.ts#L43](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts#L43) | - | +| | [middleware.ts#L40](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts#L40) | - | +| | [middleware.ts#L55](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts#L55) | - | +| | [middleware.ts#L60](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts#L60) | - | | | [types.ts#L12](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/detections/components/rules/description_step/types.ts#L12) | - | | | [types.ts#L28](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/detections/components/rules/description_step/types.ts#L28) | - | | | [index.tsx#L15](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/detections/components/rules/description_step/index.tsx#L15) | - | @@ -1633,13 +1627,30 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | | [index.tsx#L44](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/overview/components/alerts_by_category/index.tsx#L44) | - | | | [index.tsx#L21](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/overview/components/event_counts/index.tsx#L21) | - | | | [index.tsx#L33](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/overview/components/event_counts/index.tsx#L33) | - | -| | [index.tsx#L9](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/containers/kuery_autocompletion/index.tsx#L9) | - | -| | [index.tsx#L21](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/containers/kuery_autocompletion/index.tsx#L21) | - | -| | [get_query_filter.ts#L15](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/common/detection_engine/get_query_filter.ts#L15) | - | -| | [get_query_filter.ts#L31](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/common/detection_engine/get_query_filter.ts#L31) | - | +| | [index.d.ts#L1](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/target/types/common/search_strategy/index_fields/index.d.ts#L1) | - | +| | [index.d.ts#L66](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/target/types/common/search_strategy/index_fields/index.d.ts#L66) | - | +| | [index.d.ts#L1](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/target/types/public/common/containers/source/index.d.ts#L1) | - | +| | [index.d.ts#L10](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/target/types/public/common/containers/source/index.d.ts#L10) | - | +| | [index.d.ts#L23](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/target/types/public/common/containers/source/index.d.ts#L23) | - | +| | [types.d.ts#L3](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/target/types/public/common/components/url_state/types.d.ts#L3) | - | +| | [types.d.ts#L25](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/target/types/public/common/components/url_state/types.d.ts#L25) | - | +| | [types.d.ts#L55](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/target/types/public/common/components/url_state/types.d.ts#L55) | - | +| | [columns.d.ts#L1](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/target/types/public/network/components/network_top_countries_table/columns.d.ts#L1) | - | +| | [columns.d.ts#L20](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/target/types/public/network/components/network_top_countries_table/columns.d.ts#L20) | - | +| | [columns.d.ts#L21](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/target/types/public/network/components/network_top_countries_table/columns.d.ts#L21) | - | +| | [index.d.ts#L3](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/target/types/public/common/components/search_bar/index.d.ts#L3) | - | +| | [index.d.ts#L9](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/target/types/public/common/components/search_bar/index.d.ts#L9) | - | +| | [types.d.ts#L2](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/target/types/public/hosts/pages/details/types.d.ts#L2) | - | +| | [types.d.ts#L40](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/target/types/public/hosts/pages/details/types.d.ts#L40) | - | +| | [index.d.ts#L2](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/target/types/public/network/components/network_top_countries_table/index.d.ts#L2) | - | +| | [index.d.ts#L10](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/target/types/public/network/components/network_top_countries_table/index.d.ts#L10) | - | +| | [types.d.ts#L1](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/target/types/public/network/pages/details/types.d.ts#L1) | - | +| | [types.d.ts#L25](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/target/types/public/network/pages/details/types.d.ts#L25) | - | | | [types.ts#L9](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/network/pages/navigation/types.ts#L9) | - | | | [types.ts#L35](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/network/pages/navigation/types.ts#L35) | - | | | [types.ts#L53](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/network/pages/navigation/types.ts#L53) | - | +| | [get_query_filter.ts#L16](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/common/detection_engine/get_query_filter.ts#L16) | - | +| | [get_query_filter.ts#L31](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/common/detection_engine/get_query_filter.ts#L31) | - | | | [helpers.tsx#L39](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/exceptions/helpers.tsx#L39) | - | | | [helpers.tsx#L49](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/exceptions/helpers.tsx#L49) | - | | | [helpers.tsx#L52](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/exceptions/helpers.tsx#L52) | - | @@ -1658,11 +1669,6 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | | [use_field_value_autocomplete.ts#L31](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/autocomplete/hooks/use_field_value_autocomplete.ts#L31) | - | | | [field_value_match.tsx#L19](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/autocomplete/field_value_match.tsx#L19) | - | | | [field_value_match.tsx#L30](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/autocomplete/field_value_match.tsx#L30) | - | -| | [field_value_match_any.tsx#L13](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/autocomplete/field_value_match_any.tsx#L13) | - | -| | [field_value_match_any.tsx#L24](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/autocomplete/field_value_match_any.tsx#L24) | - | -| | [helpers.test.tsx#L43](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/exceptions/helpers.test.tsx#L43) | - | -| | [helpers.test.tsx#L49](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/exceptions/helpers.test.tsx#L49) | - | -| | [helpers.test.tsx#L368](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/exceptions/helpers.test.tsx#L368) | - | | | [model.ts#L8](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/store/sourcerer/model.ts#L8) | - | | | [model.ts#L30](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/store/sourcerer/model.ts#L30) | - | | | [index.tsx#L33](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/detections/components/rules/severity_mapping/index.tsx#L33) | - | @@ -1709,10 +1715,6 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | | [use_field_value_autocomplete.ts#L27](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/autocomplete/hooks/use_field_value_autocomplete.ts#L27) | - | | | [field_value_match.tsx#L19](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/autocomplete/field_value_match.tsx#L19) | - | | | [field_value_match.tsx#L28](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/autocomplete/field_value_match.tsx#L28) | - | -| | [field_value_lists.tsx#L12](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/autocomplete/field_value_lists.tsx#L12) | - | -| | [field_value_lists.tsx#L20](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/autocomplete/field_value_lists.tsx#L20) | - | -| | [field_value_match_any.tsx#L13](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/autocomplete/field_value_match_any.tsx#L13) | - | -| | [field_value_match_any.tsx#L22](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/autocomplete/field_value_match_any.tsx#L22) | - | | | [helpers.test.ts#L11](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/autocomplete/helpers.test.ts#L11) | - | | | [helpers.test.ts#L333](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/autocomplete/helpers.test.ts#L333) | - | | | [helpers.test.ts#L339](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/autocomplete/helpers.test.ts#L339) | - | @@ -1721,10 +1723,8 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | | [helpers.test.ts#L363](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/autocomplete/helpers.test.ts#L363) | - | | | [helpers.test.ts#L371](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/autocomplete/helpers.test.ts#L371) | - | | | [helpers.test.ts#L380](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/autocomplete/helpers.test.ts#L380) | - | -| | [operator.tsx#L11](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/autocomplete/operator.tsx#L11) | - | -| | [operator.tsx#L17](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/autocomplete/operator.tsx#L17) | - | -| | [helpers.test.tsx#L43](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/exceptions/helpers.test.tsx#L43) | - | -| | [helpers.test.tsx#L104](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/exceptions/helpers.test.tsx#L104) | - | +| | [helpers.test.d.ts#L1](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/target/types/public/common/components/exceptions/helpers.test.d.ts#L1) | - | +| | [helpers.test.d.ts#L2](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/target/types/public/common/components/exceptions/helpers.test.d.ts#L2) | - | | | [index.tsx#L32](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/detections/components/rules/severity_mapping/index.tsx#L32) | - | | | [index.tsx#L86](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/detections/components/rules/severity_mapping/index.tsx#L86) | - | | | [index.tsx#L305](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/detections/components/rules/severity_mapping/index.tsx#L305) | - | @@ -1767,10 +1767,6 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | | [use_field_value_autocomplete.ts#L27](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/autocomplete/hooks/use_field_value_autocomplete.ts#L27) | - | | | [field_value_match.tsx#L19](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/autocomplete/field_value_match.tsx#L19) | - | | | [field_value_match.tsx#L28](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/autocomplete/field_value_match.tsx#L28) | - | -| | [field_value_lists.tsx#L12](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/autocomplete/field_value_lists.tsx#L12) | - | -| | [field_value_lists.tsx#L20](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/autocomplete/field_value_lists.tsx#L20) | - | -| | [field_value_match_any.tsx#L13](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/autocomplete/field_value_match_any.tsx#L13) | - | -| | [field_value_match_any.tsx#L22](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/autocomplete/field_value_match_any.tsx#L22) | - | | | [helpers.test.ts#L11](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/autocomplete/helpers.test.ts#L11) | - | | | [helpers.test.ts#L333](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/autocomplete/helpers.test.ts#L333) | - | | | [helpers.test.ts#L339](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/autocomplete/helpers.test.ts#L339) | - | @@ -1779,10 +1775,8 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | | [helpers.test.ts#L363](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/autocomplete/helpers.test.ts#L363) | - | | | [helpers.test.ts#L371](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/autocomplete/helpers.test.ts#L371) | - | | | [helpers.test.ts#L380](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/autocomplete/helpers.test.ts#L380) | - | -| | [operator.tsx#L11](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/autocomplete/operator.tsx#L11) | - | -| | [operator.tsx#L17](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/autocomplete/operator.tsx#L17) | - | -| | [helpers.test.tsx#L43](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/exceptions/helpers.test.tsx#L43) | - | -| | [helpers.test.tsx#L104](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/exceptions/helpers.test.tsx#L104) | - | +| | [helpers.test.d.ts#L1](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/target/types/public/common/components/exceptions/helpers.test.d.ts#L1) | - | +| | [helpers.test.d.ts#L2](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/target/types/public/common/components/exceptions/helpers.test.d.ts#L2) | - | | | [index.tsx#L32](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/detections/components/rules/severity_mapping/index.tsx#L32) | - | | | [index.tsx#L86](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/detections/components/rules/severity_mapping/index.tsx#L86) | - | | | [index.tsx#L305](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/detections/components/rules/severity_mapping/index.tsx#L305) | - | @@ -1791,12 +1785,12 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | | [index.tsx#L242](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/detections/components/rules/risk_score_mapping/index.tsx#L242) | - | | | [index.tsx#L12](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/detections/components/rules/autocomplete_field/index.tsx#L12) | - | | | [index.tsx#L35](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/detections/components/rules/autocomplete_field/index.tsx#L35) | - | +| | [types.ts#L21](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/types.ts#L21) | - | +| | [types.ts#L66](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/types.ts#L66) | - | +| | [action.ts#L19](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/action.ts#L19) | - | +| | [action.ts#L100](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/action.ts#L100) | - | | | [index.ts#L8](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/common/search_strategy/index_fields/index.ts#L8) | - | | | [index.ts#L86](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/common/search_strategy/index_fields/index.ts#L86) | - | -| | [types.ts#L20](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/types.ts#L20) | - | -| | [types.ts#L64](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/types.ts#L64) | - | -| | [action.ts#L17](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/action.ts#L17) | - | -| | [action.ts#L98](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/action.ts#L98) | - | | | [index.tsx#L12](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/containers/source/index.tsx#L12) | - | | | [index.tsx#L48](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/containers/source/index.tsx#L48) | - | | | [index.tsx#L122](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/containers/source/index.tsx#L122) | - | @@ -1830,9 +1824,9 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | | [types.ts#L41](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/network/pages/details/types.ts#L41) | - | | | [index.tsx#L12](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/network/components/network_top_countries_table/index.tsx#L12) | - | | | [index.tsx#L34](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/network/components/network_top_countries_table/index.tsx#L34) | - | -| | [middleware.ts#L32](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts#L32) | - | -| | [middleware.ts#L38](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts#L38) | - | -| | [middleware.ts#L43](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts#L43) | - | +| | [middleware.ts#L40](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts#L40) | - | +| | [middleware.ts#L55](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts#L55) | - | +| | [middleware.ts#L60](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts#L60) | - | | | [types.ts#L12](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/detections/components/rules/description_step/types.ts#L12) | - | | | [types.ts#L28](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/detections/components/rules/description_step/types.ts#L28) | - | | | [index.tsx#L15](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/detections/components/rules/description_step/index.tsx#L15) | - | @@ -1845,13 +1839,30 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | | [index.tsx#L44](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/overview/components/alerts_by_category/index.tsx#L44) | - | | | [index.tsx#L21](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/overview/components/event_counts/index.tsx#L21) | - | | | [index.tsx#L33](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/overview/components/event_counts/index.tsx#L33) | - | -| | [index.tsx#L9](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/containers/kuery_autocompletion/index.tsx#L9) | - | -| | [index.tsx#L21](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/containers/kuery_autocompletion/index.tsx#L21) | - | -| | [get_query_filter.ts#L15](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/common/detection_engine/get_query_filter.ts#L15) | - | -| | [get_query_filter.ts#L31](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/common/detection_engine/get_query_filter.ts#L31) | - | +| | [index.d.ts#L1](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/target/types/common/search_strategy/index_fields/index.d.ts#L1) | - | +| | [index.d.ts#L66](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/target/types/common/search_strategy/index_fields/index.d.ts#L66) | - | +| | [index.d.ts#L1](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/target/types/public/common/containers/source/index.d.ts#L1) | - | +| | [index.d.ts#L10](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/target/types/public/common/containers/source/index.d.ts#L10) | - | +| | [index.d.ts#L23](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/target/types/public/common/containers/source/index.d.ts#L23) | - | +| | [types.d.ts#L3](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/target/types/public/common/components/url_state/types.d.ts#L3) | - | +| | [types.d.ts#L25](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/target/types/public/common/components/url_state/types.d.ts#L25) | - | +| | [types.d.ts#L55](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/target/types/public/common/components/url_state/types.d.ts#L55) | - | +| | [columns.d.ts#L1](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/target/types/public/network/components/network_top_countries_table/columns.d.ts#L1) | - | +| | [columns.d.ts#L20](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/target/types/public/network/components/network_top_countries_table/columns.d.ts#L20) | - | +| | [columns.d.ts#L21](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/target/types/public/network/components/network_top_countries_table/columns.d.ts#L21) | - | +| | [index.d.ts#L3](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/target/types/public/common/components/search_bar/index.d.ts#L3) | - | +| | [index.d.ts#L9](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/target/types/public/common/components/search_bar/index.d.ts#L9) | - | +| | [types.d.ts#L2](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/target/types/public/hosts/pages/details/types.d.ts#L2) | - | +| | [types.d.ts#L40](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/target/types/public/hosts/pages/details/types.d.ts#L40) | - | +| | [index.d.ts#L2](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/target/types/public/network/components/network_top_countries_table/index.d.ts#L2) | - | +| | [index.d.ts#L10](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/target/types/public/network/components/network_top_countries_table/index.d.ts#L10) | - | +| | [types.d.ts#L1](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/target/types/public/network/pages/details/types.d.ts#L1) | - | +| | [types.d.ts#L25](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/target/types/public/network/pages/details/types.d.ts#L25) | - | | | [types.ts#L9](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/network/pages/navigation/types.ts#L9) | - | | | [types.ts#L35](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/network/pages/navigation/types.ts#L35) | - | | | [types.ts#L53](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/network/pages/navigation/types.ts#L53) | - | +| | [get_query_filter.ts#L16](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/common/detection_engine/get_query_filter.ts#L16) | - | +| | [get_query_filter.ts#L31](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/common/detection_engine/get_query_filter.ts#L31) | - | | | [helpers.tsx#L39](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/exceptions/helpers.tsx#L39) | - | | | [helpers.tsx#L49](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/exceptions/helpers.tsx#L49) | - | | | [helpers.tsx#L52](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/exceptions/helpers.tsx#L52) | - | @@ -1870,11 +1881,6 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | | [use_field_value_autocomplete.ts#L31](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/autocomplete/hooks/use_field_value_autocomplete.ts#L31) | - | | | [field_value_match.tsx#L19](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/autocomplete/field_value_match.tsx#L19) | - | | | [field_value_match.tsx#L30](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/autocomplete/field_value_match.tsx#L30) | - | -| | [field_value_match_any.tsx#L13](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/autocomplete/field_value_match_any.tsx#L13) | - | -| | [field_value_match_any.tsx#L24](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/autocomplete/field_value_match_any.tsx#L24) | - | -| | [helpers.test.tsx#L43](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/exceptions/helpers.test.tsx#L43) | - | -| | [helpers.test.tsx#L49](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/exceptions/helpers.test.tsx#L49) | - | -| | [helpers.test.tsx#L368](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/exceptions/helpers.test.tsx#L368) | - | | | [model.ts#L8](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/store/sourcerer/model.ts#L8) | - | | | [model.ts#L30](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/store/sourcerer/model.ts#L30) | - | | | [index.tsx#L33](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/detections/components/rules/severity_mapping/index.tsx#L33) | - | @@ -1921,10 +1927,6 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | | [use_field_value_autocomplete.ts#L27](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/autocomplete/hooks/use_field_value_autocomplete.ts#L27) | - | | | [field_value_match.tsx#L19](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/autocomplete/field_value_match.tsx#L19) | - | | | [field_value_match.tsx#L28](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/autocomplete/field_value_match.tsx#L28) | - | -| | [field_value_lists.tsx#L12](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/autocomplete/field_value_lists.tsx#L12) | - | -| | [field_value_lists.tsx#L20](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/autocomplete/field_value_lists.tsx#L20) | - | -| | [field_value_match_any.tsx#L13](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/autocomplete/field_value_match_any.tsx#L13) | - | -| | [field_value_match_any.tsx#L22](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/autocomplete/field_value_match_any.tsx#L22) | - | | | [helpers.test.ts#L11](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/autocomplete/helpers.test.ts#L11) | - | | | [helpers.test.ts#L333](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/autocomplete/helpers.test.ts#L333) | - | | | [helpers.test.ts#L339](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/autocomplete/helpers.test.ts#L339) | - | @@ -1933,10 +1935,8 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | | [helpers.test.ts#L363](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/autocomplete/helpers.test.ts#L363) | - | | | [helpers.test.ts#L371](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/autocomplete/helpers.test.ts#L371) | - | | | [helpers.test.ts#L380](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/autocomplete/helpers.test.ts#L380) | - | -| | [operator.tsx#L11](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/autocomplete/operator.tsx#L11) | - | -| | [operator.tsx#L17](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/autocomplete/operator.tsx#L17) | - | -| | [helpers.test.tsx#L43](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/exceptions/helpers.test.tsx#L43) | - | -| | [helpers.test.tsx#L104](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/common/components/exceptions/helpers.test.tsx#L104) | - | +| | [helpers.test.d.ts#L1](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/target/types/public/common/components/exceptions/helpers.test.d.ts#L1) | - | +| | [helpers.test.d.ts#L2](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/target/types/public/common/components/exceptions/helpers.test.d.ts#L2) | - | | | [index.tsx#L32](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/detections/components/rules/severity_mapping/index.tsx#L32) | - | | | [index.tsx#L86](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/detections/components/rules/severity_mapping/index.tsx#L86) | - | | | [index.tsx#L305](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/detections/components/rules/severity_mapping/index.tsx#L305) | - | diff --git a/api_docs/features.json b/api_docs/features.json index 6881b65061fac..63c3ebe3a92de 100644 --- a/api_docs/features.json +++ b/api_docs/features.json @@ -1599,13 +1599,6 @@ "path": "x-pack/plugins/security/server/authorization/disable_ui_capabilities.ts", "lineNumber": 311 } - }, - { - "plugin": "beatsManagement", - "link": { - "path": "x-pack/plugins/beats_management/server/plugin.ts", - "lineNumber": 61 - } } ] }, @@ -3298,13 +3291,6 @@ "path": "x-pack/plugins/security/server/authorization/disable_ui_capabilities.ts", "lineNumber": 311 } - }, - { - "plugin": "beatsManagement", - "link": { - "path": "x-pack/plugins/beats_management/server/plugin.ts", - "lineNumber": 61 - } } ] }, diff --git a/api_docs/fleet.json b/api_docs/fleet.json index 94f2acc12adf7..389a56cccefc5 100644 --- a/api_docs/fleet.json +++ b/api_docs/fleet.json @@ -8837,7 +8837,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent_policy.ts", - "lineNumber": 113 + "lineNumber": 114 }, "deprecated": false, "children": [ @@ -8855,7 +8855,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent_policy.ts", - "lineNumber": 117 + "lineNumber": 118 }, "deprecated": false }, @@ -8870,7 +8870,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent_policy.ts", - "lineNumber": 121 + "lineNumber": 122 }, "deprecated": false }, @@ -8885,7 +8885,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent_policy.ts", - "lineNumber": 125 + "lineNumber": 126 }, "deprecated": false }, @@ -8900,7 +8900,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent_policy.ts", - "lineNumber": 129 + "lineNumber": 130 }, "deprecated": false }, @@ -8918,7 +8918,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent_policy.ts", - "lineNumber": 133 + "lineNumber": 134 }, "deprecated": false }, @@ -8933,7 +8933,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent_policy.ts", - "lineNumber": 139 + "lineNumber": 140 }, "deprecated": false } @@ -9085,7 +9085,7 @@ "label": "agent", "description": [], "signature": [ - "{ monitoring: { use_output?: string | undefined; enabled: boolean; metrics: boolean; logs: boolean; }; } | undefined" + "{ monitoring: { namespace?: string | undefined; use_output?: string | undefined; enabled: boolean; metrics: boolean; logs: boolean; }; } | undefined" ], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent_policy.ts", @@ -9326,7 +9326,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent_policy.ts", - "lineNumber": 102 + "lineNumber": 103 }, "deprecated": false, "children": [ @@ -9342,7 +9342,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent_policy.ts", - "lineNumber": 103 + "lineNumber": 104 }, "deprecated": false }, @@ -9355,7 +9355,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent_policy.ts", - "lineNumber": 104 + "lineNumber": 105 }, "deprecated": false }, @@ -9371,7 +9371,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/agent_policy.ts", - "lineNumber": 105 + "lineNumber": 106 }, "deprecated": false } diff --git a/api_docs/home.json b/api_docs/home.json index bc99a31a09c30..2aa23c1b756df 100644 --- a/api_docs/home.json +++ b/api_docs/home.json @@ -953,13 +953,6 @@ }, "deprecated": true, "references": [ - { - "plugin": "cloud", - "link": { - "path": "x-pack/plugins/cloud/public/plugin.ts", - "lineNumber": 66 - } - }, { "plugin": "ml", "link": { @@ -973,6 +966,13 @@ "path": "x-pack/plugins/apm/public/plugin.ts", "lineNumber": 82 } + }, + { + "plugin": "cloud", + "link": { + "path": "x-pack/plugins/cloud/public/plugin.ts", + "lineNumber": 66 + } } ] } diff --git a/api_docs/kibana_utils.json b/api_docs/kibana_utils.json index ade7a843a6841..173348ea2f263 100644 --- a/api_docs/kibana_utils.json +++ b/api_docs/kibana_utils.json @@ -3799,7 +3799,7 @@ "description": [], "source": { "path": "src/core/public/application/types.ts", - "lineNumber": 717 + "lineNumber": 704 }, "deprecated": false }, @@ -3822,7 +3822,7 @@ ], "source": { "path": "src/core/public/application/types.ts", - "lineNumber": 717 + "lineNumber": 704 }, "deprecated": false } diff --git a/api_docs/licensing.json b/api_docs/licensing.json index f3ec50895547f..873f40bd301a1 100644 --- a/api_docs/licensing.json +++ b/api_docs/licensing.json @@ -554,192 +554,192 @@ "deprecated": true, "references": [ { - "plugin": "securitySolution", + "plugin": "apm", "link": { - "path": "x-pack/plugins/security_solution/common/license/policy_config.test.ts", - "lineNumber": 22 + "path": "x-pack/plugins/apm/common/license_check.test.ts", + "lineNumber": 19 } }, { - "plugin": "securitySolution", + "plugin": "apm", "link": { - "path": "x-pack/plugins/security_solution/common/license/policy_config.test.ts", - "lineNumber": 23 + "path": "x-pack/plugins/apm/common/license_check.test.ts", + "lineNumber": 36 } }, { - "plugin": "securitySolution", + "plugin": "apm", "link": { - "path": "x-pack/plugins/security_solution/common/license/policy_config.test.ts", - "lineNumber": 24 + "path": "x-pack/plugins/apm/common/license_check.test.ts", + "lineNumber": 53 } }, { - "plugin": "securitySolution", + "plugin": "apm", "link": { - "path": "x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/index.test.ts", - "lineNumber": 159 + "path": "x-pack/plugins/apm/common/license_check.test.ts", + "lineNumber": 70 } }, { - "plugin": "securitySolution", + "plugin": "apm", "link": { - "path": "x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/index.test.ts", - "lineNumber": 161 + "path": "x-pack/plugins/apm/common/license_check.test.ts", + "lineNumber": 87 } }, { - "plugin": "securitySolution", + "plugin": "apm", "link": { - "path": "x-pack/plugins/security_solution/server/endpoint/lib/policy/license_watch.test.ts", - "lineNumber": 42 + "path": "x-pack/plugins/apm/common/license_check.test.ts", + "lineNumber": 104 } }, { - "plugin": "securitySolution", + "plugin": "apm", "link": { - "path": "x-pack/plugins/security_solution/server/endpoint/lib/policy/license_watch.test.ts", - "lineNumber": 43 + "path": "x-pack/plugins/apm/common/license_check.test.ts", + "lineNumber": 122 } }, { - "plugin": "securitySolution", + "plugin": "apm", "link": { - "path": "x-pack/plugins/security_solution/server/endpoint/lib/policy/license_watch.test.ts", - "lineNumber": 44 + "path": "x-pack/plugins/apm/common/license_check.test.ts", + "lineNumber": 139 } }, { - "plugin": "securitySolution", + "plugin": "apm", "link": { - "path": "x-pack/plugins/security_solution/server/endpoint/routes/actions/isolation.test.ts", - "lineNumber": 54 + "path": "x-pack/plugins/apm/common/license_check.test.ts", + "lineNumber": 156 } }, { - "plugin": "securitySolution", + "plugin": "apm", "link": { - "path": "x-pack/plugins/security_solution/server/endpoint/routes/actions/isolation.test.ts", - "lineNumber": 55 + "path": "x-pack/plugins/apm/common/license_check.test.ts", + "lineNumber": 173 } }, { - "plugin": "securitySolution", + "plugin": "apm", "link": { - "path": "x-pack/plugins/security_solution/server/fleet_integration/fleet_integration.test.ts", - "lineNumber": 47 + "path": "x-pack/plugins/apm/common/license_check.test.ts", + "lineNumber": 190 } }, { - "plugin": "securitySolution", + "plugin": "apm", "link": { - "path": "x-pack/plugins/security_solution/server/fleet_integration/fleet_integration.test.ts", - "lineNumber": 48 + "path": "x-pack/plugins/apm/common/license_check.test.ts", + "lineNumber": 207 } }, { - "plugin": "apm", + "plugin": "security", "link": { - "path": "x-pack/plugins/apm/common/license_check.test.ts", - "lineNumber": 19 + "path": "x-pack/plugins/security/common/licensing/license_service.test.ts", + "lineNumber": 169 } }, { - "plugin": "apm", + "plugin": "security", "link": { - "path": "x-pack/plugins/apm/common/license_check.test.ts", - "lineNumber": 36 + "path": "x-pack/plugins/security/common/licensing/license_service.test.ts", + "lineNumber": 194 } }, { - "plugin": "apm", + "plugin": "security", "link": { - "path": "x-pack/plugins/apm/common/license_check.test.ts", - "lineNumber": 53 + "path": "x-pack/plugins/security/common/licensing/license_service.test.ts", + "lineNumber": 219 } }, { - "plugin": "apm", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/apm/common/license_check.test.ts", - "lineNumber": 70 + "path": "x-pack/plugins/security_solution/common/license/policy_config.test.ts", + "lineNumber": 22 } }, { - "plugin": "apm", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/apm/common/license_check.test.ts", - "lineNumber": 87 + "path": "x-pack/plugins/security_solution/common/license/policy_config.test.ts", + "lineNumber": 23 } }, { - "plugin": "apm", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/apm/common/license_check.test.ts", - "lineNumber": 104 + "path": "x-pack/plugins/security_solution/common/license/policy_config.test.ts", + "lineNumber": 24 } }, { - "plugin": "apm", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/apm/common/license_check.test.ts", - "lineNumber": 122 + "path": "x-pack/plugins/security_solution/server/fleet_integration/fleet_integration.test.ts", + "lineNumber": 47 } }, { - "plugin": "apm", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/apm/common/license_check.test.ts", - "lineNumber": 139 + "path": "x-pack/plugins/security_solution/server/fleet_integration/fleet_integration.test.ts", + "lineNumber": 48 } }, { - "plugin": "apm", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/apm/common/license_check.test.ts", - "lineNumber": 156 + "path": "x-pack/plugins/security_solution/server/endpoint/lib/policy/license_watch.test.ts", + "lineNumber": 42 } }, { - "plugin": "apm", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/apm/common/license_check.test.ts", - "lineNumber": 173 + "path": "x-pack/plugins/security_solution/server/endpoint/lib/policy/license_watch.test.ts", + "lineNumber": 43 } }, { - "plugin": "apm", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/apm/common/license_check.test.ts", - "lineNumber": 190 + "path": "x-pack/plugins/security_solution/server/endpoint/lib/policy/license_watch.test.ts", + "lineNumber": 44 } }, { - "plugin": "apm", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/apm/common/license_check.test.ts", - "lineNumber": 207 + "path": "x-pack/plugins/security_solution/server/endpoint/routes/actions/isolation.test.ts", + "lineNumber": 54 } }, { - "plugin": "security", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/security/common/licensing/license_service.test.ts", - "lineNumber": 169 + "path": "x-pack/plugins/security_solution/server/endpoint/routes/actions/isolation.test.ts", + "lineNumber": 55 } }, { - "plugin": "security", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/security/common/licensing/license_service.test.ts", - "lineNumber": 194 + "path": "x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/index.test.ts", + "lineNumber": 159 } }, { - "plugin": "security", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/security/common/licensing/license_service.test.ts", - "lineNumber": 219 + "path": "x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/index.test.ts", + "lineNumber": 161 } } ] @@ -942,73 +942,66 @@ "deprecated": true, "references": [ { - "plugin": "security", - "link": { - "path": "x-pack/plugins/security/public/plugin.tsx", - "lineNumber": 82 - } - }, - { - "plugin": "licenseManagement", + "plugin": "reporting", "link": { - "path": "x-pack/plugins/license_management/public/plugin.ts", - "lineNumber": 61 + "path": "x-pack/plugins/reporting/public/panel_actions/get_csv_panel_action.tsx", + "lineNumber": 40 } }, { - "plugin": "ml", + "plugin": "reporting", "link": { - "path": "x-pack/plugins/ml/public/application/license/check_license.tsx", - "lineNumber": 26 + "path": "x-pack/plugins/reporting/public/share_context_menu/register_csv_reporting.tsx", + "lineNumber": 33 } }, { - "plugin": "ml", + "plugin": "reporting", "link": { - "path": "x-pack/plugins/ml/public/plugin.ts", - "lineNumber": 136 + "path": "x-pack/plugins/reporting/public/share_context_menu/register_pdf_png_reporting.tsx", + "lineNumber": 81 } }, { - "plugin": "fleet", + "plugin": "reporting", "link": { - "path": "x-pack/plugins/fleet/public/plugin.ts", - "lineNumber": 97 + "path": "x-pack/plugins/reporting/public/plugin.ts", + "lineNumber": 116 } }, { "plugin": "reporting", "link": { - "path": "x-pack/plugins/reporting/public/panel_actions/get_csv_panel_action.tsx", - "lineNumber": 40 + "path": "x-pack/plugins/reporting/public/components/report_listing.tsx", + "lineNumber": 61 } }, { - "plugin": "reporting", + "plugin": "licenseManagement", "link": { - "path": "x-pack/plugins/reporting/public/share_context_menu/register_csv_reporting.tsx", - "lineNumber": 33 + "path": "x-pack/plugins/license_management/public/plugin.ts", + "lineNumber": 61 } }, { - "plugin": "reporting", + "plugin": "security", "link": { - "path": "x-pack/plugins/reporting/public/share_context_menu/register_pdf_png_reporting.tsx", - "lineNumber": 81 + "path": "x-pack/plugins/security/public/plugin.tsx", + "lineNumber": 82 } }, { - "plugin": "reporting", + "plugin": "ml", "link": { - "path": "x-pack/plugins/reporting/public/plugin.ts", - "lineNumber": 116 + "path": "x-pack/plugins/ml/public/application/license/check_license.tsx", + "lineNumber": 26 } }, { - "plugin": "reporting", + "plugin": "ml", "link": { - "path": "x-pack/plugins/reporting/public/components/report_listing.tsx", - "lineNumber": 61 + "path": "x-pack/plugins/ml/public/plugin.ts", + "lineNumber": 136 } }, { @@ -1019,17 +1012,17 @@ } }, { - "plugin": "beatsManagement", + "plugin": "crossClusterReplication", "link": { - "path": "x-pack/plugins/beats_management/public/lib/adapters/framework/kibana_framework_adapter.ts", - "lineNumber": 65 + "path": "x-pack/plugins/cross_cluster_replication/public/plugin.ts", + "lineNumber": 75 } }, { - "plugin": "crossClusterReplication", + "plugin": "fleet", "link": { - "path": "x-pack/plugins/cross_cluster_replication/public/plugin.ts", - "lineNumber": 75 + "path": "x-pack/plugins/fleet/public/plugin.ts", + "lineNumber": 97 } }, { @@ -2650,192 +2643,192 @@ "deprecated": true, "references": [ { - "plugin": "securitySolution", + "plugin": "apm", "link": { - "path": "x-pack/plugins/security_solution/common/license/policy_config.test.ts", - "lineNumber": 22 + "path": "x-pack/plugins/apm/common/license_check.test.ts", + "lineNumber": 19 } }, { - "plugin": "securitySolution", + "plugin": "apm", "link": { - "path": "x-pack/plugins/security_solution/common/license/policy_config.test.ts", - "lineNumber": 23 + "path": "x-pack/plugins/apm/common/license_check.test.ts", + "lineNumber": 36 } }, { - "plugin": "securitySolution", + "plugin": "apm", "link": { - "path": "x-pack/plugins/security_solution/common/license/policy_config.test.ts", - "lineNumber": 24 + "path": "x-pack/plugins/apm/common/license_check.test.ts", + "lineNumber": 53 } }, { - "plugin": "securitySolution", + "plugin": "apm", "link": { - "path": "x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/index.test.ts", - "lineNumber": 159 + "path": "x-pack/plugins/apm/common/license_check.test.ts", + "lineNumber": 70 } }, { - "plugin": "securitySolution", + "plugin": "apm", "link": { - "path": "x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/index.test.ts", - "lineNumber": 161 + "path": "x-pack/plugins/apm/common/license_check.test.ts", + "lineNumber": 87 } }, { - "plugin": "securitySolution", + "plugin": "apm", "link": { - "path": "x-pack/plugins/security_solution/server/endpoint/lib/policy/license_watch.test.ts", - "lineNumber": 42 + "path": "x-pack/plugins/apm/common/license_check.test.ts", + "lineNumber": 104 } }, { - "plugin": "securitySolution", + "plugin": "apm", "link": { - "path": "x-pack/plugins/security_solution/server/endpoint/lib/policy/license_watch.test.ts", - "lineNumber": 43 + "path": "x-pack/plugins/apm/common/license_check.test.ts", + "lineNumber": 122 } }, { - "plugin": "securitySolution", + "plugin": "apm", "link": { - "path": "x-pack/plugins/security_solution/server/endpoint/lib/policy/license_watch.test.ts", - "lineNumber": 44 + "path": "x-pack/plugins/apm/common/license_check.test.ts", + "lineNumber": 139 } }, { - "plugin": "securitySolution", + "plugin": "apm", "link": { - "path": "x-pack/plugins/security_solution/server/endpoint/routes/actions/isolation.test.ts", - "lineNumber": 54 + "path": "x-pack/plugins/apm/common/license_check.test.ts", + "lineNumber": 156 } }, { - "plugin": "securitySolution", + "plugin": "apm", "link": { - "path": "x-pack/plugins/security_solution/server/endpoint/routes/actions/isolation.test.ts", - "lineNumber": 55 + "path": "x-pack/plugins/apm/common/license_check.test.ts", + "lineNumber": 173 } }, { - "plugin": "securitySolution", + "plugin": "apm", "link": { - "path": "x-pack/plugins/security_solution/server/fleet_integration/fleet_integration.test.ts", - "lineNumber": 47 + "path": "x-pack/plugins/apm/common/license_check.test.ts", + "lineNumber": 190 } }, { - "plugin": "securitySolution", + "plugin": "apm", "link": { - "path": "x-pack/plugins/security_solution/server/fleet_integration/fleet_integration.test.ts", - "lineNumber": 48 + "path": "x-pack/plugins/apm/common/license_check.test.ts", + "lineNumber": 207 } }, { - "plugin": "apm", + "plugin": "security", "link": { - "path": "x-pack/plugins/apm/common/license_check.test.ts", - "lineNumber": 19 + "path": "x-pack/plugins/security/common/licensing/license_service.test.ts", + "lineNumber": 169 } }, { - "plugin": "apm", + "plugin": "security", "link": { - "path": "x-pack/plugins/apm/common/license_check.test.ts", - "lineNumber": 36 + "path": "x-pack/plugins/security/common/licensing/license_service.test.ts", + "lineNumber": 194 } }, { - "plugin": "apm", + "plugin": "security", "link": { - "path": "x-pack/plugins/apm/common/license_check.test.ts", - "lineNumber": 53 + "path": "x-pack/plugins/security/common/licensing/license_service.test.ts", + "lineNumber": 219 } }, { - "plugin": "apm", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/apm/common/license_check.test.ts", - "lineNumber": 70 + "path": "x-pack/plugins/security_solution/common/license/policy_config.test.ts", + "lineNumber": 22 } }, { - "plugin": "apm", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/apm/common/license_check.test.ts", - "lineNumber": 87 + "path": "x-pack/plugins/security_solution/common/license/policy_config.test.ts", + "lineNumber": 23 } }, { - "plugin": "apm", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/apm/common/license_check.test.ts", - "lineNumber": 104 + "path": "x-pack/plugins/security_solution/common/license/policy_config.test.ts", + "lineNumber": 24 } }, { - "plugin": "apm", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/apm/common/license_check.test.ts", - "lineNumber": 122 + "path": "x-pack/plugins/security_solution/server/fleet_integration/fleet_integration.test.ts", + "lineNumber": 47 } }, { - "plugin": "apm", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/apm/common/license_check.test.ts", - "lineNumber": 139 + "path": "x-pack/plugins/security_solution/server/fleet_integration/fleet_integration.test.ts", + "lineNumber": 48 } }, { - "plugin": "apm", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/apm/common/license_check.test.ts", - "lineNumber": 156 + "path": "x-pack/plugins/security_solution/server/endpoint/lib/policy/license_watch.test.ts", + "lineNumber": 42 } }, { - "plugin": "apm", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/apm/common/license_check.test.ts", - "lineNumber": 173 + "path": "x-pack/plugins/security_solution/server/endpoint/lib/policy/license_watch.test.ts", + "lineNumber": 43 } }, { - "plugin": "apm", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/apm/common/license_check.test.ts", - "lineNumber": 190 + "path": "x-pack/plugins/security_solution/server/endpoint/lib/policy/license_watch.test.ts", + "lineNumber": 44 } }, { - "plugin": "apm", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/apm/common/license_check.test.ts", - "lineNumber": 207 + "path": "x-pack/plugins/security_solution/server/endpoint/routes/actions/isolation.test.ts", + "lineNumber": 54 } }, { - "plugin": "security", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/security/common/licensing/license_service.test.ts", - "lineNumber": 169 + "path": "x-pack/plugins/security_solution/server/endpoint/routes/actions/isolation.test.ts", + "lineNumber": 55 } }, { - "plugin": "security", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/security/common/licensing/license_service.test.ts", - "lineNumber": 194 + "path": "x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/index.test.ts", + "lineNumber": 159 } }, { - "plugin": "security", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/security/common/licensing/license_service.test.ts", - "lineNumber": 219 + "path": "x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/index.test.ts", + "lineNumber": 161 } } ] @@ -3060,7 +3053,7 @@ "plugin": "spaces", "link": { "path": "x-pack/plugins/spaces/server/usage_collection/spaces_usage_collector.ts", - "lineNumber": 442 + "lineNumber": 431 } }, { @@ -3126,13 +3119,6 @@ "lineNumber": 139 } }, - { - "plugin": "fleet", - "link": { - "path": "x-pack/plugins/fleet/server/plugin.ts", - "lineNumber": 213 - } - }, { "plugin": "indexManagement", "link": { @@ -3147,6 +3133,13 @@ "lineNumber": 73 } }, + { + "plugin": "fleet", + "link": { + "path": "x-pack/plugins/fleet/server/plugin.ts", + "lineNumber": 213 + } + }, { "plugin": "graph", "link": { diff --git a/api_docs/lists.json b/api_docs/lists.json index 8932650bdff76..90f5cd726287b 100644 --- a/api_docs/lists.json +++ b/api_docs/lists.json @@ -273,1055 +273,8 @@ "initialIsOpen": false } ], - "functions": [ - { - "parentPluginId": "lists", - "id": "def-public.addEndpointExceptionListWithValidation", - "type": "Function", - "tags": [], - "label": "addEndpointExceptionListWithValidation", - "description": [], - "signature": [ - "({ http, signal, }: ", - "AddEndpointExceptionListProps", - ") => Promise<{ _version: string | undefined; created_at: string; created_by: string; description: string; id: string; immutable: boolean; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"endpoint\" | \"detection\" | \"endpoint_events\"; updated_at: string; updated_by: string; version: number; } | {}>" - ], - "source": { - "path": "x-pack/plugins/lists/public/exceptions/api.ts", - "lineNumber": 532 - }, - "deprecated": false, - "children": [ - { - "parentPluginId": "lists", - "id": "def-public.addEndpointExceptionListWithValidation.$1", - "type": "Object", - "tags": [], - "label": "{\n http,\n signal,\n}", - "description": [], - "signature": [ - "AddEndpointExceptionListProps" - ], - "source": { - "path": "x-pack/plugins/lists/public/exceptions/api.ts", - "lineNumber": 532 - }, - "deprecated": false, - "isRequired": true - } - ], - "returnComment": [], - "initialIsOpen": false - }, - { - "parentPluginId": "lists", - "id": "def-public.addExceptionListWithValidation", - "type": "Function", - "tags": [], - "label": "addExceptionListWithValidation", - "description": [], - "signature": [ - "({ http, list, signal, }: ", - "AddExceptionListProps", - ") => Promise<{ _version: string | undefined; created_at: string; created_by: string; description: string; id: string; immutable: boolean; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"endpoint\" | \"detection\" | \"endpoint_events\"; updated_at: string; updated_by: string; version: number; }>" - ], - "source": { - "path": "x-pack/plugins/lists/public/exceptions/api.ts", - "lineNumber": 66 - }, - "deprecated": false, - "children": [ - { - "parentPluginId": "lists", - "id": "def-public.addExceptionListWithValidation.$1", - "type": "Object", - "tags": [], - "label": "{\n http,\n list,\n signal,\n}", - "description": [], - "signature": [ - "AddExceptionListProps" - ], - "source": { - "path": "x-pack/plugins/lists/public/exceptions/api.ts", - "lineNumber": 66 - }, - "deprecated": false, - "isRequired": true - } - ], - "returnComment": [], - "initialIsOpen": false - }, - { - "parentPluginId": "lists", - "id": "def-public.exportListWithValidation", - "type": "Function", - "tags": [], - "label": "exportListWithValidation", - "description": [], - "signature": [ - "({ http, listId, signal, }: ", - "ExportListParams", - ") => Promise" - ], - "source": { - "path": "x-pack/plugins/lists/public/lists/api.ts", - "lineNumber": 174 - }, - "deprecated": false, - "children": [ - { - "parentPluginId": "lists", - "id": "def-public.exportListWithValidation.$1", - "type": "Object", - "tags": [], - "label": "{\n http,\n listId,\n signal,\n}", - "description": [], - "signature": [ - "ExportListParams" - ], - "source": { - "path": "x-pack/plugins/lists/public/lists/api.ts", - "lineNumber": 174 - }, - "deprecated": false, - "isRequired": true - } - ], - "returnComment": [], - "initialIsOpen": false - }, - { - "parentPluginId": "lists", - "id": "def-public.fetchExceptionListByIdWithValidation", - "type": "Function", - "tags": [], - "label": "fetchExceptionListByIdWithValidation", - "description": [], - "signature": [ - "({ http, id, namespaceType, signal, }: ", - "ApiCallByIdProps", - ") => Promise<{ _version: string | undefined; created_at: string; created_by: string; description: string; id: string; immutable: boolean; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"endpoint\" | \"detection\" | \"endpoint_events\"; updated_at: string; updated_by: string; version: number; }>" - ], - "source": { - "path": "x-pack/plugins/lists/public/exceptions/api.ts", - "lineNumber": 299 - }, - "deprecated": false, - "children": [ - { - "parentPluginId": "lists", - "id": "def-public.fetchExceptionListByIdWithValidation.$1", - "type": "Object", - "tags": [], - "label": "{\n http,\n id,\n namespaceType,\n signal,\n}", - "description": [], - "signature": [ - "ApiCallByIdProps" - ], - "source": { - "path": "x-pack/plugins/lists/public/exceptions/api.ts", - "lineNumber": 299 - }, - "deprecated": false, - "isRequired": true - } - ], - "returnComment": [], - "initialIsOpen": false - }, - { - "parentPluginId": "lists", - "id": "def-public.transformNewItemOutput", - "type": "Function", - "tags": [], - "label": "transformNewItemOutput", - "description": [], - "signature": [ - "(exceptionItem: { description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"text\" | \"keyword\" | \"long\" | \"double\" | \"ip\" | \"date_nanos\" | \"geo_point\" | \"geo_shape\" | \"binary\" | \"short\" | \"date_range\" | \"ip_range\" | \"shape\" | \"integer\" | \"byte\" | \"float\" | \"half_float\" | \"integer_range\" | \"float_range\" | \"long_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; })[]; list_id: string; name: string; type: \"simple\"; } & { comments?: { comment: string; }[] | undefined; item_id?: string | undefined; meta?: object | undefined; namespace_type?: \"single\" | \"agnostic\" | undefined; os_types?: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags?: string[] | undefined; }) => { description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"text\" | \"keyword\" | \"long\" | \"double\" | \"ip\" | \"date_nanos\" | \"geo_point\" | \"geo_shape\" | \"binary\" | \"short\" | \"date_range\" | \"ip_range\" | \"shape\" | \"integer\" | \"byte\" | \"float\" | \"half_float\" | \"integer_range\" | \"float_range\" | \"long_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; })[]; list_id: string; name: string; type: \"simple\"; } & { comments?: { comment: string; }[] | undefined; item_id?: string | undefined; meta?: object | undefined; namespace_type?: \"single\" | \"agnostic\" | undefined; os_types?: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags?: string[] | undefined; }" - ], - "source": { - "path": "x-pack/plugins/lists/public/exceptions/transforms.ts", - "lineNumber": 40 - }, - "deprecated": false, - "children": [ - { - "parentPluginId": "lists", - "id": "def-public.transformNewItemOutput.$1", - "type": "CompoundType", - "tags": [], - "label": "exceptionItem", - "description": [], - "signature": [ - "{ description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"text\" | \"keyword\" | \"long\" | \"double\" | \"ip\" | \"date_nanos\" | \"geo_point\" | \"geo_shape\" | \"binary\" | \"short\" | \"date_range\" | \"ip_range\" | \"shape\" | \"integer\" | \"byte\" | \"float\" | \"half_float\" | \"integer_range\" | \"float_range\" | \"long_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; })[]; list_id: string; name: string; type: \"simple\"; } & { comments?: { comment: string; }[] | undefined; item_id?: string | undefined; meta?: object | undefined; namespace_type?: \"single\" | \"agnostic\" | undefined; os_types?: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags?: string[] | undefined; }" - ], - "source": { - "path": "x-pack/plugins/lists/public/exceptions/transforms.ts", - "lineNumber": 41 - }, - "deprecated": false, - "isRequired": true - } - ], - "returnComment": [], - "initialIsOpen": false - }, - { - "parentPluginId": "lists", - "id": "def-public.transformOutput", - "type": "Function", - "tags": [], - "label": "transformOutput", - "description": [ - "\nTransforms the output of exception items to compensate for technical debt or UI concerns such as\nReactJS preferences for having ids within arrays if the data is not modeled that way.\n\nIf you add a new transform of the output called \"myNewTransform\" do it\nin the form of:\nflow(removeIdFromExceptionItemsEntries, myNewTransform)(exceptionItem)\n" - ], - "signature": [ - "(exceptionItem: { _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"text\" | \"keyword\" | \"long\" | \"double\" | \"ip\" | \"date_nanos\" | \"geo_point\" | \"geo_shape\" | \"binary\" | \"short\" | \"date_range\" | \"ip_range\" | \"shape\" | \"integer\" | \"byte\" | \"float\" | \"half_float\" | \"integer_range\" | \"float_range\" | \"long_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; } | ({ description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"text\" | \"keyword\" | \"long\" | \"double\" | \"ip\" | \"date_nanos\" | \"geo_point\" | \"geo_shape\" | \"binary\" | \"short\" | \"date_range\" | \"ip_range\" | \"shape\" | \"integer\" | \"byte\" | \"float\" | \"half_float\" | \"integer_range\" | \"float_range\" | \"long_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; })[]; name: string; type: \"simple\"; } & { _version?: string | undefined; comments?: ({ comment: string; } & { id?: string | undefined; })[] | undefined; id?: string | undefined; item_id?: string | undefined; meta?: object | undefined; namespace_type?: \"single\" | \"agnostic\" | undefined; os_types?: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags?: string[] | undefined; })) => { _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"text\" | \"keyword\" | \"long\" | \"double\" | \"ip\" | \"date_nanos\" | \"geo_point\" | \"geo_shape\" | \"binary\" | \"short\" | \"date_range\" | \"ip_range\" | \"shape\" | \"integer\" | \"byte\" | \"float\" | \"half_float\" | \"integer_range\" | \"float_range\" | \"long_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; } | ({ description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"text\" | \"keyword\" | \"long\" | \"double\" | \"ip\" | \"date_nanos\" | \"geo_point\" | \"geo_shape\" | \"binary\" | \"short\" | \"date_range\" | \"ip_range\" | \"shape\" | \"integer\" | \"byte\" | \"float\" | \"half_float\" | \"integer_range\" | \"float_range\" | \"long_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; })[]; name: string; type: \"simple\"; } & { _version?: string | undefined; comments?: ({ comment: string; } & { id?: string | undefined; })[] | undefined; id?: string | undefined; item_id?: string | undefined; meta?: object | undefined; namespace_type?: \"single\" | \"agnostic\" | undefined; os_types?: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags?: string[] | undefined; })" - ], - "source": { - "path": "x-pack/plugins/lists/public/exceptions/transforms.ts", - "lineNumber": 35 - }, - "deprecated": false, - "children": [ - { - "parentPluginId": "lists", - "id": "def-public.transformOutput.$1", - "type": "CompoundType", - "tags": [], - "label": "exceptionItem", - "description": [], - "signature": [ - "{ _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"text\" | \"keyword\" | \"long\" | \"double\" | \"ip\" | \"date_nanos\" | \"geo_point\" | \"geo_shape\" | \"binary\" | \"short\" | \"date_range\" | \"ip_range\" | \"shape\" | \"integer\" | \"byte\" | \"float\" | \"half_float\" | \"integer_range\" | \"float_range\" | \"long_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; } | ({ description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"text\" | \"keyword\" | \"long\" | \"double\" | \"ip\" | \"date_nanos\" | \"geo_point\" | \"geo_shape\" | \"binary\" | \"short\" | \"date_range\" | \"ip_range\" | \"shape\" | \"integer\" | \"byte\" | \"float\" | \"half_float\" | \"integer_range\" | \"float_range\" | \"long_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; })[]; name: string; type: \"simple\"; } & { _version?: string | undefined; comments?: ({ comment: string; } & { id?: string | undefined; })[] | undefined; id?: string | undefined; item_id?: string | undefined; meta?: object | undefined; namespace_type?: \"single\" | \"agnostic\" | undefined; os_types?: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags?: string[] | undefined; })" - ], - "source": { - "path": "x-pack/plugins/lists/public/exceptions/transforms.ts", - "lineNumber": 36 - }, - "deprecated": false, - "isRequired": true - } - ], - "returnComment": [ - "The exceptionItem transformed from the output" - ], - "initialIsOpen": false - }, - { - "parentPluginId": "lists", - "id": "def-public.useApi", - "type": "Function", - "tags": [], - "label": "useApi", - "description": [], - "signature": [ - "(http: ", - { - "pluginId": "core", - "scope": "public", - "docId": "kibCoreHttpPluginApi", - "section": "def-public.HttpSetup", - "text": "HttpSetup" - }, - ") => ", - "ExceptionsApi" - ], - "source": { - "path": "x-pack/plugins/lists/public/exceptions/hooks/use_api.ts", - "lineNumber": 41 - }, - "deprecated": false, - "children": [ - { - "parentPluginId": "lists", - "id": "def-public.useApi.$1", - "type": "Object", - "tags": [], - "label": "http", - "description": [], - "signature": [ - { - "pluginId": "core", - "scope": "public", - "docId": "kibCoreHttpPluginApi", - "section": "def-public.HttpSetup", - "text": "HttpSetup" - } - ], - "source": { - "path": "x-pack/plugins/lists/public/exceptions/hooks/use_api.ts", - "lineNumber": 41 - }, - "deprecated": false, - "isRequired": true - } - ], - "returnComment": [], - "initialIsOpen": false - }, - { - "parentPluginId": "lists", - "id": "def-public.useAsync", - "type": "Function", - "tags": [], - "label": "useAsync", - "description": [ - "\n" - ], - "signature": [ - "(fn: (...args: Args) => Promise) => ", - "Async", - "" - ], - "source": { - "path": "x-pack/plugins/lists/public/common/hooks/use_async.ts", - "lineNumber": 25 - }, - "deprecated": false, - "children": [ - { - "parentPluginId": "lists", - "id": "def-public.useAsync.$1", - "type": "Function", - "tags": [], - "label": "fn", - "description": [], - "signature": [ - "(...args: Args) => Promise" - ], - "source": { - "path": "x-pack/plugins/lists/public/common/hooks/use_async.ts", - "lineNumber": 26 - }, - "deprecated": false, - "isRequired": true - } - ], - "returnComment": [ - "An {@link AsyncTask} containing the underlying task's state along with a start callback" - ], - "initialIsOpen": false - }, - { - "parentPluginId": "lists", - "id": "def-public.useCreateListIndex", - "type": "Function", - "tags": [], - "label": "useCreateListIndex", - "description": [], - "signature": [ - "() => ", - "Async", - "<[args: ", - "OptionalSignalArgs", - "<", - "ApiParams", - ">], { acknowledged: boolean; }>" - ], - "source": { - "path": "x-pack/plugins/lists/public/lists/hooks/use_create_list_index.ts", - "lineNumber": 15 - }, - "deprecated": false, - "children": [], - "returnComment": [], - "initialIsOpen": false - }, - { - "parentPluginId": "lists", - "id": "def-public.useCursor", - "type": "Function", - "tags": [], - "label": "useCursor", - "description": [], - "signature": [ - "({ pageIndex, pageSize }: ", - "UseCursorProps", - ") => [string | undefined, SetCursor]" - ], - "source": { - "path": "x-pack/plugins/lists/public/common/hooks/use_cursor.ts", - "lineNumber": 20 - }, - "deprecated": false, - "children": [ - { - "parentPluginId": "lists", - "id": "def-public.useCursor.$1", - "type": "Object", - "tags": [], - "label": "{ pageIndex, pageSize }", - "description": [], - "signature": [ - "UseCursorProps" - ], - "source": { - "path": "x-pack/plugins/lists/public/common/hooks/use_cursor.ts", - "lineNumber": 20 - }, - "deprecated": false, - "isRequired": true - } - ], - "returnComment": [], - "initialIsOpen": false - }, - { - "parentPluginId": "lists", - "id": "def-public.useDeleteList", - "type": "Function", - "tags": [], - "label": "useDeleteList", - "description": [], - "signature": [ - "() => ", - "Async", - "<[args: ", - "OptionalSignalArgs", - "<", - "DeleteListParams", - ">], { _version: string | undefined; created_at: string; created_by: string; description: string; deserializer: string | undefined; id: string; immutable: boolean; meta: object | undefined; name: string; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"text\" | \"keyword\" | \"long\" | \"double\" | \"ip\" | \"date_nanos\" | \"geo_point\" | \"geo_shape\" | \"binary\" | \"short\" | \"date_range\" | \"ip_range\" | \"shape\" | \"integer\" | \"byte\" | \"float\" | \"half_float\" | \"integer_range\" | \"float_range\" | \"long_range\" | \"double_range\"; updated_at: string; updated_by: string; version: number; }>" - ], - "source": { - "path": "x-pack/plugins/lists/public/lists/hooks/use_delete_list.ts", - "lineNumber": 15 - }, - "deprecated": false, - "children": [], - "returnComment": [], - "initialIsOpen": false - }, - { - "parentPluginId": "lists", - "id": "def-public.useExceptionListItems", - "type": "Function", - "tags": [], - "label": "useExceptionListItems", - "description": [ - "\nHook for using to get an ExceptionList and it's ExceptionListItems\n" - ], - "signature": [ - "({ http, lists, pagination, filterOptions, showDetectionsListsOnly, showEndpointListsOnly, matchFilters, onError, onSuccess, }: ", - "UseExceptionListProps", - ") => ", - "ReturnExceptionListAndItems" - ], - "source": { - "path": "x-pack/plugins/lists/public/exceptions/hooks/use_exception_list_items.ts", - "lineNumber": 39 - }, - "deprecated": false, - "children": [ - { - "parentPluginId": "lists", - "id": "def-public.useExceptionListItems.$1", - "type": "Object", - "tags": [], - "label": "{\n http,\n lists,\n pagination = {\n page: 1,\n perPage: 20,\n total: 0,\n },\n filterOptions,\n showDetectionsListsOnly,\n showEndpointListsOnly,\n matchFilters,\n onError,\n onSuccess,\n}", - "description": [], - "signature": [ - "UseExceptionListProps" - ], - "source": { - "path": "x-pack/plugins/lists/public/exceptions/hooks/use_exception_list_items.ts", - "lineNumber": 39 - }, - "deprecated": false, - "isRequired": true - } - ], - "returnComment": [], - "initialIsOpen": false - }, - { - "parentPluginId": "lists", - "id": "def-public.useExceptionLists", - "type": "Function", - "tags": [], - "label": "useExceptionLists", - "description": [ - "\nHook for fetching ExceptionLists\n" - ], - "signature": [ - "({ errorMessage, http, pagination, filterOptions, namespaceTypes, notifications, showTrustedApps, }: ", - "UseExceptionListsProps", - ") => ", - "ReturnExceptionLists" - ], - "source": { - "path": "x-pack/plugins/lists/public/exceptions/hooks/use_exception_lists.ts", - "lineNumber": 30 - }, - "deprecated": false, - "children": [ - { - "parentPluginId": "lists", - "id": "def-public.useExceptionLists.$1", - "type": "Object", - "tags": [], - "label": "{\n errorMessage,\n http,\n pagination = {\n page: 1,\n perPage: 20,\n total: 0,\n },\n filterOptions = {},\n namespaceTypes,\n notifications,\n showTrustedApps = false,\n}", - "description": [], - "signature": [ - "UseExceptionListsProps" - ], - "source": { - "path": "x-pack/plugins/lists/public/exceptions/hooks/use_exception_lists.ts", - "lineNumber": 30 - }, - "deprecated": false, - "isRequired": true - } - ], - "returnComment": [], - "initialIsOpen": false - }, - { - "parentPluginId": "lists", - "id": "def-public.useExportList", - "type": "Function", - "tags": [], - "label": "useExportList", - "description": [], - "signature": [ - "() => ", - "Async", - "<[args: ", - "OptionalSignalArgs", - "<", - "ExportListParams", - ">], Blob>" - ], - "source": { - "path": "x-pack/plugins/lists/public/lists/hooks/use_export_list.ts", - "lineNumber": 15 - }, - "deprecated": false, - "children": [], - "returnComment": [], - "initialIsOpen": false - }, - { - "parentPluginId": "lists", - "id": "def-public.useFindLists", - "type": "Function", - "tags": [], - "label": "useFindLists", - "description": [], - "signature": [ - "() => ", - "Async", - "<[args: ", - "OptionalSignalArgs", - "<", - "FindListsParams", - ">], { cursor: string; data: { _version: string | undefined; created_at: string; created_by: string; description: string; deserializer: string | undefined; id: string; immutable: boolean; meta: object | undefined; name: string; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"text\" | \"keyword\" | \"long\" | \"double\" | \"ip\" | \"date_nanos\" | \"geo_point\" | \"geo_shape\" | \"binary\" | \"short\" | \"date_range\" | \"ip_range\" | \"shape\" | \"integer\" | \"byte\" | \"float\" | \"half_float\" | \"integer_range\" | \"float_range\" | \"long_range\" | \"double_range\"; updated_at: string; updated_by: string; version: number; }[]; page: number; per_page: number; total: number; }>" - ], - "source": { - "path": "x-pack/plugins/lists/public/lists/hooks/use_find_lists.ts", - "lineNumber": 15 - }, - "deprecated": false, - "children": [], - "returnComment": [], - "initialIsOpen": false - }, - { - "parentPluginId": "lists", - "id": "def-public.useImportList", - "type": "Function", - "tags": [], - "label": "useImportList", - "description": [], - "signature": [ - "() => ", - "Async", - "<[args: ", - "OptionalSignalArgs", - "<", - "ImportListParams", - ">], { _version: string | undefined; created_at: string; created_by: string; description: string; deserializer: string | undefined; id: string; immutable: boolean; meta: object | undefined; name: string; serializer: string | undefined; tie_breaker_id: string; type: \"boolean\" | \"date\" | \"text\" | \"keyword\" | \"long\" | \"double\" | \"ip\" | \"date_nanos\" | \"geo_point\" | \"geo_shape\" | \"binary\" | \"short\" | \"date_range\" | \"ip_range\" | \"shape\" | \"integer\" | \"byte\" | \"float\" | \"half_float\" | \"integer_range\" | \"float_range\" | \"long_range\" | \"double_range\"; updated_at: string; updated_by: string; version: number; }>" - ], - "source": { - "path": "x-pack/plugins/lists/public/lists/hooks/use_import_list.ts", - "lineNumber": 15 - }, - "deprecated": false, - "children": [], - "returnComment": [], - "initialIsOpen": false - }, - { - "parentPluginId": "lists", - "id": "def-public.useReadListIndex", - "type": "Function", - "tags": [], - "label": "useReadListIndex", - "description": [], - "signature": [ - "() => ", - "Async", - "<[args: ", - "OptionalSignalArgs", - "<", - "ApiParams", - ">], { list_index: boolean; list_item_index: boolean; }>" - ], - "source": { - "path": "x-pack/plugins/lists/public/lists/hooks/use_read_list_index.ts", - "lineNumber": 15 - }, - "deprecated": false, - "children": [], - "returnComment": [], - "initialIsOpen": false - }, - { - "parentPluginId": "lists", - "id": "def-public.useReadListPrivileges", - "type": "Function", - "tags": [], - "label": "useReadListPrivileges", - "description": [], - "signature": [ - "() => ", - "Async", - "<[args: ", - "OptionalSignalArgs", - "<", - "ApiParams", - ">], unknown>" - ], - "source": { - "path": "x-pack/plugins/lists/public/lists/hooks/use_read_list_privileges.ts", - "lineNumber": 15 - }, - "deprecated": false, - "children": [], - "returnComment": [], - "initialIsOpen": false - }, - { - "parentPluginId": "lists", - "id": "def-public.withOptionalSignal", - "type": "Function", - "tags": [], - "label": "withOptionalSignal", - "description": [ - "\n" - ], - "signature": [ - "(fn: (args: Args) => Result) => (args: ", - "OptionalSignalArgs", - ") => Result" - ], - "source": { - "path": "x-pack/plugins/lists/public/common/with_optional_signal.ts", - "lineNumber": 20 - }, - "deprecated": false, - "children": [ - { - "parentPluginId": "lists", - "id": "def-public.withOptionalSignal.$1", - "type": "Function", - "tags": [], - "label": "fn", - "description": [], - "signature": [ - "(args: Args) => Result" - ], - "source": { - "path": "x-pack/plugins/lists/public/common/with_optional_signal.ts", - "lineNumber": 20 - }, - "deprecated": false, - "isRequired": true - } - ], - "returnComment": [ - "An async function where the AbortSignal argument is optional" - ], - "initialIsOpen": false - } - ], - "interfaces": [ - { - "parentPluginId": "lists", - "id": "def-public.ExceptionList", - "type": "Interface", - "tags": [], - "label": "ExceptionList", - "description": [], - "signature": [ - { - "pluginId": "lists", - "scope": "public", - "docId": "kibListsPluginApi", - "section": "def-public.ExceptionList", - "text": "ExceptionList" - }, - " extends { _version: string | undefined; created_at: string; created_by: string; description: string; id: string; immutable: boolean; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"endpoint\" | \"detection\" | \"endpoint_events\"; updated_at: string; updated_by: string; version: number; }" - ], - "source": { - "path": "x-pack/plugins/lists/public/exceptions/types.ts", - "lineNumber": 42 - }, - "deprecated": false, - "children": [ - { - "parentPluginId": "lists", - "id": "def-public.ExceptionList.totalItems", - "type": "number", - "tags": [], - "label": "totalItems", - "description": [], - "source": { - "path": "x-pack/plugins/lists/public/exceptions/types.ts", - "lineNumber": 43 - }, - "deprecated": false - } - ], - "initialIsOpen": false - }, - { - "parentPluginId": "lists", - "id": "def-public.ExceptionListFilter", - "type": "Interface", - "tags": [], - "label": "ExceptionListFilter", - "description": [], - "source": { - "path": "x-pack/plugins/lists/public/exceptions/types.ts", - "lineNumber": 126 - }, - "deprecated": false, - "children": [ - { - "parentPluginId": "lists", - "id": "def-public.ExceptionListFilter.name", - "type": "CompoundType", - "tags": [], - "label": "name", - "description": [], - "signature": [ - "string | null | undefined" - ], - "source": { - "path": "x-pack/plugins/lists/public/exceptions/types.ts", - "lineNumber": 127 - }, - "deprecated": false - }, - { - "parentPluginId": "lists", - "id": "def-public.ExceptionListFilter.list_id", - "type": "CompoundType", - "tags": [], - "label": "list_id", - "description": [], - "signature": [ - "string | null | undefined" - ], - "source": { - "path": "x-pack/plugins/lists/public/exceptions/types.ts", - "lineNumber": 128 - }, - "deprecated": false - }, - { - "parentPluginId": "lists", - "id": "def-public.ExceptionListFilter.created_by", - "type": "CompoundType", - "tags": [], - "label": "created_by", - "description": [], - "signature": [ - "string | null | undefined" - ], - "source": { - "path": "x-pack/plugins/lists/public/exceptions/types.ts", - "lineNumber": 129 - }, - "deprecated": false - }, - { - "parentPluginId": "lists", - "id": "def-public.ExceptionListFilter.type", - "type": "CompoundType", - "tags": [], - "label": "type", - "description": [], - "signature": [ - "string | null | undefined" - ], - "source": { - "path": "x-pack/plugins/lists/public/exceptions/types.ts", - "lineNumber": 130 - }, - "deprecated": false - }, - { - "parentPluginId": "lists", - "id": "def-public.ExceptionListFilter.tags", - "type": "CompoundType", - "tags": [], - "label": "tags", - "description": [], - "signature": [ - "string | null | undefined" - ], - "source": { - "path": "x-pack/plugins/lists/public/exceptions/types.ts", - "lineNumber": 131 - }, - "deprecated": false - } - ], - "initialIsOpen": false - }, - { - "parentPluginId": "lists", - "id": "def-public.ExceptionListIdentifiers", - "type": "Interface", - "tags": [], - "label": "ExceptionListIdentifiers", - "description": [], - "source": { - "path": "x-pack/plugins/lists/public/exceptions/types.ts", - "lineNumber": 63 - }, - "deprecated": false, - "children": [ - { - "parentPluginId": "lists", - "id": "def-public.ExceptionListIdentifiers.id", - "type": "string", - "tags": [], - "label": "id", - "description": [], - "source": { - "path": "x-pack/plugins/lists/public/exceptions/types.ts", - "lineNumber": 64 - }, - "deprecated": false - }, - { - "parentPluginId": "lists", - "id": "def-public.ExceptionListIdentifiers.listId", - "type": "string", - "tags": [], - "label": "listId", - "description": [], - "source": { - "path": "x-pack/plugins/lists/public/exceptions/types.ts", - "lineNumber": 65 - }, - "deprecated": false - }, - { - "parentPluginId": "lists", - "id": "def-public.ExceptionListIdentifiers.namespaceType", - "type": "CompoundType", - "tags": [], - "label": "namespaceType", - "description": [], - "signature": [ - "\"single\" | \"agnostic\"" - ], - "source": { - "path": "x-pack/plugins/lists/public/exceptions/types.ts", - "lineNumber": 66 - }, - "deprecated": false - }, - { - "parentPluginId": "lists", - "id": "def-public.ExceptionListIdentifiers.type", - "type": "CompoundType", - "tags": [], - "label": "type", - "description": [], - "signature": [ - "\"endpoint\" | \"detection\" | \"endpoint_events\"" - ], - "source": { - "path": "x-pack/plugins/lists/public/exceptions/types.ts", - "lineNumber": 67 - }, - "deprecated": false - } - ], - "initialIsOpen": false - }, - { - "parentPluginId": "lists", - "id": "def-public.Pagination", - "type": "Interface", - "tags": [], - "label": "Pagination", - "description": [], - "source": { - "path": "x-pack/plugins/lists/public/exceptions/types.ts", - "lineNumber": 29 - }, - "deprecated": false, - "children": [ - { - "parentPluginId": "lists", - "id": "def-public.Pagination.page", - "type": "number", - "tags": [], - "label": "page", - "description": [], - "source": { - "path": "x-pack/plugins/lists/public/exceptions/types.ts", - "lineNumber": 30 - }, - "deprecated": false - }, - { - "parentPluginId": "lists", - "id": "def-public.Pagination.perPage", - "type": "number", - "tags": [], - "label": "perPage", - "description": [], - "source": { - "path": "x-pack/plugins/lists/public/exceptions/types.ts", - "lineNumber": 31 - }, - "deprecated": false - }, - { - "parentPluginId": "lists", - "id": "def-public.Pagination.total", - "type": "number", - "tags": [], - "label": "total", - "description": [], - "signature": [ - "number | undefined" - ], - "source": { - "path": "x-pack/plugins/lists/public/exceptions/types.ts", - "lineNumber": 32 - }, - "deprecated": false - } - ], - "initialIsOpen": false - }, - { - "parentPluginId": "lists", - "id": "def-public.UseExceptionListItemsSuccess", - "type": "Interface", - "tags": [], - "label": "UseExceptionListItemsSuccess", - "description": [], - "source": { - "path": "x-pack/plugins/lists/public/exceptions/types.ts", - "lineNumber": 46 - }, - "deprecated": false, - "children": [ - { - "parentPluginId": "lists", - "id": "def-public.UseExceptionListItemsSuccess.exceptions", - "type": "Array", - "tags": [], - "label": "exceptions", - "description": [], - "signature": [ - "{ _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"text\" | \"keyword\" | \"long\" | \"double\" | \"ip\" | \"date_nanos\" | \"geo_point\" | \"geo_shape\" | \"binary\" | \"short\" | \"date_range\" | \"ip_range\" | \"shape\" | \"integer\" | \"byte\" | \"float\" | \"half_float\" | \"integer_range\" | \"float_range\" | \"long_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; }[]" - ], - "source": { - "path": "x-pack/plugins/lists/public/exceptions/types.ts", - "lineNumber": 47 - }, - "deprecated": false - }, - { - "parentPluginId": "lists", - "id": "def-public.UseExceptionListItemsSuccess.pagination", - "type": "Object", - "tags": [], - "label": "pagination", - "description": [], - "signature": [ - { - "pluginId": "lists", - "scope": "public", - "docId": "kibListsPluginApi", - "section": "def-public.Pagination", - "text": "Pagination" - } - ], - "source": { - "path": "x-pack/plugins/lists/public/exceptions/types.ts", - "lineNumber": 48 - }, - "deprecated": false - } - ], - "initialIsOpen": false - }, - { - "parentPluginId": "lists", - "id": "def-public.UseExceptionListsSuccess", - "type": "Interface", - "tags": [], - "label": "UseExceptionListsSuccess", - "description": [], - "source": { - "path": "x-pack/plugins/lists/public/exceptions/types.ts", - "lineNumber": 121 - }, - "deprecated": false, - "children": [ - { - "parentPluginId": "lists", - "id": "def-public.UseExceptionListsSuccess.exceptions", - "type": "Array", - "tags": [], - "label": "exceptions", - "description": [], - "signature": [ - "{ _version: string | undefined; created_at: string; created_by: string; description: string; id: string; immutable: boolean; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"endpoint\" | \"detection\" | \"endpoint_events\"; updated_at: string; updated_by: string; version: number; }[]" - ], - "source": { - "path": "x-pack/plugins/lists/public/exceptions/types.ts", - "lineNumber": 122 - }, - "deprecated": false - }, - { - "parentPluginId": "lists", - "id": "def-public.UseExceptionListsSuccess.pagination", - "type": "Object", - "tags": [], - "label": "pagination", - "description": [], - "signature": [ - { - "pluginId": "lists", - "scope": "public", - "docId": "kibListsPluginApi", - "section": "def-public.Pagination", - "text": "Pagination" - } - ], - "source": { - "path": "x-pack/plugins/lists/public/exceptions/types.ts", - "lineNumber": 123 - }, - "deprecated": false - } - ], - "initialIsOpen": false - } - ], + "functions": [], + "interfaces": [], "enums": [], "misc": [], "objects": [ @@ -1338,7 +291,7 @@ ], "source": { "path": "x-pack/plugins/lists/public/shared_exports.ts", - "lineNumber": 36 + "lineNumber": 10 }, "deprecated": false, "initialIsOpen": false @@ -1388,7 +341,7 @@ "description": [], "source": { "path": "x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts", - "lineNumber": 57 + "lineNumber": 56 }, "deprecated": false, "children": [ @@ -1404,7 +357,7 @@ ], "source": { "path": "x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts", - "lineNumber": 62 + "lineNumber": 61 }, "deprecated": false, "children": [ @@ -1420,7 +373,7 @@ ], "source": { "path": "x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts", - "lineNumber": 62 + "lineNumber": 61 }, "deprecated": false, "isRequired": true @@ -1442,7 +395,7 @@ ], "source": { "path": "x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts", - "lineNumber": 67 + "lineNumber": 66 }, "deprecated": false, "children": [ @@ -1458,7 +411,7 @@ ], "source": { "path": "x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts", - "lineNumber": 67 + "lineNumber": 66 }, "deprecated": false, "isRequired": true @@ -1480,7 +433,7 @@ ], "source": { "path": "x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts", - "lineNumber": 76 + "lineNumber": 75 }, "deprecated": false, "children": [ @@ -1496,7 +449,7 @@ ], "source": { "path": "x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts", - "lineNumber": 76 + "lineNumber": 75 }, "deprecated": false, "isRequired": true @@ -1518,7 +471,7 @@ ], "source": { "path": "x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts", - "lineNumber": 91 + "lineNumber": 90 }, "deprecated": false, "children": [], @@ -1540,7 +493,7 @@ ], "source": { "path": "x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts", - "lineNumber": 103 + "lineNumber": 102 }, "deprecated": false, "children": [], @@ -1560,7 +513,7 @@ ], "source": { "path": "x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts", - "lineNumber": 115 + "lineNumber": 114 }, "deprecated": false, "children": [], @@ -1582,7 +535,7 @@ ], "source": { "path": "x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts", - "lineNumber": 129 + "lineNumber": 128 }, "deprecated": false, "children": [ @@ -1598,7 +551,7 @@ ], "source": { "path": "x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts", - "lineNumber": 129 + "lineNumber": 128 }, "deprecated": false, "isRequired": true @@ -1622,7 +575,7 @@ ], "source": { "path": "x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts", - "lineNumber": 165 + "lineNumber": 164 }, "deprecated": false, "children": [ @@ -1638,7 +591,7 @@ ], "source": { "path": "x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts", - "lineNumber": 165 + "lineNumber": 164 }, "deprecated": false, "isRequired": true @@ -1662,7 +615,7 @@ ], "source": { "path": "x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts", - "lineNumber": 201 + "lineNumber": 200 }, "deprecated": false, "children": [ @@ -1678,7 +631,7 @@ ], "source": { "path": "x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts", - "lineNumber": 201 + "lineNumber": 200 }, "deprecated": false, "isRequired": true @@ -1700,7 +653,7 @@ ], "source": { "path": "x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts", - "lineNumber": 209 + "lineNumber": 208 }, "deprecated": false, "children": [ @@ -1716,7 +669,7 @@ ], "source": { "path": "x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts", - "lineNumber": 209 + "lineNumber": 208 }, "deprecated": false, "isRequired": true @@ -1738,7 +691,7 @@ ], "source": { "path": "x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts", - "lineNumber": 236 + "lineNumber": 235 }, "deprecated": false, "children": [ @@ -1754,7 +707,7 @@ ], "source": { "path": "x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts", - "lineNumber": 236 + "lineNumber": 235 }, "deprecated": false, "isRequired": true @@ -1776,7 +729,7 @@ ], "source": { "path": "x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts", - "lineNumber": 267 + "lineNumber": 266 }, "deprecated": false, "children": [ @@ -1792,7 +745,7 @@ ], "source": { "path": "x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts", - "lineNumber": 267 + "lineNumber": 266 }, "deprecated": false, "isRequired": true @@ -1820,7 +773,7 @@ ], "source": { "path": "x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts", - "lineNumber": 281 + "lineNumber": 280 }, "deprecated": false, "children": [ @@ -1842,7 +795,7 @@ ], "source": { "path": "x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts", - "lineNumber": 281 + "lineNumber": 280 }, "deprecated": false, "isRequired": true @@ -1870,7 +823,7 @@ ], "source": { "path": "x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts", - "lineNumber": 312 + "lineNumber": 311 }, "deprecated": false, "children": [ @@ -1892,7 +845,7 @@ ], "source": { "path": "x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts", - "lineNumber": 312 + "lineNumber": 311 }, "deprecated": false, "isRequired": true @@ -1914,7 +867,7 @@ ], "source": { "path": "x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts", - "lineNumber": 345 + "lineNumber": 344 }, "deprecated": false, "children": [ @@ -1930,7 +883,7 @@ ], "source": { "path": "x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts", - "lineNumber": 345 + "lineNumber": 344 }, "deprecated": false, "isRequired": true @@ -1952,7 +905,7 @@ ], "source": { "path": "x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts", - "lineNumber": 359 + "lineNumber": 358 }, "deprecated": false, "children": [ @@ -1968,7 +921,7 @@ ], "source": { "path": "x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts", - "lineNumber": 359 + "lineNumber": 358 }, "deprecated": false, "isRequired": true @@ -1992,7 +945,7 @@ ], "source": { "path": "x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts", - "lineNumber": 374 + "lineNumber": 373 }, "deprecated": false, "children": [ @@ -2008,7 +961,7 @@ ], "source": { "path": "x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts", - "lineNumber": 374 + "lineNumber": 373 }, "deprecated": false, "isRequired": true @@ -2030,7 +983,7 @@ ], "source": { "path": "x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts", - "lineNumber": 387 + "lineNumber": 386 }, "deprecated": false, "children": [ @@ -2046,7 +999,7 @@ ], "source": { "path": "x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts", - "lineNumber": 387 + "lineNumber": 386 }, "deprecated": false, "isRequired": true @@ -2068,7 +1021,7 @@ ], "source": { "path": "x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts", - "lineNumber": 409 + "lineNumber": 408 }, "deprecated": false, "children": [ @@ -2084,7 +1037,7 @@ ], "source": { "path": "x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts", - "lineNumber": 409 + "lineNumber": 408 }, "deprecated": false, "isRequired": true @@ -2106,7 +1059,7 @@ ], "source": { "path": "x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts", - "lineNumber": 431 + "lineNumber": 430 }, "deprecated": false, "children": [ @@ -2122,7 +1075,7 @@ ], "source": { "path": "x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts", - "lineNumber": 431 + "lineNumber": 430 }, "deprecated": false, "isRequired": true @@ -2144,7 +1097,7 @@ ], "source": { "path": "x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts", - "lineNumber": 449 + "lineNumber": 448 }, "deprecated": false, "children": [ @@ -2160,7 +1113,7 @@ ], "source": { "path": "x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts", - "lineNumber": 449 + "lineNumber": 448 }, "deprecated": false, "isRequired": true @@ -2184,7 +1137,7 @@ ], "source": { "path": "x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts", - "lineNumber": 477 + "lineNumber": 476 }, "deprecated": false, "children": [ @@ -2200,7 +1153,7 @@ ], "source": { "path": "x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts", - "lineNumber": 477 + "lineNumber": 476 }, "deprecated": false, "isRequired": true @@ -4234,228 +3187,10 @@ }, "common": { "classes": [], - "functions": [ - { - "parentPluginId": "lists", - "id": "def-common.buildExceptionFilter", - "type": "Function", - "tags": [], - "label": "buildExceptionFilter", - "description": [], - "signature": [ - "({ lists, excludeExceptions, chunkSize, }: { lists: ({ _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"text\" | \"keyword\" | \"long\" | \"double\" | \"ip\" | \"date_nanos\" | \"geo_point\" | \"geo_shape\" | \"binary\" | \"short\" | \"date_range\" | \"ip_range\" | \"shape\" | \"integer\" | \"byte\" | \"float\" | \"half_float\" | \"integer_range\" | \"float_range\" | \"long_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; } | ({ description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"text\" | \"keyword\" | \"long\" | \"double\" | \"ip\" | \"date_nanos\" | \"geo_point\" | \"geo_shape\" | \"binary\" | \"short\" | \"date_range\" | \"ip_range\" | \"shape\" | \"integer\" | \"byte\" | \"float\" | \"half_float\" | \"integer_range\" | \"float_range\" | \"long_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; })[]; list_id: string; name: string; type: \"simple\"; } & { comments?: { comment: string; }[] | undefined; item_id?: string | undefined; meta?: object | undefined; namespace_type?: \"single\" | \"agnostic\" | undefined; os_types?: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags?: string[] | undefined; }))[]; excludeExceptions: boolean; chunkSize: number; }) => ", - { - "pluginId": "data", - "scope": "common", - "docId": "kibDataPluginApi", - "section": "def-common.Filter", - "text": "Filter" - }, - " | undefined" - ], - "source": { - "path": "x-pack/plugins/lists/common/exceptions/build_exceptions_filter.ts", - "lineNumber": 69 - }, - "deprecated": false, - "children": [ - { - "parentPluginId": "lists", - "id": "def-common.buildExceptionFilter.$1.listsexcludeExceptionschunkSize", - "type": "Object", - "tags": [], - "label": "{\n lists,\n excludeExceptions,\n chunkSize,\n}", - "description": [], - "source": { - "path": "x-pack/plugins/lists/common/exceptions/build_exceptions_filter.ts", - "lineNumber": 73 - }, - "deprecated": false, - "children": [ - { - "parentPluginId": "lists", - "id": "def-common.buildExceptionFilter.$1.listsexcludeExceptionschunkSize.lists", - "type": "Array", - "tags": [], - "label": "lists", - "description": [], - "signature": [ - "({ _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"text\" | \"keyword\" | \"long\" | \"double\" | \"ip\" | \"date_nanos\" | \"geo_point\" | \"geo_shape\" | \"binary\" | \"short\" | \"date_range\" | \"ip_range\" | \"shape\" | \"integer\" | \"byte\" | \"float\" | \"half_float\" | \"integer_range\" | \"float_range\" | \"long_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; } | ({ description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"text\" | \"keyword\" | \"long\" | \"double\" | \"ip\" | \"date_nanos\" | \"geo_point\" | \"geo_shape\" | \"binary\" | \"short\" | \"date_range\" | \"ip_range\" | \"shape\" | \"integer\" | \"byte\" | \"float\" | \"half_float\" | \"integer_range\" | \"float_range\" | \"long_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; })[]; list_id: string; name: string; type: \"simple\"; } & { comments?: { comment: string; }[] | undefined; item_id?: string | undefined; meta?: object | undefined; namespace_type?: \"single\" | \"agnostic\" | undefined; os_types?: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags?: string[] | undefined; }))[]" - ], - "source": { - "path": "x-pack/plugins/lists/common/exceptions/build_exceptions_filter.ts", - "lineNumber": 74 - }, - "deprecated": false - }, - { - "parentPluginId": "lists", - "id": "def-common.buildExceptionFilter.$1.listsexcludeExceptionschunkSize.excludeExceptions", - "type": "boolean", - "tags": [], - "label": "excludeExceptions", - "description": [], - "source": { - "path": "x-pack/plugins/lists/common/exceptions/build_exceptions_filter.ts", - "lineNumber": 75 - }, - "deprecated": false - }, - { - "parentPluginId": "lists", - "id": "def-common.buildExceptionFilter.$1.listsexcludeExceptionschunkSize.chunkSize", - "type": "number", - "tags": [], - "label": "chunkSize", - "description": [], - "source": { - "path": "x-pack/plugins/lists/common/exceptions/build_exceptions_filter.ts", - "lineNumber": 76 - }, - "deprecated": false - } - ] - } - ], - "returnComment": [], - "initialIsOpen": false - } - ], + "functions": [], "interfaces": [], "enums": [], - "misc": [ - { - "parentPluginId": "lists", - "id": "def-common.ENDPOINT_EVENT_FILTERS_LIST_DESCRIPTION", - "type": "string", - "tags": [], - "label": "ENDPOINT_EVENT_FILTERS_LIST_DESCRIPTION", - "description": [ - "Description of event filters agnostic list" - ], - "signature": [ - "\"Endpoint Security Event Filters List\"" - ], - "source": { - "path": "x-pack/plugins/lists/common/constants.ts", - "lineNumber": 71 - }, - "deprecated": false, - "initialIsOpen": false - }, - { - "parentPluginId": "lists", - "id": "def-common.ENDPOINT_EVENT_FILTERS_LIST_ID", - "type": "string", - "tags": [], - "label": "ENDPOINT_EVENT_FILTERS_LIST_ID", - "description": [ - "ID of event filters agnostic list" - ], - "signature": [ - "\"endpoint_event_filters\"" - ], - "source": { - "path": "x-pack/plugins/lists/common/constants.ts", - "lineNumber": 65 - }, - "deprecated": false, - "initialIsOpen": false - }, - { - "parentPluginId": "lists", - "id": "def-common.ENDPOINT_EVENT_FILTERS_LIST_NAME", - "type": "string", - "tags": [], - "label": "ENDPOINT_EVENT_FILTERS_LIST_NAME", - "description": [ - "Name of event filters agnostic list" - ], - "signature": [ - "\"Endpoint Security Event Filters List\"" - ], - "source": { - "path": "x-pack/plugins/lists/common/constants.ts", - "lineNumber": 68 - }, - "deprecated": false, - "initialIsOpen": false - }, - { - "parentPluginId": "lists", - "id": "def-common.ENDPOINT_LIST_ID", - "type": "string", - "tags": [], - "label": "ENDPOINT_LIST_ID", - "description": [ - "\nThis ID is used for _both_ the Saved Object ID and for the list_id\nfor the single global space agnostic endpoint list" - ], - "signature": [ - "\"endpoint_list\"" - ], - "source": { - "path": "x-pack/plugins/lists/common/constants.ts", - "lineNumber": 45 - }, - "deprecated": false, - "initialIsOpen": false - }, - { - "parentPluginId": "lists", - "id": "def-common.ENDPOINT_TRUSTED_APPS_LIST_ID", - "type": "string", - "tags": [], - "label": "ENDPOINT_TRUSTED_APPS_LIST_ID", - "description": [ - "ID of trusted apps agnostic list" - ], - "signature": [ - "\"endpoint_trusted_apps\"" - ], - "source": { - "path": "x-pack/plugins/lists/common/constants.ts", - "lineNumber": 56 - }, - "deprecated": false, - "initialIsOpen": false - }, - { - "parentPluginId": "lists", - "id": "def-common.EXCEPTION_LIST_ITEM_URL", - "type": "string", - "tags": [], - "label": "EXCEPTION_LIST_ITEM_URL", - "description": [], - "signature": [ - "\"/api/exception_lists/items\"" - ], - "source": { - "path": "x-pack/plugins/lists/common/constants.ts", - "lineNumber": 20 - }, - "deprecated": false, - "initialIsOpen": false - }, - { - "parentPluginId": "lists", - "id": "def-common.EXCEPTION_LIST_URL", - "type": "string", - "tags": [], - "label": "EXCEPTION_LIST_URL", - "description": [ - "\nException list routes" - ], - "signature": [ - "\"/api/exception_lists\"" - ], - "source": { - "path": "x-pack/plugins/lists/common/constants.ts", - "lineNumber": 19 - }, - "deprecated": false, - "initialIsOpen": false - } - ], + "misc": [], "objects": [] } } \ No newline at end of file diff --git a/api_docs/lists.mdx b/api_docs/lists.mdx index 1fe986ef4a06b..8ef77a85fb548 100644 --- a/api_docs/lists.mdx +++ b/api_docs/lists.mdx @@ -22,15 +22,9 @@ import listsObj from './lists.json'; ### Objects -### Functions - - ### Classes -### Interfaces - - ## Server ### Classes @@ -39,11 +33,3 @@ import listsObj from './lists.json'; ### Interfaces -## Common - -### Functions - - -### Consts, variables and types - - diff --git a/api_docs/management.json b/api_docs/management.json index 2a3bb7e3cb1eb..41801e2f2bafc 100644 --- a/api_docs/management.json +++ b/api_docs/management.json @@ -22,7 +22,7 @@ ], "source": { "path": "src/plugins/management/public/utils/management_app.ts", - "lineNumber": 19 + "lineNumber": 18 }, "deprecated": false, "children": [ @@ -50,7 +50,7 @@ ], "source": { "path": "src/plugins/management/public/utils/management_app.ts", - "lineNumber": 20 + "lineNumber": 19 }, "deprecated": false, "returnComment": [], @@ -88,29 +88,23 @@ "description": [], "source": { "path": "src/plugins/management/public/utils/management_app.ts", - "lineNumber": 21 + "lineNumber": 20 }, "deprecated": false }, { "parentPluginId": "management", - "id": "def-public.ManagementApp.meta", - "type": "Object", + "id": "def-public.ManagementApp.keywords", + "type": "Array", "tags": [], - "label": "meta", + "label": "keywords", "description": [], "signature": [ - { - "pluginId": "core", - "scope": "public", - "docId": "kibCoreApplicationPluginApi", - "section": "def-public.AppMeta", - "text": "AppMeta" - } + "string[]" ], "source": { "path": "src/plugins/management/public/utils/management_app.ts", - "lineNumber": 22 + "lineNumber": 21 }, "deprecated": false }, @@ -126,7 +120,7 @@ ], "source": { "path": "src/plugins/management/public/utils/management_app.ts", - "lineNumber": 24 + "lineNumber": 23 }, "deprecated": false, "children": [ @@ -148,7 +142,7 @@ ], "source": { "path": "src/plugins/management/public/utils/management_app.ts", - "lineNumber": 24 + "lineNumber": 23 }, "deprecated": false, "isRequired": true @@ -260,7 +254,7 @@ "section": "def-public.RegisterManagementAppArgs", "text": "RegisterManagementAppArgs" }, - ", \"title\" | \"id\" | \"meta\" | \"order\" | \"mount\" | \"euiIconType\" | \"icon\" | \"tip\">) => ", + ", \"title\" | \"id\" | \"order\" | \"mount\" | \"keywords\" | \"euiIconType\" | \"icon\" | \"tip\">) => ", { "pluginId": "management", "scope": "public", @@ -291,7 +285,7 @@ "section": "def-public.RegisterManagementAppArgs", "text": "RegisterManagementAppArgs" }, - ", \"title\" | \"id\" | \"meta\" | \"order\" | \"mount\" | \"euiIconType\" | \"icon\" | \"tip\">" + ", \"title\" | \"id\" | \"order\" | \"mount\" | \"keywords\" | \"euiIconType\" | \"icon\" | \"tip\">" ], "source": { "path": "src/plugins/management/public/utils/management_section.ts", @@ -653,7 +647,7 @@ ], "source": { "path": "src/plugins/management/public/utils/management_app.ts", - "lineNumber": 13 + "lineNumber": 12 }, "deprecated": false, "children": [ @@ -681,7 +675,7 @@ ], "source": { "path": "src/plugins/management/public/utils/management_app.ts", - "lineNumber": 14 + "lineNumber": 13 }, "deprecated": false, "returnComment": [], @@ -719,30 +713,23 @@ "description": [], "source": { "path": "src/plugins/management/public/utils/management_app.ts", - "lineNumber": 15 + "lineNumber": 14 }, "deprecated": false }, { "parentPluginId": "management", - "id": "def-public.RegisterManagementAppArgs.meta", - "type": "Object", + "id": "def-public.RegisterManagementAppArgs.keywords", + "type": "Array", "tags": [], - "label": "meta", + "label": "keywords", "description": [], "signature": [ - { - "pluginId": "core", - "scope": "public", - "docId": "kibCoreApplicationPluginApi", - "section": "def-public.AppMeta", - "text": "AppMeta" - }, - " | undefined" + "string[] | undefined" ], "source": { "path": "src/plugins/management/public/utils/management_app.ts", - "lineNumber": 16 + "lineNumber": 15 }, "deprecated": false } diff --git a/api_docs/ml.json b/api_docs/ml.json index 51a5608578026..dee66858b9be9 100644 --- a/api_docs/ml.json +++ b/api_docs/ml.json @@ -1320,7 +1320,7 @@ }, " extends Pick<", "UseDataGridReturnType", - ", \"status\" | \"errorMessage\" | \"baseline\" | \"pagination\" | \"chartsVisible\" | \"chartsButtonVisible\" | \"ccsWarning\" | \"columnsWithCharts\" | \"invalidSortingColumnns\" | \"noDataMessage\" | \"onChangeItemsPerPage\" | \"onChangePage\" | \"onSort\" | \"setPagination\" | \"setVisibleColumns\" | \"rowCount\" | \"rowCountRelation\" | \"sortingColumns\" | \"tableItems\" | \"toggleChartVisibility\" | \"visibleColumns\" | \"predictionFieldName\" | \"resultsField\">" + ", \"status\" | \"errorMessage\" | \"baseline\" | \"chartsVisible\" | \"chartsButtonVisible\" | \"ccsWarning\" | \"columnsWithCharts\" | \"invalidSortingColumnns\" | \"noDataMessage\" | \"onChangeItemsPerPage\" | \"onChangePage\" | \"onSort\" | \"pagination\" | \"setPagination\" | \"setVisibleColumns\" | \"rowCount\" | \"rowCountRelation\" | \"sortingColumns\" | \"tableItems\" | \"toggleChartVisibility\" | \"visibleColumns\" | \"predictionFieldName\" | \"resultsField\">" ], "source": { "path": "x-pack/plugins/ml/public/application/components/data_grid/types.ts", diff --git a/api_docs/saved_objects.json b/api_docs/saved_objects.json index 566e0e9a14ae9..48579ca8e589e 100644 --- a/api_docs/saved_objects.json +++ b/api_docs/saved_objects.json @@ -680,20 +680,6 @@ }, "deprecated": true, "references": [ - { - "plugin": "visualizations", - "link": { - "path": "src/plugins/visualizations/public/saved_visualizations/find_list_items.ts", - "lineNumber": 16 - } - }, - { - "plugin": "visualizations", - "link": { - "path": "src/plugins/visualizations/public/saved_visualizations/find_list_items.ts", - "lineNumber": 35 - } - }, { "plugin": "discover", "link": { @@ -722,6 +708,20 @@ "lineNumber": 88 } }, + { + "plugin": "visualizations", + "link": { + "path": "src/plugins/visualizations/public/saved_visualizations/find_list_items.ts", + "lineNumber": 16 + } + }, + { + "plugin": "visualizations", + "link": { + "path": "src/plugins/visualizations/public/saved_visualizations/find_list_items.ts", + "lineNumber": 35 + } + }, { "plugin": "visualizations", "link": { @@ -2569,31 +2569,31 @@ } }, { - "plugin": "visualizations", + "plugin": "discover", "link": { - "path": "src/plugins/visualizations/public/types.ts", + "path": "src/plugins/discover/public/saved_searches/_saved_search.ts", "lineNumber": 9 } }, { - "plugin": "visualizations", + "plugin": "discover", "link": { - "path": "src/plugins/visualizations/public/types.ts", - "lineNumber": 41 + "path": "src/plugins/discover/public/saved_searches/_saved_search.ts", + "lineNumber": 61 } }, { - "plugin": "discover", + "plugin": "visualizations", "link": { - "path": "src/plugins/discover/public/saved_searches/_saved_search.ts", + "path": "src/plugins/visualizations/public/types.ts", "lineNumber": 9 } }, { - "plugin": "discover", + "plugin": "visualizations", "link": { - "path": "src/plugins/discover/public/saved_searches/_saved_search.ts", - "lineNumber": 61 + "path": "src/plugins/visualizations/public/types.ts", + "lineNumber": 41 } }, { diff --git a/api_docs/security.json b/api_docs/security.json index 6cc84bc75f009..7e28ad2a222bb 100644 --- a/api_docs/security.json +++ b/api_docs/security.json @@ -1306,13 +1306,6 @@ "lineNumber": 444 } }, - { - "plugin": "cases", - "link": { - "path": "x-pack/plugins/cases/server/plugin.ts", - "lineNumber": 89 - } - }, { "plugin": "ml", "link": { @@ -1321,52 +1314,52 @@ } }, { - "plugin": "securitySolution", + "plugin": "cases", "link": { - "path": "x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/create_signals_migration_route.ts", - "lineNumber": 48 + "path": "x-pack/plugins/cases/server/plugin.ts", + "lineNumber": 89 } }, { - "plugin": "securitySolution", + "plugin": "dashboardMode", "link": { - "path": "x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/delete_signals_migration_route.ts", - "lineNumber": 45 + "path": "x-pack/plugins/dashboard_mode/server/interceptors/dashboard_mode_request_interceptor.ts", + "lineNumber": 33 } }, { - "plugin": "securitySolution", + "plugin": "dataEnhanced", "link": { - "path": "x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/finalize_signals_migration_route.ts", - "lineNumber": 45 + "path": "x-pack/plugins/data_enhanced/server/search/session/session_service.ts", + "lineNumber": 448 } }, { - "plugin": "beatsManagement", + "plugin": "logstash", "link": { - "path": "x-pack/plugins/beats_management/server/lib/adapters/framework/kibana_framework_adapter.ts", - "lineNumber": 44 + "path": "x-pack/plugins/logstash/server/routes/pipeline/save.ts", + "lineNumber": 41 } }, { - "plugin": "dashboardMode", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/dashboard_mode/server/interceptors/dashboard_mode_request_interceptor.ts", - "lineNumber": 33 + "path": "x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/create_signals_migration_route.ts", + "lineNumber": 48 } }, { - "plugin": "dataEnhanced", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/data_enhanced/server/search/session/session_service.ts", - "lineNumber": 448 + "path": "x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/delete_signals_migration_route.ts", + "lineNumber": 45 } }, { - "plugin": "logstash", + "plugin": "securitySolution", "link": { - "path": "x-pack/plugins/logstash/server/routes/pipeline/save.ts", - "lineNumber": 41 + "path": "x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/finalize_signals_migration_route.ts", + "lineNumber": 45 } }, { diff --git a/api_docs/spaces.json b/api_docs/spaces.json index aa4e651b9477b..5225e8cebbeb5 100644 --- a/api_docs/spaces.json +++ b/api_docs/spaces.json @@ -1213,13 +1213,6 @@ "lineNumber": 271 } }, - { - "plugin": "securitySolution", - "link": { - "path": "x-pack/plugins/security_solution/server/plugin.ts", - "lineNumber": 194 - } - }, { "plugin": "apm", "link": { @@ -1248,6 +1241,13 @@ "lineNumber": 153 } }, + { + "plugin": "securitySolution", + "link": { + "path": "x-pack/plugins/security_solution/server/plugin.ts", + "lineNumber": 194 + } + }, { "plugin": "security", "link": { @@ -2047,13 +2047,6 @@ "lineNumber": 303 } }, - { - "plugin": "securitySolution", - "link": { - "path": "x-pack/plugins/security_solution/server/plugin.ts", - "lineNumber": 194 - } - }, { "plugin": "apm", "link": { @@ -2088,6 +2081,13 @@ "path": "x-pack/plugins/infra/server/plugin.ts", "lineNumber": 153 } + }, + { + "plugin": "securitySolution", + "link": { + "path": "x-pack/plugins/security_solution/server/plugin.ts", + "lineNumber": 194 + } } ] }, diff --git a/docs/developer/plugin-list.asciidoc b/docs/developer/plugin-list.asciidoc index 94384024e0935..087626240ff33 100644 --- a/docs/developer/plugin-list.asciidoc +++ b/docs/developer/plugin-list.asciidoc @@ -332,11 +332,6 @@ which will load the visualization's editor. |Allow to add a header banner that will be displayed on every page of the Kibana application -|{kib-repo}blob/{branch}/x-pack/plugins/beats_management/readme.md[beatsManagement] -|Notes: -Failure to have auth enabled in Kibana will make for a broken UI. UI-based errors not yet in place - - |{kib-repo}blob/{branch}/x-pack/plugins/canvas/README.md[canvas] |"Never look back. The past is done. The future is a blank canvas." ― Suzy Kassem, Rise Up and Salute the Sun diff --git a/docs/management/managing-beats.asciidoc b/docs/management/managing-beats.asciidoc deleted file mode 100644 index 232efb60cadd3..0000000000000 --- a/docs/management/managing-beats.asciidoc +++ /dev/null @@ -1,108 +0,0 @@ -[[managing-beats]] -[role="xpack"] -== {beats} Central Management - -include::{asciidoc-dir}/../../shared/discontinued.asciidoc[tag=cm-discontinued] - -To use {beats} Central Management, open the main menu, click *Stack Management > -{beats} Central Management*, then define and -manage configurations in a central location in {kib} and quickly deploy -configuration changes to all {beats} running across your enterprise. For more -about central management, see the related {beats} documentation: - -* {filebeat-ref}/configuration-central-management.html[{filebeat} documentation] -* {metricbeat-ref}/configuration-central-management.html[{metricbeat} documentation] - -[NOTE] -==== -This feature requires an Elastic license that includes {beats} central -management. - -Don't have a license? You can start a 30-day trial. Open the main menu, then -click *Stack Management > License Management*. At the end of the trial -period, you can purchase a subscription to keep using central management. For -more information, see https://www.elastic.co/subscriptions and -<>. -==== - -{kib} makes it easy for you to use central management by walking you through the -enrollment and configuration process step by step the first time you use the -Central Management UI. - -[float] -=== Required permissions - -You must have the `beats_admin` role assigned to use **{beats} Central Management** - -To assign the role, open the menu, then click *Stack Management > Users*. - - -[float] -=== Enroll {beats} - -You need to enroll {beats} to register them in central management and establish -trust. Enrolled {beats} will have the credentials needed to retrieve -configurations from {kib}. - -[float] -=== Create configuration tags - -A _configuration tag_ is a group of configuration blocks that you can apply to -one or more {beats}. For example, you can create a tag called `development` to -group configurations for {beats} running in your development environment. - -The first time you walk through the enrollment process, you'll create a -configuration tag that's applied to the {beats} instance you're enrolling. - -After that, under *Configuration tags*, you can create additional tags and -apply them to any enrolled {beats}, and the {beats} will use the configurations -defined in the tag. - -[float] -=== Add configuration blocks - -Add one or more configuration blocks to the tag. A tag can have configuration -blocks for different types of {beats}. When the enrolled {beats} run, they will -use the configuration blocks that are valid for their type. - -Central management supports configuration settings for: - -* {filebeat} modules -* {metricbeat} modules -* {filebeat} inputs -* {filebeat} and {metricbeat} outputs - -NOTE: Central management supports the following outputs only: {es}, {ls}, Kafka, -and Redis. Other output types are not supported for {beats} that are enrolled in -central management. - -Use the Central Management UI to define and manage settings for supported -configuration blocks. You cannot define those settings in local {beats} -configuration files. For configuration blocks that are not supported by central -management, configure the settings in the local configuration file after -enrolling the Beat in central management. - -[float] -=== Manage enrolled {beats} - -Under *Enrolled {beats}*, you can view the list of enrolled {beats} to see -details, including the type, applied tags, configuration status, and the last -configuration update. Click the *Beat name* or *Type* column heading to sort the -list. To filter the list, enter a search string. If there are errors in a -configuration, you’ll see an Error status in the Central Management UI and need -to look at {beats} logs to troubleshoot the problem. - -You can add or remove tags, and the configuration changes are automatically -deployed to all {beats} that have the tag. Avoid applying tags with conflicting -configurations. Because the configurations for all assigned tags are merged, -conflicting configurations result in errors. - -You can unenroll {beats} to remove them from central management. - -[float] -=== Manage tags - -Under *Configuration tags*, you can select tags and delete them, or you can -drill down into a tag to add, modify, or remove configuration blocks from the -tag. When you change the configuration blocks or remove tags, the configuration -changes are automatically deployed to all {beats} that have the tag. diff --git a/docs/user/management.asciidoc b/docs/user/management.asciidoc index 397ab1717183b..c5fabb15dc4de 100644 --- a/docs/user/management.asciidoc +++ b/docs/user/management.asciidoc @@ -24,10 +24,6 @@ and enrichments on your data. | {logstash-ref}/logstash-centralized-pipeline-management.html[Logstash Pipelines] | Create, edit, and delete your Logstash pipeline configurations. -| <> -| Manage your Beats configurations in a central location and -quickly deploy configuration changes to all Beats running across your enterprise. - |=== @@ -182,8 +178,6 @@ next major version of {es}, and then reindex, if needed. include::{kib-repo-dir}/management/advanced-options.asciidoc[] -include::{kib-repo-dir}/management/managing-beats.asciidoc[] - include::{kib-repo-dir}/management/action-types.asciidoc[] include::{kib-repo-dir}/management/managing-licenses.asciidoc[] diff --git a/packages/kbn-optimizer/limits.yml b/packages/kbn-optimizer/limits.yml index 2e76c26dd7b38..c28fd83591960 100644 --- a/packages/kbn-optimizer/limits.yml +++ b/packages/kbn-optimizer/limits.yml @@ -3,7 +3,6 @@ pageLoadAssetSize: alerting: 106936 apm: 64385 apmOss: 18996 - beatsManagement: 188135 bfetch: 41874 canvas: 1066647 charts: 195358 diff --git a/tsconfig.json b/tsconfig.json index ceb03107076c2..37fc9ee05a29b 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -73,7 +73,6 @@ { "path": "./x-pack/plugins/actions/tsconfig.json" }, { "path": "./x-pack/plugins/alerting/tsconfig.json" }, { "path": "./x-pack/plugins/apm/tsconfig.json" }, - { "path": "./x-pack/plugins/beats_management/tsconfig.json" }, { "path": "./x-pack/plugins/canvas/tsconfig.json" }, { "path": "./x-pack/plugins/cases/tsconfig.json" }, { "path": "./x-pack/plugins/cloud/tsconfig.json" }, diff --git a/tsconfig.refs.json b/tsconfig.refs.json index 7343165e4a4ad..1b8a76d601e38 100644 --- a/tsconfig.refs.json +++ b/tsconfig.refs.json @@ -58,7 +58,6 @@ { "path": "./x-pack/plugins/actions/tsconfig.json" }, { "path": "./x-pack/plugins/alerting/tsconfig.json" }, { "path": "./x-pack/plugins/apm/tsconfig.json" }, - { "path": "./x-pack/plugins/beats_management/tsconfig.json" }, { "path": "./x-pack/plugins/canvas/tsconfig.json" }, { "path": "./x-pack/plugins/cases/tsconfig.json" }, { "path": "./x-pack/plugins/cloud/tsconfig.json" }, diff --git a/x-pack/.i18nrc.json b/x-pack/.i18nrc.json index 2db2f31ae09c3..b2c3a36ae3414 100644 --- a/x-pack/.i18nrc.json +++ b/x-pack/.i18nrc.json @@ -7,7 +7,6 @@ "xpack.eventLog": "plugins/event_log", "xpack.stackAlerts": "plugins/stack_alerts", "xpack.apm": "plugins/apm", - "xpack.beatsManagement": "plugins/beats_management", "xpack.canvas": "plugins/canvas", "xpack.cases": "plugins/cases", "xpack.cloud": "plugins/cloud", diff --git a/x-pack/plugins/beats_management/common/config_schemas.ts b/x-pack/plugins/beats_management/common/config_schemas.ts deleted file mode 100644 index 95330655a7796..0000000000000 --- a/x-pack/plugins/beats_management/common/config_schemas.ts +++ /dev/null @@ -1,384 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -// Note: importing this is a temp thing. This file will be replaced with JSON from Beats/ES at some point -import { ConfigBlockSchema } from './domain_types'; - -export const configBlockSchemas: ConfigBlockSchema[] = [ - { - id: 'filebeat.inputs', - name: 'Filebeat Input', - version: 6.7, - allowOtherConfigs: true, - configs: [ - { - id: 'paths', - ui: { - label: 'Paths', - labelId: 'filebeatInputConfig.paths.ui.label', - type: 'multi-input', - helpText: 'filebeatInputConfig.paths.ui.helpText', - helpTextId: 'filebeatInputConfig.paths.ui.helpText', - placeholder: `first/path/to/file.json second/path/to/otherfile.json`, - }, - validation: 'isPaths', - error: 'filebeatInputConfig.paths.error', - errorId: 'filebeatInputConfig.paths.error', - required: true, - }, - ], - }, - { - id: 'filebeat.modules', - name: 'Filebeat Modules', - version: 6.7, - allowOtherConfigs: true, - configs: [ - { - id: '_sub_type', - ui: { - label: 'filebeatModuleConfig.module.ui.label', - labelId: 'filebeatModuleConfig.module.ui.label', - type: 'select', - }, - options: [ - { - value: 'apache2', - text: 'apache2', - }, - { - value: 'auditd', - text: 'auditd', - }, - { - value: 'elasticsearch', - text: 'elasticsearch', - }, - { - value: 'haproxy', - text: 'haproxy', - }, - { - value: 'icinga', - text: 'icinga', - }, - { - value: 'iis', - text: 'iis', - }, - { - value: 'kafka', - text: 'kafka', - }, - { - value: 'kibana', - text: 'kibana', - }, - { - value: 'logstash', - text: 'logstash', - }, - { - value: 'mongodb', - text: 'mongodb', - }, - { - value: 'mysql', - text: 'mysql', - }, - { - value: 'nginx', - text: 'nginx', - }, - { - value: 'osquery', - text: 'osquery', - }, - { - value: 'postgresql', - text: 'postgresql', - }, - { - value: 'redis', - text: 'redis', - }, - { - value: 'system', - text: 'system', - }, - { - value: 'traefik', - text: 'traefik', - }, - ], - error: 'filebeatModuleConfig.module.error', - errorId: 'filebeatModuleConfig.module.error', - required: true, - }, - ], - }, - { - id: 'metricbeat.modules', - name: 'Metricbeat Modules', - version: 6.7, - allowOtherConfigs: true, - configs: [ - { - id: '_sub_type', - ui: { - label: 'metricbeatModuleConfig.module.ui.label', - labelId: 'metricbeatModuleConfig.module.ui.label', - type: 'select', - }, - options: [ - { - value: 'aerospike', - text: 'aerospike', - }, - { - value: 'apache', - text: 'apache', - }, - { - value: 'ceph', - text: 'ceph', - }, - { - value: 'couchbase', - text: 'couchbase', - }, - { - value: 'docker', - text: 'docker', - }, - { - value: 'dropwizard', - text: 'dropwizard', - }, - { - value: 'elasticsearch', - text: 'elasticsearch', - }, - { - value: 'envoyproxy', - text: 'envoyproxy', - }, - { - value: 'etcd', - text: 'etcd', - }, - { - value: 'golang', - text: 'golang', - }, - { - value: 'graphite', - text: 'graphite', - }, - { - value: 'haproxy', - text: 'haproxy', - }, - { - value: 'http', - text: 'http', - }, - { - value: 'jolokia', - text: 'jolokia', - }, - { - value: 'kafka', - text: 'kafka', - }, - { - value: 'kibana', - text: 'kibana', - }, - { - value: 'kubernetes', - text: 'kubernetes', - }, - { - value: 'kvm', - text: 'kvm', - }, - { - value: 'logstash', - text: 'logstash', - }, - { - value: 'memcached', - text: 'memcached', - }, - { - value: 'mongodb', - text: 'mongodb', - }, - { - value: 'munin', - text: 'munin', - }, - { - value: 'mysql', - text: 'mysql', - }, - { - value: 'nginx', - text: 'nginx', - }, - { - value: 'php_fpm', - text: 'php_fpm', - }, - { - value: 'postgresql', - text: 'postgresql', - }, - { - value: 'prometheus', - text: 'prometheus', - }, - { - value: 'rabbitmq', - text: 'rabbitmq', - }, - { - value: 'redis', - text: 'redis', - }, - { - value: 'system', - text: 'system', - }, - { - value: 'traefik', - text: 'traefik', - }, - { - value: 'uwsgi', - text: 'uwsgi', - }, - { - value: 'vsphere', - text: 'vsphere', - }, - { - value: 'windows', - text: 'windows', - }, - { - value: 'zookeeper', - text: 'zookeeper', - }, - ], - error: 'metricbeatModuleConfig.module.error', - errorId: 'metricbeatModuleConfig.module.error', - required: true, - }, - { - id: 'hosts', - ui: { - label: 'metricbeatModuleConfig.hosts.ui.label', - labelId: 'metricbeatModuleConfig.hosts.ui.label', - type: 'multi-input', - helpText: 'metricbeatModuleConfig.hosts.ui.helpText', - helpTextId: 'metricbeatModuleConfig.hosts.ui.helpText', - placeholder: `somehost.local otherhost.local`, - }, - validation: 'isHosts', - error: 'metricbeatModuleConfig.hosts.error', - errorId: 'metricbeatModuleConfig.hosts.error', - required: false, - }, - { - id: 'period', - ui: { - label: 'metricbeatModuleConfig.period.ui.label', - labelId: 'metricbeatModuleConfig.period.ui.label', - type: 'input', - }, - defaultValue: '10s', - validation: 'isPeriod', - error: 'metricbeatModuleConfig.period.error', - errorId: 'metricbeatModuleConfig.period.error', - required: true, - }, - ], - }, - { - id: 'output', - name: 'Outputs', - allowOtherConfigs: true, - version: 6.7, - configs: [ - { - id: '_sub_type', - ui: { - label: 'outputConfig.output.ui.label', - labelId: 'outputConfig.output.ui.label', - type: 'select', - }, - options: [ - { - value: 'elasticsearch', - text: 'Elasticsearch', - }, - { - value: 'logstash', - text: 'Logstash', - }, - { - value: 'kafka', - text: 'Kafka', - }, - { - value: 'redis', - text: 'Redis', - }, - ], - error: 'outputConfig.output.error', - errorId: 'outputConfig.output.error', - required: true, - }, - { - id: 'hosts', - ui: { - label: 'outputConfig.hosts.ui.label', - labelId: 'outputConfig.hosts.ui.label', - type: 'multi-input', - }, - validation: 'isHosts', - error: 'outputConfig.hosts.error', - errorId: 'outputConfig.hosts.error', - parseValidResult: (v) => v.split('\n'), - }, - { - id: 'username', - ui: { - label: 'outputConfig.username.ui.label', - labelId: 'outputConfig.username.ui.label', - type: 'input', - }, - validation: 'isString', - error: 'outputConfig.username.error', - errorId: 'outputConfig.username.error', - }, - { - id: 'password', - ui: { - label: 'outputConfig.password.ui.label', - labelId: 'outputConfig.password.ui.label', - type: 'password', - }, - validation: 'isString', - error: 'outputConfig.password.error', - errorId: 'outputConfig.password.error', - }, - ], - }, -]; diff --git a/x-pack/plugins/beats_management/common/config_schemas_translations_map.ts b/x-pack/plugins/beats_management/common/config_schemas_translations_map.ts deleted file mode 100644 index ca2d48998ee06..0000000000000 --- a/x-pack/plugins/beats_management/common/config_schemas_translations_map.ts +++ /dev/null @@ -1,243 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { i18n } from '@kbn/i18n'; -import { ConfigBlockSchema } from './domain_types'; - -const supportedConfigLabelsMap = new Map([ - [ - 'filebeatInputConfig.paths.ui.label', - i18n.translate('xpack.beatsManagement.filebeatInputConfig.pathsLabel', { - defaultMessage: 'Paths', - }), - ], - [ - 'filebeatInputConfig.paths.ui.helpText', - i18n.translate('xpack.beatsManagement.filebeatInputConfig.pathsDescription', { - defaultMessage: 'Put each of the paths on a separate line', - }), - ], - [ - 'filebeatInputConfig.paths.error', - i18n.translate('xpack.beatsManagement.filebeatInputConfig.pathsErrorMessage', { - defaultMessage: 'One file path per line', - }), - ], - [ - 'filebeatInputConfig.other.ui.label', - i18n.translate('xpack.beatsManagement.filebeatInputConfig.otherConfigLabel', { - defaultMessage: 'Other Config', - }), - ], - [ - 'filebeatInputConfig.other.ui.helpText', - i18n.translate('xpack.beatsManagement.filebeatInputConfig.otherConfigDescription', { - defaultMessage: 'Use YAML format to specify other settings for the Filebeat Input', - }), - ], - [ - 'filebeatInputConfig.other.error', - i18n.translate('xpack.beatsManagement.filebeatInputConfig.otherConfigErrorMessage', { - defaultMessage: 'Use valid YAML format', - }), - ], - [ - 'filebeatModuleConfig.module.ui.label', - i18n.translate('xpack.beatsManagement.filebeatModuleConfig.moduleLabel', { - defaultMessage: 'Module', - }), - ], - [ - 'filebeatModuleConfig.module.error', - i18n.translate('xpack.beatsManagement.filebeatModuleConfig.moduleErrorMessage', { - defaultMessage: 'Please select a module', - }), - ], - [ - 'filebeatModuleConfig.other.ui.label', - i18n.translate('xpack.beatsManagement.filebeatModuleConfig.otherConfigLabel', { - defaultMessage: 'Other Config', - }), - ], - [ - 'filebeatModuleConfig.other.ui.helpText', - i18n.translate('xpack.beatsManagement.filebeatModuleConfig.moduleDescription', { - defaultMessage: 'Use YAML format to specify other settings for the Filebeat Module', - }), - ], - [ - 'filebeatModuleConfig.other.error', - i18n.translate('xpack.beatsManagement.filebeatModuleConfig.otherConfigErrorMessage', { - defaultMessage: 'Use valid YAML format', - }), - ], - - [ - 'metricbeatModuleConfig.module.ui.label', - i18n.translate('xpack.beatsManagement.metricbeatModuleConfig.moduleLabel', { - defaultMessage: 'Module', - }), - ], - [ - 'metricbeatModuleConfig.module.error', - i18n.translate('xpack.beatsManagement.metricbeatModuleConfig.moduleErrorMessage', { - defaultMessage: 'Please select a module', - }), - ], - [ - 'metricbeatModuleConfig.hosts.ui.label', - i18n.translate('xpack.beatsManagement.metricbeatModuleConfig.hostsLabel', { - defaultMessage: 'Hosts', - }), - ], - [ - 'metricbeatModuleConfig.hosts.ui.helpText', - i18n.translate('xpack.beatsManagement.metricbeatModuleConfig.hostsDescription', { - defaultMessage: 'Put each of the paths on a seperate line', - }), - ], - [ - 'metricbeatModuleConfig.hosts.error', - i18n.translate('xpack.beatsManagement.metricbeatModuleConfig.hostsErrorMessage', { - defaultMessage: 'One file host per line', - }), - ], - [ - 'metricbeatModuleConfig.period.ui.label', - i18n.translate('xpack.beatsManagement.metricbeatModuleConfig.periodLabel', { - defaultMessage: 'Period', - }), - ], - [ - 'metricbeatModuleConfig.period.error', - i18n.translate('xpack.beatsManagement.metricbeatModuleConfig.periodErrorMessage', { - defaultMessage: 'Invalid Period, must be formatted as `10s` for 10 seconds', - }), - ], - [ - 'metricbeatModuleConfig.other.ui.label', - i18n.translate('xpack.beatsManagement.metricbeatModuleConfig.otherConfigLabel', { - defaultMessage: 'Other Config', - }), - ], - [ - 'metricbeatModuleConfig.other.ui.helpText', - i18n.translate('xpack.beatsManagement.metricbeatModuleConfig.otherConfigDescription', { - defaultMessage: 'Use YAML format to specify other settings for the Metricbeat Module', - }), - ], - [ - 'metricbeatModuleConfig.other.error', - i18n.translate('xpack.beatsManagement.metricbeatModuleConfig.otherConfigErrorMessage', { - defaultMessage: 'Use valid YAML format', - }), - ], - - [ - 'outputConfig.output.ui.label', - i18n.translate('xpack.beatsManagement.outputConfig.outputTypeLabel', { - defaultMessage: 'Output Type', - }), - ], - [ - 'outputConfig.output.error', - i18n.translate('xpack.beatsManagement.outputConfig.outputTypeErrorMessage', { - defaultMessage: 'Please select an output type', - }), - ], - [ - 'outputConfig.hosts.ui.label', - i18n.translate('xpack.beatsManagement.outputConfig.hostsLabel', { - defaultMessage: 'Hosts', - }), - ], - [ - 'outputConfig.hosts.error', - i18n.translate('xpack.beatsManagement.outputConfig.hostsErrorMessage', { - defaultMessage: 'One file host per line', - }), - ], - [ - 'outputConfig.username.ui.label', - i18n.translate('xpack.beatsManagement.outputConfig.usernameLabel', { - defaultMessage: 'Username', - }), - ], - [ - 'outputConfig.username.error', - i18n.translate('xpack.beatsManagement.outputConfig.usernameErrorMessage', { - defaultMessage: 'Unprocessable username', - }), - ], - [ - 'outputConfig.password.ui.label', - i18n.translate('xpack.beatsManagement.outputConfig.passwordLabel', { - defaultMessage: 'Password', - }), - ], - [ - 'outputConfig.password.error', - i18n.translate('xpack.beatsManagement.outputConfig.passwordErrorMessage', { - defaultMessage: 'Unprocessable password', - }), - ], - - [ - 'supportedConfigs.filebeat.input.text', - i18n.translate('xpack.beatsManagement.tagConfig.filebeatInputLabel', { - defaultMessage: 'Filebeat Input', - }), - ], - [ - 'supportedConfigs.filebeat.modules.text', - i18n.translate('xpack.beatsManagement.tagConfig.filebeatModuleLabel', { - defaultMessage: 'Filebeat Module', - }), - ], - [ - 'supportedConfigs.metricbeatModule.text', - i18n.translate('xpack.beatsManagement.tagConfig.metricbeatModuleLabel', { - defaultMessage: 'Metricbeat Module', - }), - ], - [ - 'supportedConfigs.output.text', - i18n.translate('xpack.beatsManagement.tagConfig.outputLabel', { - defaultMessage: 'Output', - }), - ], -]); - -export let translatedConfigs: ConfigBlockSchema[]; -export const translateConfigSchema = (schemas: ConfigBlockSchema[]) => { - if (translatedConfigs) { - return translatedConfigs; - } - - translatedConfigs = schemas.map((schema) => { - schema.name = supportedConfigLabelsMap.get(`supportedConfigs.${schema.id}.text`) || schema.name; - - schema.configs = schema.configs.map((configBlock) => { - if (configBlock.ui.label) { - configBlock.ui.label = - supportedConfigLabelsMap.get(configBlock.ui.labelId || '') || configBlock.ui.label; - } - if (configBlock.ui.helpText) { - configBlock.ui.helpText = - supportedConfigLabelsMap.get(configBlock.ui.helpTextId || '') || configBlock.ui.helpText; - } - if (configBlock.error) { - configBlock.error = - supportedConfigLabelsMap.get(configBlock.errorId || '') || configBlock.error; - } - return configBlock; - }); - return schema; - }); - - return translatedConfigs; -}; diff --git a/x-pack/plugins/beats_management/common/constants/configuration_blocks.ts b/x-pack/plugins/beats_management/common/constants/configuration_blocks.ts deleted file mode 100644 index 7f0a1442a374e..0000000000000 --- a/x-pack/plugins/beats_management/common/constants/configuration_blocks.ts +++ /dev/null @@ -1,8 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export const UNIQUENESS_ENFORCING_TYPES = ['output']; diff --git a/x-pack/plugins/beats_management/common/constants/index.ts b/x-pack/plugins/beats_management/common/constants/index.ts deleted file mode 100644 index ac4f89b639c22..0000000000000 --- a/x-pack/plugins/beats_management/common/constants/index.ts +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export { UNIQUENESS_ENFORCING_TYPES } from './configuration_blocks'; -export { INDEX_NAMES } from './index_names'; -export { PLUGIN, MANAGEMENT_SECTION } from './plugin'; -export { LICENSES, REQUIRED_LICENSES, REQUIRED_ROLES } from './security'; -export { TABLE_CONFIG } from './table'; -export const BASE_PATH = '/management/ingest/beats_management'; diff --git a/x-pack/plugins/beats_management/common/constants/index_names.ts b/x-pack/plugins/beats_management/common/constants/index_names.ts deleted file mode 100644 index f0a00c5ca2891..0000000000000 --- a/x-pack/plugins/beats_management/common/constants/index_names.ts +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export const INDEX_NAMES = { - BEATS: '.management-beats', - EVENTS: '.management-beats-events-*', - EVENTS_ALIAS: '.management-beats-events', -}; - -export const POLICY_NAMES = { - EVENTS: '.beats-management-events-retention', -}; diff --git a/x-pack/plugins/beats_management/common/constants/plugin.ts b/x-pack/plugins/beats_management/common/constants/plugin.ts deleted file mode 100644 index 912bc75b98f60..0000000000000 --- a/x-pack/plugins/beats_management/common/constants/plugin.ts +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export const PLUGIN = { - ID: 'beats_management', -}; -export const CONFIG_PREFIX = 'xpack.beats'; -export const MANAGEMENT_SECTION = 'beats_management'; diff --git a/x-pack/plugins/beats_management/common/constants/security.ts b/x-pack/plugins/beats_management/common/constants/security.ts deleted file mode 100644 index af4ef129f54b4..0000000000000 --- a/x-pack/plugins/beats_management/common/constants/security.ts +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export const REQUIRED_ROLES = ['beats_admin']; -export const REQUIRED_LICENSES = ['standard', 'gold', 'trial', 'platinum', 'enterprise']; -export const LICENSES = ['oss', 'basic', 'standard', 'gold', 'trial', 'platinum', 'enterprise']; -export type LicenseType = - | 'oss' - | 'basic' - | 'trial' - | 'standard' - | 'gold' - | 'platinum' - | 'enterprise'; diff --git a/x-pack/plugins/beats_management/common/constants/table.ts b/x-pack/plugins/beats_management/common/constants/table.ts deleted file mode 100644 index 54751c29cd35a..0000000000000 --- a/x-pack/plugins/beats_management/common/constants/table.ts +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export const TABLE_CONFIG = { - INITIAL_ROW_SIZE: 5, - PAGE_SIZE_OPTIONS: [3, 5, 10, 20], - TRUNCATE_TAG_LENGTH: 33, - TRUNCATE_TAG_LENGTH_SMALL: 20, -}; diff --git a/x-pack/plugins/beats_management/common/domain_types.ts b/x-pack/plugins/beats_management/common/domain_types.ts deleted file mode 100644 index f7efb77f0dc39..0000000000000 --- a/x-pack/plugins/beats_management/common/domain_types.ts +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import * as t from 'io-ts'; -import { configBlockSchemas } from './config_schemas'; -import { DateFromString } from './io_ts_types'; - -// Here we create the runtime check for a generic, unknown beat config type. -// We can also pass in optional params to create spacific runtime checks that -// can be used to validate blocs on the API and UI -export const createConfigurationBlockInterface = ( - configType: t.LiteralType | t.KeyofC> = t.keyof( - Object.fromEntries(configBlockSchemas.map((s) => [s.id, null])) as Record - ), - beatConfigInterface: t.Mixed = t.Dictionary -) => - t.interface( - { - id: t.union([t.undefined, t.string]), - type: configType, - description: t.union([t.undefined, t.string]), - tag: t.string, - config: beatConfigInterface, - last_updated: t.union([t.undefined, t.number]), - }, - 'ConfigBlock' - ); -const BaseConfigurationBlock = createConfigurationBlockInterface(); -export interface ConfigurationBlock - extends Pick< - t.TypeOf, - Exclude, 'id'> - > { - id: string; -} - -export interface CMBeat { - id: string; - status?: BeatEvent; - enrollment_token: string; - active: boolean; - access_token?: string; - verified_on?: string; - type: string; - version?: string; - host_ip: string; - host_name: string; - ephemeral_id?: string; - last_checkin?: Date; - event_rate?: string; - local_configuration_yml?: string; - tags: string[]; - central_configuration_yml?: string; - metadata?: {}; - name?: string; - last_updated: number; -} - -export interface ConfigBlockSchema { - id: string; - name: string; - version: number; - allowOtherConfigs?: boolean; - configs: BeatConfigSchema[]; -} - -export interface BeatConfigSchema { - id: string; - ui: { - label: string; - labelId?: string; - type: 'input' | 'multi-input' | 'select' | 'code' | 'password'; - helpText?: string; - helpTextId?: string; - placeholder?: string; - }; - options?: Array<{ value: string; text: string }>; - validation?: 'isHosts' | 'isString' | 'isPeriod' | 'isPath' | 'isPaths' | 'isYaml'; - error: string; - errorId: string; - defaultValue?: string; - required?: boolean; - parseValidResult?: (value: any) => any; -} - -export const RuntimeBeatTag = t.interface( - { - id: t.union([t.undefined, t.string]), - name: t.string, - color: t.string, - hasConfigurationBlocksTypes: t.array(t.string), - }, - 'CMBeat' -); -export interface BeatTag - extends Pick< - t.TypeOf, - Exclude, 'id'> - > { - id: string; - // Used by the UI and api when a tag exists but is an invalid option - disabled?: boolean; -} - -export const RuntimeBeatEvent = t.interface( - { - type: t.union([t.literal('STATE'), t.literal('ERROR')]), - beat: t.union([t.undefined, t.string]), - timestamp: DateFromString, - event: t.type({ - type: t.union([ - t.literal('RUNNING'), - t.literal('STARTING'), - t.literal('IN_PROGRESS'), - t.literal('CONFIG'), - t.literal('FAILED'), - t.literal('STOPPED'), - ]), - message: t.string, - uuid: t.union([t.undefined, t.string]), - }), - }, - 'BeatEvent' -); -export interface BeatEvent - extends Pick< - t.TypeOf, - Exclude, 'timestamp'> - > { - beat: string; - timestamp: Date; -} diff --git a/x-pack/plugins/beats_management/common/index.ts b/x-pack/plugins/beats_management/common/index.ts deleted file mode 100644 index a7dde2298054f..0000000000000 --- a/x-pack/plugins/beats_management/common/index.ts +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { schema, TypeOf } from '@kbn/config-schema'; - -const DEFAULT_ENROLLMENT_TOKENS_TTL_S = 10 * 60; // 10 minutes - -export const beatsManagementConfigSchema = schema.object({ - enabled: schema.boolean({ defaultValue: true }), - defaultUserRoles: schema.arrayOf(schema.string(), { defaultValue: ['superuser'] }), - encryptionKey: schema.string({ defaultValue: 'xpack_beats_default_encryptionKey' }), - enrollmentTokensTtlInSeconds: schema.number({ - min: 1, - max: 10 * 60 * 14, // No more then 2 weeks for security reasons, - defaultValue: DEFAULT_ENROLLMENT_TOKENS_TTL_S, - }), -}); - -export type BeatsManagementConfigType = TypeOf; diff --git a/x-pack/plugins/beats_management/common/io_ts_types.ts b/x-pack/plugins/beats_management/common/io_ts_types.ts deleted file mode 100644 index b1abd3d8b6b3b..0000000000000 --- a/x-pack/plugins/beats_management/common/io_ts_types.ts +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import * as t from 'io-ts'; -import { isRight } from 'fp-ts/lib/Either'; - -class DateFromStringType extends t.Type { - public readonly _tag: 'DateFromISOStringType' = 'DateFromISOStringType'; - constructor() { - super( - 'DateFromString', - (u): u is Date => u instanceof Date, - (u, c) => { - const validation = t.string.validate(u, c); - if (!isRight(validation)) { - return validation as any; - } else { - const s = validation.right; - const d = new Date(s); - return isNaN(d.getTime()) ? t.failure(s, c) : t.success(d); - } - }, - (a) => a.toISOString() - ); - } -} -// eslint-disable-next-line -export interface DateFromString extends DateFromStringType {} - -export const DateFromString: DateFromString = new DateFromStringType(); diff --git a/x-pack/plugins/beats_management/common/return_types.ts b/x-pack/plugins/beats_management/common/return_types.ts deleted file mode 100644 index c498038d6a21d..0000000000000 --- a/x-pack/plugins/beats_management/common/return_types.ts +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export interface BaseReturnType { - error?: { - message: string; - code?: number; - }; - success: boolean; -} - -export interface ReturnTypeCreate extends BaseReturnType { - item: T; - action: 'created'; -} - -export interface ReturnTypeUpdate extends BaseReturnType { - item: T; - action: 'updated'; -} - -export interface ReturnTypeBulkCreate extends BaseReturnType { - results: Array<{ - item: T; - success: boolean; - action: 'created'; - error?: { - message: string; - code?: number; - }; - }>; -} - -export interface ReturnTypeBulkDelete extends BaseReturnType { - results: Array<{ - success: boolean; - action: 'deleted'; - error?: { - message: string; - code?: number; - }; - }>; -} - -// upsert -export interface ReturnTypeUpsert extends BaseReturnType { - item: T; - action: 'created' | 'updated'; -} - -// upsert bulk -export interface ReturnTypeBulkUpsert extends BaseReturnType { - results: Array<{ - success: boolean; - action: 'created' | 'updated'; - error?: { - message: string; - code?: number; - }; - }>; -} - -// list -export interface ReturnTypeList extends BaseReturnType { - list: T[]; - page: number; - total: number; -} - -// get -export interface ReturnTypeGet extends BaseReturnType { - item: T; -} - -export interface ReturnTypeBulkGet extends BaseReturnType { - items: T[]; -} - -// e.g. -// { -// result: { -// username: { valid: true }, -// password: { valid: false, error: 'something' }, -// hosts: [ -// { valid: false }, { valid: true }, -// ] -// } -// } - -// bulk action -- e.g. assign tags to beats -export interface ReturnTypeBulkAction extends BaseReturnType { - results?: Array<{ - success: boolean; - result?: { - [key: string]: any; - }; - error?: { - message: string; - code?: number; - }; - }>; -} diff --git a/x-pack/plugins/beats_management/jest.config.js b/x-pack/plugins/beats_management/jest.config.js deleted file mode 100644 index be07035045003..0000000000000 --- a/x-pack/plugins/beats_management/jest.config.js +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -module.exports = { - preset: '@kbn/test', - rootDir: '../../..', - roots: ['/x-pack/plugins/beats_management'], -}; diff --git a/x-pack/plugins/beats_management/kibana.json b/x-pack/plugins/beats_management/kibana.json deleted file mode 100644 index c1070eedf07a6..0000000000000 --- a/x-pack/plugins/beats_management/kibana.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "id": "beatsManagement", - "configPath": ["xpack", "beats_management"], - "ui": true, - "server": true, - "version": "kibana", - "requiredPlugins": [ - "data", - "licensing", - "management", - "features" - ], - "optionalPlugins": [ - "security" - ] -} diff --git a/x-pack/plugins/beats_management/public/application.tsx b/x-pack/plugins/beats_management/public/application.tsx deleted file mode 100644 index 5a9b0a768856e..0000000000000 --- a/x-pack/plugins/beats_management/public/application.tsx +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import * as euiVars from '@elastic/eui/dist/eui_theme_light.json'; -import { i18n } from '@kbn/i18n'; -import { FormattedMessage } from '@kbn/i18n/react'; -import React from 'react'; -import ReactDOM from 'react-dom'; -import { Router } from 'react-router-dom'; -import { ThemeProvider } from 'styled-components'; -import { Provider as UnstatedProvider, Subscribe } from 'unstated'; -import { EuiCallOut, EuiLink, EuiSpacer } from '@elastic/eui'; -import { Background } from './components/layouts/background'; -import { BreadcrumbProvider } from './components/navigation/breadcrumb'; -import { Breadcrumb } from './components/navigation/breadcrumb/breadcrumb'; -import { BeatsContainer } from './containers/beats'; -import { TagsContainer } from './containers/tags'; -import { FrontendLibs } from './lib/types'; -import { AppRouter } from './router'; -import { services } from './kbn_services'; -import { ManagementAppMountParams } from '../../../../src/plugins/management/public'; - -export const renderApp = ({ element, history }: ManagementAppMountParams, libs: FrontendLibs) => { - ReactDOM.render( - - - - - - - {(beats: BeatsContainer, tags: TagsContainer) => ( - - - -

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

-
- - -
- )} -
-
-
-
-
-
, - element - ); - - return () => { - ReactDOM.unmountComponentAtNode(element); - }; -}; diff --git a/x-pack/plugins/beats_management/public/bootstrap.tsx b/x-pack/plugins/beats_management/public/bootstrap.tsx deleted file mode 100644 index b5bdd39fa0817..0000000000000 --- a/x-pack/plugins/beats_management/public/bootstrap.tsx +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { FrontendLibs } from './lib/types'; -import { compose } from './lib/compose/kibana'; - -import { setServices } from './kbn_services'; -import { ManagementSetup } from '../../../../src/plugins/management/public'; -import { SecurityPluginSetup } from '../../security/public'; -import { CoreSetup } from '../../../../src/core/public'; -import { DataPublicPluginStart } from '../../../../src/plugins/data/public'; -import { LicensingPluginSetup } from '../../licensing/public'; -import { BeatsManagementConfigType } from '../common'; -import { MANAGEMENT_SECTION } from '../common/constants'; - -async function startApp(libs: FrontendLibs, core: CoreSetup) { - const startServices = await core.getStartServices(); - - if (startServices[0].http.anonymousPaths.isAnonymous(window.location.pathname)) { - return; - } - // Can't run until the `start` lifecycle, so we wait for start services to resolve above before calling this. - await libs.framework.waitUntilFrameworkReady(); - - const capabilities = startServices[0].application.capabilities; - const hasBeatsCapability = capabilities.management.ingest?.[MANAGEMENT_SECTION] ?? false; - - if (libs.framework.licenseIsAtLeast('standard') && hasBeatsCapability) { - const mount = async (params: any) => { - const [coreStart, pluginsStart] = await core.getStartServices(); - setServices(coreStart, pluginsStart, params); - const { renderApp } = await import('./application'); - return renderApp(params, libs); - }; - - libs.framework.registerManagementUI(mount); - } -} - -interface SetupDeps { - management: ManagementSetup; - licensing: LicensingPluginSetup; - security?: SecurityPluginSetup; -} - -interface StartDeps { - data: DataPublicPluginStart; -} - -export const bootstrap = ( - core: CoreSetup, - plugins: SetupDeps, - config: BeatsManagementConfigType, - version: string -) => { - startApp( - compose({ - core, - config, - version, - ...plugins, - }), - core - ); -}; diff --git a/x-pack/plugins/beats_management/public/components/autocomplete_field/index.tsx b/x-pack/plugins/beats_management/public/components/autocomplete_field/index.tsx deleted file mode 100644 index 320296274e262..0000000000000 --- a/x-pack/plugins/beats_management/public/components/autocomplete_field/index.tsx +++ /dev/null @@ -1,290 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { - EuiFieldSearch, - EuiFieldSearchProps, - EuiOutsideClickDetector, - EuiPanel, -} from '@elastic/eui'; -import React from 'react'; -import styled from 'styled-components'; - -import { QuerySuggestion } from '../../../../../../src/plugins/data/public'; - -import { composeStateUpdaters } from '../../utils/typed_react'; -import { SuggestionItem } from './suggestion_item'; - -interface AutocompleteFieldProps { - isLoadingSuggestions: boolean; - isValid: boolean; - loadSuggestions: (value: string, cursorPosition: number, maxCount?: number) => void; - onSubmit?: (value: string) => void; - onChange?: (value: string) => void; - placeholder?: string; - suggestions: QuerySuggestion[]; - value: string; -} - -interface AutocompleteFieldState { - areSuggestionsVisible: boolean; - selectedIndex: number | null; -} - -export class AutocompleteField extends React.Component< - AutocompleteFieldProps, - AutocompleteFieldState -> { - public readonly state: AutocompleteFieldState = { - areSuggestionsVisible: false, - selectedIndex: null, - }; - - private inputElement: HTMLInputElement | null = null; - - public render() { - const { suggestions, isLoadingSuggestions, isValid, placeholder, value } = this.props; - const { areSuggestionsVisible, selectedIndex } = this.state; - - return ( - - - - {areSuggestionsVisible && !isLoadingSuggestions && suggestions.length > 0 ? ( - - {suggestions.map((suggestion, suggestionIndex) => ( - - ))} - - ) : null} - - - ); - } - - public componentDidUpdate(prevProps: AutocompleteFieldProps, prevState: AutocompleteFieldState) { - const hasNewSuggestions = prevProps.suggestions !== this.props.suggestions; - const hasNewValue = prevProps.value !== this.props.value; - - if (hasNewValue) { - this.updateSuggestions(); - } - - if (hasNewSuggestions) { - this.showSuggestions(); - } - } - - private handleChangeInputRef = (element: HTMLInputElement | null) => { - this.inputElement = element; - }; - - private handleChange = (evt: React.ChangeEvent) => { - this.changeValue(evt.currentTarget.value); - }; - - private handleKeyDown = (evt: React.KeyboardEvent) => { - const { suggestions } = this.props; - - switch (evt.key) { - case 'ArrowUp': - evt.preventDefault(); - if (suggestions.length > 0) { - this.setState( - composeStateUpdaters(withSuggestionsVisible, withPreviousSuggestionSelected) - ); - } - break; - case 'ArrowDown': - evt.preventDefault(); - if (suggestions.length > 0) { - this.setState(composeStateUpdaters(withSuggestionsVisible, withNextSuggestionSelected)); - } else { - this.updateSuggestions(); - } - break; - case 'Enter': - evt.preventDefault(); - if (this.state.selectedIndex !== null) { - this.applySelectedSuggestion(); - } else { - this.submit(); - } - break; - case 'Escape': - evt.preventDefault(); - this.setState(withSuggestionsHidden); - break; - } - }; - - private handleKeyUp = (evt: React.KeyboardEvent) => { - switch (evt.key) { - case 'ArrowLeft': - case 'ArrowRight': - case 'Home': - case 'End': - this.updateSuggestions(); - break; - } - }; - - private selectSuggestionAt = (index: number) => () => { - this.setState(withSuggestionAtIndexSelected(index)); - }; - - private applySelectedSuggestion = () => { - if (this.state.selectedIndex !== null) { - this.applySuggestionAt(this.state.selectedIndex)(); - } - }; - - private applySuggestionAt = (index: number) => () => { - const { value, suggestions } = this.props; - const selectedSuggestion = suggestions[index]; - - if (!selectedSuggestion) { - return; - } - - const newValue = - value.substr(0, selectedSuggestion.start) + - selectedSuggestion.text + - value.substr(selectedSuggestion.end); - - this.setState(withSuggestionsHidden); - this.changeValue(newValue); - this.focusInputElement(); - }; - - private changeValue = (value: string) => { - const { onChange } = this.props; - if (onChange) { - onChange(value); - } - }; - - private focusInputElement = () => { - if (this.inputElement) { - this.inputElement.focus(); - } - }; - - private showSuggestions = () => { - this.setState(withSuggestionsVisible); - }; - - private hideSuggestions = () => { - this.setState(withSuggestionsHidden); - }; - - private submit = () => { - const { isValid, onSubmit, value } = this.props; - - if (isValid && onSubmit) { - onSubmit(value); - } - - this.setState(withSuggestionsHidden); - }; - - private updateSuggestions = (value?: string) => { - const inputCursorPosition = this.inputElement ? this.inputElement.selectionStart || 0 : 0; - this.props.loadSuggestions(value || this.props.value, inputCursorPosition, 10); - }; -} - -const withPreviousSuggestionSelected = ( - state: AutocompleteFieldState, - props: AutocompleteFieldProps -): AutocompleteFieldState => ({ - ...state, - selectedIndex: - props.suggestions.length === 0 - ? null - : state.selectedIndex !== null - ? (state.selectedIndex + props.suggestions.length - 1) % props.suggestions.length - : Math.max(props.suggestions.length - 1, 0), -}); - -const withNextSuggestionSelected = ( - state: AutocompleteFieldState, - props: AutocompleteFieldProps -): AutocompleteFieldState => ({ - ...state, - selectedIndex: - props.suggestions.length === 0 - ? null - : state.selectedIndex !== null - ? (state.selectedIndex + 1) % props.suggestions.length - : 0, -}); - -const withSuggestionAtIndexSelected = (suggestionIndex: number) => ( - state: AutocompleteFieldState, - props: AutocompleteFieldProps -): AutocompleteFieldState => ({ - ...state, - selectedIndex: - props.suggestions.length === 0 - ? null - : suggestionIndex >= 0 && suggestionIndex < props.suggestions.length - ? suggestionIndex - : 0, -}); - -const withSuggestionsVisible = (state: AutocompleteFieldState) => ({ - ...state, - areSuggestionsVisible: true, -}); - -const withSuggestionsHidden = (state: AutocompleteFieldState) => ({ - ...state, - areSuggestionsVisible: false, - selectedIndex: null, -}); - -const FixedEuiFieldSearch: React.FC< - React.InputHTMLAttributes & - EuiFieldSearchProps & { - inputRef?: (element: HTMLInputElement | null) => void; - onSearch: (value: string) => void; - } -> = EuiFieldSearch as any; - -const AutocompleteContainer = styled.div` - position: relative; -`; - -const SuggestionsPanel = styled(EuiPanel).attrs(() => ({ - paddingSize: 'none', - hasShadow: true, -}))` - position: absolute; - width: 100%; - margin-top: 2px; - overflow: hidden; - z-index: 1000; -`; diff --git a/x-pack/plugins/beats_management/public/components/autocomplete_field/suggestion_item.tsx b/x-pack/plugins/beats_management/public/components/autocomplete_field/suggestion_item.tsx deleted file mode 100644 index b870982d63d22..0000000000000 --- a/x-pack/plugins/beats_management/public/components/autocomplete_field/suggestion_item.tsx +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { EuiIcon } from '@elastic/eui'; -import { tint } from 'polished'; -import React from 'react'; -import styled from 'styled-components'; - -import { QuerySuggestion } from '../../../../../../src/plugins/data/public'; - -interface SuggestionItemProps { - isSelected?: boolean; - onClick?: React.MouseEventHandler; - onMouseEnter?: React.MouseEventHandler; - suggestion: QuerySuggestion; -} - -export const SuggestionItem: React.FC = (props) => { - const { isSelected, onClick, onMouseEnter, suggestion } = props; - - return ( - - - - - {suggestion.text} - {suggestion.description} - - ); -}; - -SuggestionItem.defaultProps = { - isSelected: false, -}; - -const SuggestionItemContainer = styled.div<{ - isSelected?: boolean; -}>` - display: flex; - flex-direction: row; - font-size: ${(props) => props.theme.eui.default.euiFontSizeS}; - height: ${(props) => props.theme.eui.default.euiSizeXl}; - white-space: nowrap; - background-color: ${(props) => - props.isSelected ? props.theme.eui.default.euiColorLightestShade : 'transparent'}; -`; - -const SuggestionItemField = styled.div` - align-items: center; - cursor: pointer; - display: flex; - flex-direction: row; - height: ${(props) => props.theme.eui.default.euiSizeXl}; - padding: ${(props) => props.theme.eui.default.euiSizeXs}; -`; - -const SuggestionItemIconField = styled(SuggestionItemField)<{ suggestionType: string }>` - background-color: ${(props) => { - return tint(0.1, getEuiIconColor(props.theme, props.suggestionType)); - }}; - color: ${(props) => { - return getEuiIconColor(props.theme, props.suggestionType); - }}; - flex: 0 0 auto; - justify-content: center; - width: ${(props) => props.theme.eui.default.euiSizeXl}; -`; - -const SuggestionItemTextField = styled(SuggestionItemField)` - flex: 2 0 0; - font-family: ${(props) => props.theme.eui.default.euiCodeFontFamily}; -`; - -const SuggestionItemDescriptionField = styled(SuggestionItemField)` - flex: 3 0 0; - p { - display: inline; - span { - font-family: ${(props) => props.theme.eui.default.euiCodeFontFamily}; - } - } -`; - -const getEuiIconType = (suggestionType: string) => { - switch (suggestionType) { - case 'field': - return 'kqlField'; - case 'value': - return 'kqlValue'; - case 'recentSearch': - return 'search'; - case 'conjunction': - return 'kqlSelector'; - case 'operator': - return 'kqlOperand'; - default: - return 'empty'; - } -}; - -const getEuiIconColor = (theme: any, suggestionType: string): string => { - switch (suggestionType) { - case 'field': - return theme.eui.default.euiColorVis7; - case 'value': - return theme.eui.default.euiColorVis0; - case 'operator': - return theme.eui.default.euiColorVis1; - case 'conjunction': - return theme.eui.default.euiColorVis2; - case 'recentSearch': - default: - return theme.eui.default.euiColorMediumShade; - } -}; diff --git a/x-pack/plugins/beats_management/public/components/config_list.tsx b/x-pack/plugins/beats_management/public/components/config_list.tsx deleted file mode 100644 index 44a581a866735..0000000000000 --- a/x-pack/plugins/beats_management/public/components/config_list.tsx +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -// @ts-ignore -import { EuiBasicTable, EuiLink } from '@elastic/eui'; -import { InjectedIntl, injectI18n } from '@kbn/i18n/react'; -import React from 'react'; -import { configBlockSchemas } from '../../common/config_schemas'; -import { translateConfigSchema } from '../../common/config_schemas_translations_map'; -import { ConfigurationBlock } from '../../common/domain_types'; - -interface ComponentProps { - configs: { - error?: string | undefined; - list: ConfigurationBlock[]; - page: number; - total: number; - }; - onConfigClick: (action: 'edit' | 'delete', config: ConfigurationBlock) => any; - onTableChange: (index: number, size: number) => void; - intl: InjectedIntl; -} -const pagination = { - pageSize: 5, - hidePerPageOptions: true, -}; - -const ConfigListUi: React.FC = (props) => ( - { - if (props.onTableChange) { - props.onTableChange(table.page.index, table.page.size); - } - }} - columns={[ - { - field: 'type', - name: props.intl.formatMessage({ - id: 'xpack.beatsManagement.tagTable.typeColumnName', - defaultMessage: 'Type', - }), - truncateText: false, - render: (type: string, config: ConfigurationBlock) => { - const translatedConfig = translateConfigSchema(configBlockSchemas).find( - (sc) => sc.id === type - ); - - return ( - props.onConfigClick('edit', config)}> - {translatedConfig ? translatedConfig.name : type} - - ); - }, - }, - { - field: 'module', - name: props.intl.formatMessage({ - id: 'xpack.beatsManagement.tagTable.moduleColumnName', - defaultMessage: 'Module', - }), - truncateText: false, - render: (value: string, config: ConfigurationBlock) => { - return ( - config.config._sub_type || - props.intl.formatMessage({ - id: 'xpack.beatsManagement.tagTable.moduleColumn.notAvailibaleLabel', - defaultMessage: 'N/A', - }) - ); - }, - }, - { - field: 'description', - name: props.intl.formatMessage({ - id: 'xpack.beatsManagement.tagTable.descriptionColumnName', - defaultMessage: 'Description', - }), - }, - { - name: props.intl.formatMessage({ - id: 'xpack.beatsManagement.tagTable.actionsColumnName', - defaultMessage: 'Actions', - }), - actions: [ - { - name: props.intl.formatMessage({ - id: 'xpack.beatsManagement.tagTable.actions.removeButtonAriaLabel', - defaultMessage: 'Remove', - }), - description: props.intl.formatMessage({ - id: 'xpack.beatsManagement.tagTable.actions.removeTooltip', - defaultMessage: 'Remove this config from tag', - }), - type: 'icon', - icon: 'trash', - onClick: (item: ConfigurationBlock) => props.onConfigClick('delete', item), - }, - ], - }, - ]} - /> -); - -export const ConfigList = injectI18n(ConfigListUi); diff --git a/x-pack/plugins/beats_management/public/components/enroll_beats.tsx b/x-pack/plugins/beats_management/public/components/enroll_beats.tsx deleted file mode 100644 index 4c85509f13256..0000000000000 --- a/x-pack/plugins/beats_management/public/components/enroll_beats.tsx +++ /dev/null @@ -1,292 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { - EuiBasicTable, - EuiButton, - EuiCodeBlock, - EuiCopy, - EuiFlexGroup, - EuiFlexItem, - EuiLoadingSpinner, - EuiModalBody, - // @ts-ignore - EuiSelect, - EuiSpacer, - EuiTitle, -} from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n/react'; -import { upperFirst } from 'lodash'; -import React from 'react'; -import { CMBeat } from '../../common/domain_types'; - -interface ComponentProps { - /** Such as kibanas basePath, for use to generate command */ - frameworkBasePath?: string; - enrollmentToken?: string; - getBeatWithToken(token: string): Promise; - createEnrollmentToken(): Promise; - onBeatEnrolled(enrolledBeat: CMBeat): void; -} - -interface ComponentState { - enrolledBeat: CMBeat | null; - hasPolledForBeat: boolean; - command: string; - beatType: string; -} - -export class EnrollBeat extends React.Component { - private pinging = false; - constructor(props: ComponentProps) { - super(props); - - this.state = { - enrolledBeat: null, - hasPolledForBeat: false, - command: 'sudo {{beatType}}', - beatType: 'filebeat', - }; - } - public pingForBeatWithToken = async (token: string): Promise => { - try { - const beats = await this.props.getBeatWithToken(token); - - if (!beats) { - throw new Error('no beats'); - } - return beats; - } catch (err) { - if (this.pinging) { - const timeout = (ms: number) => new Promise((res) => setTimeout(res, ms)); - await timeout(5000); - return await this.pingForBeatWithToken(token); - } - } - }; - public async componentDidMount() { - if (!this.props.enrollmentToken) { - await this.props.createEnrollmentToken(); - } - } - public waitForTokenToEnrollBeat = async () => { - if (this.pinging || !this.props.enrollmentToken) { - return; - } - this.pinging = true; - const enrolledBeat = (await this.pingForBeatWithToken(this.props.enrollmentToken)) as CMBeat; - - this.setState({ - enrolledBeat, - }); - this.props.onBeatEnrolled(enrolledBeat); - this.pinging = false; - }; - public render() { - if (!this.props.enrollmentToken && !this.state.enrolledBeat) { - return null; - } - if (this.props.enrollmentToken && !this.state.enrolledBeat) { - this.waitForTokenToEnrollBeat(); - } - const cmdText = `${this.state.command - .replace('{{beatType}}', this.state.beatType) - .replace('{{beatTypeInCaps}}', upperFirst(this.state.beatType))} enroll ${ - window.location.protocol - }//${window.location.host}${this.props.frameworkBasePath} ${this.props.enrollmentToken}`; - - return ( - - {!this.state.enrolledBeat && ( - - - - - - -

- -

-
-
-
- this.setState({ beatType: e.target.value })} - fullWidth={true} - /> -
-
- -
-
- - - - - -

- -

-
-
-
- {{beatType}}.exe`, - text: 'Windows', - }, - { - value: `./{{beatType}}`, - text: 'MacOS', - }, - ]} - onChange={(e: any) => this.setState({ command: e.target.value })} - fullWidth={true} - /> -
-
-
-
- {this.state.command && ( - - - - - -

- -

-
-
- - - {(copy: any) => ( - - - - )} - - -
- -
- - {`$ ${cmdText}`} -
- - - - - - - - -

- -

-
-
-
-
-
-
- -
-
- )} -
- )} - {this.state.enrolledBeat && ( - - -
-
-
- - ), - sortable: false, - }, - { - field: 'version', - name: ( - - ), - sortable: false, - }, - { - field: 'host_name', - name: ( - - ), - sortable: false, - }, - ]} - /> -
-
-
- )} -
- ); - } -} diff --git a/x-pack/plugins/beats_management/public/components/inputs/code_editor.tsx b/x-pack/plugins/beats_management/public/components/inputs/code_editor.tsx deleted file mode 100644 index 9116725bfe06a..0000000000000 --- a/x-pack/plugins/beats_management/public/components/inputs/code_editor.tsx +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -// @ts-ignore -import { CommonProps, EuiCodeEditor, EuiCodeEditorProps, EuiFormRow } from '@elastic/eui'; -// @ts-ignore -import { FormsyInputProps, withFormsy } from 'formsy-react'; -import React, { Component, InputHTMLAttributes } from 'react'; - -interface ComponentProps extends FormsyInputProps, CommonProps, EuiCodeEditorProps { - instantValidation: boolean; - label: string; - isReadOnly: boolean; - mode: 'javascript' | 'yaml'; - errorText: string; - fullWidth: boolean; - helpText: React.ReactElement; - compressed: boolean; - onChange(value: string): void; - onBlur(): void; -} - -interface ComponentState { - allowError: boolean; -} - -class CodeEditor extends Component< - InputHTMLAttributes & ComponentProps, - ComponentState -> { - public static defaultProps = { - passRequiredToField: true, - }; - - public state = { allowError: false }; - - public componentDidMount() { - const { defaultValue, setValue } = this.props; - setValue(defaultValue || ''); - } - - public UNSAFE_componentWillReceiveProps(nextProps: ComponentProps) { - if (nextProps.isFormSubmitted()) { - this.showError(); - } - } - - public handleChange = (value: string) => { - this.props.setValue(value); - if (this.props.onChange) { - this.props.onChange(value); - } - if (this.props.instantValidation) { - this.showError(); - } - }; - - public handleBlur = () => { - this.showError(); - if (this.props.onBlur) { - this.props.onBlur(); - } - }; - - public showError = () => this.setState({ allowError: true }); - - public render() { - const { - name, - id, - label, - isReadOnly, - isValid, - getValue, - isPristine, - getErrorMessage, - mode, - fullWidth, - className, - helpText, - } = this.props; - - const { allowError } = this.state; - const error = !isPristine() && !isValid() && allowError; - - return ( - - - - ); - } -} - -export const FormsyEuiCodeEditor = withFormsy(CodeEditor); diff --git a/x-pack/plugins/beats_management/public/components/inputs/index.ts b/x-pack/plugins/beats_management/public/components/inputs/index.ts deleted file mode 100644 index 58f5ba4c81f71..0000000000000 --- a/x-pack/plugins/beats_management/public/components/inputs/index.ts +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export { FormsyEuiCodeEditor } from './code_editor'; -export { FormsyEuiFieldText } from './input'; -export { FormsyEuiPasswordText } from './password_input'; -export { FormsyEuiMultiFieldText } from './multi_input'; -export { FormsyEuiSelect } from './select'; diff --git a/x-pack/plugins/beats_management/public/components/inputs/input.tsx b/x-pack/plugins/beats_management/public/components/inputs/input.tsx deleted file mode 100644 index 3fb18e1b218b4..0000000000000 --- a/x-pack/plugins/beats_management/public/components/inputs/input.tsx +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { EuiFieldText, EuiFormRow } from '@elastic/eui'; -import { CommonProps } from '@elastic/eui/src/components/common'; -import { FormsyInputProps, withFormsy } from 'formsy-react'; -import React, { Component, InputHTMLAttributes } from 'react'; - -interface ComponentProps - extends FormsyInputProps, - CommonProps, - Omit, 'onChange' | 'onBlur'> { - instantValidation?: boolean; - label: string; - errorText: string; - fullWidth: boolean; - helpText: React.ReactElement; - compressed: boolean; - onChange?(e: React.ChangeEvent, value: any): void; - onBlur?(e: React.ChangeEvent, value: any): void; -} - -interface ComponentState { - allowError: boolean; -} - -class FieldText extends Component< - InputHTMLAttributes & ComponentProps, - ComponentState -> { - public static defaultProps = { - passRequiredToField: true, - }; - - public state = { allowError: false }; - - public componentDidMount() { - const { defaultValue, setValue } = this.props; - if (defaultValue) { - setValue(defaultValue); - } - } - - public UNSAFE_componentWillReceiveProps(nextProps: ComponentProps) { - if (nextProps.isFormSubmitted()) { - this.showError(); - } - } - - public handleChange = (e: React.ChangeEvent) => { - const { value } = e.currentTarget; - this.props.setValue(value); - if (this.props.onChange) { - this.props.onChange(e, e.currentTarget.value); - } - if (this.props.instantValidation) { - this.showError(); - } - }; - - public handleBlur = (e: React.ChangeEvent) => { - this.showError(); - if (this.props.onBlur) { - this.props.onBlur(e, e.currentTarget.value); - } - }; - - public showError = () => this.setState({ allowError: true }); - - public render() { - const { - name, - id, - required, - label, - getValue, - isValid, - isPristine, - getErrorMessage, - fullWidth, - className, - disabled, - helpText, - placeholder, - } = this.props; - - const { allowError } = this.state; - const error = !isPristine() && !isValid() && allowError; - - return ( - - - - ); - } -} - -export const FormsyEuiFieldText = withFormsy(FieldText); diff --git a/x-pack/plugins/beats_management/public/components/inputs/multi_input.tsx b/x-pack/plugins/beats_management/public/components/inputs/multi_input.tsx deleted file mode 100644 index ffc208f6f94fd..0000000000000 --- a/x-pack/plugins/beats_management/public/components/inputs/multi_input.tsx +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { EuiFormRow, EuiTextArea, EuiTextAreaProps } from '@elastic/eui'; -import { CommonProps } from '@elastic/eui/src/components/common'; -// @ts-ignore -import { FormsyInputProps, withFormsy } from 'formsy-react'; -import React, { Component, InputHTMLAttributes } from 'react'; - -interface ComponentProps - extends FormsyInputProps, - CommonProps, - Omit { - instantValidation: boolean; - label: string; - errorText: string; - fullWidth: boolean; - helpText: React.ReactElement; - compressed: boolean; - onChange(e: React.ChangeEvent, value: any): void; - onBlur(e: React.ChangeEvent, value: any): void; -} - -interface ComponentState { - allowError: boolean; -} - -class MultiFieldText extends Component< - InputHTMLAttributes & ComponentProps, - ComponentState -> { - public static defaultProps = { - passRequiredToField: true, - }; - - public state = { allowError: false }; - - public componentDidMount() { - const { defaultValue, setValue } = this.props; - - if (defaultValue) { - setValue(defaultValue); - } - } - - public UNSAFE_componentWillReceiveProps(nextProps: ComponentProps) { - if (nextProps.isFormSubmitted()) { - this.showError(); - } - } - - public handleChange = (e: React.ChangeEvent) => { - const value = e.currentTarget.value.split('\n'); - this.props.setValue(value); - if (this.props.onChange) { - this.props.onChange(e, value); - } - if (this.props.instantValidation) { - this.showError(); - } - }; - - public handleBlur = (e: React.ChangeEvent) => { - this.showError(); - if (this.props.onBlur) { - this.props.onBlur(e, e.currentTarget.value); - } - }; - - public showError = () => this.setState({ allowError: true }); - - public render() { - const { - name, - id, - required, - label, - getValue, - isValid, - isPristine, - getErrorMessage, - fullWidth, - className, - disabled, - helpText, - placeholder, - } = this.props; - - const { allowError } = this.state; - const error = !isPristine() && !isValid() && allowError; - - return ( - - - - ); - } -} - -export const FormsyEuiMultiFieldText = withFormsy(MultiFieldText); diff --git a/x-pack/plugins/beats_management/public/components/inputs/password_input.tsx b/x-pack/plugins/beats_management/public/components/inputs/password_input.tsx deleted file mode 100644 index 7d4b0c369c19a..0000000000000 --- a/x-pack/plugins/beats_management/public/components/inputs/password_input.tsx +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { CommonProps, EuiFieldPassword, EuiFieldPasswordProps, EuiFormRow } from '@elastic/eui'; -import { FormsyInputProps, withFormsy } from 'formsy-react'; -import React, { Component, InputHTMLAttributes } from 'react'; - -interface ComponentProps - extends FormsyInputProps, - CommonProps, - Omit { - instantValidation?: boolean; - label: string; - errorText: string; - fullWidth: boolean; - helpText: React.ReactElement; - compressed: boolean; - onChange?(e: React.ChangeEvent, value: any): void; - onBlur?(e: React.ChangeEvent, value: any): void; -} - -interface ComponentState { - allowError: boolean; -} - -class FieldPassword extends Component< - InputHTMLAttributes & ComponentProps, - ComponentState -> { - constructor(props: any) { - super(props); - - this.state = { - allowError: false, - }; - } - - public componentDidMount() { - const { defaultValue, setValue } = this.props; - if (defaultValue) { - setValue(defaultValue); - } - } - - public handleChange = (e: React.ChangeEvent) => { - const { value } = e.currentTarget; - this.props.setValue(value); - if (this.props.onChange) { - this.props.onChange(e, value); - } - if (this.props.instantValidation) { - this.showError(); - } - }; - - public handleBlur = (e: React.ChangeEvent) => { - this.showError(); - if (this.props.onBlur) { - this.props.onBlur(e, e.currentTarget.value); - } - }; - - public showError = () => this.setState({ allowError: true }); - - public render() { - const { - name, - id, - required, - label, - getValue, - isValid, - isPristine, - getErrorMessage, - fullWidth, - className, - disabled, - helpText, - onBlur, - } = this.props; - - const { allowError } = this.state; - const error = !isPristine() && !isValid() && allowError; - - return ( - - - - ); - } -} - -export const FormsyEuiPasswordText = withFormsy(FieldPassword); diff --git a/x-pack/plugins/beats_management/public/components/inputs/select.tsx b/x-pack/plugins/beats_management/public/components/inputs/select.tsx deleted file mode 100644 index edd1a7fee90c5..0000000000000 --- a/x-pack/plugins/beats_management/public/components/inputs/select.tsx +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { - EuiFormRow, - // @ts-ignore - EuiSelect, -} from '@elastic/eui'; -import { CommonProps } from '@elastic/eui/src/components/common'; -// @ts-ignore -import { FormsyInputProps, withFormsy } from 'formsy-react'; -import React, { Component, InputHTMLAttributes } from 'react'; - -const FixedSelect = EuiSelect as React.FC; - -interface ComponentProps extends FormsyInputProps, CommonProps { - instantValidation: boolean; - options: Array<{ value: string; text: string }>; - label: string; - errorText: string; - fullWidth: boolean; - helpText: React.ReactElement; - compressed: boolean; - onChange(e: React.ChangeEvent, value: any): void; - onBlur(e: React.ChangeEvent, value: any): void; -} - -interface ComponentState { - allowError: boolean; -} - -class FieldSelect extends Component< - InputHTMLAttributes & ComponentProps, - ComponentState -> { - public static defaultProps = { - passRequiredToField: true, - }; - - public state = { allowError: false }; - - public componentDidMount() { - const { defaultValue, setValue } = this.props; - if (defaultValue) { - setValue(defaultValue); - } - } - - public UNSAFE_componentWillReceiveProps(nextProps: ComponentProps) { - if (nextProps.isFormSubmitted()) { - this.showError(); - } - } - - public handleChange = (e: React.ChangeEvent) => { - const { value } = e.currentTarget; - - this.props.setValue(value); - if (this.props.onChange) { - this.props.onChange(e, e.currentTarget.value); - } - if (this.props.instantValidation) { - this.showError(); - } - }; - - public handleBlur = (e: React.ChangeEvent) => { - this.showError(); - if (this.props.onBlur) { - this.props.onBlur(e, e.currentTarget.value); - } - }; - - public showError = () => this.setState({ allowError: true }); - - public render() { - const { - id, - required, - label, - options, - getValue, - isValid, - isPristine, - getErrorMessage, - fullWidth, - className, - disabled, - helpText, - } = this.props; - - const { allowError } = this.state; - const error = !isPristine() && !isValid() && allowError; - - return ( - - - - ); - } -} - -export const FormsyEuiSelect = withFormsy(FieldSelect); diff --git a/x-pack/plugins/beats_management/public/components/layouts/background.tsx b/x-pack/plugins/beats_management/public/components/layouts/background.tsx deleted file mode 100644 index ff060cb5869fa..0000000000000 --- a/x-pack/plugins/beats_management/public/components/layouts/background.tsx +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import styled from 'styled-components'; - -export const Background = styled.div` - flex-grow: 1; -`; diff --git a/x-pack/plugins/beats_management/public/components/layouts/no_data.tsx b/x-pack/plugins/beats_management/public/components/layouts/no_data.tsx deleted file mode 100644 index e61c3db2ebd13..0000000000000 --- a/x-pack/plugins/beats_management/public/components/layouts/no_data.tsx +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { EuiEmptyPrompt, EuiFlexGroup, EuiFlexItem, EuiPageContent } from '@elastic/eui'; -import React from 'react'; -import { withRouter, RouteComponentProps } from 'react-router-dom'; - -interface LayoutProps extends RouteComponentProps { - children: React.ReactNode; - title: string | React.ReactNode; - actionSection?: React.ReactNode; -} - -export const NoDataLayout = withRouter(({ actionSection, title, children }: LayoutProps) => ( - - - - {title}} - body={children} - actions={actionSection} - /> - - - -)); diff --git a/x-pack/plugins/beats_management/public/components/layouts/primary.tsx b/x-pack/plugins/beats_management/public/components/layouts/primary.tsx deleted file mode 100644 index 0a1c0bb028c77..0000000000000 --- a/x-pack/plugins/beats_management/public/components/layouts/primary.tsx +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { - EuiHeader, - EuiHeaderBreadcrumbs, - EuiHeaderSection, - EuiPage, - EuiPageBody, - EuiPageContent, - EuiPageContentBody, - EuiPageHeader, - EuiPageHeaderSection, - EuiTitle, -} from '@elastic/eui'; -import React, { Component, ReactNode } from 'react'; -import styled from 'styled-components'; -import { BreadcrumbConsumer } from '../navigation/breadcrumb'; - -type RenderCallback = (component: () => JSX.Element) => void; -interface PrimaryLayoutProps { - title: string | React.ReactNode; - actionSection?: React.ReactNode; - hideBreadcrumbs?: boolean; -} -export class PrimaryLayout extends Component { - private actionSection: (() => JSX.Element) | null = null; - constructor(props: PrimaryLayoutProps) { - super(props); - } - - public render() { - const children: (callback: RenderCallback) => void | ReactNode = this.props.children as any; - return ( - - {!this.props.hideBreadcrumbs && ( - - {({ breadcrumbs }) => ( - - - - - - )} - - )} - - - - - -

{this.props.title}

-
-
- - {(this.actionSection && this.actionSection()) || this.props.actionSection} - -
- - - {(children && typeof children === 'function' - ? children(this.renderAction) - : children) || } - - -
-
-
- ); - } - - private renderAction = (component: () => JSX.Element) => { - this.actionSection = component; - this.forceUpdate(); - }; -} - -const HeaderWrapper = styled(EuiHeader)` - height: 29px; -`; diff --git a/x-pack/plugins/beats_management/public/components/layouts/walkthrough.tsx b/x-pack/plugins/beats_management/public/components/layouts/walkthrough.tsx deleted file mode 100644 index 4d0fb9126d5b5..0000000000000 --- a/x-pack/plugins/beats_management/public/components/layouts/walkthrough.tsx +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; - -import { EuiPageContent, EuiPageContentBody, EuiStepsHorizontal, EuiTitle } from '@elastic/eui'; - -interface LayoutProps { - title: string; - goTo: (path: string) => any; - walkthroughSteps: Array<{ - id: string; - name: string; - }>; - activePath: string; -} - -export const WalkthroughLayout: React.FC = ({ - walkthroughSteps, - title, - activePath, - goTo, - children, -}) => { - const indexOfCurrent = walkthroughSteps.findIndex((step) => activePath === step.id); - return ( - - -

{title}

-
-
-
- ({ - title: step.name, - isComplete: i <= indexOfCurrent, - onClick: () => goTo(step.id), - }))} - /> -
-
- {children} -
- ); -}; diff --git a/x-pack/plugins/beats_management/public/components/loading.tsx b/x-pack/plugins/beats_management/public/components/loading.tsx deleted file mode 100644 index fabbee359946c..0000000000000 --- a/x-pack/plugins/beats_management/public/components/loading.tsx +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { EuiFlexGroup, EuiFlexItem, EuiLoadingSpinner } from '@elastic/eui'; -import * as React from 'react'; - -export const Loading: React.FC<{}> = () => ( - - - - - -); diff --git a/x-pack/plugins/beats_management/public/components/navigation/breadcrumb/breadcrumb.tsx b/x-pack/plugins/beats_management/public/components/navigation/breadcrumb/breadcrumb.tsx deleted file mode 100644 index 7af0270822422..0000000000000 --- a/x-pack/plugins/beats_management/public/components/navigation/breadcrumb/breadcrumb.tsx +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { Component } from 'react'; -import { RouteProps } from 'react-router-dom'; -import { BASE_PATH } from '../../../../common/constants'; -import { BreadcrumbConsumer } from './consumer'; -import { Breadcrumb as BreadcrumbData, BreadcrumbContext } from './types'; - -interface BreadcrumbManagerProps extends RouteProps { - text: string; - href?: string; - parents?: BreadcrumbData[]; - context: BreadcrumbContext; -} - -class BreadcrumbManager extends Component { - public componentWillUnmount() { - const { text, href, context } = this.props; - - context.removeCrumb({ - text, - href, - }); - } - - public componentDidMount() { - const { text, href, parents, context } = this.props; - context.addCrumb( - { - text, - href, - }, - parents - ); - } - - public render() { - return ; - } -} - -interface BreadcrumbProps extends RouteProps { - title: string; - path?: string; - parentBreadcrumbs?: BreadcrumbData[]; -} - -export const Breadcrumb: React.FC = ({ title, path, parentBreadcrumbs }) => ( - - {(context) => ( - - )} - -); diff --git a/x-pack/plugins/beats_management/public/components/navigation/breadcrumb/consumer.tsx b/x-pack/plugins/beats_management/public/components/navigation/breadcrumb/consumer.tsx deleted file mode 100644 index 3062095a06383..0000000000000 --- a/x-pack/plugins/beats_management/public/components/navigation/breadcrumb/consumer.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export { Consumer as BreadcrumbConsumer } from './context'; diff --git a/x-pack/plugins/beats_management/public/components/navigation/breadcrumb/context.tsx b/x-pack/plugins/beats_management/public/components/navigation/breadcrumb/context.tsx deleted file mode 100644 index 3d11194bc3fb9..0000000000000 --- a/x-pack/plugins/beats_management/public/components/navigation/breadcrumb/context.tsx +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; - -import { Breadcrumb, BreadcrumbContext } from './types'; - -/* istanbul ignore next */ -const defaultContext: BreadcrumbContext = { - breadcrumbs: [], - addCrumb: (crumb: Breadcrumb) => null, - removeCrumb: (crumb: Breadcrumb) => null, -}; - -export const { Provider, Consumer } = React.createContext(defaultContext); diff --git a/x-pack/plugins/beats_management/public/components/navigation/breadcrumb/index.ts b/x-pack/plugins/beats_management/public/components/navigation/breadcrumb/index.ts deleted file mode 100644 index e4839a75c39e0..0000000000000 --- a/x-pack/plugins/beats_management/public/components/navigation/breadcrumb/index.ts +++ /dev/null @@ -1,10 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export { BreadcrumbProvider } from './provider'; -export { BreadcrumbConsumer } from './consumer'; -export { Breadcrumb } from './breadcrumb'; diff --git a/x-pack/plugins/beats_management/public/components/navigation/breadcrumb/provider.tsx b/x-pack/plugins/beats_management/public/components/navigation/breadcrumb/provider.tsx deleted file mode 100644 index 20919a52b658e..0000000000000 --- a/x-pack/plugins/beats_management/public/components/navigation/breadcrumb/provider.tsx +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { Component, ReactElement } from 'react'; -import { Provider } from './context'; -import { Breadcrumb } from './types'; -import { services } from '../../../kbn_services'; - -interface ComponentProps { - useGlobalBreadcrumbs: boolean; - children: ReactElement | Array>; -} - -interface ComponentState { - breadcrumbs: Array<{ - href?: string; - breadcrumb: Breadcrumb; - parents?: Breadcrumb[]; - }>; -} - -export class BreadcrumbProvider extends Component { - public state = { - breadcrumbs: [] as ComponentState['breadcrumbs'], - }; - - public addCrumb = (breadcrumb: Breadcrumb, parents?: Breadcrumb[]) => { - this.setState(({ breadcrumbs: prevCrumbs }) => ({ - breadcrumbs: [ - ...prevCrumbs, - { - href: breadcrumb.href, - breadcrumb, - parents, - }, - ], - })); - }; - - public removeCrumb = (crumbToRemove: Breadcrumb) => { - this.setState(({ breadcrumbs: prevCrumbs }) => { - const breadcrumbs = prevCrumbs.filter((prevCrumb) => { - const { href } = prevCrumb; - return !(crumbToRemove.href === href); - }); - return { breadcrumbs }; - }); - }; - - public render() { - const { breadcrumbs } = this.state; - - const context = { - breadcrumbs: breadcrumbs.reduce((crumbs, crumbStorageItem) => { - if (crumbStorageItem.parents) { - crumbs = crumbs.concat(crumbStorageItem.parents); - } - crumbs.push(crumbStorageItem.breadcrumb); - return crumbs; - }, [] as Breadcrumb[]), - addCrumb: this.addCrumb, - removeCrumb: this.removeCrumb, - }; - if (this.props.useGlobalBreadcrumbs) { - services.setBreadcrumbs(context.breadcrumbs); - } - return {this.props.children}; - } -} diff --git a/x-pack/plugins/beats_management/public/components/navigation/breadcrumb/types.d.ts b/x-pack/plugins/beats_management/public/components/navigation/breadcrumb/types.d.ts deleted file mode 100644 index 33a947d649c46..0000000000000 --- a/x-pack/plugins/beats_management/public/components/navigation/breadcrumb/types.d.ts +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export interface BreadcrumbContext { - breadcrumbs: Breadcrumb[]; - addCrumb: (crumb: Breadcrumb, parents?: Breadcrumb[]) => void; - removeCrumb: (crumb: Breadcrumb) => void; -} -export interface Breadcrumb { - text: string; - href?: string; -} diff --git a/x-pack/plugins/beats_management/public/components/navigation/child_routes.tsx b/x-pack/plugins/beats_management/public/components/navigation/child_routes.tsx deleted file mode 100644 index 9e4eaa98c41e9..0000000000000 --- a/x-pack/plugins/beats_management/public/components/navigation/child_routes.tsx +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { FC } from 'react'; -import { Route, Switch } from 'react-router-dom'; - -export interface RouteConfig { - path: string; - component: React.ComponentType; - routes?: RouteConfig[]; -} - -export const ChildRoutes: FC<{ - routes?: RouteConfig[]; - useSwitch?: boolean; - [other: string]: any; -}> = ({ routes, useSwitch = true, ...rest }) => { - if (!routes) { - return null; - } - const Parent = useSwitch ? Switch : React.Fragment; - return ( - - {routes.map((route) => ( - { - const Component = route.component; - return ; - }} - /> - ))} - - ); -}; diff --git a/x-pack/plugins/beats_management/public/components/navigation/connected_link.tsx b/x-pack/plugins/beats_management/public/components/navigation/connected_link.tsx deleted file mode 100644 index 3eb00c8714868..0000000000000 --- a/x-pack/plugins/beats_management/public/components/navigation/connected_link.tsx +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { get } from 'lodash'; -import React from 'react'; - -import { EuiLink } from '@elastic/eui'; -import { Link, withRouter, RouteComponentProps } from 'react-router-dom'; - -interface ConnectedLinkComponent extends RouteComponentProps { - location: any; - path: string; - disabled: boolean; - query: any; - [key: string]: any; -} - -export const ConnectedLinkComponent = ({ - location, - path, - query, - disabled, - children, - ...props -}: ConnectedLinkComponent) => { - if (disabled) { - return ; - } - - // Shorthand for pathname - const pathname = path || get(props.to, 'pathname') || location.pathname; - - return ( - - ); -}; - -export const ConnectedLink = withRouter(ConnectedLinkComponent); diff --git a/x-pack/plugins/beats_management/public/components/table/action_schema.ts b/x-pack/plugins/beats_management/public/components/table/action_schema.ts deleted file mode 100644 index 254188e764590..0000000000000 --- a/x-pack/plugins/beats_management/public/components/table/action_schema.ts +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { i18n } from '@kbn/i18n'; -import { AssignmentActionType } from './table'; - -export enum ActionComponentType { - Action, - Popover, - SelectionCount, - TagBadgeList, -} -export interface ControlSchema { - id?: number; - name: string; - danger?: boolean; - type: ActionComponentType; - action?: AssignmentActionType; - actionDataKey?: string; - showWarning?: boolean; - warningHeading?: string; - warningMessage?: string; - lazyLoad?: boolean; - grow?: boolean; -} - -export const beatsListActions: ControlSchema[] = [ - { - grow: false, - name: i18n.translate('xpack.beatsManagement.beatsListAssignmentOptions.unenrollButtonLabel', { - defaultMessage: 'Unenroll selected', - }), - showWarning: true, - type: ActionComponentType.Action, - warningHeading: i18n.translate( - 'xpack.beatsManagement.beatsListAssignmentOptions.unenrollBeatsWarninigTitle', - { defaultMessage: 'Unenroll selected beats?' } - ), - warningMessage: i18n.translate( - 'xpack.beatsManagement.beatsListAssignmentOptions.unenrollBeatsWarninigMessage', - { defaultMessage: 'The selected Beats will no longer use central management' } - ), - action: AssignmentActionType.Delete, - danger: true, - }, - { - name: i18n.translate('xpack.beatsManagement.beatsListAssignmentOptions.setTagsButtonLabel', { - defaultMessage: 'Set tags', - }), - grow: false, - type: ActionComponentType.TagBadgeList, - actionDataKey: 'tags', - lazyLoad: true, - }, -]; - -export const tagListActions: ControlSchema[] = [ - { - danger: true, - grow: false, - name: i18n.translate('xpack.beatsManagement.tagListAssignmentOptions.removeTagsButtonLabel', { - defaultMessage: 'Remove selected', - }), - type: ActionComponentType.Action, - showWarning: true, - warningHeading: i18n.translate( - 'xpack.beatsManagement.tagListAssignmentOptions.removeTagsWarninigTitle', - { defaultMessage: 'Remove tag(s)' } - ), - warningMessage: i18n.translate( - 'xpack.beatsManagement.tagListAssignmentOptions.removeTagWarninigMessage', - { defaultMessage: 'Remove the tag?' } - ), - action: AssignmentActionType.Delete, - }, -]; - -export const tagConfigActions: ControlSchema[] = [ - { - danger: true, - grow: false, - name: i18n.translate('xpack.beatsManagement.tagConfigAssignmentOptions.removeTagsButtonLabel', { - defaultMessage: 'Remove tag(s)', - }), - type: ActionComponentType.Action, - showWarning: true, - warningHeading: i18n.translate( - 'xpack.beatsManagement.tagConfigAssignmentOptions.removeTagsWarninigTitle', - { defaultMessage: 'Remove tag(s)' } - ), - warningMessage: i18n.translate( - 'xpack.beatsManagement.tagConfigAssignmentOptions.removeTagsWarninigMessage', - { defaultMessage: 'Remove the tag from the selected beat(s)?' } - ), - action: AssignmentActionType.Delete, - }, -]; 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 deleted file mode 100644 index 5badef9a71fe1..0000000000000 --- a/x-pack/plugins/beats_management/public/components/table/controls/action_control.tsx +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { EuiButton, EuiConfirmModal } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n/react'; -import React from 'react'; -import { AssignmentActionType } from '../table'; - -interface ActionControlProps { - action: AssignmentActionType; - disabled: boolean; - danger?: boolean; - name: string; - showWarning?: boolean; - warningHeading?: string; - warningMessage?: string; - actionHandler(action: AssignmentActionType, payload?: any): void; -} - -interface ActionControlState { - showModal: boolean; -} - -export class ActionControl extends React.PureComponent { - constructor(props: ActionControlProps) { - super(props); - - this.state = { - showModal: false, - }; - } - - public render() { - const { - action, - actionHandler, - danger, - name, - showWarning, - warningHeading, - warningMessage, - } = this.props; - - return ( -
- this.setState({ showModal: true }) : () => actionHandler(action) - } - > - {name} - - {this.state.showModal && ( - - } - confirmButtonText={ - - } - onConfirm={() => { - actionHandler(action); - this.setState({ showModal: false }); - }} - onCancel={() => this.setState({ showModal: false })} - title={ - warningHeading ? ( - warningHeading - ) : ( - - ) - } - > - {warningMessage} - - )} -
- ); - } -} diff --git a/x-pack/plugins/beats_management/public/components/table/controls/index.ts b/x-pack/plugins/beats_management/public/components/table/controls/index.ts deleted file mode 100644 index 72cbc7fcb23fd..0000000000000 --- a/x-pack/plugins/beats_management/public/components/table/controls/index.ts +++ /dev/null @@ -1,8 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export { OptionControl } from './option_control'; diff --git a/x-pack/plugins/beats_management/public/components/table/controls/option_control.tsx b/x-pack/plugins/beats_management/public/components/table/controls/option_control.tsx deleted file mode 100644 index f07c84f584d91..0000000000000 --- a/x-pack/plugins/beats_management/public/components/table/controls/option_control.tsx +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import { ActionComponentType, ControlSchema } from '../action_schema'; -import { AssignmentActionType } from '../table'; -import { ActionControl } from './action_control'; -import { TagBadgeList } from './tag_badge_list'; - -interface ComponentProps extends ControlSchema { - actionData?: { - [key: string]: any; - }; - disabled: boolean; - actionHandler(action: AssignmentActionType, payload?: any): void; -} - -export const OptionControl: React.FC = (props: ComponentProps) => { - switch (props.type) { - case ActionComponentType.Action: - if (!props.action) { - throw Error('Action cannot be undefined'); - } - return ( - - ); - case ActionComponentType.TagBadgeList: - if (!props.actionDataKey) { - throw Error('actionDataKey cannot be undefined'); - } - if (!props.actionData) { - throw Error('actionData cannot be undefined'); - } - return ( - - ); - } - return
Invalid config
; -}; diff --git a/x-pack/plugins/beats_management/public/components/table/controls/tag_badge_list.tsx b/x-pack/plugins/beats_management/public/components/table/controls/tag_badge_list.tsx deleted file mode 100644 index 15cc3f3fce577..0000000000000 --- a/x-pack/plugins/beats_management/public/components/table/controls/tag_badge_list.tsx +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { - EuiButton, - EuiContextMenuPanel, - EuiFlexGroup, - EuiFlexItem, - EuiLoadingSpinner, - EuiPopover, -} from '@elastic/eui'; -import React from 'react'; -import { TABLE_CONFIG } from '../../../../common/constants/table'; -import { TagBadge } from '../../tag/tag_badge'; -import { AssignmentActionType } from '../index'; - -interface TagBadgeListProps { - items: object[]; - disabled: boolean; - name: string; - action?: AssignmentActionType; - actionHandler(action: AssignmentActionType, payload?: any): void; -} - -interface ComponentState { - isPopoverOpen: boolean; - items: object[]; -} - -export class TagBadgeList extends React.Component { - constructor(props: TagBadgeListProps) { - super(props); - - this.state = { - isPopoverOpen: false, - items: [], - }; - } - - public render() { - const button = ( - - {this.props.name} - - ); - - return ( - - - - {!this.props.items && } - {this.props.items && this.props.items.length === 0 && ( - - - No options avaliable - - - )} - {this.props.items && - this.props.items.map((tag: any) => ( - - - - - this.props.actionHandler(AssignmentActionType.Assign, tag.id) - } - onClickAriaLabel={tag.id} - tag={tag} - /> - - - - ))} - - - - ); - } - private onButtonClick = async () => { - this.props.actionHandler(AssignmentActionType.Reload); - this.setState((prevState) => ({ - isPopoverOpen: !prevState.isPopoverOpen, - })); - }; - - private closePopover = () => { - this.setState({ - isPopoverOpen: false, - }); - }; -} diff --git a/x-pack/plugins/beats_management/public/components/table/index.ts b/x-pack/plugins/beats_management/public/components/table/index.ts deleted file mode 100644 index bc6590c2e5c21..0000000000000 --- a/x-pack/plugins/beats_management/public/components/table/index.ts +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export { beatsListActions, tagConfigActions } from './action_schema'; -export { AssignmentActionType, KueryBarProps, Table } from './table'; -export { - ActionDefinition, - BeatDetailTagsTable, - BeatsTableType, - FilterDefinition, - TagsTableType, -} from './table_type_configs'; diff --git a/x-pack/plugins/beats_management/public/components/table/table.tsx b/x-pack/plugins/beats_management/public/components/table/table.tsx deleted file mode 100644 index f22799c8b55b7..0000000000000 --- a/x-pack/plugins/beats_management/public/components/table/table.tsx +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { EuiBasicTable, EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import React from 'react'; -import styled from 'styled-components'; -import { QuerySuggestion } from '../../../../../../src/plugins/data/public'; -import { TABLE_CONFIG } from '../../../common/constants'; -import { AutocompleteField } from '../autocomplete_field/index'; -import { ControlSchema } from './action_schema'; -import { OptionControl } from './controls/option_control'; -import { TableType } from './table_type_configs'; - -export enum AssignmentActionType { - Add, - Assign, - Delete, - Edit, - Reload, - Search, -} - -export interface KueryBarProps { - filterQueryDraft: string; - isLoadingSuggestions: boolean; - isValid: boolean; - loadSuggestions: (value: string, cursorPosition: number, maxCount?: number) => void; - onChange?: (value: string) => void; - onSubmit?: (value: string) => void; - suggestions: QuerySuggestion[]; - value: string; -} - -interface TableProps { - actions?: ControlSchema[]; - actionData?: { - [key: string]: any; - }; - hideTableControls?: boolean; - kueryBarProps?: KueryBarProps; - items: any[]; - onTableChange?: (index: number, size: number) => void; - type: TableType; - actionHandler?(action: AssignmentActionType, payload?: any): void; -} - -interface TableState { - selection: any[]; - pageIndex: number; -} - -const TableContainer = styled.div` - padding: 16px; -`; - -export class Table extends React.Component { - constructor(props: any) { - super(props); - - this.state = { - selection: [], - pageIndex: 0, - }; - } - - public resetSelection = () => { - this.setSelection([]); - }; - - public setSelection = (selection: any[]) => { - this.setState({ - selection, - }); - }; - - public actionHandler = (action: AssignmentActionType, payload?: any): void => { - if (this.props.actionHandler) { - this.props.actionHandler(action, payload); - } - }; - - public render() { - const { actionData, actions, hideTableControls, items, kueryBarProps, type } = this.props; - - const pagination = { - pageIndex: this.state.pageIndex, - pageSize: TABLE_CONFIG.INITIAL_ROW_SIZE, - pageSizeOptions: TABLE_CONFIG.PAGE_SIZE_OPTIONS, - }; - - const selectionOptions = hideTableControls - ? undefined - : { - onSelectionChange: this.setSelection, - selectable: () => true, - selectableMessage: () => - i18n.translate('xpack.beatsManagement.table.selectThisBeatTooltip', { - defaultMessage: 'Select this beat', - }), - selection: this.state.selection, - }; - - return ( - - - {actions && - actions.map((action) => ( - - - - ))} - - {kueryBarProps && ( - - - - )} - - - - - - ); - } - - private onTableChange = ({ page }: { page: { index: number; size: number } }) => { - if (this.props.onTableChange) { - this.props.onTableChange(page.index, page.size); - } - this.setState({ - pageIndex: page.index, - }); - }; -} diff --git a/x-pack/plugins/beats_management/public/components/table/table_type_configs.tsx b/x-pack/plugins/beats_management/public/components/table/table_type_configs.tsx deleted file mode 100644 index 56cf99b01e8d9..0000000000000 --- a/x-pack/plugins/beats_management/public/components/table/table_type_configs.tsx +++ /dev/null @@ -1,345 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { EuiFlexGroup, EuiFlexItem, EuiHealth, EuiToolTip, IconColor } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import { sortBy, uniqBy } from 'lodash'; -import moment from 'moment'; -import React from 'react'; -import { BeatTag, CMBeat } from '../../../common/domain_types'; -import { ConnectedLink } from '../navigation/connected_link'; -import { TagBadge } from '../tag'; - -export interface ColumnDefinition { - align?: 'left' | 'right' | 'center' | undefined; - field: string; - name: string; - sortable?: boolean; - width?: string; - render?(value: any, object?: any): any; -} - -export interface ActionDefinition { - action: string; - danger?: boolean; - icon?: any; - name: string; -} - -interface FilterOption { - value: string; -} - -export interface FilterDefinition { - field: string; - name: string; - options?: FilterOption[]; - type: string; -} - -export interface ControlDefinitions { - actions: ActionDefinition[]; - filters: FilterDefinition[]; - primaryActions?: ActionDefinition[]; -} - -export interface TableType { - itemType: 'Beats' | 'Tags'; - columnDefinitions: ColumnDefinition[]; - controlDefinitions(items: any[]): ControlDefinitions; -} - -const dynamicStatuses = { - STARTING: { - color: 'success', - status: i18n.translate('xpack.beatsManagement.beatsTable.startingStatusLabel', { - defaultMessage: 'Starting', - }), - details: i18n.translate('xpack.beatsManagement.beatsTable.configStatus.startingTooltip', { - defaultMessage: 'This Beat is starting.', - }), - }, - IN_PROGRESS: { - color: 'warning', - status: i18n.translate('xpack.beatsManagement.beatsTable.updatingStatusLabel', { - defaultMessage: 'Updating', - }), - details: i18n.translate('xpack.beatsManagement.beatsTable.configStatus.progressTooltip', { - defaultMessage: 'This Beat is currently reloading config from CM.', - }), - }, - RUNNING: { - color: 'success', - status: i18n.translate('xpack.beatsManagement.beatsTable.runningStatusLabel', { - defaultMessage: 'Running', - }), - details: i18n.translate('xpack.beatsManagement.beatsTable.configStatus.runningTooltip', { - defaultMessage: 'This Beat is running without issues.', - }), - }, - CONFIG: { - color: 'danger', - status: i18n.translate('xpack.beatsManagement.beatsTable.configErrorStatusLabel', { - defaultMessage: 'Config error', - }), - }, - FAILED: { - color: 'danger', - status: i18n.translate('xpack.beatsManagement.beatsTable.failedStatusLabel', { - defaultMessage: 'Error', - }), - details: i18n.translate('xpack.beatsManagement.beatsTable.configStatus.errorTooltip', { - defaultMessage: 'There is an error on this beat, please check the logs for this host.', - }), - }, - STOPPED: { - color: 'danger', - status: i18n.translate('xpack.beatsManagement.beatsTable.stoppedStatusLabel', { - defaultMessage: 'stopped', - }), - details: i18n.translate('xpack.beatsManagement.beatsTable.configStatus.errorTooltip', { - defaultMessage: 'There is an error on this beat, please check the logs for this host.', - }), - }, -}; - -export const BeatsTableType: TableType = { - itemType: 'Beats', - columnDefinitions: [ - { - field: 'name', - name: i18n.translate('xpack.beatsManagement.beatsTable.beatNameTitle', { - defaultMessage: 'Beat name', - }), - render: (name: string, beat: CMBeat) => ( - {name} - ), - sortable: true, - }, - { - field: 'type', - name: i18n.translate('xpack.beatsManagement.beatsTable.typeTitle', { - defaultMessage: 'Type', - }), - sortable: true, - }, - { - field: 'full_tags', - name: i18n.translate('xpack.beatsManagement.beatsTable.tagsTitle', { - defaultMessage: 'Tags', - }), - render: (value: string, beat: CMBeat & { tags: BeatTag[] }) => ( - - {(sortBy(beat.tags, 'id') || []).map((tag) => ( - - - - - - ))} - - ), - sortable: false, - }, - { - field: 'config_status', - name: i18n.translate('xpack.beatsManagement.beatsTable.configStatusTitle', { - defaultMessage: 'Config Status', - }), - render: (value: string, beat: CMBeat) => { - let color: IconColor = 'success'; - let statusText = i18n.translate('xpack.beatsManagement.beatsTable.configStatus.okLabel', { - defaultMessage: 'OK', - }); - let tooltipText = i18n.translate( - 'xpack.beatsManagement.beatsTable.configStatus.okTooltip', - { - defaultMessage: 'Beat successfully applied latest config', - } - ); - - if (beat.status && moment().diff(beat.last_checkin, 'minutes') < 10) { - color = dynamicStatuses[beat.status.event.type].color; - statusText = dynamicStatuses[beat.status.event.type].status; - tooltipText = - (dynamicStatuses[beat.status.event.type] as any).details || beat.status.event.message; - } else if (!beat.status && moment().diff(beat.last_checkin, 'minutes') >= 10) { - color = 'danger'; - statusText = i18n.translate( - 'xpack.beatsManagement.beatsTable.configStatus.offlineLabel', - { - defaultMessage: 'Offline', - } - ); - tooltipText = i18n.translate( - 'xpack.beatsManagement.beatsTable.configStatus.noConnectionTooltip', - { - defaultMessage: 'This Beat has not connected to kibana in over 10min', - } - ); - } else if (beat.status && moment().diff(beat.last_checkin, 'minutes') >= 10) { - color = 'subdued'; - - tooltipText = i18n.translate( - 'xpack.beatsManagement.beatsTable.configStatus.notStartedTooltip', - { - defaultMessage: 'This Beat has not yet been started.', - } - ); - statusText = i18n.translate( - 'xpack.beatsManagement.beatsTable.configStatus.notStartedLabel', - { - defaultMessage: 'Not started', - } - ); - } else { - color = 'subdued'; - statusText = i18n.translate( - 'xpack.beatsManagement.beatsTable.configStatus.offlineLabel', - { - defaultMessage: 'Offline', - } - ); - } - - return ( - - - {statusText} - - - ); - }, - sortable: false, - }, - // { - // field: 'full_tags', - // name: i18n.translate('xpack.beatsManagement.beatsTable.lastConfigUpdateTitle', { - // defaultMessage: 'Last config update', - // }), - // render: (tags?: BeatTag[]) => - // tags && tags.length ? ( - // - // {moment(first(orderBy(tags, ['last_updated'], ['desc'])).last_updated).fromNow()} - // - // ) : null, - // sortable: true, - // }, - ], - controlDefinitions: (data: any[]) => ({ - actions: [ - { - name: i18n.translate('xpack.beatsManagement.beatsTable.disenrollSelectedLabel', { - defaultMessage: 'Unenroll Selected', - }), - action: 'delete', - danger: true, - }, - ], - filters: [ - { - type: 'field_value_selection', - field: 'type', - name: i18n.translate('xpack.beatsManagement.beatsTable.typeLabel', { - defaultMessage: 'Type', - }), - options: uniqBy( - data.map(({ type }: { type: any }) => ({ value: type })), - 'value' - ), - }, - ], - }), -}; - -export const TagsTableType: TableType = { - itemType: 'Tags', - columnDefinitions: [ - { - field: 'id', - name: i18n.translate('xpack.beatsManagement.tagsTable.tagNameTitle', { - defaultMessage: 'Tag name', - }), - render: (id: string, tag: BeatTag) => ( - - - - ), - sortable: true, - width: '45%', - }, - { - align: 'right', - field: 'last_updated', - name: i18n.translate('xpack.beatsManagement.tagsTable.lastUpdateTitle', { - defaultMessage: 'Last update', - }), - render: (lastUpdate: Date) =>
{moment(lastUpdate).fromNow()}
, - sortable: true, - }, - ], - controlDefinitions: (data: any) => ({ - actions: [ - { - name: i18n.translate('xpack.beatsManagement.tagsTable.removeSelectedLabel', { - defaultMessage: 'Remove Selected', - }), - action: 'delete', - danger: true, - }, - ], - filters: [], - }), -}; - -export const BeatDetailTagsTable: TableType = { - itemType: 'Tags', - columnDefinitions: [ - { - field: 'id', - name: i18n.translate('xpack.beatsManagement.beatTagsTable.tagNameTitle', { - defaultMessage: 'Tag name', - }), - render: (id: string, tag: BeatTag) => ( - - - - ), - sortable: true, - width: '55%', - }, - { - align: 'right', - field: 'last_updated', - name: i18n.translate('xpack.beatsManagement.beatTagsTable.lastUpdateTitle', { - defaultMessage: 'Last update', - }), - render: (lastUpdate: string) => {moment(lastUpdate).fromNow()}, - sortable: true, - }, - ], - controlDefinitions: (data: any) => ({ - actions: [], - filters: [], - primaryActions: [ - { - name: i18n.translate('xpack.beatsManagement.beatTagsTable.addTagLabel', { - defaultMessage: 'Add Tag', - }), - action: 'add', - danger: false, - }, - { - name: i18n.translate('xpack.beatsManagement.beatTagsTable.removeSelectedLabel', { - defaultMessage: 'Remove Selected', - }), - action: 'remove', - danger: true, - }, - ], - }), -}; diff --git a/x-pack/plugins/beats_management/public/components/tag/config_view/config_form.tsx b/x-pack/plugins/beats_management/public/components/tag/config_view/config_form.tsx deleted file mode 100644 index a3512a395570f..0000000000000 --- a/x-pack/plugins/beats_management/public/components/tag/config_view/config_form.tsx +++ /dev/null @@ -1,216 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -// @ts-ignore -import { i18n } from '@kbn/i18n'; -import Formsy from 'formsy-react'; -import { get } from 'lodash'; -import React from 'react'; -import { ConfigBlockSchema, ConfigurationBlock } from '../../../../common/domain_types'; -import { - FormsyEuiCodeEditor, - FormsyEuiFieldText, - FormsyEuiMultiFieldText, - FormsyEuiPasswordText, - FormsyEuiSelect, -} from '../../inputs'; - -interface ComponentProps { - values: ConfigurationBlock; - schema: ConfigBlockSchema; - id: string; - onSubmit?: (modal: any) => any; - canSubmit(canIt: boolean): any; -} - -interface ComponentState { - canSubmit: boolean; -} - -class ConfigFormUi extends React.Component { - private form = React.createRef(); - constructor(props: ComponentProps) { - super(props); - - this.state = { - canSubmit: false, - }; - } - - public enableButton = () => { - this.setState({ - canSubmit: true, - }); - this.props.canSubmit(true); - }; - public disableButton = () => { - this.setState({ - canSubmit: false, - }); - this.props.canSubmit(false); - }; - public submit = () => { - if (this.form.current && this.props.onSubmit) { - this.form.current.click(); - } - }; - public onValidSubmit = (model: ModelType) => { - if (!this.props.onSubmit) { - return; - } - - this.props.onSubmit(model); - }; - public render() { - return ( -
-
- - {this.props.schema.configs.map((schema) => { - switch (schema.ui.type) { - case 'input': - return ( - - ); - case 'password': - return ( - - ); - case 'multi-input': - return ( - - ); - case 'select': - return ( - - ); - case 'code': - return ( - - ); - } - })} - {this.props.schema && ( - - )} - {this.props.onSubmit && ( -
- ); - } -} -export const ConfigForm = ConfigFormUi; diff --git a/x-pack/plugins/beats_management/public/components/tag/config_view/index.tsx b/x-pack/plugins/beats_management/public/components/tag/config_view/index.tsx deleted file mode 100644 index 601d517e95e9e..0000000000000 --- a/x-pack/plugins/beats_management/public/components/tag/config_view/index.tsx +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { - EuiButton, - EuiButtonEmpty, - EuiFieldText, - EuiFlexGroup, - EuiFlexItem, - EuiFlyout, - EuiFlyoutBody, - EuiFlyoutFooter, - EuiFlyoutHeader, - EuiFormRow, - EuiHorizontalRule, - EuiSelect, - EuiSpacer, - EuiTitle, -} from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import React from 'react'; -import { configBlockSchemas } from '../../../../common/config_schemas'; -import { translateConfigSchema } from '../../../../common/config_schemas_translations_map'; -import { ConfigurationBlock } from '../../../../common/domain_types'; -import { ConfigForm } from './config_form'; - -interface ComponentProps { - configBlock?: ConfigurationBlock; - onClose(): any; - onSave?(config: ConfigurationBlock): any; -} - -interface ComponentState { - valid: boolean; - configBlock: ConfigurationBlock; -} - -class ConfigViewUi extends React.Component { - private form = React.createRef(); - private editMode: boolean; - private schema = translateConfigSchema(configBlockSchemas); - constructor(props: any) { - super(props); - this.editMode = props.configBlock !== undefined; - - this.state = { - valid: false, - configBlock: props.configBlock || { - type: this.schema[0].id, - }, - }; - } - public onValueChange = (field: string) => (e: any) => { - const value = e.currentTarget ? e.currentTarget.value : e; - this.setState((state: any) => ({ - configBlock: { - ...state.configBlock, - [field]: value, - }, - })); - }; - public render() { - const thisConfigSchema = this.schema.find((s) => this.state.configBlock.type === s.id); - - if (!thisConfigSchema) { - return i18n.translate('xpack.beatsManagement.tagConfig.invalidSchema', { - defaultMessage: - 'Error: This config is invalid, it is not supported by Beats and should be removed', - }); - } - return ( - - - -

- {this.editMode - ? this.props.onSave - ? i18n.translate('xpack.beatsManagement.tagConfig.editConfigurationTitle', { - defaultMessage: 'Edit configuration block', - }) - : i18n.translate('xpack.beatsManagement.tagConfig.viewConfigurationTitle"', { - defaultMessage: 'View configuration block', - }) - : i18n.translate('xpack.beatsManagement.tagConfig.addConfigurationTitle"', { - defaultMessage: 'Add configuration block', - })} -

-
-
- - - ({ value: s.id, text: s.name }))} - value={this.state.configBlock.type} - disabled={this.editMode} - onChange={this.onValueChange('type')} - /> - - - - - -

- {i18n.translate('xpack.beatsManagement.tagConfig.configurationTypeText', { - defaultMessage: '{configType} configuration', - values: { - configType: thisConfigSchema ? thisConfigSchema.name : 'Unknown', - }, - })} -

- - - { - if (this.props.onSave) { - this.props.onSave({ - ...this.state.configBlock, - config: data, - }); - } - this.props.onClose(); - } - : undefined - } - canSubmit={(canIt) => this.setState({ valid: canIt })} - ref={this.form} - values={this.state.configBlock} - id={thisConfigSchema ? thisConfigSchema.name : 'Undefined'} - schema={thisConfigSchema} - /> -
- - - - - {i18n.translate('xpack.beatsManagement.tagConfig.closeButtonLabel', { - defaultMessage: 'Close', - })} - - - {this.props.onSave && ( - - { - if (this.form.current) { - this.form.current.submit(); - } - }} - > - {i18n.translate('xpack.beatsManagement.tagConfig.saveButtonLabel', { - defaultMessage: 'Save', - })} - - - )} - - -
- ); - } -} - -export const ConfigView = ConfigViewUi; diff --git a/x-pack/plugins/beats_management/public/components/tag/index.ts b/x-pack/plugins/beats_management/public/components/tag/index.ts deleted file mode 100644 index 9bf533537a3b5..0000000000000 --- a/x-pack/plugins/beats_management/public/components/tag/index.ts +++ /dev/null @@ -1,9 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export { TagBadge } from './tag_badge'; -export { TagEdit } from './tag_edit'; diff --git a/x-pack/plugins/beats_management/public/components/tag/tag_badge.tsx b/x-pack/plugins/beats_management/public/components/tag/tag_badge.tsx deleted file mode 100644 index 0940b9c4fbdf9..0000000000000 --- a/x-pack/plugins/beats_management/public/components/tag/tag_badge.tsx +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { EuiBadge, EuiBadgeProps } from '@elastic/eui'; -import React from 'react'; -import { TABLE_CONFIG } from '../../../common/constants'; - -type TagBadgeProps = EuiBadgeProps & { - maxIdRenderSize?: number; - tag: { name: string; color: string; disabled?: boolean; id: string }; -}; - -export const TagBadge = (props: TagBadgeProps) => { - const { iconType, onClick, onClickAriaLabel, tag } = props; - const maxIdRenderSize = props.maxIdRenderSize || TABLE_CONFIG.TRUNCATE_TAG_LENGTH; - const idToRender = `${tag.name.substring(0, maxIdRenderSize)}${ - tag.name.length > maxIdRenderSize ? '...' : '' - }`; - - if (tag.disabled) { - return ( - - {idToRender} - - ); - } else if (onClick && onClickAriaLabel) { - return ( - } - onClickAriaLabel={onClickAriaLabel} - > - {idToRender} - - ); - } else { - return ( - - {idToRender} - - ); - } -}; diff --git a/x-pack/plugins/beats_management/public/components/tag/tag_edit.tsx b/x-pack/plugins/beats_management/public/components/tag/tag_edit.tsx deleted file mode 100644 index bbf5a8407905e..0000000000000 --- a/x-pack/plugins/beats_management/public/components/tag/tag_edit.tsx +++ /dev/null @@ -1,238 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { - EuiButton, - // @ts-ignore - EuiColorPicker, - EuiFieldText, - EuiFlexGroup, - EuiFlexItem, - // @ts-ignore - EuiForm, - EuiFormRow, - EuiHorizontalRule, - EuiSpacer, - EuiText, - EuiTitle, -} from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import { FormattedMessage } from '@kbn/i18n/react'; -import 'brace/mode/yaml'; -import 'brace/theme/github'; -import React from 'react'; -import { BeatTag, CMBeat, ConfigurationBlock } from '../../../common/domain_types'; -import { ConfigList } from '../config_list'; -import { AssignmentActionType, BeatsTableType, Table, tagConfigActions } from '../table'; -import { ConfigView } from './config_view'; -import { TagBadge } from './tag_badge'; - -interface TagEditProps { - tag: BeatTag; - configuration_blocks: { - error?: string | undefined; - list: ConfigurationBlock[]; - page: number; - total: number; - }; - onConfigListChange: (index: number, size: number) => void; - onDetachBeat?: (beatIds: string[]) => void; - onTagChange: (field: keyof BeatTag, value: string) => any; - onConfigAddOrEdit: (block: ConfigurationBlock) => any; - onConfigRemoved: (block: ConfigurationBlock) => any; - attachedBeats?: CMBeat[]; -} - -interface TagEditState { - showFlyout: boolean; - tableRef: any; - selectedConfig?: ConfigurationBlock; -} - -export class TagEdit extends React.PureComponent { - constructor(props: TagEditProps) { - super(props); - - this.state = { - showFlyout: false, - tableRef: React.createRef(), - }; - } - - public render() { - // eslint-disable-next-line @typescript-eslint/naming-convention - const { tag, attachedBeats, configuration_blocks } = this.props; - - return ( -
- - - -

- -

-
- -

- -

-
-
- -
-
- - - - } - isInvalid={!!this.getNameError(tag.name)} - error={this.getNameError(tag.name) || undefined} - > - - - - - - - -
- - - - - -

- -

-
- -

- -

-
-
- -
- { - if (action === 'delete') { - this.props.onConfigRemoved(block); - } else { - this.setState({ - showFlyout: true, - selectedConfig: block, - }); - } - }} - /> -
- { - this.setState({ showFlyout: true }); - }} - > - - -
-
-
- - {attachedBeats && ( -
- - - -

- -

-
- - - )} - {this.state.showFlyout && ( - this.setState({ showFlyout: false, selectedConfig: undefined })} - onSave={(config: ConfigurationBlock) => { - this.setState({ showFlyout: false, selectedConfig: undefined }); - this.props.onConfigAddOrEdit(config); - }} - /> - )} - - ); - } - - private getNameError = (name: string) => { - if (name && name !== '' && name.search(/^[a-zA-Z0-9-]+$/) === -1) { - return i18n.translate('xpack.beatsManagement.tag.tagName.validationErrorMessage', { - defaultMessage: 'Tag name must consist of letters, numbers, and dashes only', - }); - } else { - return false; - } - }; - - private handleAssignmentActions = (action: AssignmentActionType) => { - switch (action) { - case AssignmentActionType.Delete: - const { selection } = this.state.tableRef.current.state; - if (this.props.onDetachBeat) { - this.props.onDetachBeat(selection.map((beat: any) => beat.id)); - } - } - }; - - private updateTag = (key: keyof BeatTag, value?: any) => - value !== undefined - ? this.props.onTagChange(key, value) - : (e: any) => this.props.onTagChange(key, e.target ? e.target.value : e); -} diff --git a/x-pack/plugins/beats_management/public/containers/beats.ts b/x-pack/plugins/beats_management/public/containers/beats.ts deleted file mode 100644 index 73f77c08282e1..0000000000000 --- a/x-pack/plugins/beats_management/public/containers/beats.ts +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { Container } from 'unstated'; -import { CMBeat } from '../../common/domain_types'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import type { BeatsTagAssignment } from '../../server/lib/adapters/beats/adapter_types'; -import { FrontendLibs } from './../lib/types'; - -interface ContainerState { - list: CMBeat[]; -} - -export class BeatsContainer extends Container { - private query?: string; - constructor(private readonly libs: FrontendLibs) { - super(); - this.state = { - list: [], - }; - } - - public getBeatWithToken = async (token: string) => { - const beat = await this.libs.beats.getBeatWithToken(token); - - if (beat) { - this.setState({ - list: [beat as CMBeat, ...this.state.list], - }); - return beat as CMBeat; - } - return null; - }; - - public reload = async (kuery?: string) => { - if (kuery) { - this.query = kuery; - } else { - this.query = undefined; - } - const beats = await this.libs.beats.getAll(this.query); - - this.setState({ - list: beats, - }); - }; - - public deactivate = async (beats: CMBeat[]) => { - for (const beat of beats) { - await this.libs.beats.update(beat.id, { active: false }); - } - - // because the compile code above has a very minor race condition, we wait, - // the max race condition time is really 10ms but doing 100 to be safe - setTimeout(async () => { - await this.reload(this.query); - }, 100); - }; - - public toggleTagAssignment = async (tagId: string, beats: CMBeat[]) => { - if (beats.some((beat) => beat.tags !== undefined && beat.tags.some((id) => id === tagId))) { - await this.removeTagsFromBeats(beats, tagId); - return 'removed'; - } - await this.assignTagsToBeats(beats, tagId); - return 'added'; - }; - - public removeTagsFromBeats = async (beats: CMBeat[] | string[], tagId: string) => { - if (!beats.length) { - return false; - } - const assignments = createBeatTagAssignments(beats, tagId); - await this.libs.beats.removeTagsFromBeats(assignments); - // ES responds incorrectly when we call too soon - setTimeout(async () => { - await this.reload(this.query); - }, 150); - }; - - public assignTagsToBeats = async (beats: CMBeat[] | string[], tagId: string) => { - if (!beats.length) { - return false; - } - const assignments = createBeatTagAssignments(beats, tagId); - await this.libs.beats.assignTagsToBeats(assignments); - // ES responds incorrectly when we call too soon - setTimeout(async () => { - await this.reload(this.query); - }, 150); - }; -} - -function createBeatTagAssignments(beats: CMBeat[] | string[], tagId: string): BeatsTagAssignment[] { - if (typeof beats[0] === 'string') { - return (beats as string[]).map((id) => ({ beatId: id, tag: tagId })); - } else { - return (beats as CMBeat[]).map(({ id }) => ({ beatId: id, tag: tagId })); - } -} diff --git a/x-pack/plugins/beats_management/public/containers/tags.ts b/x-pack/plugins/beats_management/public/containers/tags.ts deleted file mode 100644 index f7b4996fc750d..0000000000000 --- a/x-pack/plugins/beats_management/public/containers/tags.ts +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { Container } from 'unstated'; -import { BeatTag } from '../../common/domain_types'; -import { FrontendLibs } from '../lib/types'; - -interface ContainerState { - list: BeatTag[]; -} - -export class TagsContainer extends Container { - private query?: string; - constructor(private readonly libs: FrontendLibs) { - super(); - this.state = { - list: [], - }; - } - public reload = async (kuery?: string) => { - if (kuery) { - this.query = kuery; - } else { - this.query = undefined; - } - - const tags = await this.libs.tags.getAll(this.query); - - this.setState({ - list: tags, - }); - }; - - public delete = async (tags: BeatTag[]) => { - const tagIds = tags.map((tag: BeatTag) => tag.id); - const success = await this.libs.tags.delete(tagIds); - if (success) { - this.setState({ - list: this.state.list.filter((tag) => tagIds.includes(tag.id)), - }); - } - return success; - }; - - public upsertTag = async (tag: BeatTag) => { - const beatTag = await this.libs.tags.upsertTag(tag); - await this.reload(); - return beatTag !== null; - }; -} diff --git a/x-pack/plugins/beats_management/public/containers/with_kuery_autocompletion.tsx b/x-pack/plugins/beats_management/public/containers/with_kuery_autocompletion.tsx deleted file mode 100644 index 5bd3a4194d4f7..0000000000000 --- a/x-pack/plugins/beats_management/public/containers/with_kuery_autocompletion.tsx +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; - -import { QuerySuggestion } from '../../../../../src/plugins/data/public'; - -import { FrontendLibs } from '../lib/types'; -import { RendererFunction } from '../utils/typed_react'; - -interface WithKueryAutocompletionLifecycleProps { - libs: FrontendLibs; - fieldPrefix?: string; - children: RendererFunction<{ - isLoadingSuggestions: boolean; - loadSuggestions: (expression: string, cursorPosition: number, maxSuggestions?: number) => void; - suggestions: QuerySuggestion[]; - }>; -} - -interface WithKueryAutocompletionLifecycleState { - // lacking cancellation support in the autocompletion api, - // this is used to keep older, slower requests from clobbering newer ones - currentRequest: { - expression: string; - cursorPosition: number; - } | null; - suggestions: QuerySuggestion[]; -} - -export class WithKueryAutocompletion extends React.Component< - WithKueryAutocompletionLifecycleProps, - WithKueryAutocompletionLifecycleState -> { - public readonly state: WithKueryAutocompletionLifecycleState = { - currentRequest: null, - suggestions: [], - }; - - public render() { - const { currentRequest, suggestions } = this.state; - - return this.props.children({ - isLoadingSuggestions: currentRequest !== null, - loadSuggestions: this.loadSuggestions, - suggestions, - }); - } - - private loadSuggestions = async ( - expression: string, - cursorPosition: number, - maxSuggestions?: number - ) => { - this.setState({ - currentRequest: { - expression, - cursorPosition, - }, - suggestions: [], - }); - let suggestions: any[] = []; - try { - suggestions = await this.props.libs.elasticsearch.getSuggestions( - expression, - cursorPosition, - this.props.fieldPrefix - ); - } catch (e) { - suggestions = []; - } - - this.setState((state) => - state.currentRequest && - state.currentRequest.expression !== expression && - state.currentRequest.cursorPosition !== cursorPosition - ? state // ignore this result, since a newer request is in flight - : { - ...state, - currentRequest: null, - suggestions: maxSuggestions ? suggestions.slice(0, maxSuggestions) : suggestions, - } - ); - }; -} diff --git a/x-pack/plugins/beats_management/public/containers/with_url_state.tsx b/x-pack/plugins/beats_management/public/containers/with_url_state.tsx deleted file mode 100644 index a72a60bf04a18..0000000000000 --- a/x-pack/plugins/beats_management/public/containers/with_url_state.tsx +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { parse, stringify } from 'query-string'; -import React from 'react'; -import { withRouter, RouteComponentProps } from 'react-router-dom'; -import { FlatObject } from '../frontend_types'; -import { RendererFunction } from '../utils/typed_react'; - -type StateCallback = (previousState: T) => T; - -export interface URLStateProps { - goTo: (path: string) => void; - setUrlState: ( - newState: - | Partial> - | StateCallback - | Promise> - ) => void; - urlState: URLState; -} -interface ComponentProps extends RouteComponentProps { - children: RendererFunction>; -} - -export class WithURLStateComponent extends React.Component< - ComponentProps -> { - private get URLState(): URLState { - // slice because parse does not account for the initial ? in the search string - return parse(decodeURIComponent(this.props.history.location.search).substring(1), { - sort: false, - }) as URLState; - } - - private historyListener: (() => void) | null = null; - - public componentWillUnmount() { - if (this.historyListener) { - this.historyListener(); - } - } - public render() { - return this.props.children({ - goTo: this.goTo, - setUrlState: this.setURLState, - urlState: this.URLState || {}, - }); - } - - private setURLState = async ( - state: - | Partial> - | StateCallback - | Promise> - ) => { - let newState; - const pastState = this.URLState; - if (typeof state === 'function') { - newState = await state(pastState); - } else { - newState = state; - } - - const search: string = stringify( - { - ...pastState, - ...newState, - }, - { sort: false } - ); - - const newLocation = { - ...this.props.history.location, - search, - }; - - this.props.history.replace(newLocation); - this.forceUpdate(); - }; - - private goTo = (path: string) => { - this.props.history.push({ - pathname: path, - search: this.props.history.location.search, - }); - }; -} -export const WithURLState = withRouter(WithURLStateComponent); - -export function withUrlState(UnwrappedComponent: React.ComponentType) { - return (origProps: OP) => ( - - {(URLProps: URLStateProps) => } - - ); -} diff --git a/x-pack/plugins/beats_management/public/frontend_types.d.ts b/x-pack/plugins/beats_management/public/frontend_types.d.ts deleted file mode 100644 index 2fa6da067d2b0..0000000000000 --- a/x-pack/plugins/beats_management/public/frontend_types.d.ts +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { RouteComponentProps } from 'react-router-dom'; -import { BeatsContainer } from './containers/beats'; -import { TagsContainer } from './containers/tags'; -import { URLStateProps } from './containers/with_url_state'; -import { FrontendLibs } from './lib/types'; - -export type FlatObject = { [Key in keyof T]: string }; - -export interface AppURLState { - beatsKBar?: string; - tagsKBar?: string; - enrollmentToken?: string; - createdTag?: string; -} - -export interface RouteConfig { - path: string; - component: React.ComponentType; - routes?: RouteConfig[]; -} - -export interface AppPageProps extends URLStateProps, RouteComponentProps { - libs: FrontendLibs; - containers: { - beats: BeatsContainer; - tags: TagsContainer; - }; - routes?: RouteConfig[]; -} diff --git a/x-pack/plugins/beats_management/public/index.ts b/x-pack/plugins/beats_management/public/index.ts deleted file mode 100644 index da124a3c50da1..0000000000000 --- a/x-pack/plugins/beats_management/public/index.ts +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { CoreSetup, Plugin, PluginInitializerContext } from '../../../../src/core/public'; - -import { ManagementSetup } from '../../../../src/plugins/management/public'; -import { SecurityPluginSetup } from '../../security/public'; -import { DataPublicPluginStart } from '../../../../src/plugins/data/public'; -import { LicensingPluginSetup } from '../../licensing/public'; - -import { bootstrap } from './bootstrap'; -import { BeatsManagementConfigType } from '../common'; - -interface SetupDeps { - management: ManagementSetup; - licensing: LicensingPluginSetup; - security?: SecurityPluginSetup; -} - -interface StartDeps { - data: DataPublicPluginStart; -} - -class BeatsManagementPlugin implements Plugin { - constructor(private readonly initContext: PluginInitializerContext) {} - - public setup(core: CoreSetup, plugins: SetupDeps) { - const config = this.initContext.config.get(); - bootstrap(core, plugins, config, this.initContext.env.packageInfo.version); - } - - public start() {} - public stop() {} -} - -export const plugin = (init: PluginInitializerContext) => new BeatsManagementPlugin(init); diff --git a/x-pack/plugins/beats_management/public/kbn_services.ts b/x-pack/plugins/beats_management/public/kbn_services.ts deleted file mode 100644 index 7c7ddef0dabc4..0000000000000 --- a/x-pack/plugins/beats_management/public/kbn_services.ts +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { CoreStart } from '../../../../src/core/public'; -import { DataPublicPluginStart } from '../../../../src/plugins/data/public'; -import { ManagementAppMountParams } from '../../../../src/plugins/management/public'; - -export const services = { - I18nContext: (null as any) as CoreStart['i18n']['Context'], - setBreadcrumbs: (null as any) as ManagementAppMountParams['setBreadcrumbs'], - dataStart: (null as any) as DataPublicPluginStart, -}; - -export const setServices = ( - core: CoreStart, - plugins: { data: DataPublicPluginStart }, - params: ManagementAppMountParams -) => { - services.I18nContext = core.i18n.Context; - services.setBreadcrumbs = params.setBreadcrumbs; - services.dataStart = plugins.data; -}; diff --git a/x-pack/plugins/beats_management/public/lib/adapters/beats/adapter_types.ts b/x-pack/plugins/beats_management/public/lib/adapters/beats/adapter_types.ts deleted file mode 100644 index da61655e2c856..0000000000000 --- a/x-pack/plugins/beats_management/public/lib/adapters/beats/adapter_types.ts +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { CMBeat } from '../../../../common/domain_types'; -import { ReturnTypeBulkAction } from '../../../../common/return_types'; - -export interface CMBeatsAdapter { - get(id: string): Promise; - update(id: string, beatData: Partial): Promise; - getBeatsWithTag(tagId: string): Promise; - getAll(ESQuery?: any): Promise; - removeTagsFromBeats(removals: BeatsTagAssignment[]): Promise; - assignTagsToBeats(assignments: BeatsTagAssignment[]): Promise; - getBeatWithToken(enrollmentToken: string): Promise; -} - -export interface BeatsTagAssignment { - beatId: string; - tag: string; - idxInRequest?: number; -} - -interface BeatsReturnedTagAssignment { - status: number | null; - result?: string; -} - -export interface CMAssignmentReturn { - assignments: BeatsReturnedTagAssignment[]; -} - -export interface BeatsRemovalReturn { - removals: BeatsReturnedTagAssignment[]; -} diff --git a/x-pack/plugins/beats_management/public/lib/adapters/beats/memory_beats_adapter.ts b/x-pack/plugins/beats_management/public/lib/adapters/beats/memory_beats_adapter.ts deleted file mode 100644 index 172635fb14f9a..0000000000000 --- a/x-pack/plugins/beats_management/public/lib/adapters/beats/memory_beats_adapter.ts +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { omit } from 'lodash'; -import { CMBeat } from '../../../../common/domain_types'; -import { ReturnTypeBulkAction } from '../../../../common/return_types'; -import { BeatsTagAssignment, CMBeatsAdapter } from './adapter_types'; - -export class MemoryBeatsAdapter implements CMBeatsAdapter { - private beatsDB: CMBeat[]; - - constructor(beatsDB: CMBeat[]) { - this.beatsDB = beatsDB; - } - - public async get(id: string) { - return this.beatsDB.find((beat) => beat.id === id) || null; - } - - public async update(id: string, beatData: Partial): Promise { - const index = this.beatsDB.findIndex((beat) => beat.id === id); - - if (index === -1) { - return false; - } - - this.beatsDB[index] = { ...this.beatsDB[index], ...beatData }; - return true; - } - - public async getAll() { - return this.beatsDB.map((beat: any) => omit(beat, ['access_token'])) as CMBeat[]; - } - public async getBeatsWithTag(tagId: string): Promise { - return this.beatsDB.map((beat: any) => omit(beat, ['access_token'])) as CMBeat[]; - } - - public async getBeatWithToken(enrollmentToken: string): Promise { - return this.beatsDB.map((beat: any) => omit(beat, ['access_token']))[0] as CMBeat | null; - } - public async removeTagsFromBeats( - removals: BeatsTagAssignment[] - ): Promise { - const beatIds = removals.map((r) => r.beatId); - - const response = this.beatsDB - .filter((beat) => beatIds.includes(beat.id)) - .map((beat) => { - const tagData = removals.find((r) => r.beatId === beat.id); - if (tagData) { - if (beat.tags) { - beat.tags = beat.tags.filter((tag) => tag !== tagData.tag); - } - } - const removalsForBeat = removals.filter((r) => r.beatId === beat.id); - if (removalsForBeat.length) { - removalsForBeat.forEach((assignment: BeatsTagAssignment) => { - if (beat.tags) { - beat.tags = beat.tags.filter((tag) => tag !== assignment.tag); - } - }); - } - return beat; - }); - - return response.map((item: CMBeat, resultIdx: number) => ({ - idxInRequest: removals[resultIdx].idxInRequest, - result: 'updated', - status: 200, - })) as any; - } - - public async assignTagsToBeats( - assignments: BeatsTagAssignment[] - ): Promise { - const beatIds = assignments.map((r) => r.beatId); - - this.beatsDB - .filter((beat) => beatIds.includes(beat.id)) - .map((beat) => { - // get tags that need to be assigned to this beat - const tags = assignments - .filter((a) => a.beatId === beat.id) - .map((t: BeatsTagAssignment) => t.tag); - - if (tags.length > 0) { - if (!beat.tags) { - beat.tags = []; - } - const nonExistingTags = tags.filter((t: string) => beat.tags && !beat.tags.includes(t)); - - if (nonExistingTags.length > 0) { - beat.tags = beat.tags.concat(nonExistingTags); - } - } - return beat; - }); - - return assignments.map((item: BeatsTagAssignment, resultIdx: number) => ({ - idxInRequest: assignments[resultIdx].idxInRequest, - result: 'updated', - status: 200, - })); - } -} diff --git a/x-pack/plugins/beats_management/public/lib/adapters/beats/rest_beats_adapter.ts b/x-pack/plugins/beats_management/public/lib/adapters/beats/rest_beats_adapter.ts deleted file mode 100644 index 489eb4d721cd3..0000000000000 --- a/x-pack/plugins/beats_management/public/lib/adapters/beats/rest_beats_adapter.ts +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { CMBeat } from '../../../../common/domain_types'; -import { - ReturnTypeBulkAction, - ReturnTypeGet, - ReturnTypeList, - ReturnTypeUpdate, -} from '../../../../common/return_types'; -import { RestAPIAdapter } from '../rest_api/adapter_types'; -import { BeatsTagAssignment, CMBeatsAdapter } from './adapter_types'; - -export class RestBeatsAdapter implements CMBeatsAdapter { - constructor(private readonly REST: RestAPIAdapter) {} - - public async get(id: string): Promise { - try { - return (await this.REST.get>(`/api/beats/agent/${id}`)).item; - } catch (e) { - return null; - } - } - - public async getBeatWithToken(enrollmentToken: string): Promise { - try { - return ( - await this.REST.get>(`/api/beats/agent/unknown/${enrollmentToken}`) - ).item; - } catch (e) { - return null; - } - } - - public async getAll(ESQuery?: string): Promise { - try { - return (await this.REST.get>('/api/beats/agents/all', { ESQuery })) - .list; - } catch (e) { - return []; - } - } - - public async getBeatsWithTag(tagId: string): Promise { - try { - return (await this.REST.get>(`/api/beats/agents/tag/${tagId}`)).list; - } catch (e) { - return []; - } - } - - public async update(id: string, beatData: Partial): Promise { - await this.REST.put>(`/api/beats/agent/${id}`, beatData); - return true; - } - - public async removeTagsFromBeats( - removals: BeatsTagAssignment[] - ): Promise { - return ( - await this.REST.post(`/api/beats/agents_tags/removals`, { - removals, - }) - ).results; - } - - public async assignTagsToBeats( - assignments: BeatsTagAssignment[] - ): Promise { - return ( - await this.REST.post(`/api/beats/agents_tags/assignments`, { - assignments, - }) - ).results; - } -} diff --git a/x-pack/plugins/beats_management/public/lib/adapters/configuration_blocks/adapter_types.ts b/x-pack/plugins/beats_management/public/lib/adapters/configuration_blocks/adapter_types.ts deleted file mode 100644 index 24921f1778b6c..0000000000000 --- a/x-pack/plugins/beats_management/public/lib/adapters/configuration_blocks/adapter_types.ts +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { ConfigurationBlock } from '../../../../common/domain_types'; -import { ReturnTypeBulkUpsert, ReturnTypeList } from '../../../../common/return_types'; - -export interface FrontendConfigBlocksAdapter { - upsert(blocks: ConfigurationBlock[]): Promise; - getForTags(tagIds: string[], page: number): Promise>; - delete(id: string): Promise; -} diff --git a/x-pack/plugins/beats_management/public/lib/adapters/configuration_blocks/memory_config_blocks_adapter.ts b/x-pack/plugins/beats_management/public/lib/adapters/configuration_blocks/memory_config_blocks_adapter.ts deleted file mode 100644 index 6b3549465e171..0000000000000 --- a/x-pack/plugins/beats_management/public/lib/adapters/configuration_blocks/memory_config_blocks_adapter.ts +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { ConfigurationBlock } from '../../../../common/domain_types'; -import { ReturnTypeBulkUpsert, ReturnTypeList } from '../../../../common/return_types'; -import { FrontendConfigBlocksAdapter } from './adapter_types'; - -export class MemoryConfigBlocksAdapter implements FrontendConfigBlocksAdapter { - constructor(private db: ConfigurationBlock[]) {} - - public async upsert(blocks: ConfigurationBlock[]): Promise { - this.db = this.db.concat(blocks); - return { - success: true, - results: blocks.map(() => ({ - success: true, - action: 'created', - })), - } as ReturnTypeBulkUpsert; - } - public async getForTags(tagIds: string[]): Promise> { - return { - success: true, - list: this.db.filter((block) => tagIds.includes(block.tag)), - page: 0, - total: this.db.filter((block) => tagIds.includes(block.tag)).length, - }; - } - public async delete(id: string): Promise { - this.db = this.db.reduce((newDB: ConfigurationBlock[], block) => { - if (block.id !== id) { - newDB.push(block); - } - return newDB; - }, []); - return !!this.db.find((block) => block.id === id); - } -} diff --git a/x-pack/plugins/beats_management/public/lib/adapters/configuration_blocks/rest_config_blocks_adapter.ts b/x-pack/plugins/beats_management/public/lib/adapters/configuration_blocks/rest_config_blocks_adapter.ts deleted file mode 100644 index 295455dfaa48d..0000000000000 --- a/x-pack/plugins/beats_management/public/lib/adapters/configuration_blocks/rest_config_blocks_adapter.ts +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { ConfigurationBlock } from '../../../../common/domain_types'; -import { - ReturnTypeBulkDelete, - ReturnTypeBulkUpsert, - ReturnTypeList, -} from '../../../../common/return_types'; -import { RestAPIAdapter } from '../rest_api/adapter_types'; -import { FrontendConfigBlocksAdapter } from './adapter_types'; - -export class RestConfigBlocksAdapter implements FrontendConfigBlocksAdapter { - constructor(private readonly REST: RestAPIAdapter) {} - - public async upsert(blocks: ConfigurationBlock[]) { - const result = await this.REST.put(`/api/beats/configurations`, blocks); - return result; - } - public async getForTags( - tagIds: string[], - page: number - ): Promise> { - return await this.REST.get>( - `/api/beats/configurations/${tagIds.join(',')}/${page}` - ); - } - public async delete(id: string): Promise { - return (await this.REST.delete(`/api/beats/configurations/${id}`)) - .success; - } -} diff --git a/x-pack/plugins/beats_management/public/lib/adapters/elasticsearch/adapter_types.ts b/x-pack/plugins/beats_management/public/lib/adapters/elasticsearch/adapter_types.ts deleted file mode 100644 index b414648a192cb..0000000000000 --- a/x-pack/plugins/beats_management/public/lib/adapters/elasticsearch/adapter_types.ts +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { QuerySuggestion } from '../../../../../../../src/plugins/data/public'; - -export interface ElasticsearchAdapter { - convertKueryToEsQuery: (kuery: string) => Promise; - getSuggestions: (kuery: string, selectionStart: any) => Promise; - isKueryValid(kuery: string): boolean; -} diff --git a/x-pack/plugins/beats_management/public/lib/adapters/elasticsearch/memory.ts b/x-pack/plugins/beats_management/public/lib/adapters/elasticsearch/memory.ts deleted file mode 100644 index e5a24f53d049e..0000000000000 --- a/x-pack/plugins/beats_management/public/lib/adapters/elasticsearch/memory.ts +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { QuerySuggestion } from '../../../../../../../src/plugins/data/public'; -import { ElasticsearchAdapter } from './adapter_types'; - -export class MemoryElasticsearchAdapter implements ElasticsearchAdapter { - constructor( - private readonly mockIsKueryValid: (kuery: string) => boolean, - private readonly mockKueryToEsQuery: (kuery: string) => string, - private readonly suggestions: QuerySuggestion[] - ) {} - - public isKueryValid(kuery: string): boolean { - return this.mockIsKueryValid(kuery); - } - public async convertKueryToEsQuery(kuery: string): Promise { - return this.mockKueryToEsQuery(kuery); - } - public async getSuggestions(kuery: string, selectionStart: any): Promise { - return this.suggestions; - } -} diff --git a/x-pack/plugins/beats_management/public/lib/adapters/elasticsearch/rest.ts b/x-pack/plugins/beats_management/public/lib/adapters/elasticsearch/rest.ts deleted file mode 100644 index 0143fc8b4a364..0000000000000 --- a/x-pack/plugins/beats_management/public/lib/adapters/elasticsearch/rest.ts +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { isEmpty } from 'lodash'; -import { ElasticsearchAdapter } from './adapter_types'; -import { QuerySuggestion, esKuery } from '../../../../../../../src/plugins/data/public'; -import { services } from '../../../kbn_services'; - -export class RestElasticsearchAdapter implements ElasticsearchAdapter { - private cachedIndexPattern: any = null; - constructor(private readonly indexPatternName: string) {} - - public isKueryValid(kuery: string): boolean { - try { - esKuery.fromKueryExpression(kuery); - } catch (err) { - return false; - } - - return true; - } - public async convertKueryToEsQuery(kuery: string): Promise { - if (!this.isKueryValid(kuery)) { - return ''; - } - const ast = esKuery.fromKueryExpression(kuery); - const indexPattern = await this.getIndexPattern(); - return JSON.stringify(esKuery.toElasticsearchQuery(ast, indexPattern)); - } - - public async getSuggestions(kuery: string, selectionStart: any): Promise { - const indexPattern = await this.getIndexPattern(); - - return ( - (await services.dataStart.autocomplete.getQuerySuggestions({ - language: 'kuery', - indexPatterns: [indexPattern], - boolFilter: [], - query: kuery || '', - selectionStart, - selectionEnd: selectionStart, - })) || [] - ); - } - - private async getIndexPattern() { - if (this.cachedIndexPattern) { - return this.cachedIndexPattern; - } - const res = await services.dataStart.indexPatterns.getFieldsForWildcard({ - pattern: this.indexPatternName, - }); - if (isEmpty(res.fields)) { - return; - } - this.cachedIndexPattern = { - fields: res.fields, - title: `${this.indexPatternName}`, - }; - return this.cachedIndexPattern; - } -} diff --git a/x-pack/plugins/beats_management/public/lib/adapters/framework/adapter_types.ts b/x-pack/plugins/beats_management/public/lib/adapters/framework/adapter_types.ts deleted file mode 100644 index c9a0e6029dada..0000000000000 --- a/x-pack/plugins/beats_management/public/lib/adapters/framework/adapter_types.ts +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -/* eslint-disable @typescript-eslint/no-empty-interface */ - -import * as t from 'io-ts'; -import { LICENSES } from '../../../../common/constants/security'; -import { RegisterManagementAppArgs } from '../../../../../../../src/plugins/management/public'; - -export interface FrameworkAdapter { - // Instance vars - info: FrameworkInfo; - version: string; - currentUser: FrameworkUser; - // Methods - waitUntilFrameworkReady(): Promise; - registerManagementUI(mount: RegisterManagementAppArgs['mount']): void; -} - -export const RuntimeFrameworkInfo = t.type({ - basePath: t.string, - license: t.type({ - type: t.keyof(Object.fromEntries(LICENSES.map((s) => [s, null])) as Record), - expired: t.boolean, - expiry_date_in_millis: t.number, - }), - security: t.type({ - enabled: t.boolean, - available: t.boolean, - }), - settings: t.type({ - encryptionKey: t.string, - enrollmentTokensTtlInSeconds: t.number, - defaultUserRoles: t.array(t.string), - }), -}); - -export interface FrameworkInfo extends t.TypeOf {} - -export const RuntimeFrameworkUser = t.interface( - { - username: t.string, - roles: t.readonlyArray(t.string), - full_name: t.union([t.null, t.string]), - email: t.union([t.null, t.string]), - enabled: t.boolean, - }, - 'FrameworkUser' -); -export interface FrameworkUser extends t.TypeOf {} diff --git a/x-pack/plugins/beats_management/public/lib/adapters/framework/kibana_framework_adapter.ts b/x-pack/plugins/beats_management/public/lib/adapters/framework/kibana_framework_adapter.ts deleted file mode 100644 index 03a9a77608498..0000000000000 --- a/x-pack/plugins/beats_management/public/lib/adapters/framework/kibana_framework_adapter.ts +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -/* eslint-disable max-classes-per-file */ -import { IScope } from 'angular'; -import { PathReporter } from 'io-ts/lib/PathReporter'; -import { isLeft } from 'fp-ts/lib/Either'; -import { first } from 'rxjs/operators'; -import { i18n } from '@kbn/i18n'; -import { MANAGEMENT_SECTION } from '../../../../common/constants'; -import { SecurityPluginSetup } from '../../../../../security/public'; -import { BufferedKibanaServiceCall, KibanaAdapterServiceRefs, KibanaUIConfig } from '../../types'; -import { - FrameworkAdapter, - FrameworkInfo, - FrameworkUser, - RuntimeFrameworkInfo, - RuntimeFrameworkUser, -} from './adapter_types'; -import { - ManagementSetup, - RegisterManagementAppArgs, -} from '../../../../../../../src/plugins/management/public'; -import { LicensingPluginSetup } from '../../../../../licensing/public'; -import { BeatsManagementConfigType } from '../../../../common'; - -export class KibanaFrameworkAdapter implements FrameworkAdapter { - public get info() { - if (this.xpackInfo) { - return this.xpackInfo; - } else { - throw new Error('framework adapter must have init called before anything else'); - } - } - - public get currentUser() { - return this.shieldUser!; - } - private xpackInfo: FrameworkInfo | null = null; - private adapterService: KibanaAdapterServiceProvider; - private shieldUser: FrameworkUser | null = null; - constructor( - private readonly PLUGIN_ID: string, - private readonly management: ManagementSetup, - private readonly getBasePath: () => string, - private readonly licensing: LicensingPluginSetup, - private readonly securitySetup: SecurityPluginSetup | undefined, - private readonly config: BeatsManagementConfigType, - public readonly version: string - ) { - this.adapterService = new KibanaAdapterServiceProvider(); - } - - public setUISettings = (key: string, value: any) => { - this.adapterService.callOrBuffer(({ config }) => { - config.set(key, value); - }); - }; - - public async waitUntilFrameworkReady(): Promise { - const license = await this.licensing.license$.pipe(first()).toPromise(); - let xpackInfoUnpacked: FrameworkInfo; - - try { - xpackInfoUnpacked = { - basePath: this.getBasePath(), - license: { - type: license.type ?? 'oss', - expired: !license.isActive, - expiry_date_in_millis: license.expiryDateInMillis ?? -1, - }, - security: { - enabled: license.getFeature('security').isEnabled, - available: license.getFeature('security').isAvailable, - }, - settings: this.config, - }; - } catch (e) { - throw new Error(`Unexpected data structure from xpackInfoService, ${JSON.stringify(e)}`); - } - - const assertData = RuntimeFrameworkInfo.decode(xpackInfoUnpacked); - if (isLeft(assertData)) { - throw new Error( - `Error parsing xpack info in ${this.PLUGIN_ID}, ${PathReporter.report(assertData)[0]}` - ); - } - this.xpackInfo = xpackInfoUnpacked; - - try { - this.shieldUser = (await this.securitySetup?.authc.getCurrentUser()) || null; - const assertUser = RuntimeFrameworkUser.decode(this.shieldUser); - - if (isLeft(assertUser)) { - throw new Error( - `Error parsing user info in ${this.PLUGIN_ID}, ${PathReporter.report(assertUser)[0]}` - ); - } - } catch (e) { - this.shieldUser = null; - } - } - - public registerManagementUI(mount: RegisterManagementAppArgs['mount']) { - const section = this.management.sections.section.ingest; - section.registerApp({ - id: MANAGEMENT_SECTION, - title: i18n.translate('xpack.beatsManagement.centralManagementLinkLabel', { - defaultMessage: 'Beats Central Management', - }), - order: 2, - mount, - }); - } -} - -class KibanaAdapterServiceProvider { - public serviceRefs: KibanaAdapterServiceRefs | null = null; - public bufferedCalls: Array> = []; - - public $get($rootScope: IScope, config: KibanaUIConfig) { - this.serviceRefs = { - config, - rootScope: $rootScope, - }; - - this.applyBufferedCalls(this.bufferedCalls); - - return this; - } - - public callOrBuffer(serviceCall: (serviceRefs: KibanaAdapterServiceRefs) => void) { - if (this.serviceRefs !== null) { - this.applyBufferedCalls([serviceCall]); - } else { - this.bufferedCalls.push(serviceCall); - } - } - - public applyBufferedCalls( - bufferedCalls: Array> - ) { - if (!this.serviceRefs) { - return; - } - - this.serviceRefs.rootScope.$apply(() => { - bufferedCalls.forEach((serviceCall) => { - if (!this.serviceRefs) { - return; - } - return serviceCall(this.serviceRefs); - }); - }); - } -} diff --git a/x-pack/plugins/beats_management/public/lib/adapters/framework/testing_framework_adapter.ts b/x-pack/plugins/beats_management/public/lib/adapters/framework/testing_framework_adapter.ts deleted file mode 100644 index 46aab987fb0a4..0000000000000 --- a/x-pack/plugins/beats_management/public/lib/adapters/framework/testing_framework_adapter.ts +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { FrameworkAdapter, FrameworkInfo, FrameworkUser } from './adapter_types'; - -export class TestingFrameworkAdapter implements FrameworkAdapter { - public get info() { - if (this.xpackInfo) { - return this.xpackInfo; - } else { - throw new Error('framework adapter must have init called before anything else'); - } - } - - public get currentUser() { - return this.shieldUser!; - } - private settings: any; - constructor( - private readonly xpackInfo: FrameworkInfo | null, - private readonly shieldUser: FrameworkUser | null, - public readonly version: string - ) {} - - // We dont really want to have this, but it's needed to conditionaly render for k7 due to - // when that data is needed. - public getUISetting(key: 'k7design'): boolean { - return this.settings[key]; - } - - public setUISettings = (key: string, value: any) => { - this.settings[key] = value; - }; - - public async waitUntilFrameworkReady(): Promise { - return; - } - - public registerManagementUI(settings: { sectionId?: string; name: string; order?: number }) { - throw new Error('not yet implamented'); - } -} diff --git a/x-pack/plugins/beats_management/public/lib/adapters/rest_api/adapter_types.ts b/x-pack/plugins/beats_management/public/lib/adapters/rest_api/adapter_types.ts deleted file mode 100644 index db79031ade7b4..0000000000000 --- a/x-pack/plugins/beats_management/public/lib/adapters/rest_api/adapter_types.ts +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { FlatObject } from '../../../frontend_types'; - -export interface RestAPIAdapter { - get(url: string, query?: FlatObject): Promise; - post(url: string, body?: { [key: string]: any }): Promise; - delete(url: string): Promise; - put(url: string, body?: any): Promise; -} diff --git a/x-pack/plugins/beats_management/public/lib/adapters/rest_api/axios_rest_api_adapter.ts b/x-pack/plugins/beats_management/public/lib/adapters/rest_api/axios_rest_api_adapter.ts deleted file mode 100644 index acf4734ed58ee..0000000000000 --- a/x-pack/plugins/beats_management/public/lib/adapters/rest_api/axios_rest_api_adapter.ts +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import axios, { AxiosInstance } from 'axios'; -import { FlatObject } from '../../../frontend_types'; -import { RestAPIAdapter } from './adapter_types'; -let globalAPI: AxiosInstance; - -export class AxiosRestAPIAdapter implements RestAPIAdapter { - constructor(private readonly xsrfToken: string, private readonly basePath: string) {} - - public async get(url: string, query?: FlatObject): Promise { - return await this.REST.get(url, query ? { params: query } : {}).then((resp) => resp.data); - } - - public async post( - url: string, - body?: { [key: string]: any } - ): Promise { - return await this.REST.post(url, body).then((resp) => resp.data); - } - - public async delete(url: string): Promise { - return await this.REST.delete(url).then((resp) => resp.data); - } - - public async put(url: string, body?: any): Promise { - return await this.REST.put(url, body).then((resp) => resp.data); - } - - private get REST() { - if (globalAPI) { - return globalAPI; - } - - globalAPI = axios.create({ - baseURL: this.basePath, - withCredentials: true, - responseType: 'json', - timeout: 30000, - headers: { - Accept: 'application/json', - credentials: 'same-origin', - 'Content-Type': 'application/json', - 'kbn-version': this.xsrfToken, - 'kbn-xsrf': this.xsrfToken, - }, - }); - // Add a request interceptor - globalAPI.interceptors.request.use( - (config) => { - // Do something before request is sent - return config; - }, - (error) => { - // Do something with request error - return Promise.reject(error); - } - ); - - // Add a response interceptor - globalAPI.interceptors.response.use( - (response) => { - // Do something with response data - return response; - }, - (error) => { - // Do something with response error - return Promise.reject(error); - } - ); - - return globalAPI; - } -} diff --git a/x-pack/plugins/beats_management/public/lib/adapters/rest_api/node_axios_api_adapter.ts b/x-pack/plugins/beats_management/public/lib/adapters/rest_api/node_axios_api_adapter.ts deleted file mode 100644 index 675f28b2edb7d..0000000000000 --- a/x-pack/plugins/beats_management/public/lib/adapters/rest_api/node_axios_api_adapter.ts +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import axios, { AxiosInstance } from 'axios'; -import fs from 'fs'; -import { join, resolve } from 'path'; -import { FlatObject } from '../../../frontend_types'; -import { RestAPIAdapter } from './adapter_types'; -const pkg = JSON.parse( - fs.readFileSync(resolve(join(__dirname, '../../../../../../../../package.json'))).toString() -); - -let globalAPI: AxiosInstance; - -export class NodeAxiosAPIAdapter implements RestAPIAdapter { - constructor( - private readonly username: string, - private readonly password: string, - private readonly basePath: string - ) {} - - public async get(url: string, query?: FlatObject): Promise { - return await this.REST.get(url, query ? { params: query } : {}).then((resp) => resp.data); - } - - public async post( - url: string, - body?: { [key: string]: any } - ): Promise { - return await this.REST.post(url, body).then((resp) => resp.data); - } - - public async delete(url: string): Promise { - return await this.REST.delete(url).then((resp) => resp.data); - } - - public async put(url: string, body?: any): Promise { - return await this.REST.put(url, body).then((resp) => resp.data); - } - - private get REST() { - if (globalAPI) { - return globalAPI; - } - - globalAPI = axios.create({ - baseURL: this.basePath, - withCredentials: true, - responseType: 'json', - timeout: 60 * 10 * 1000, // 10min - auth: { - username: this.username, - password: this.password, - }, - headers: { - 'Access-Control-Allow-Origin': '*', - Accept: 'application/json', - 'Content-Type': 'application/json', - 'kbn-version': (pkg as any).version, - 'kbn-xsrf': 'xxx', - }, - }); - // Add a request interceptor - globalAPI.interceptors.request.use( - (config) => { - // Do something before request is sent - return config; - }, - (error) => { - // Do something with request error - return Promise.reject(error); - } - ); - - // Add a response interceptor - globalAPI.interceptors.response.use( - (response) => { - // Do something with response data - return response; - }, - (error) => { - // Do something with response error - return Promise.reject(JSON.stringify(error.response.data)); - } - ); - - return globalAPI; - } -} diff --git a/x-pack/plugins/beats_management/public/lib/adapters/tags/adapter_types.ts b/x-pack/plugins/beats_management/public/lib/adapters/tags/adapter_types.ts deleted file mode 100644 index c45b354bab5d0..0000000000000 --- a/x-pack/plugins/beats_management/public/lib/adapters/tags/adapter_types.ts +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { BeatTag, CMBeat } from '../../../../common/domain_types'; - -export interface CMTagsAdapter { - getTagsWithIds(tagIds: string[]): Promise; - delete(tagIds: string[]): Promise; - getAll(ESQuery?: string): Promise; - upsertTag(tag: BeatTag): Promise; - getAssignable(beats: CMBeat[]): Promise; -} diff --git a/x-pack/plugins/beats_management/public/lib/adapters/tags/memory_tags_adapter.ts b/x-pack/plugins/beats_management/public/lib/adapters/tags/memory_tags_adapter.ts deleted file mode 100644 index bdab45c9c9d3f..0000000000000 --- a/x-pack/plugins/beats_management/public/lib/adapters/tags/memory_tags_adapter.ts +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { BeatTag, CMBeat } from '../../../../common/domain_types'; -import { CMTagsAdapter } from './adapter_types'; - -export class MemoryTagsAdapter implements CMTagsAdapter { - private tagsDB: BeatTag[] = []; - - constructor(tagsDB: BeatTag[]) { - this.tagsDB = tagsDB; - } - - public async getTagsWithIds(tagIds: string[]) { - return this.tagsDB.filter((tag) => tagIds.includes(tag.id)); - } - - public async delete(tagIds: string[]) { - this.tagsDB = this.tagsDB.filter((tag) => !tagIds.includes(tag.id)); - return true; - } - - public async getAll(ESQuery?: string) { - return this.tagsDB; - } - - public async upsertTag(tag: BeatTag) { - const existingTagIndex = this.tagsDB.findIndex((t) => t.id === tag.id); - if (existingTagIndex !== -1) { - this.tagsDB[existingTagIndex] = tag; - } else { - this.tagsDB.push(tag); - } - return tag; - } - - public async getAssignable(beats: CMBeat[]) { - return this.tagsDB; - } -} diff --git a/x-pack/plugins/beats_management/public/lib/adapters/tags/rest_tags_adapter.ts b/x-pack/plugins/beats_management/public/lib/adapters/tags/rest_tags_adapter.ts deleted file mode 100644 index 7c8e563948b22..0000000000000 --- a/x-pack/plugins/beats_management/public/lib/adapters/tags/rest_tags_adapter.ts +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { uniq } from 'lodash'; -import { BeatTag, CMBeat } from '../../../../common/domain_types'; -import { - ReturnTypeBulkDelete, - ReturnTypeBulkGet, - ReturnTypeList, - ReturnTypeUpsert, -} from '../../../../common/return_types'; -import { RestAPIAdapter } from '../rest_api/adapter_types'; -import { CMTagsAdapter } from './adapter_types'; - -export class RestTagsAdapter implements CMTagsAdapter { - constructor(private readonly REST: RestAPIAdapter) {} - - public async getTagsWithIds(tagIds: string[]): Promise { - try { - return ( - await this.REST.get>(`/api/beats/tags/${uniq(tagIds).join(',')}`) - ).items; - } catch (e) { - return []; - } - } - - public async getAll(ESQuery: string): Promise { - try { - return (await this.REST.get>(`/api/beats/tags`, { ESQuery })).list; - } catch (e) { - return []; - } - } - - public async delete(tagIds: string[]): Promise { - return ( - await this.REST.delete(`/api/beats/tags/${uniq(tagIds).join(',')}`) - ).success; - } - - public async upsertTag(tag: BeatTag): Promise { - const response = await this.REST.put>(`/api/beats/tag/${tag.id}`, { - color: tag.color, - name: tag.name, - }); - - return response.success ? tag : null; - } - - public async getAssignable(beats: CMBeat[]) { - try { - return ( - await this.REST.get>( - `/api/beats/tags/assignable/${beats.map((beat) => beat.id).join(',')}` - ) - ).items; - } catch (e) { - return []; - } - } -} diff --git a/x-pack/plugins/beats_management/public/lib/adapters/tokens/adapter_types.ts b/x-pack/plugins/beats_management/public/lib/adapters/tokens/adapter_types.ts deleted file mode 100644 index 7a5f334aee6d2..0000000000000 --- a/x-pack/plugins/beats_management/public/lib/adapters/tokens/adapter_types.ts +++ /dev/null @@ -1,10 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export interface CMTokensAdapter { - createEnrollmentTokens(numTokens?: number): Promise; -} diff --git a/x-pack/plugins/beats_management/public/lib/adapters/tokens/memory_tokens_adapter.ts b/x-pack/plugins/beats_management/public/lib/adapters/tokens/memory_tokens_adapter.ts deleted file mode 100644 index c5f871884609a..0000000000000 --- a/x-pack/plugins/beats_management/public/lib/adapters/tokens/memory_tokens_adapter.ts +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { CMTokensAdapter } from './adapter_types'; - -export class MemoryTokensAdapter implements CMTokensAdapter { - public async createEnrollmentTokens(): Promise { - return ['2jnwkrhkwuehriauhweair']; - } -} diff --git a/x-pack/plugins/beats_management/public/lib/adapters/tokens/rest_tokens_adapter.ts b/x-pack/plugins/beats_management/public/lib/adapters/tokens/rest_tokens_adapter.ts deleted file mode 100644 index cac45c6b9f674..0000000000000 --- a/x-pack/plugins/beats_management/public/lib/adapters/tokens/rest_tokens_adapter.ts +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { ReturnTypeBulkCreate } from '../../../../common/return_types'; -import { RestAPIAdapter } from '../rest_api/adapter_types'; -import { CMTokensAdapter } from './adapter_types'; - -export class RestTokensAdapter implements CMTokensAdapter { - constructor(private readonly REST: RestAPIAdapter) {} - - public async createEnrollmentTokens(numTokens: number = 1): Promise { - const results = ( - await this.REST.post>('/api/beats/enrollment_tokens', { - num_tokens: numTokens, - }) - ).results; - return results.map((result) => result.item); - } -} diff --git a/x-pack/plugins/beats_management/public/lib/beats.ts b/x-pack/plugins/beats_management/public/lib/beats.ts deleted file mode 100644 index ebe2f4125ba85..0000000000000 --- a/x-pack/plugins/beats_management/public/lib/beats.ts +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { ReturnTypeBulkAction } from '../../common/return_types'; -import { CMBeat } from '../../common/domain_types'; -import { BeatsTagAssignment, CMBeatsAdapter } from './adapters/beats/adapter_types'; -import { ElasticsearchLib } from './elasticsearch'; - -export class BeatsLib { - constructor( - private readonly adapter: CMBeatsAdapter, - private readonly elasticsearch: ElasticsearchLib - ) {} - - /** Get a single beat using it's ID for lookup */ - public async get(id: string): Promise { - const beat = await this.adapter.get(id); - return beat; - } - - /** Get a single beat using the token it was enrolled in for lookup */ - public getBeatWithToken = async (enrollmentToken: string): Promise => { - const beat = await this.adapter.getBeatWithToken(enrollmentToken); - return beat; - }; - - /** Get an array of beats that have a given tag id assigned to it */ - public getBeatsWithTag = async (tagId: string): Promise => { - const beats = await this.adapter.getBeatsWithTag(tagId); - return beats; - }; - - // FIXME: This needs to be paginated https://github.com/elastic/kibana/issues/26022 - /** Get an array of all enrolled beats. */ - public getAll = async (kuery?: string): Promise => { - let ESQuery; - if (kuery) { - ESQuery = await this.elasticsearch.convertKueryToEsQuery(kuery); - } - const beats = await this.adapter.getAll(ESQuery); - return beats; - }; - - /** Update a given beat via it's ID */ - public update = async (id: string, beatData: Partial): Promise => { - return await this.adapter.update(id, beatData); - }; - - /** unassign tags from beats using an array of tags and beats */ - public removeTagsFromBeats = async ( - removals: BeatsTagAssignment[] - ): Promise => { - return await this.adapter.removeTagsFromBeats(removals); - }; - - /** assign tags from beats using an array of tags and beats */ - public assignTagsToBeats = async ( - assignments: BeatsTagAssignment[] - ): Promise => { - return await this.adapter.assignTagsToBeats(assignments); - }; -} diff --git a/x-pack/plugins/beats_management/public/lib/compose/kibana.ts b/x-pack/plugins/beats_management/public/lib/compose/kibana.ts deleted file mode 100644 index bd562f03548c2..0000000000000 --- a/x-pack/plugins/beats_management/public/lib/compose/kibana.ts +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { camelCase } from 'lodash'; -import { configBlockSchemas } from '../../../common/config_schemas'; -import { translateConfigSchema } from '../../../common/config_schemas_translations_map'; -import { INDEX_NAMES } from '../../../common/constants/index_names'; -import { RestBeatsAdapter } from '../adapters/beats/rest_beats_adapter'; -import { RestConfigBlocksAdapter } from '../adapters/configuration_blocks/rest_config_blocks_adapter'; -import { RestElasticsearchAdapter } from '../adapters/elasticsearch/rest'; -import { KibanaFrameworkAdapter } from '../adapters/framework/kibana_framework_adapter'; -import { AxiosRestAPIAdapter } from '../adapters/rest_api/axios_rest_api_adapter'; -import { RestTagsAdapter } from '../adapters/tags/rest_tags_adapter'; -import { RestTokensAdapter } from '../adapters/tokens/rest_tokens_adapter'; -import { BeatsLib } from '../beats'; -import { ConfigBlocksLib } from '../configuration_blocks'; -import { ElasticsearchLib } from '../elasticsearch'; -import { TagsLib } from '../tags'; -import { FrontendLibs } from '../types'; -import { PLUGIN } from '../../../common/constants/plugin'; -import { FrameworkLib } from './../framework'; -import { ManagementSetup } from '../../../../../../src/plugins/management/public'; -import { SecurityPluginSetup } from '../../../../security/public'; -import { CoreSetup } from '../../../../../../src/core/public'; -import { LicensingPluginSetup } from '../../../../licensing/public'; -import { BeatsManagementConfigType } from '../../../common'; - -interface ComposeDeps { - core: CoreSetup; - management: ManagementSetup; - licensing: LicensingPluginSetup; - config: BeatsManagementConfigType; - version: string; - security?: SecurityPluginSetup; -} - -export function compose({ - core, - management, - licensing, - config, - version, - security, -}: ComposeDeps): FrontendLibs { - const api = new AxiosRestAPIAdapter(version, core.http.basePath.get()); - const esAdapter = new RestElasticsearchAdapter(INDEX_NAMES.BEATS); - const elasticsearchLib = new ElasticsearchLib(esAdapter); - const configBlocks = new ConfigBlocksLib( - new RestConfigBlocksAdapter(api), - translateConfigSchema(configBlockSchemas) - ); - const tags = new TagsLib(new RestTagsAdapter(api), elasticsearchLib); - const tokens = new RestTokensAdapter(api); - const beats = new BeatsLib(new RestBeatsAdapter(api), elasticsearchLib); - - const framework = new FrameworkLib( - new KibanaFrameworkAdapter( - camelCase(PLUGIN.ID), - management, - core.http.basePath.get, - licensing, - security, - config, - version - ) - ); - - const libs: FrontendLibs = { - framework, - elasticsearch: elasticsearchLib, - tags, - tokens, - beats, - configBlocks, - }; - return libs; -} diff --git a/x-pack/plugins/beats_management/public/lib/compose/scripts.ts b/x-pack/plugins/beats_management/public/lib/compose/scripts.ts deleted file mode 100644 index 37a1bc9ac4944..0000000000000 --- a/x-pack/plugins/beats_management/public/lib/compose/scripts.ts +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { configBlockSchemas } from '../../../common/config_schemas'; -import { translateConfigSchema } from '../../../common/config_schemas_translations_map'; -import { RestBeatsAdapter } from '../adapters/beats/rest_beats_adapter'; -import { RestConfigBlocksAdapter } from '../adapters/configuration_blocks/rest_config_blocks_adapter'; -import { MemoryElasticsearchAdapter } from '../adapters/elasticsearch/memory'; -import { TestingFrameworkAdapter } from '../adapters/framework/testing_framework_adapter'; -import { NodeAxiosAPIAdapter } from '../adapters/rest_api/node_axios_api_adapter'; -import { RestTagsAdapter } from '../adapters/tags/rest_tags_adapter'; -import { RestTokensAdapter } from '../adapters/tokens/rest_tokens_adapter'; -import { BeatsLib } from '../beats'; -import { ConfigBlocksLib } from '../configuration_blocks'; -import { ElasticsearchLib } from '../elasticsearch'; -import { FrameworkLib } from '../framework'; -import { TagsLib } from '../tags'; -import { FrontendLibs } from '../types'; - -export function compose(basePath: string): FrontendLibs { - const api = new NodeAxiosAPIAdapter('elastic', 'changeme', basePath); - const esAdapter = new MemoryElasticsearchAdapter( - () => true, - () => '', - [] - ); - const elasticsearchLib = new ElasticsearchLib(esAdapter); - const configBlocks = new ConfigBlocksLib( - new RestConfigBlocksAdapter(api), - translateConfigSchema(configBlockSchemas) - ); - const tags = new TagsLib(new RestTagsAdapter(api), elasticsearchLib); - const tokens = new RestTokensAdapter(api); - const beats = new BeatsLib(new RestBeatsAdapter(api), elasticsearchLib); - - const framework = new FrameworkLib( - new TestingFrameworkAdapter( - { - basePath, - license: { - type: 'gold', - expired: false, - expiry_date_in_millis: 34353453452345, - }, - security: { - enabled: true, - available: true, - }, - settings: { - encryptionKey: 'xpack_beats_default_encryptionKey', - enrollmentTokensTtlInSeconds: 10 * 60, // 10 minutes - defaultUserRoles: ['superuser'], - }, - }, - { - username: 'joeuser', - roles: ['beats_admin'], - enabled: true, - full_name: null, - email: null, - }, - '6.7.0' - ) - ); - - const libs: FrontendLibs = { - framework, - elasticsearch: elasticsearchLib, - tags, - tokens, - beats, - configBlocks, - }; - return libs; -} diff --git a/x-pack/plugins/beats_management/public/lib/config_blocks.test.ts b/x-pack/plugins/beats_management/public/lib/config_blocks.test.ts deleted file mode 100644 index 5fcd30e32d023..0000000000000 --- a/x-pack/plugins/beats_management/public/lib/config_blocks.test.ts +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { configBlockSchemas } from '../../common/config_schemas'; -import { translateConfigSchema } from '../../common/config_schemas_translations_map'; -import { ConfigBlocksLib } from './configuration_blocks'; -import { MemoryConfigBlocksAdapter } from './adapters/configuration_blocks/memory_config_blocks_adapter'; - -describe('Tags Client Domain Lib', () => { - let lib: ConfigBlocksLib; - - beforeEach(async () => { - lib = new ConfigBlocksLib( - new MemoryConfigBlocksAdapter([]), - translateConfigSchema(configBlockSchemas) - ); - }); - - it('should use helper function to convert users yaml in tag to config object', async () => { - const convertedBlocks = await lib.userConfigsToJson([ - { - id: 'foo', - tag: 'basic', - last_updated: parseInt(new Date().toISOString(), 10), - type: 'filebeat.inputs', - description: 'string', - config: { - paths: ['adad/adasd'], - other: "something: 'here'", - }, - }, - ]); - - expect(convertedBlocks.length).toBe(1); - expect(convertedBlocks[0]).toHaveProperty('config'); - expect(convertedBlocks[0].config).not.toHaveProperty('other'); - expect(convertedBlocks[0].config).toHaveProperty('something'); - expect(convertedBlocks[0].config.something).toBe('here'); - }); - - it('should use helper function to convert user config to json with undefined `other`', async () => { - const convertedTag = await lib.userConfigsToJson([ - { - id: 'foo', - tag: 'basic', - last_updated: parseInt(new Date().toISOString(), 10), - type: 'filebeat.inputs', - description: 'sdfsdf', - config: { - paths: ['sdfsfsdf'], - other: undefined, - }, - }, - ]); - - expect(convertedTag.length).toBe(1); - expect(convertedTag[0]).not.toHaveProperty('other'); - }); - - it('should use helper function to convert users yaml in tag to config object, where empty other leads to no other fields saved', async () => { - const convertedTag = await lib.userConfigsToJson([ - { - id: 'foo', - tag: 'basic', - last_updated: parseInt(new Date().toISOString(), 10), - type: 'filebeat.inputs', - description: 'string', - config: { - paths: ['adad/adasd'], - other: ` - sdfsdf: "foo" - `, - }, - }, - ]); - - expect(convertedTag.length).toBe(1); - expect(convertedTag[0].config).not.toHaveProperty('other'); - expect(convertedTag[0].config.sdfsdf).toBe('foo'); - }); - - it('should convert tokenized fields to JSON', async () => { - const convertedTag = await lib.userConfigsToJson([ - { - id: 'foo', - tag: 'basic', - last_updated: parseInt(new Date().toISOString(), 10), - type: 'output', - description: 'something', - config: { - _sub_type: 'console', - hosts: ['esefsfsgg', 'drgdrgdgr'], - username: '', - password: '', - }, - }, - ]); - - expect(convertedTag.length).toBe(1); - expect(convertedTag[0].config).toHaveProperty('_sub_type'); - expect(convertedTag[0].config).toHaveProperty('hosts'); - expect(convertedTag[0].config.hosts.length).toBe(2); - }); - - it('should use helper function to convert config object to users yaml', async () => { - const convertedTag = await lib.jsonConfigToUserYaml([ - { - id: 'foo', - tag: 'basic', - last_updated: parseInt(new Date().toISOString(), 10), - type: 'filebeat.inputs', - description: 'sdfsdf', - config: { - paths: ['sdfsfsdf'], - something: 'here', - }, - }, - ]); - - expect(convertedTag.length).toBe(1); - expect(convertedTag[0].config).not.toHaveProperty('something'); - expect(convertedTag[0].config).toHaveProperty('other'); - expect(convertedTag[0].config.other).toBe('something: here\n'); - }); - - it('should use helper function to convert config object to users yaml with empty `other`', async () => { - const convertedTag = await lib.jsonConfigToUserYaml([ - { - id: 'foo', - tag: 'basic', - last_updated: parseInt(new Date().toISOString(), 10), - type: 'filebeat.inputs', - description: undefined, - config: { - paths: ['sdfsfsdf'], - }, - }, - ]); - - expect(convertedTag.length).toBe(1); - expect(convertedTag[0].config).not.toHaveProperty('something'); - expect(convertedTag[0].config).toHaveProperty('other'); - expect(convertedTag[0].config.other).toBe(''); - }); -}); diff --git a/x-pack/plugins/beats_management/public/lib/configuration_blocks.ts b/x-pack/plugins/beats_management/public/lib/configuration_blocks.ts deleted file mode 100644 index 2328b353fe326..0000000000000 --- a/x-pack/plugins/beats_management/public/lib/configuration_blocks.ts +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { set } from '@elastic/safer-lodash-set'; -import { get, has, omit } from 'lodash'; -import { ConfigBlockSchema, ConfigurationBlock } from '../../common/domain_types'; -import { FrontendConfigBlocksAdapter } from './adapters/configuration_blocks/adapter_types'; - -export class ConfigBlocksLib { - public delete = this.adapter.delete.bind(this.adapter); - - constructor( - private readonly adapter: FrontendConfigBlocksAdapter, - private readonly configSchemas: ConfigBlockSchema[] - ) {} - - public upsert = async (blocks: ConfigurationBlock[]) => { - return await this.adapter.upsert(await this.userConfigsToJson(blocks)); - }; - - public getForTags = async (tagIds: string[], page: number) => { - const result = await this.adapter.getForTags(tagIds, page); - result.list = await this.jsonConfigToUserYaml(result.list); - return result; - }; - - public async jsonConfigToUserYaml(blocks: ConfigurationBlock[]): Promise { - const yaml = await import('js-yaml'); - // configuration_blocks yaml, JS cant read YAML so we parse it into JS, - // because beats flattens all fields, and we need more structure. - // we take tagConfigs, grab the config that applies here, render what we can into - // an object, and the rest we assume to be the yaml string that goes - // into the yaml editor... - // NOTE: The perk of this, is that as we support more features via controls - // vs yaml editing, it should "just work", and things that were in YAML - // will now be in the UI forms... - return blocks.map((block) => { - const { type, config } = block; - - const thisConfigSchema = this.configSchemas.find((conf) => conf.id === type); - const thisConfigBlockSchema = thisConfigSchema ? thisConfigSchema.configs : null; - if (!thisConfigBlockSchema) { - throw new Error('No config block schema '); - } - - const knownConfigIds: string[] = thisConfigBlockSchema.map((schema) => schema.id); - - const convertedConfig: ConfigurationBlock['config'] = knownConfigIds.reduce( - (blockObj: any, configKey: string, index: number) => { - const unhydratedKey = knownConfigIds[index]; - - set(blockObj, configKey, get(config, unhydratedKey)); - - return blockObj; - }, - thisConfigSchema && thisConfigSchema.allowOtherConfigs - ? { other: yaml.safeDump(omit(config, knownConfigIds)) } - : {} - ); - - // Workaround to empty object passed into dump resulting in this odd output - if (convertedConfig.other && convertedConfig.other === '{}\n') { - convertedConfig.other = ''; - } - - return { - ...block, - config: convertedConfig, - }; - }); - } - - public async userConfigsToJson(blocks: ConfigurationBlock[]): Promise { - const yaml = await import('js-yaml'); - // configurations is the JS representation of the config yaml, - // so here we take that JS and convert it into a YAML string. - // we do so while also flattening "other" into the flat yaml beats expect - return blocks.map((block) => { - const { type, config } = block; - const thisConfigSchema = this.configSchemas.find((conf) => conf.id === type); - const thisConfigBlockSchema = thisConfigSchema ? thisConfigSchema.configs : null; - if (!thisConfigBlockSchema) { - throw new Error('No config block schema '); - } - const knownConfigIds = thisConfigBlockSchema - .map((schema: ConfigurationBlock['config']) => schema.id) - .filter((id: string) => id !== 'other'); - - const picked = this.pickDeep(config, knownConfigIds); - let other = yaml.safeLoad(config.other || '{}'); - if (typeof other === 'string') { - other = { - [other]: '', - }; - } - - const convertedConfig = { - ...other, - ...picked, - }; - - return { - ...block, - config: convertedConfig, - }; - }); - } - - private pickDeep(obj: { [key: string]: any }, keys: string[]) { - const copy = {}; - keys.forEach((key) => { - if (has(obj, key)) { - const val = get(obj, key); - set(copy, key, val); - } - }); - return copy; - } -} diff --git a/x-pack/plugins/beats_management/public/lib/elasticsearch.ts b/x-pack/plugins/beats_management/public/lib/elasticsearch.ts deleted file mode 100644 index b64c307682f2f..0000000000000 --- a/x-pack/plugins/beats_management/public/lib/elasticsearch.ts +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { QuerySuggestion } from '../../../../../src/plugins/data/public'; -import { ElasticsearchAdapter } from './adapters/elasticsearch/adapter_types'; - -interface HiddenFields { - op: 'is' | 'startsWith' | 'withoutPrefix'; - value: string; -} - -export class ElasticsearchLib { - private readonly hiddenFields: HiddenFields[] = [ - { op: 'startsWith', value: 'enrollment_token' }, - { op: 'is', value: 'beat.active' }, - { op: 'is', value: 'beat.enrollment_token' }, - { op: 'is', value: 'beat.access_token' }, - { op: 'is', value: 'beat.ephemeral_id' }, - { op: 'is', value: 'beat.verified_on' }, - ]; - - constructor(private readonly adapter: ElasticsearchAdapter) {} - - public isKueryValid(kuery: string): boolean { - return this.adapter.isKueryValid(kuery); - } - public async convertKueryToEsQuery(kuery: string): Promise { - return await this.adapter.convertKueryToEsQuery(kuery); - } - - public async getSuggestions( - kuery: string, - selectionStart: any, - fieldPrefix?: string - ): Promise { - const suggestions = await this.adapter.getSuggestions(kuery, selectionStart); - - const filteredSuggestions = suggestions.filter((suggestion) => { - const hiddenFieldsCheck = this.hiddenFields; - - if (fieldPrefix) { - hiddenFieldsCheck.push({ - op: 'withoutPrefix', - value: `${fieldPrefix}.`, - }); - } - - return hiddenFieldsCheck.reduce((isvalid: boolean, field) => { - if (!isvalid) { - return false; - } - - switch (field.op) { - case 'startsWith': - return !suggestion.text.startsWith(field.value); - case 'is': - return suggestion.text.trim() !== field.value; - case 'withoutPrefix': - return suggestion.text.startsWith(field.value); - } - }, true); - }); - - return filteredSuggestions; - } -} diff --git a/x-pack/plugins/beats_management/public/lib/framework.ts b/x-pack/plugins/beats_management/public/lib/framework.ts deleted file mode 100644 index 94f6df20e4b4d..0000000000000 --- a/x-pack/plugins/beats_management/public/lib/framework.ts +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { difference, get } from 'lodash'; -import { LICENSES, LicenseType } from '../../common/constants/security'; -import { FrameworkAdapter } from './adapters/framework/adapter_types'; - -export class FrameworkLib { - public waitUntilFrameworkReady = this.adapter.waitUntilFrameworkReady.bind(this.adapter); - public registerManagementUI = this.adapter.registerManagementUI.bind(this.adapter); - - constructor(private readonly adapter: FrameworkAdapter) {} - - public get currentUser() { - return this.adapter.currentUser; - } - - public get info() { - return this.adapter.info; - } - - public licenseIsAtLeast(type: LicenseType) { - return ( - LICENSES.indexOf(get(this.adapter.info, 'license.type', 'oss')) >= LICENSES.indexOf(type) - ); - } - - public versionGreaterThen(version: string) { - const pa = this.adapter.version.split('.'); - const pb = version.split('.'); - for (let i = 0; i < 3; i++) { - const na = Number(pa[i]); - const nb = Number(pb[i]); - // version is greater - if (na > nb) { - return true; - } - // version is less then - if (nb > na) { - return false; - } - if (!isNaN(na) && isNaN(nb)) { - return true; - } - if (isNaN(na) && !isNaN(nb)) { - return false; - } - } - return true; - } - - public currentUserHasOneOfRoles(roles: string[]) { - // If the user has at least one of the roles requested, the returnd difference will be less - // then the orig array size. difference only compares based on the left side arg - return difference(roles, get(this.currentUser, 'roles', []) as string[]).length < roles.length; - } -} diff --git a/x-pack/plugins/beats_management/public/lib/tags.ts b/x-pack/plugins/beats_management/public/lib/tags.ts deleted file mode 100644 index 45f840be8e062..0000000000000 --- a/x-pack/plugins/beats_management/public/lib/tags.ts +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import uuidv4 from 'uuid/v4'; -import { BeatTag, CMBeat } from '../../common/domain_types'; -import { CMTagsAdapter } from './adapters/tags/adapter_types'; -import { ElasticsearchLib } from './elasticsearch'; - -export class TagsLib { - constructor( - private readonly adapter: CMTagsAdapter, - private readonly elasticsearch: ElasticsearchLib - ) {} - - public async getTagsWithIds(tagIds: string[]): Promise { - if (tagIds.length === 0) { - return []; - } - return await this.adapter.getTagsWithIds([...new Set(tagIds)]); - } - public async delete(tagIds: string[]): Promise { - return await this.adapter.delete([...new Set(tagIds)]); - } - - // FIXME: This needs to be paginated https://github.com/elastic/kibana/issues/26022 - public async getAll(kuery?: string): Promise { - let ESQuery; - if (kuery) { - ESQuery = await this.elasticsearch.convertKueryToEsQuery(kuery); - } - - return await this.adapter.getAll(ESQuery); - } - public async upsertTag(tag: BeatTag): Promise { - if (!tag.id) { - tag.id = uuidv4(); - } - return await this.adapter.upsertTag(tag); - } - - public async getassignableTagsForBeats(beats: CMBeat[]): Promise { - return await this.adapter.getAssignable(beats); - } -} diff --git a/x-pack/plugins/beats_management/public/lib/types.ts b/x-pack/plugins/beats_management/public/lib/types.ts deleted file mode 100644 index 68f09cc3e8ba4..0000000000000 --- a/x-pack/plugins/beats_management/public/lib/types.ts +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { IModule, IScope } from 'angular'; -import { AxiosRequestConfig } from 'axios'; -import { FrameworkAdapter } from './adapters/framework/adapter_types'; -import { CMTokensAdapter } from './adapters/tokens/adapter_types'; -import { BeatsLib } from './beats'; -import { ConfigBlocksLib } from './configuration_blocks'; -import { ElasticsearchLib } from './elasticsearch'; -import { FrameworkLib } from './framework'; -import { TagsLib } from './tags'; - -export interface FrontendLibs { - elasticsearch: ElasticsearchLib; - framework: FrameworkLib; - beats: BeatsLib; - tags: TagsLib; - tokens: CMTokensAdapter; - configBlocks: ConfigBlocksLib; -} - -export type FramworkAdapterConstructable = new (uiModule: IModule) => FrameworkAdapter; - -// FIXME: replace AxiosRequestConfig with something more defined -export type RequestConfig = AxiosRequestConfig; - -export interface ApiAdapter { - kbnVersion: string; - - get(url: string, config?: RequestConfig | undefined): Promise; - post(url: string, data?: any, config?: AxiosRequestConfig | undefined): Promise; - delete(url: string, config?: RequestConfig | undefined): Promise; - put(url: string, data?: any, config?: RequestConfig | undefined): Promise; -} - -export interface UiKibanaAdapterScope extends IScope { - breadcrumbs: any[]; - topNavMenu: any[]; -} - -export interface KibanaUIConfig { - get(key: string): any; - set(key: string, value: any): Promise; -} - -export interface KibanaAdapterServiceRefs { - config: KibanaUIConfig; - rootScope: IScope; -} - -export type BufferedKibanaServiceCall = (serviceRefs: ServiceRefs) => void; - -export interface Chrome { - setRootTemplate(template: string): void; -} diff --git a/x-pack/plugins/beats_management/public/pages/__404.tsx b/x-pack/plugins/beats_management/public/pages/__404.tsx deleted file mode 100644 index d5813d36e2c6d..0000000000000 --- a/x-pack/plugins/beats_management/public/pages/__404.tsx +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { FormattedMessage } from '@kbn/i18n/react'; -import React from 'react'; - -export class NotFoundPage extends React.PureComponent { - public render() { - return ( -
- -
- ); - } -} diff --git a/x-pack/plugins/beats_management/public/pages/beat/details.tsx b/x-pack/plugins/beats_management/public/pages/beat/details.tsx deleted file mode 100644 index c9b26da9349b1..0000000000000 --- a/x-pack/plugins/beats_management/public/pages/beat/details.tsx +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { - EuiFlexGroup, - EuiFlexItem, - // @ts-ignore EuiInMemoryTable typings not yet available - EuiInMemoryTable, - EuiLink, - EuiSpacer, - EuiText, - EuiTitle, - EuiBasicTableColumn, -} from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import { FormattedMessage, InjectedIntl, injectI18n } from '@kbn/i18n/react'; -import { get } from 'lodash'; -import React from 'react'; -import { configBlockSchemas } from '../../../common/config_schemas'; -import { translateConfigSchema } from '../../../common/config_schemas_translations_map'; -import { TABLE_CONFIG } from '../../../common/constants'; -import { BeatTag, CMBeat, ConfigurationBlock } from '../../../common/domain_types'; -import { Breadcrumb } from '../../components/navigation/breadcrumb'; -import { ConnectedLink } from '../../components/navigation/connected_link'; -import { TagBadge } from '../../components/tag'; -import { ConfigView } from '../../components/tag/config_view/index'; -import { AppPageProps } from '../../frontend_types'; - -interface PageProps extends AppPageProps { - beat: CMBeat; - intl: InjectedIntl; -} - -interface PageState { - selectedConfig: ConfigurationBlock | null; - tags: BeatTag[]; - configuration_blocks: ConfigurationBlock[]; - configurationBlocksPage: number; -} - -class BeatDetailPageUi extends React.PureComponent { - constructor(props: PageProps) { - super(props); - - this.state = { - selectedConfig: null, - tags: [], - configuration_blocks: [], - configurationBlocksPage: 0, - }; - } - - public async UNSAFE_componentWillMount() { - const tags = await this.props.libs.tags.getTagsWithIds(this.props.beat.tags); - const blocksResult = await this.props.libs.configBlocks.getForTags( - this.props.beat.tags, - this.state.configurationBlocksPage - ); - - this.setState({ - configuration_blocks: blocksResult.list, - tags, - }); - } - public render() { - const props = this.props; - const { beat, intl } = props; - if (!beat) { - return ( - - ); - } - const configurationBlocks = !this.state.configuration_blocks - ? [] - : this.state.configuration_blocks.map((configuration) => ({ - // @ts-ignore one of the types on ConfigurationBlock doesn't define a "module" property - module: configuration.config.type || null, - tagId: configuration.tag, - tagColor: - ((this.state.tags || []).find((tag) => tag.id === configuration.tag) || ({} as BeatTag)) - .color || 'grey', - tagName: - ((this.state.tags || []).find((tag) => tag.id === configuration.tag) || ({} as BeatTag)) - .name || configuration.tag, - ...beat, - ...configuration, - displayValue: get( - translateConfigSchema(configBlockSchemas).find( - (config) => config.id === configuration.type - ), - 'text', - null - ), - })); - - const columns: Array> = [ - { - field: 'displayValue', - name: intl.formatMessage({ - id: 'xpack.beatsManagement.beatConfigurations.typeColumnName', - defaultMessage: 'Type', - }), - sortable: true, - render: (value: string | null, configuration: any) => ( - { - this.setState({ - selectedConfig: configuration, - }); - }} - > - {value || configuration.type} - - ), - }, - { - field: 'module', - name: intl.formatMessage({ - id: 'xpack.beatsManagement.beatConfigurations.moduleColumnName', - defaultMessage: 'Module', - }), - sortable: true, - }, - { - field: 'description', - name: intl.formatMessage({ - id: 'xpack.beatsManagement.beatConfigurations.descriptionColumnName', - defaultMessage: 'Description', - }), - sortable: true, - }, - { - field: 'tagId', - name: intl.formatMessage({ - id: 'xpack.beatsManagement.beatConfigurations.tagColumnName', - defaultMessage: 'Tag', - }), - render: (id: string, block: any) => ( - - - - ), - sortable: true, - }, - ]; - return ( - - - - - - -

- -

-
- -

- -

-
-
- - - -
- {this.state.selectedConfig && ( - this.setState({ selectedConfig: null })} - /> - )} -
- ); - } -} -export const BeatDetailPage = injectI18n(BeatDetailPageUi); diff --git a/x-pack/plugins/beats_management/public/pages/beat/index.tsx b/x-pack/plugins/beats_management/public/pages/beat/index.tsx deleted file mode 100644 index 3b306d6699a44..0000000000000 --- a/x-pack/plugins/beats_management/public/pages/beat/index.tsx +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { - EuiFlexGroup, - EuiFlexItem, - // @ts-ignore - EuiTab, - // @ts-ignore - EuiTabs, - EuiText, -} from '@elastic/eui'; -import { FormattedMessage, InjectedIntl, injectI18n } from '@kbn/i18n/react'; -import moment from 'moment'; -import React from 'react'; -import { Redirect, Route, Switch } from 'react-router-dom'; -import { CMBeat } from '../../../common/domain_types'; -import { PrimaryLayout } from '../../components/layouts/primary'; -import { Breadcrumb } from '../../components/navigation/breadcrumb'; -import { ChildRoutes } from '../../components/navigation/child_routes'; -import { AppPageProps } from '../../frontend_types'; - -interface PageProps extends AppPageProps { - intl: InjectedIntl; -} -interface PageState { - beat: CMBeat | undefined; - beatId: string; - isLoading: boolean; -} - -class BeatDetailsPageComponent extends React.PureComponent { - constructor(props: PageProps) { - super(props); - this.state = { - beat: undefined, - beatId: props.match.params.beatId, - isLoading: true, - }; - this.loadBeat(); - } - - public onSelectedTabChanged = (id: string) => { - this.props.history.push({ - pathname: id, - search: this.props.location.search, - }); - }; - - public renderActionSection(beat?: CMBeat) { - return beat ? ( - - - - {beat.type} }} - /> - - - - - {beat.version} }} - /> - - - {beat.last_updated && ( - - - {moment(beat.last_updated).fromNow()}, - }} - /> - - - )} - - ) : ( - - ); - } - - public render() { - const { intl } = this.props; - const { beat } = this.state; - let id: string | undefined; - let name; - - if (beat) { - id = beat.id; - name = beat.name; - } - - const title = this.state.isLoading - ? intl.formatMessage({ - id: 'xpack.beatsManagement.beat.loadingTitle', - defaultMessage: 'Loading', - }) - : intl.formatMessage( - { - id: 'xpack.beatsManagement.beat.beatNameAndIdTitle', - defaultMessage: 'Beat: {nameOrNoName} (id: {id})', - }, - { - nameOrNoName: - name || - intl.formatHTMLMessage({ - id: 'xpack.beatsManagement.beat.noNameReceivedFromBeatTitle', - defaultMessage: 'No name received from beat', - }), - id, - } - ); - - return ( - - - - - - - - - - - - {!this.state.beat &&
Beat not found
} - {this.state.beat && ( - - - {id && } />} - - )} -
-
- ); - } - - private onTabClicked = (path: string) => { - return () => { - this.props.goTo(path); - }; - }; - - private async loadBeat() { - const { intl } = this.props; - const { beatId } = this.props.match.params; - let beat; - try { - beat = await this.props.libs.beats.get(beatId); - if (!beat) { - throw new Error( - intl.formatMessage({ - id: 'xpack.beatsManagement.beat.beatNotFoundErrorMessage', - defaultMessage: 'beat not found', - }) - ); - } - } catch (e) { - throw new Error(e); - } - this.setState({ beat, isLoading: false }); - } -} - -export const BeatDetailsPage = injectI18n(BeatDetailsPageComponent); diff --git a/x-pack/plugins/beats_management/public/pages/beat/tags.tsx b/x-pack/plugins/beats_management/public/pages/beat/tags.tsx deleted file mode 100644 index e5f7e7c3711a0..0000000000000 --- a/x-pack/plugins/beats_management/public/pages/beat/tags.tsx +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { EuiGlobalToastList } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import React from 'react'; -import { BeatTag, CMBeat } from '../../../common/domain_types'; -import { Breadcrumb } from '../../components/navigation/breadcrumb'; -import { BeatDetailTagsTable, Table } from '../../components/table'; -import { FrontendLibs } from '../../lib/types'; - -interface BeatTagsPageProps { - beat: CMBeat; - libs: FrontendLibs; - refreshBeat(): void; -} - -interface BeatTagsPageState { - notifications: any[]; - tags: BeatTag[]; -} - -export class BeatTagsPage extends React.PureComponent { - private tableRef = React.createRef
(); - constructor(props: BeatTagsPageProps) { - super(props); - - this.state = { - notifications: [], - tags: [], - }; - } - - public UNSAFE_componentWillMount() { - this.updateBeatsData(); - } - - public async updateBeatsData() { - const tags = await this.props.libs.tags.getTagsWithIds(this.props.beat.tags); - this.setState({ - tags, - }); - } - - public render() { - const { beat } = this.props; - return ( - - - -
- - this.setState({ notifications: [] })} - toastLifeTimeMs={5000} - /> - - ); - } -} diff --git a/x-pack/plugins/beats_management/public/pages/error/enforce_security.tsx b/x-pack/plugins/beats_management/public/pages/error/enforce_security.tsx deleted file mode 100644 index 2d55df7be6923..0000000000000 --- a/x-pack/plugins/beats_management/public/pages/error/enforce_security.tsx +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { FormattedMessage, injectI18n } from '@kbn/i18n/react'; -import * as React from 'react'; -import { NoDataLayout } from '../../components/layouts/no_data'; - -export const EnforceSecurityPage = injectI18n(({ intl }) => ( - -

- -

-
-)); diff --git a/x-pack/plugins/beats_management/public/pages/error/invalid_license.tsx b/x-pack/plugins/beats_management/public/pages/error/invalid_license.tsx deleted file mode 100644 index d34e3d22e4e67..0000000000000 --- a/x-pack/plugins/beats_management/public/pages/error/invalid_license.tsx +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { FormattedMessage, injectI18n } from '@kbn/i18n/react'; -import * as React from 'react'; -import { NoDataLayout } from '../../components/layouts/no_data'; - -export const InvalidLicensePage = injectI18n(({ intl }) => ( - -

- -

-
-)); diff --git a/x-pack/plugins/beats_management/public/pages/error/no_access.tsx b/x-pack/plugins/beats_management/public/pages/error/no_access.tsx deleted file mode 100644 index 2a380a64ccd89..0000000000000 --- a/x-pack/plugins/beats_management/public/pages/error/no_access.tsx +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { FormattedMessage, injectI18n } from '@kbn/i18n/react'; -import * as React from 'react'; -import { NoDataLayout } from '../../components/layouts/no_data'; - -export const NoAccessPage = injectI18n(({ intl }) => ( - -

- -

-
-)); diff --git a/x-pack/plugins/beats_management/public/pages/index.ts b/x-pack/plugins/beats_management/public/pages/index.ts deleted file mode 100644 index eafe9f9b1394f..0000000000000 --- a/x-pack/plugins/beats_management/public/pages/index.ts +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { BeatDetailPage } from './beat/details'; -import { BeatDetailsPage } from './beat/index'; -import { BeatTagsPage } from './beat/tags'; -import { EnforceSecurityPage } from './error/enforce_security'; -import { InvalidLicensePage } from './error/invalid_license'; -import { NoAccessPage } from './error/no_access'; -import { TagsPage } from './overview/configuration_tags'; -import { BeatsPage } from './overview/enrolled_beats'; -import { MainPage } from './overview/index'; -import { TagCreatePage } from './tag/create'; -import { TagEditPage } from './tag/edit'; -import { BeatsInitialEnrollmentPage } from './walkthrough/initial/beat'; -import { FinishWalkthroughPage } from './walkthrough/initial/finish'; -import { InitialWalkthroughPage } from './walkthrough/initial/index'; -import { InitialTagPage } from './walkthrough/initial/tag'; -import type { RouteConfig } from '../components/navigation/child_routes'; - -export const routeMap: RouteConfig[] = [ - { path: '/tag/create/:tagid?', component: TagCreatePage }, - { path: '/tag/edit/:tagid?', component: TagEditPage }, - { - path: '/beat/:beatId', - component: BeatDetailsPage, - routes: [ - { path: '/beat/:beatId/details', component: BeatDetailPage }, - { path: '/beat/:beatId/tags', component: BeatTagsPage }, - ], - }, - { path: '/error/enforce_security', component: EnforceSecurityPage }, - { path: '/error/invalid_license', component: InvalidLicensePage }, - { path: '/error/no_access', component: NoAccessPage }, - { - path: '/overview', - component: MainPage, - routes: [ - { path: '/overview/configuration_tags', component: TagsPage }, - { path: '/overview/enrolled_beats', component: BeatsPage }, - ], - }, - { - path: '/walkthrough/initial', - component: InitialWalkthroughPage, - routes: [ - { path: '/walkthrough/initial/beat', component: BeatsInitialEnrollmentPage }, - { path: '/walkthrough/initial/finish', component: FinishWalkthroughPage }, - { path: '/walkthrough/initial/tag', component: InitialTagPage }, - ], - }, -]; diff --git a/x-pack/plugins/beats_management/public/pages/overview/configuration_tags.tsx b/x-pack/plugins/beats_management/public/pages/overview/configuration_tags.tsx deleted file mode 100644 index 0b7c4f17a6e2c..0000000000000 --- a/x-pack/plugins/beats_management/public/pages/overview/configuration_tags.tsx +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { EuiButton } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import { FormattedMessage, InjectedIntl, injectI18n } from '@kbn/i18n/react'; -import React from 'react'; -import { Breadcrumb } from '../../components/navigation/breadcrumb'; -import { AssignmentActionType, Table, TagsTableType } from '../../components/table'; -import { tagListActions } from '../../components/table/action_schema'; -import { WithKueryAutocompletion } from '../../containers/with_kuery_autocompletion'; -import { AppPageProps } from '../../frontend_types'; - -interface PageProps extends AppPageProps { - renderAction: (area: () => JSX.Element) => void; - intl: InjectedIntl; -} - -interface PageState { - tableRef: any; -} - -class TagsPageComponent extends React.PureComponent { - constructor(props: PageProps) { - super(props); - - this.state = { - tableRef: React.createRef(), - }; - - props.containers.tags.reload(props.urlState.tagsKBar); - props.renderAction(this.renderActionArea); - } - - public renderActionArea = () => ( - { - this.props.goTo('/tag/create'); - }} - > - - - ); - - public render() { - return ( - - - - {(autocompleteProps) => ( -
{ - this.props.setUrlState({ tagsKBar: value }); - this.props.containers.tags.reload(value); - }, - onSubmit: () => null, // todo - value: this.props.urlState.tagsKBar || '', - }} - actions={tagListActions} - actionHandler={this.handleTagsAction} - ref={this.state.tableRef} - items={this.props.containers.tags.state.list} - type={TagsTableType} - /> - )} - - - ); - } - - private handleTagsAction = async (action: AssignmentActionType) => { - const { intl } = this.props; - switch (action) { - case AssignmentActionType.Delete: - const success = await this.props.containers.tags.delete(this.getSelectedTags()); - if (!success) { - alert( - intl.formatMessage({ - id: 'xpack.beatsManagement.tags.someTagsMightBeAssignedToBeatsTitle', - defaultMessage: - 'Some of these tags might be assigned to beats. Please ensure tags being removed are not activly assigned', - }) - ); - } else { - if (this.state.tableRef && this.state.tableRef.current) { - this.state.tableRef.current.resetSelection(); - } - } - break; - } - }; - - private getSelectedTags = () => { - return this.state.tableRef.current ? this.state.tableRef.current.state.selection : []; - }; -} - -export const TagsPage = injectI18n(TagsPageComponent); 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 deleted file mode 100644 index 0ab02430e90e6..0000000000000 --- a/x-pack/plugins/beats_management/public/pages/overview/enrolled_beats.tsx +++ /dev/null @@ -1,355 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { - EuiButton, - EuiButtonEmpty, - EuiGlobalToastList, - EuiModal, - EuiModalBody, - EuiModalHeader, - EuiModalHeaderTitle, -} from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import { FormattedMessage, InjectedIntl, injectI18n } from '@kbn/i18n/react'; -import { flatten, sortBy } from 'lodash'; -import moment from 'moment'; -import React from 'react'; -import { BeatTag, CMBeat } from '../../../common/domain_types'; -import { EnrollBeat } from '../../components/enroll_beats'; -import { Breadcrumb } from '../../components/navigation/breadcrumb'; -import { BeatsTableType, Table } from '../../components/table'; -import { beatsListActions } from '../../components/table/action_schema'; -import { AssignmentActionType } from '../../components/table/table'; -import { WithKueryAutocompletion } from '../../containers/with_kuery_autocompletion'; -import { AppPageProps } from '../../frontend_types'; - -interface PageProps extends AppPageProps { - renderAction: (area: () => JSX.Element) => void; - intl: InjectedIntl; -} - -interface PageState { - notifications: any[]; - tags: BeatTag[] | null; - beats: CMBeat[]; - assignmentOptions: BeatTag[] | null; -} - -class BeatsPageComponent extends React.PureComponent { - private tableRef: React.RefObject = React.createRef(); - constructor(props: PageProps) { - super(props); - - this.state = { - notifications: [], - tags: null, - beats: [], - assignmentOptions: null, - }; - - props.renderAction(this.renderActionArea); - } - - public componentDidMount() { - if (this.props.urlState.beatsKBar) { - this.props.containers.beats.reload(this.props.urlState.beatsKBar); - } - this.updateBeatsData(this.props.urlState.beatsKBar); - } - - public async updateBeatsData(beatsKBar?: string) { - const beats = sortBy(await this.props.libs.beats.getAll(beatsKBar), 'id') || []; - const tags = await this.props.libs.tags.getTagsWithIds(flatten(beats.map((beat) => beat.tags))); - - this.setState({ - tags, - beats, - }); - } - - public renderActionArea = () => ( - - { - // random, but specific number ensures new tab does not overwrite another _newtab in chrome - // and at the same time not truly random so that many clicks of the link open many tabs at this same URL - window.open( - 'https://www.elastic.co/guide/en/beats/libbeat/current/getting-started.html', - '_newtab35628937456' - ); - }} - > - - - { - this.props.goTo(`/overview/enrolled_beats/enroll`); - }} - > - - - - {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.urlState.enrollmentToken && ( - - { - this.props.goTo('/overview/enrolled_beats'); - }} - > - Done - - - )} - - - )} - - ); - - public render() { - return ( - - - - {(autocompleteProps) => ( -
{ - this.props.setUrlState({ beatsKBar: value }); - - this.updateBeatsData(value); - }, - onSubmit: () => null, // todo - value: this.props.urlState.beatsKBar || '', - }} - actions={beatsListActions} - actionData={{ - tags: this.state.assignmentOptions, - }} - actionHandler={async (action: AssignmentActionType, payload: any) => { - switch (action) { - case AssignmentActionType.Assign: - const status = await this.props.containers.beats.toggleTagAssignment( - payload, - this.getSelectedBeats() - ); - await this.updateBeatsData(); - this.notifyUpdatedTagAssociation(status, this.getSelectedBeats(), payload); - break; - case AssignmentActionType.Delete: - await this.props.containers.beats.deactivate(this.getSelectedBeats()); - await this.updateBeatsData(); - this.notifyBeatDisenrolled(this.getSelectedBeats()); - break; - case AssignmentActionType.Reload: - const assignmentOptions = await this.props.libs.tags.getassignableTagsForBeats( - this.getSelectedBeats() - ); - this.setState({ assignmentOptions }); - break; - } - }} - items={this.state.beats.map((beat) => ({ - ...beat, - tags: (this.state.tags || []).filter((tag) => beat.tags.includes(tag.id)), - }))} - ref={this.tableRef} - type={BeatsTableType} - /> - )} - - this.setState({ notifications: [] })} - toastLifeTimeMs={5000} - /> - - ); - } - - private notifyBeatDisenrolled = async (beats: CMBeat[]) => { - const { intl } = this.props; - let title; - let text; - if (beats.length === 1) { - title = intl.formatMessage( - { - id: 'xpack.beatsManagement.beats.beatDisenrolledNotificationTitle', - defaultMessage: '{firstBeatNameOrId} disenrolled', - }, - { - firstBeatNameOrId: `"${beats[0].name || beats[0].id}"`, - } - ); - text = intl.formatMessage( - { - id: 'xpack.beatsManagement.beats.beatDisenrolledNotificationDescription', - defaultMessage: 'Beat with ID {firstBeatId} was disenrolled.', - }, - { - firstBeatId: `"${beats[0].id}"`, - } - ); - } else { - title = intl.formatMessage( - { - id: 'xpack.beatsManagement.beats.disenrolledBeatsNotificationTitle', - defaultMessage: '{beatsLength} beats disenrolled', - }, - { - beatsLength: beats.length, - } - ); - } - - this.setState({ - notifications: this.state.notifications.concat({ - color: 'warning', - id: `disenroll_${new Date()}`, - title, - text, - }), - }); - }; - - private notifyUpdatedTagAssociation = ( - action: 'added' | 'removed', - beats: CMBeat[], - tag: string - ) => { - const { intl } = this.props; - const notificationMessage = - action === 'removed' - ? intl.formatMessage( - { - id: 'xpack.beatsManagement.beats.removedNotificationDescription', - defaultMessage: - 'Removed tag {tag} from {assignmentsLength, plural, one {beat {beatName}} other {# beats}}.', - }, - { - tag: `"${tag}"`, - assignmentsLength: beats.length, - beatName: `"${beats[0].name || beats[0].id}"`, - } - ) - : intl.formatMessage( - { - id: 'xpack.beatsManagement.beats.addedNotificationDescription', - defaultMessage: - 'Added tag {tag} to {assignmentsLength, plural, one {beat {beatName}} other {# beats}}.', - }, - { - tag: `"${tag}"`, - assignmentsLength: beats.length, - beatName: `"${beats[0].name || beats[0].id}"`, - } - ); - const notificationTitle = - action === 'removed' - ? intl.formatMessage( - { - id: 'xpack.beatsManagement.beats.removedNotificationTitle', - defaultMessage: '{assignmentsLength, plural, one {Tag} other {Tags}} removed', - }, - { - assignmentsLength: beats.length, - } - ) - : intl.formatMessage( - { - id: 'xpack.beatsManagement.beats.addedNotificationTitle', - defaultMessage: '{assignmentsLength, plural, one {Tag} other {Tags}} added', - }, - { - assignmentsLength: beats.length, - } - ); - - this.setState({ - notifications: this.state.notifications.concat({ - color: 'success', - id: `tag-${moment.now()}`, - text:

{notificationMessage}

, - title: notificationTitle, - }), - }); - }; - - private getSelectedBeats = (): CMBeat[] => { - if (!this.tableRef.current) { - return []; - } - const selectedIds = this.tableRef.current.state.selection.map((beat: any) => beat.id); - const beats: CMBeat[] = []; - selectedIds.forEach((id: any) => { - const beat = this.props.containers.beats.state.list.find((b) => b.id === id); - if (beat) { - beats.push(beat); - } - }); - return beats; - }; -} - -export const BeatsPage = injectI18n(BeatsPageComponent); diff --git a/x-pack/plugins/beats_management/public/pages/overview/index.tsx b/x-pack/plugins/beats_management/public/pages/overview/index.tsx deleted file mode 100644 index 942f600b09ea8..0000000000000 --- a/x-pack/plugins/beats_management/public/pages/overview/index.tsx +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { - EuiBetaBadge, - EuiFlexGroup, - EuiFlexItem, - EuiTab, - // @ts-ignore types for EuiTab not currently available - EuiTabs, -} from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import { FormattedMessage } from '@kbn/i18n/react'; -import React from 'react'; -import { Subscribe } from 'unstated'; -import { CMBeat } from '../../../common/domain_types'; -import { PrimaryLayout } from '../../components/layouts/primary'; -import { ChildRoutes } from '../../components/navigation/child_routes'; -import { BeatsContainer } from '../../containers/beats'; -import { TagsContainer } from '../../containers/tags'; -import { withUrlState } from '../../containers/with_url_state'; -import { AppPageProps } from '../../frontend_types'; - -interface MainPagesState { - enrollBeat?: { - enrollmentToken: string; - } | null; - beats: CMBeat[]; - loadedBeatsAtLeastOnce: boolean; -} - -class MainPageComponent extends React.PureComponent { - constructor(props: AppPageProps) { - super(props); - this.state = { - loadedBeatsAtLeastOnce: false, - beats: [], - }; - } - public onTabClicked = (path: string) => { - return () => { - this.props.goTo(path); - }; - }; - - public render() { - return ( - - {'Beats'} - - - - - - } - hideBreadcrumbs={this.props.libs.framework.versionGreaterThen('6.7.0')} - > - {(renderAction: any) => ( - - {(beats: BeatsContainer, tags: TagsContainer) => ( - - - - - - - - - - - - )} - - )} - - ); - } -} - -export const MainPage = withUrlState(MainPageComponent); diff --git a/x-pack/plugins/beats_management/public/pages/tag/create.tsx b/x-pack/plugins/beats_management/public/pages/tag/create.tsx deleted file mode 100644 index 6365115676001..0000000000000 --- a/x-pack/plugins/beats_management/public/pages/tag/create.tsx +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { EuiButton, EuiButtonEmpty, EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui'; -import euiVars from '@elastic/eui/dist/eui_theme_light.json'; -import { i18n } from '@kbn/i18n'; -import { FormattedMessage, InjectedIntl, injectI18n } from '@kbn/i18n/react'; -import 'brace/mode/yaml'; -import 'brace/theme/github'; -import { isEqual } from 'lodash'; -import React from 'react'; -import { UNIQUENESS_ENFORCING_TYPES } from '../../../common/constants/configuration_blocks'; -import { BeatTag, ConfigurationBlock } from '../../../common/domain_types'; -import { PrimaryLayout } from '../../components/layouts/primary'; -import { TagEdit } from '../../components/tag'; -import { AppPageProps } from '../../frontend_types'; -import { randomEUIColor } from '../../utils/random_eui_color'; - -interface TagPageState { - showFlyout: boolean; - tag: BeatTag; - configuration_blocks: ConfigurationBlock[]; - currentConfigPage: number; -} -class TagCreatePageComponent extends React.PureComponent< - AppPageProps & { - intl: InjectedIntl; - }, - TagPageState -> { - constructor(props: AppPageProps & { intl: InjectedIntl }) { - super(props); - - this.state = { - showFlyout: false, - currentConfigPage: 0, - tag: { - id: '', - name: '', - color: randomEUIColor(euiVars), - hasConfigurationBlocksTypes: [], - }, - configuration_blocks: [], - }; - } - public render() { - const { intl } = this.props; - const blockStartingIndex = this.state.currentConfigPage * 5; - return ( - -
- - this.setState((oldState) => ({ - tag: { ...oldState.tag, [field]: value }, - })) - } - onConfigListChange={(index: number) => { - this.setState({ - currentConfigPage: index, - }); - }} - onConfigAddOrEdit={(block: ConfigurationBlock) => { - this.setState((previousState) => ({ - configuration_blocks: previousState.configuration_blocks.concat([block]), - })); - }} - onConfigRemoved={(block: ConfigurationBlock) => { - this.setState((previousState) => { - const selectedIndex = previousState.configuration_blocks.findIndex((c) => { - return isEqual(block, c); - }); - const blocks = [...previousState.configuration_blocks]; - blocks.splice(selectedIndex, 1); - return { - configuration_blocks: blocks, - }; - }); - }} - /> - - - - 1 // || this.state.tag.configuration_blocks.length === 0 - } - onClick={this.saveTag} - > - - - - - this.props.goTo('/overview/configuration_tags')}> - - - - -
-
- ); - } - - private saveTag = async () => { - const newTag = await this.props.containers.tags.upsertTag(this.state.tag); - if (!newTag) { - return alert( - i18n.translate('xpack.beatsManagement.createTag.errorSavingTagTitle', { - defaultMessage: 'error saving tag', - }) - ); - } - const createBlocksResponse = await this.props.libs.configBlocks.upsert( - this.state.configuration_blocks.map((block) => ({ ...block, tag: this.state.tag.id })) - ); - const creationError = createBlocksResponse.results.reduce( - (err: string, resp) => (!err ? (err = resp.error ? resp.error.message : '') : err), - '' - ); - if (creationError) { - return alert(creationError); - } - - this.props.goTo(`/overview/configuration_tags`); - }; - private getNumExclusiveConfigurationBlocks = () => - this.state.configuration_blocks - .map(({ type }) => UNIQUENESS_ENFORCING_TYPES.some((uniqueType) => uniqueType === type)) - .reduce((acc, cur) => (cur ? acc + 1 : acc), 0); -} - -export const TagCreatePage = injectI18n(TagCreatePageComponent); diff --git a/x-pack/plugins/beats_management/public/pages/tag/edit.tsx b/x-pack/plugins/beats_management/public/pages/tag/edit.tsx deleted file mode 100644 index 7c023a14b16bd..0000000000000 --- a/x-pack/plugins/beats_management/public/pages/tag/edit.tsx +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { EuiButton, EuiButtonEmpty, EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui'; -import { FormattedMessage, InjectedIntl, injectI18n } from '@kbn/i18n/react'; -import 'brace/mode/yaml'; -import 'brace/theme/github'; -import { flatten } from 'lodash'; -import React from 'react'; -import { UNIQUENESS_ENFORCING_TYPES } from '../../../common/constants'; -import { BeatTag, CMBeat, ConfigurationBlock } from '../../../common/domain_types'; -import { PrimaryLayout } from '../../components/layouts/primary'; -import { TagEdit } from '../../components/tag'; -import { AppPageProps } from '../../frontend_types'; -interface TagPageState { - showFlyout: boolean; - attachedBeats: CMBeat[] | null; - tag: BeatTag; - beatsTags: BeatTag[]; - configuration_blocks: { - error?: string | undefined; - list: ConfigurationBlock[]; - page: number; - total: number; - }; -} -class TagEditPageComponent extends React.PureComponent< - AppPageProps & { - intl: InjectedIntl; - }, - TagPageState -> { - constructor(props: AppPageProps & { intl: InjectedIntl }) { - super(props); - - this.state = { - showFlyout: false, - attachedBeats: null, - beatsTags: [], - tag: { - id: props.match.params.tagid, - name: '', - color: '#fff', - hasConfigurationBlocksTypes: [], - }, - configuration_blocks: { - list: [], - page: 0, - total: 0, - }, - }; - } - - public UNSAFE_componentWillMount() { - this.loadTag(); - this.loadAttachedBeats(); - this.loadConfigBlocks(); - } - public render() { - const { intl } = this.props; - - return ( - -
- { - await this.props.containers.beats.removeTagsFromBeats(beatIds, this.state.tag.id); - await this.loadAttachedBeats(); - }} - onTagChange={(field: string, value: string | number) => - this.setState((oldState) => ({ - tag: { ...oldState.tag, [field]: value }, - })) - } - attachedBeats={ - (this.state.attachedBeats || []).map((beat) => ({ - ...beat, - tags: flatten( - beat.tags.map((tagId) => this.state.beatsTags.filter((tag) => tag.id === tagId)) - ), - })) as any - } - onConfigListChange={(index: number) => { - this.loadConfigBlocks(index); - }} - onConfigAddOrEdit={(block: ConfigurationBlock) => { - this.props.libs.configBlocks - .upsert([{ ...block, tag: this.state.tag.id }]) - .catch((e: any) => { - // eslint-disable-next-line - console.error('Error upseting config block', e); - }) - .then(() => { - this.loadConfigBlocks(this.state.configuration_blocks.page); - }); - }} - onConfigRemoved={(block: ConfigurationBlock) => { - this.props.libs.configBlocks - .delete(block.id) - .catch((e: any) => { - alert( - 'Error removing block, please check your browsers console logs for more details' - ); - // eslint-disable-next-line - console.error(`Error removing block ${block.id}`, e); - }) - .then(() => { - this.loadConfigBlocks(this.state.configuration_blocks.page); - }); - }} - /> - - - - 1 // || this.state.tag.configuration_blocks.length === 0 - } - onClick={this.saveTag} - > - - - - - this.props.goTo('/overview/configuration_tags')}> - - - - -
-
- ); - } - private loadConfigBlocks = async (page: number = -1) => { - const blocksResponse = await this.props.libs.configBlocks.getForTags([this.state.tag.id], page); - - this.setState({ - configuration_blocks: blocksResponse as { - error?: string | undefined; - list: ConfigurationBlock[]; - page: number; - total: number; - }, - }); - }; - - private loadTag = async () => { - const tags = await this.props.libs.tags.getTagsWithIds([this.props.match.params.tagid]); - if (tags.length === 0) { - // TODO do something to error https://github.com/elastic/kibana/issues/26023 - } - this.setState({ - tag: tags[0], - }); - }; - - private loadAttachedBeats = async () => { - const beats = await this.props.libs.beats.getBeatsWithTag(this.props.match.params.tagid); - const beatsTags = await this.props.libs.tags.getTagsWithIds( - flatten(beats.map((beat) => beat.tags)) - ); - this.setState({ - attachedBeats: beats, - beatsTags, - }); - }; - private saveTag = async () => { - await this.props.containers.tags.upsertTag(this.state.tag); - this.props.goTo(`/overview/configuration_tags`); - }; - private getNumExclusiveConfigurationBlocks = () => - this.state.configuration_blocks.list - .map(({ type }) => UNIQUENESS_ENFORCING_TYPES.some((uniqueType) => uniqueType === type)) - .reduce((acc, cur) => (cur ? acc + 1 : acc), 0); -} - -export const TagEditPage = injectI18n(TagEditPageComponent); diff --git a/x-pack/plugins/beats_management/public/pages/walkthrough/initial/beat.tsx b/x-pack/plugins/beats_management/public/pages/walkthrough/initial/beat.tsx deleted file mode 100644 index 2881bcfb18b56..0000000000000 --- a/x-pack/plugins/beats_management/public/pages/walkthrough/initial/beat.tsx +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { EuiButton } from '@elastic/eui'; -import React, { Component } from 'react'; -import { EnrollBeat } from '../../../components/enroll_beats'; -import { AppPageProps } from '../../../frontend_types'; - -interface ComponentState { - readyToContinue: boolean; -} - -export class BeatsInitialEnrollmentPage extends Component { - constructor(props: AppPageProps) { - super(props); - this.state = { - readyToContinue: false, - }; - } - - public onBeatEnrolled = () => { - this.setState({ - readyToContinue: true, - }); - }; - - public createEnrollmentToken = async () => { - const enrollmentToken = await this.props.libs.tokens.createEnrollmentTokens(); - this.props.setUrlState({ - enrollmentToken: enrollmentToken[0], - }); - }; - - public render() { - return ( - - - {this.state.readyToContinue && ( - - { - this.props.goTo('/walkthrough/initial/tag'); - }} - > - Continue - - - )} - - ); - } -} diff --git a/x-pack/plugins/beats_management/public/pages/walkthrough/initial/finish.tsx b/x-pack/plugins/beats_management/public/pages/walkthrough/initial/finish.tsx deleted file mode 100644 index 7a1bc5e2184fe..0000000000000 --- a/x-pack/plugins/beats_management/public/pages/walkthrough/initial/finish.tsx +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { EuiButton, EuiEmptyPrompt, EuiFlexGroup, EuiFlexItem, EuiPageContent } from '@elastic/eui'; -import { FormattedMessage, InjectedIntl, injectI18n } from '@kbn/i18n/react'; -import React from 'react'; -import { CMBeat } from '../../../../common/domain_types'; -import { AppPageProps } from '../../../frontend_types'; - -interface PageState { - assigned: boolean; -} -class FinishWalkthrough extends React.Component< - AppPageProps & { - intl: InjectedIntl; - }, - PageState -> { - constructor( - props: AppPageProps & { - intl: InjectedIntl; - } - ) { - super(props); - - this.state = { - assigned: false, - }; - } - - public componentDidMount() { - setTimeout(async () => { - const done = await this.assignTagToBeat(); - - if (done) { - this.setState({ - assigned: true, - }); - } - }, 300); - } - - public render() { - const { goTo } = this.props; - - return ( - - - - - - - } - body={ - -

- -

-
- } - actions={ - { - goTo('/overview/enrolled_beats'); - }} - > - - - } - /> -
-
-
- ); - } - - private assignTagToBeat = async () => { - const { intl } = this.props; - if (!this.props.urlState.enrollmentToken) { - return alert( - intl.formatMessage({ - id: 'xpack.beatsManagement.enrollBeat.assignTagToBeatInvalidURLNoTokenFountTitle', - defaultMessage: 'Invalid URL, no enrollmentToken found', - }) - ); - } - if (!this.props.urlState.createdTag) { - return alert( - intl.formatMessage({ - id: 'xpack.beatsManagement.enrollBeat.assignTagToBeatInvalidURLNoTagFoundTitle', - defaultMessage: 'Invalid URL, no createdTag found', - }) - ); - } - - const beat = await this.props.libs.beats.getBeatWithToken(this.props.urlState.enrollmentToken); - if (!beat) { - return alert( - intl.formatMessage({ - id: 'xpack.beatsManagement.enrollBeat.assignTagToBeatNotEnrolledProperlyTitle', - defaultMessage: 'Error: Beat not enrolled properly', - }) - ); - } - - await this.props.containers.beats.assignTagsToBeats( - [beat as CMBeat], - this.props.urlState.createdTag - ); - this.props.setUrlState({ - createdTag: '', - enrollmentToken: '', - }); - return true; - }; -} - -export const FinishWalkthroughPage = injectI18n(FinishWalkthrough); diff --git a/x-pack/plugins/beats_management/public/pages/walkthrough/initial/index.tsx b/x-pack/plugins/beats_management/public/pages/walkthrough/initial/index.tsx deleted file mode 100644 index 506aa87bc51ef..0000000000000 --- a/x-pack/plugins/beats_management/public/pages/walkthrough/initial/index.tsx +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { EuiBetaBadge, EuiButton, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import { FormattedMessage, InjectedIntl, injectI18n } from '@kbn/i18n/react'; -import React from 'react'; -import { NoDataLayout } from '../../../components/layouts/no_data'; -import { WalkthroughLayout } from '../../../components/layouts/walkthrough'; -import { ChildRoutes } from '../../../components/navigation/child_routes'; -import { ConnectedLink } from '../../../components/navigation/connected_link'; -import { AppPageProps } from '../../../frontend_types'; - -type Props = AppPageProps & { - intl: InjectedIntl; -}; - -const InitialWalkthroughPageComponent: React.FC = (props) => { - if (props.location.pathname === '/walkthrough/initial') { - return ( - - {'Beats central management '} - - - - - } - actionSection={ - - - {' '} - - - } - > -

- -

-
- ); - } - return ( - { - // FIXME implament goto - }} - activePath={props.location.pathname} - > - - - ); -}; - -export const InitialWalkthroughPage = injectI18n(InitialWalkthroughPageComponent); diff --git a/x-pack/plugins/beats_management/public/pages/walkthrough/initial/tag.tsx b/x-pack/plugins/beats_management/public/pages/walkthrough/initial/tag.tsx deleted file mode 100644 index eb1e251b2896d..0000000000000 --- a/x-pack/plugins/beats_management/public/pages/walkthrough/initial/tag.tsx +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { EuiButton, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import { FormattedMessage } from '@kbn/i18n/react'; -import { isEqual } from 'lodash'; -import React, { Component } from 'react'; -import uuidv4 from 'uuid/v4'; -import { BeatTag, ConfigurationBlock } from '../../../../common/domain_types'; -import { TagEdit } from '../../../components/tag/tag_edit'; -import { AppPageProps } from '../../../frontend_types'; -interface PageState { - tag: BeatTag; - configuration_blocks: ConfigurationBlock[]; - currentConfigPage: number; -} - -export class InitialTagPage extends Component { - constructor(props: AppPageProps) { - super(props); - this.state = { - tag: { - id: uuidv4(), - name: '', - color: '#DD0A73', - hasConfigurationBlocksTypes: [], - }, - configuration_blocks: [], - currentConfigPage: 0, - }; - - if (props.urlState.createdTag) { - this.loadTag(); - } - } - - public render() { - const blockStartingIndex = this.state.currentConfigPage * 5; - - return ( - - - this.setState((oldState) => ({ - tag: { ...oldState.tag, [field]: value }, - })) - } - onConfigListChange={(index: number) => { - this.setState({ - currentConfigPage: index, - }); - }} - onConfigAddOrEdit={(block: ConfigurationBlock) => { - this.setState((previousState) => ({ - configuration_blocks: previousState.configuration_blocks.concat([block]), - })); - }} - onConfigRemoved={(block: ConfigurationBlock) => { - this.setState((previousState) => { - const selectedIndex = previousState.configuration_blocks.findIndex((c) => { - return isEqual(block, c); - }); - const blocks = [...previousState.configuration_blocks]; - blocks.splice(selectedIndex, 1); - return { - configuration_blocks: blocks, - }; - }); - }} - /> - - - - - - - - - ); - } - - private loadTag = async () => { - const tags = await this.props.libs.tags.getTagsWithIds([this.state.tag.id]); - if (tags.length > 0) { - this.setState({ - tag: tags[0], - }); - } - }; - - private saveTag = async () => { - const newTag = await this.props.libs.tags.upsertTag(this.state.tag as BeatTag); - if (!newTag) { - return alert( - i18n.translate('xpack.beatsManagement.createTag.errorSavingTagTitle', { - defaultMessage: 'error saving tag', - }) - ); - } - const createBlocksResponse = await this.props.libs.configBlocks.upsert( - this.state.configuration_blocks.map((block) => ({ ...block, tag: this.state.tag.id })) - ); - const creationError = createBlocksResponse.results.reduce( - (err: string, resp) => (!err ? (err = resp.error ? resp.error.message : '') : err), - '' - ); - if (creationError) { - return alert(creationError); - } - this.props.setUrlState({ - createdTag: newTag.id, - }); - this.props.goTo(`/walkthrough/initial/finish`); - }; -} diff --git a/x-pack/plugins/beats_management/public/router.tsx b/x-pack/plugins/beats_management/public/router.tsx deleted file mode 100644 index 2c328c2745c14..0000000000000 --- a/x-pack/plugins/beats_management/public/router.tsx +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { get } from 'lodash'; -import React, { Component } from 'react'; -import { Redirect, Route, Switch } from 'react-router-dom'; -import { Loading } from './components/loading'; -import { ChildRoutes } from './components/navigation/child_routes'; -import { BeatsContainer } from './containers/beats'; -import { TagsContainer } from './containers/tags'; -import { URLStateProps, WithURLState } from './containers/with_url_state'; -import { FrontendLibs } from './lib/types'; -import { routeMap } from './pages/index'; - -interface RouterProps { - libs: FrontendLibs; - tagsContainer: TagsContainer; - beatsContainer: BeatsContainer; -} -interface RouterState { - loading: boolean; -} - -export class AppRouter extends Component { - constructor(props: RouterProps) { - super(props); - this.state = { - loading: true, - }; - } - - public async UNSAFE_componentWillMount() { - if (this.state.loading === true) { - try { - await this.props.beatsContainer.reload(); - await this.props.tagsContainer.reload(); - } catch (e) { - // TODO in a furture version we will better manage this "error" in a returned arg - } - - this.setState({ - loading: false, - }); - } - } - - public render() { - if (this.state.loading === true) { - return ; - } - - const countOfEverything = - this.props.beatsContainer.state.list.length + this.props.tagsContainer.state.list.length; - - return ( - - {/* Redirects mapping */} - - {/* License check (UI displays when license exists but is expired) */} - {get(this.props.libs.framework.info, 'license.expired', true) && ( - - !props.location.pathname.includes('/error') ? ( - - ) : null - } - /> - )} - - {/* Ensure security is eanabled for elastic and kibana */} - {!get(this.props.libs.framework.info, 'security.enabled', true) && ( - - !props.location.pathname.includes('/error') ? ( - - ) : null - } - /> - )} - - {/* Make sure the user has correct permissions */} - {!this.props.libs.framework.currentUserHasOneOfRoles( - ['beats_admin'].concat(this.props.libs.framework.info.settings.defaultUserRoles) - ) && ( - - !props.location.pathname.includes('/error') ? ( - - ) : null - } - /> - )} - - {/* If there are no beats or tags yet, redirect to the walkthrough */} - {countOfEverything === 0 && ( - - !props.location.pathname.includes('/walkthrough') ? ( - - ) : null - } - /> - )} - - {/* This app does not make use of a homepage. The mainpage is overview/enrolled_beats */} - } /> - - - {/* Render routes from the FS */} - - {(URLProps: URLStateProps) => ( - - )} - - - ); - } -} diff --git a/x-pack/plugins/beats_management/public/utils/random_eui_color.ts b/x-pack/plugins/beats_management/public/utils/random_eui_color.ts deleted file mode 100644 index 52d847cc6a5a0..0000000000000 --- a/x-pack/plugins/beats_management/public/utils/random_eui_color.ts +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { sample } from 'lodash'; - -export const randomEUIColor = (euiVars: any) => { - const rgb = sample( - Object.keys(euiVars) - .filter((key) => key.startsWith('euiColorVis')) - .map((key) => (euiVars as any)[key]) - ); - - const matchedrgb = rgb.match( - /^rgba?[\s+]?\([\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?/i - ); - return matchedrgb && matchedrgb.length === 4 - ? '#' + - ('0' + parseInt(matchedrgb[1], 10).toString(16)).slice(-2) + - ('0' + parseInt(matchedrgb[2], 10).toString(16)).slice(-2) + - ('0' + parseInt(matchedrgb[3], 10).toString(16)).slice(-2) - : ''; -}; diff --git a/x-pack/plugins/beats_management/public/utils/typed_react.ts b/x-pack/plugins/beats_management/public/utils/typed_react.ts deleted file mode 100644 index ee5ffc2969bb0..0000000000000 --- a/x-pack/plugins/beats_management/public/utils/typed_react.ts +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; - -export type RendererResult = React.ReactElement | null; -export type RendererFunction = (args: RenderArgs) => Result; - -export type StateUpdater = ( - prevState: Readonly, - prevProps: Readonly -) => State | null; - -export function composeStateUpdaters(...updaters: Array>) { - return (state: State, props: Props) => - updaters.reduce((currentState, updater) => updater(currentState, props) || currentState, state); -} diff --git a/x-pack/plugins/beats_management/readme.md b/x-pack/plugins/beats_management/readme.md deleted file mode 100644 index 75adf428772e4..0000000000000 --- a/x-pack/plugins/beats_management/readme.md +++ /dev/null @@ -1,39 +0,0 @@ -# Beats CM - -Notes: -Failure to have auth enabled in Kibana will make for a broken UI. UI-based errors not yet in place - -## Testing - -### Unit tests - -Run Jest tests: - -Documentation: https://www.elastic.co/guide/en/kibana/current/development-tests.html#_unit_testing - -``` -yarn test:jest x-pack/plugins/beats --watch -``` - -### API tests - -In one shell, from **~/kibana/x-pack**: -`node scripts/functional_tests-server.js` - -In another shell, from **~kibana/x-pack**: -`node ../scripts/functional_test_runner.js --config test/api_integration/config.ts`. - -### Manual e2e testing - -- Run this command to fake an enrolling beat (from beats_management dir) - -``` -node scripts/enroll.js -``` - -- Run a command to setup a fake large-scale deployment - Note: `ts-node` is required to be installed gloably from NPM/Yarn for this action - -``` -ts-node scripts/fake_env.ts <# of beats> <# of tags per beat> <# of congifs per tag> -``` diff --git a/x-pack/plugins/beats_management/scripts/enroll.js b/x-pack/plugins/beats_management/scripts/enroll.js deleted file mode 100644 index 3c6712ada8e9b..0000000000000 --- a/x-pack/plugins/beats_management/scripts/enroll.js +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -const request = require('request'); -const Chance = require('chance'); // eslint-disable-line -const args = process.argv.slice(2); -const chance = new Chance(); - -const enroll = async (kibanaURL, token) => { - const beatId = chance.word(); - - if (!token) { - token = kibanaURL; - kibanaURL = 'http://localhost:5601'; - } - - await request( - { - url: `${kibanaURL}/api/beats/agent/${beatId}`, - method: 'POST', - headers: { - 'kbn-xsrf': 'xxx', - 'kbn-beats-enrollment-token': token, - }, - body: JSON.stringify({ - type: 'filebeat', - host_name: `${chance.word()}.bar.com`, - name: chance.word(), - version: '6.3.0', - }), - }, - (error, response, body) => { - console.log(error, body); - } - ); -}; - -enroll(...args); diff --git a/x-pack/plugins/beats_management/scripts/fake_env.ts b/x-pack/plugins/beats_management/scripts/fake_env.ts deleted file mode 100644 index e45bbe2277387..0000000000000 --- a/x-pack/plugins/beats_management/scripts/fake_env.ts +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import Chance from 'chance'; -// @ts-ignore -import request from 'request'; -import uuidv4 from 'uuid/v4'; -import { configBlockSchemas } from '../common/config_schemas'; -import { BeatTag } from '../common/domain_types'; -import { compose } from '../public/lib/compose/scripts'; -const args = process.argv.slice(2); -const chance = new Chance(); - -function sleep(ms: number) { - return new Promise((resolve) => setTimeout(resolve, ms)); -} -function getRandomColor() { - const letters = '0123456789ABCDEF'; - let color = '#'; - for (let i = 0; i < 6; i++) { - color += letters[Math.floor(Math.random() * 16)]; - } - return color; -} - -const enroll = async (kibanaURL: string, token: string) => { - const beatId = uuidv4(); - - await request( - { - url: `${kibanaURL}/api/beats/agent/${beatId}`, - method: 'POST', - headers: { - 'kbn-xsrf': 'xxx', - 'kbn-beats-enrollment-token': token, - }, - body: JSON.stringify({ - type: Math.random() >= 0.5 ? 'filebeat' : 'metricbeat', - host_name: `${chance.word()}.local`, - name: chance.word(), - version: '6.7.0', - }), - }, - (error: any, response: any, body: any) => { - const res = JSON.parse(body); - if (res.message) { - // eslint-disable-next-line - console.log(res.message); - } - } - ); -}; - -const start = async ( - kibanaURL: string, - numberOfBeats = 10, - maxNumberOfTagsPerBeat = 2, - maxNumberOfConfigsPerTag = 4 -) => { - try { - const libs = compose(kibanaURL); - // eslint-disable-next-line - console.error(`Enrolling ${numberOfBeats} fake beats...`); - - const enrollmentTokens = await libs.tokens.createEnrollmentTokens(numberOfBeats); - process.stdout.write(`enrolling fake beats... 0 of ${numberOfBeats}`); - let count = 0; - for (const token of enrollmentTokens) { - count++; - // @ts-ignore - process.stdout.clearLine(); - // @ts-ignore - process.stdout.cursorTo(0); - process.stdout.write(`enrolling fake beats... ${count} of ${numberOfBeats}`); - - await enroll(kibanaURL, token); - await sleep(10); - } - process.stdout.write('\n'); - - await sleep(2000); - // eslint-disable-next-line - console.error(`${numberOfBeats} fake beats are enrolled`); - const beats = await libs.beats.getAll(); - - // eslint-disable-next-line - console.error(`Creating tags, configs, and assigning them...`); - process.stdout.write(`creating tags/configs for beat... 0 of ${numberOfBeats}`); - count = 0; - for (const beat of beats) { - count++; - // @ts-ignore - process.stdout.clearLine(); - // @ts-ignore - process.stdout.cursorTo(0); - process.stdout.write(`creating tags w/configs for beat... ${count} of ${numberOfBeats}`); - - const tags = await Promise.all( - [...Array(maxNumberOfTagsPerBeat)].map(() => { - return libs.tags.upsertTag({ - name: chance.word(), - color: getRandomColor(), - hasConfigurationBlocksTypes: [] as string[], - } as BeatTag); - }) - ); - await libs.beats.assignTagsToBeats( - tags.map((tag: any) => ({ - beatId: beat.id, - tag: tag.id, - })) - ); - - await Promise.all( - tags.map((tag: any) => { - return libs.configBlocks.upsert( - [...Array(maxNumberOfConfigsPerTag)].map( - () => - ({ - type: configBlockSchemas[Math.floor(Math.random())].id, - description: `Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sint ista Graecorum; -Nihil ad rem! Ne sit sane; Quod quidem nobis non saepe contingit. -Duo Reges: constructio interrete. Itaque his sapiens semper vacabit.`.substring( - 0, - Math.floor(Math.random() * (0 - 115 + 1)) - ), - tag: tag.id, - last_updated: new Date(), - config: {}, - } as any) - ) - ); - }) - ); - } - } catch (e) { - if (e.response && e.response.data && e.response.message) { - // eslint-disable-next-line - console.error(e.response.data.message); - } else if (e.response && e.response.data && e.response.reason) { - // eslint-disable-next-line - console.error(e.response.data.reason); - } else if (e.code) { - // eslint-disable-next-line - console.error(e.code); - } else { - // eslint-disable-next-line - console.error(e); - } - } -}; - -// @ts-ignore -start(...args); diff --git a/x-pack/plugins/beats_management/server/index.ts b/x-pack/plugins/beats_management/server/index.ts deleted file mode 100644 index 5489fce1f36a3..0000000000000 --- a/x-pack/plugins/beats_management/server/index.ts +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { PluginInitializer } from '../../../../src/core/server'; -import { beatsManagementConfigSchema } from '../common'; -import { BeatsManagementPlugin } from './plugin'; - -export const config = { - schema: beatsManagementConfigSchema, - - exposeToBrowser: { - defaultUserRoles: true, - encryptionKey: true, - enrollmentTokensTtlInSeconds: true, - }, -}; - -export const plugin: PluginInitializer<{}, {}> = (context) => new BeatsManagementPlugin(context); diff --git a/x-pack/plugins/beats_management/server/index_templates/beats_template.json b/x-pack/plugins/beats_management/server/index_templates/beats_template.json deleted file mode 100644 index 36fc753c68745..0000000000000 --- a/x-pack/plugins/beats_management/server/index_templates/beats_template.json +++ /dev/null @@ -1,137 +0,0 @@ -{ - "index_patterns": [".management-beats"], - "version": 70000, - "settings": { - "index": { - "number_of_shards": 1, - "auto_expand_replicas": "0-1", - "codec": "best_compression" - } - }, - "mappings": { - "dynamic": "strict", - "properties": { - "type": { - "type": "keyword" - }, - "configuration_block": { - "properties": { - "id": { - "type": "keyword" - }, - "type": { - "type": "keyword" - }, - "tag": { - "type": "keyword" - }, - "description": { - "type": "text" - }, - "config": { - "type": "keyword" - }, - "last_updated": { - "type": "date" - } - } - }, - "enrollment_token": { - "properties": { - "token": { - "type": "keyword" - }, - "expires_on": { - "type": "date" - } - } - }, - "tag": { - "properties": { - "id": { - "type": "keyword" - }, - "name": { - "type": "keyword" - }, - "color": { - "type": "keyword" - }, - "hasConfigurationBlocksTypes": { - "type": "keyword" - } - } - }, - "beat": { - "properties": { - "id": { - "type": "keyword" - }, - "status": { - "properties": { - "type": { - "type": "keyword" - }, - "timestamp": { - "type": "date" - }, - "event": { - "properties": { - "type": { - "type": "keyword" - }, - "message": { - "type": "text" - }, - "uuid": { - "type": "keyword" - } - } - } - } - }, - "active": { - "type": "boolean" - }, - "last_checkin": { - "type": "date" - }, - "enrollment_token": { - "type": "keyword" - }, - "access_token": { - "type": "keyword" - }, - "verified_on": { - "type": "date" - }, - "type": { - "type": "keyword" - }, - "version": { - "type": "keyword" - }, - "host_ip": { - "type": "ip" - }, - "host_name": { - "type": "keyword" - }, - "ephemeral_id": { - "type": "keyword" - }, - "tags": { - "type": "keyword" - }, - "metadata": { - "dynamic": "true", - "type": "object" - }, - "name": { - "type": "keyword" - } - } - } - } - } -} diff --git a/x-pack/plugins/beats_management/server/index_templates/events_template.json b/x-pack/plugins/beats_management/server/index_templates/events_template.json deleted file mode 100644 index 4f8063f048132..0000000000000 --- a/x-pack/plugins/beats_management/server/index_templates/events_template.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "index_patterns": [".management-beats-events-*"], - "version": 67000, - "index": { - "lifecycle": { - "name": ".beats-management-events-retention" - } - }, - "settings": { - "index": { - "number_of_shards": 1, - "auto_expand_replicas": "0-1", - "codec": "best_compression" - } - }, - "mappings": { - "_doc": { - "dynamic": "strict", - "properties": { - "type": { - "type": "keyword" - }, - "beat": { - "type": "keyword" - }, - "timestamp": { - "type": "date" - }, - "event": { - "properties": { - "type": { - "type": "keyword" - }, - "message": { - "type": "text" - }, - "uuid": { - "type": "keyword" - } - } - } - } - } - } -} diff --git a/x-pack/plugins/beats_management/server/index_templates/index.ts b/x-pack/plugins/beats_management/server/index_templates/index.ts deleted file mode 100644 index ade9a86114e63..0000000000000 --- a/x-pack/plugins/beats_management/server/index_templates/index.ts +++ /dev/null @@ -1,11 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import beatsIndexTemplate from './beats_template.json'; -import eventsIndexTemplate from './events_template.json'; - -export { beatsIndexTemplate, eventsIndexTemplate }; diff --git a/x-pack/plugins/beats_management/server/lib/adapters/beats/adapter_types.ts b/x-pack/plugins/beats_management/server/lib/adapters/beats/adapter_types.ts deleted file mode 100644 index 995fec9825db8..0000000000000 --- a/x-pack/plugins/beats_management/server/lib/adapters/beats/adapter_types.ts +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { CMBeat } from '../../../../common/domain_types'; -import { FrameworkUser } from '../framework/adapter_types'; - -export interface CMBeatsAdapter { - insert(user: FrameworkUser, beat: CMBeat): Promise; - update(user: FrameworkUser, beat: CMBeat): Promise; - get(user: FrameworkUser, id: string): Promise; - getAll(user: FrameworkUser, ESQuery?: any): Promise; - getWithIds(user: FrameworkUser, beatIds: string[]): Promise; - getAllWithTags(user: FrameworkUser, tagIds: string[]): Promise; - getBeatWithToken(user: FrameworkUser, enrollmentToken: string): Promise; - removeTagsFromBeats( - user: FrameworkUser, - removals: BeatsTagAssignment[] - ): Promise; - assignTagsToBeats( - user: FrameworkUser, - assignments: BeatsTagAssignment[] - ): Promise; -} - -export interface BeatsTagAssignment { - beatId: string; - tag: string; - idxInRequest?: number; -} - -interface BeatsReturnedTagAssignment { - status: number | null; - result?: string; -} - -export interface CMAssignmentReturn { - assignments: BeatsReturnedTagAssignment[]; -} - -export interface BeatsRemovalReturn { - removals: BeatsReturnedTagAssignment[]; -} diff --git a/x-pack/plugins/beats_management/server/lib/adapters/beats/elasticsearch_beats_adapter.ts b/x-pack/plugins/beats_management/server/lib/adapters/beats/elasticsearch_beats_adapter.ts deleted file mode 100644 index 3fdba8f7441d1..0000000000000 --- a/x-pack/plugins/beats_management/server/lib/adapters/beats/elasticsearch_beats_adapter.ts +++ /dev/null @@ -1,245 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { flatten, get as _get, omit } from 'lodash'; -import { INDEX_NAMES } from '../../../../common/constants'; -import { CMBeat } from '../../../../common/domain_types'; -import { DatabaseAdapter } from '../database/adapter_types'; -import { FrameworkUser } from '../framework/adapter_types'; -import { BeatsTagAssignment, CMBeatsAdapter } from './adapter_types'; - -function formatWithTags(beat: CMBeat) { - const { tags, ...rest } = beat; - - return { - tags: tags || [], - ...rest, - }; -} - -export class ElasticsearchBeatsAdapter implements CMBeatsAdapter { - private database: DatabaseAdapter; - - constructor(database: DatabaseAdapter) { - this.database = database; - } - - public async get(user: FrameworkUser, id: string) { - const params = { - id: `beat:${id}`, - ignore: [404], - index: INDEX_NAMES.BEATS, - }; - - const response = await this.database.get(user, params); - if (!response.found) { - return null; - } - const beat = _get(response, '_source.beat') as CMBeat; - beat.tags = beat.tags || []; - return beat; - } - - public async insert(user: FrameworkUser, beat: CMBeat) { - const body = { - beat, - type: 'beat', - }; - - await this.database.index(user, { - body, - id: `beat:${beat.id}`, - index: INDEX_NAMES.BEATS, - refresh: 'wait_for', - }); - } - - public async update(user: FrameworkUser, beat: CMBeat) { - const body = { - beat, - type: 'beat', - }; - - const params = { - body, - id: `beat:${beat.id}`, - index: INDEX_NAMES.BEATS, - refresh: 'wait_for', - }; - await this.database.index(user, params); - } - - public async getWithIds(user: FrameworkUser, beatIds: string[]) { - const ids = beatIds.map((beatId) => `beat:${beatId}`); - - const params = { - body: { - ids, - }, - index: INDEX_NAMES.BEATS, - }; - const response = await this.database.mget(user, params); - - return _get(response, 'docs', []) - .filter((b: any) => b.found) - .map((b: any) => ({ tags: [], ...b._source.beat })); - } - - public async getAllWithTags(user: FrameworkUser, tagIds: string[]): Promise { - const params = { - ignore: [404], - index: INDEX_NAMES.BEATS, - body: { - query: { - terms: { 'beat.tags': tagIds }, - }, - }, - }; - - const response = await this.database.search(user, params); - - const beats = _get(response, 'hits.hits', []) as CMBeat[]; - - if (beats.length === 0) { - return []; - } - return beats.map((beat: any) => - formatWithTags(omit(beat._source.beat as CMBeat, ['access_token']) as CMBeat) - ); - } - - public async getBeatWithToken( - user: FrameworkUser, - enrollmentToken: string - ): Promise { - const params = { - ignore: [404], - index: INDEX_NAMES.BEATS, - body: { - query: { - match: { 'beat.enrollment_token': enrollmentToken }, - }, - }, - }; - - const response = await this.database.search(user, params); - - const beats = _get(response, 'hits.hits', []) as CMBeat[]; - - if (beats.length === 0) { - return null; - } - return omit(_get(formatWithTags(beats[0]), '_source.beat'), ['access_token']) as CMBeat; - } - - public async getAll(user: FrameworkUser, ESQuery?: any) { - const params = { - index: INDEX_NAMES.BEATS, - size: 10000, - ignore: [404], - body: { - query: { - bool: { - must: { - term: { - type: 'beat', - }, - }, - }, - }, - }, - }; - - if (ESQuery) { - params.body.query = { - ...params.body.query, - ...ESQuery, - }; - } - - let response; - try { - response = await this.database.search(user, params); - } catch (e) { - // TODO something - } - if (!response) { - return []; - } - const beats = _get(response, 'hits.hits', []) as any; - - return beats.map((beat: any) => - formatWithTags(omit(beat._source.beat as CMBeat, ['access_token']) as CMBeat) - ); - } - - public async removeTagsFromBeats( - user: FrameworkUser, - removals: BeatsTagAssignment[] - ): Promise { - const body = flatten( - removals.map(({ beatId, tag }) => { - const script = ` - def beat = ctx._source.beat; - if (beat.tags != null) { - beat.tags.removeAll([params.tag]); - }`; - - return [ - { update: { _id: `beat:${beatId}` } }, - { script: { source: script.replace(' ', ''), params: { tag } } }, - ]; - }) - ); - - const response = await this.database.bulk(user, { - body, - index: INDEX_NAMES.BEATS, - refresh: 'wait_for', - }); - return (_get(response, 'items', []) as any).map((item: any, resultIdx: number) => ({ - idxInRequest: removals[resultIdx].idxInRequest, - result: item.update.result, - status: item.update.status, - })); - } - - public async assignTagsToBeats( - user: FrameworkUser, - assignments: BeatsTagAssignment[] - ): Promise { - const body = flatten( - assignments.map(({ beatId, tag }) => { - const script = ` - def beat = ctx._source.beat; - if (beat.tags == null) { - beat.tags = []; - } - if (!beat.tags.contains(params.tag)) { - beat.tags.add(params.tag); - }`; - - return [ - { update: { _id: `beat:${beatId}` } }, - { script: { source: script.replace(' ', ''), params: { tag } } }, - ]; - }) - ); - - const response = await this.database.bulk(user, { - body, - index: INDEX_NAMES.BEATS, - refresh: 'wait_for', - }); - // console.log(response.items[0].update.error); - return (_get(response, 'items', []) as any).map((item: any, resultIdx: any) => ({ - idxInRequest: assignments[resultIdx].idxInRequest, - result: item.update.result, - status: item.update.status, - })); - } -} diff --git a/x-pack/plugins/beats_management/server/lib/adapters/configuration_blocks/adapter_types.ts b/x-pack/plugins/beats_management/server/lib/adapters/configuration_blocks/adapter_types.ts deleted file mode 100644 index dcd2043bd0ea1..0000000000000 --- a/x-pack/plugins/beats_management/server/lib/adapters/configuration_blocks/adapter_types.ts +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { ConfigurationBlock } from '../../../../common/domain_types'; -import { FrameworkUser } from '../framework/adapter_types'; - -export interface ConfigurationBlockAdapter { - getByIds(user: FrameworkUser, ids: string[]): Promise; - getForTags( - user: FrameworkUser, - tagIds: string[], - page?: number, - size?: number - ): Promise<{ blocks: ConfigurationBlock[]; page: number; total: number }>; - delete( - user: FrameworkUser, - blockIds: string[] - ): Promise>; - create(user: FrameworkUser, configs: ConfigurationBlock[]): Promise; - deleteForTags( - user: FrameworkUser, - tagIds: string[] - ): Promise<{ success: boolean; reason?: string }>; -} diff --git a/x-pack/plugins/beats_management/server/lib/adapters/configuration_blocks/elasticsearch_configuration_block_adapter.ts b/x-pack/plugins/beats_management/server/lib/adapters/configuration_blocks/elasticsearch_configuration_block_adapter.ts deleted file mode 100644 index 744aa0d87c760..0000000000000 --- a/x-pack/plugins/beats_management/server/lib/adapters/configuration_blocks/elasticsearch_configuration_block_adapter.ts +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { flatten, get } from 'lodash'; -import uuidv4 from 'uuid/v4'; -import { INDEX_NAMES } from '../../../../common/constants'; -import { ConfigurationBlock } from '../../../../common/domain_types'; -import { DatabaseAdapter } from '../database/adapter_types'; -import { FrameworkUser } from '../framework/adapter_types'; -import { ConfigurationBlockAdapter } from './adapter_types'; - -export class ElasticsearchConfigurationBlockAdapter implements ConfigurationBlockAdapter { - private database: DatabaseAdapter; - - constructor(database: DatabaseAdapter) { - this.database = database; - } - - public async getByIds(user: FrameworkUser, ids: string[]): Promise { - if (ids.length === 0) { - return []; - } - - const params = { - ignore: [404], - _source: true, - size: 10000, - index: INDEX_NAMES.BEATS, - body: { - ids: ids.map((id) => `configuration_block:${id}`), - }, - }; - - const response = await this.database.search(user, params); - const configs = get(response, 'hits.hits', []); - - return configs.map((tag: any) => ({ ...tag._source.tag, config: JSON.parse(tag._source.tag) })); - } - - public async getForTags( - user: FrameworkUser, - tagIds: string[], - page: number = 0, - size: number = 100 - ): Promise<{ blocks: ConfigurationBlock[]; page: number; total: number }> { - if (tagIds.length === 0) { - return { - page: 0, - total: 0, - blocks: [] as ConfigurationBlock[], - }; - } - - const params = { - ignore: [404], - index: INDEX_NAMES.BEATS, - body: { - from: page === -1 ? undefined : page * size, - size, - query: { - terms: { 'configuration_block.tag': tagIds }, - }, - }, - }; - let response; - if (page === -1) { - response = await this.database.searchAll(user, params); - } else { - response = await this.database.search(user, params); - } - const configs = get(response, 'hits.hits', []); - - return { - blocks: configs.map((block: any) => ({ - ...block._source.configuration_block, - config: JSON.parse(block._source.configuration_block.config || '{}'), - })), - page, - total: response.hits ? (response.hits.total as any).value : 0, - }; - } - - public async delete( - user: FrameworkUser, - ids: string[] - ): Promise> { - const result = await this.database.bulk(user, { - body: ids.map((id) => ({ delete: { _id: `configuration_block:${id}` } })), - index: INDEX_NAMES.BEATS, - refresh: 'wait_for', - }); - - if (result.errors) { - if (result.items[0].result) { - throw new Error(result.items[0].result); - } - throw new Error((result.items[0] as any).index.error.reason); - } - - return result.items.map((item: any) => { - return { - id: item.delete._id, - success: item.delete.result === 'deleted', - reason: item.delete.result !== 'deleted' ? item.delete.result : undefined, - }; - }); - } - - public async deleteForTags( - user: FrameworkUser, - tagIds: string[] - ): Promise<{ success: boolean; reason?: string }> { - const result: any = await this.database.deleteByQuery(user, { - body: { - query: { - terms: { 'configuration_block.tag': tagIds }, - }, - }, - index: INDEX_NAMES.BEATS, - }); - - if (result.failures.length > 0) { - return { - success: false, - reason: result.failures[0], - }; - } - - return { - success: true, - }; - } - - public async create(user: FrameworkUser, configs: ConfigurationBlock[]): Promise { - const body = flatten( - configs.map((config) => { - const { id: configId, ...configWithoutId } = config; - const id = configId || uuidv4(); - return [ - { index: { _id: `configuration_block:${id}` } }, - { - type: 'configuration_block', - configuration_block: { id, ...configWithoutId, config: JSON.stringify(config.config) }, - }, - ]; - }) - ); - - const result = await this.database.bulk(user, { - body, - index: INDEX_NAMES.BEATS, - refresh: 'wait_for', - }); - - if (result.errors) { - if (result.items[0].result) { - throw new Error(result.items[0].result); - } - throw new Error((result.items[0] as any).index.error.reason); - } - - return result.items.map((item: any) => item.index._id); - } -} diff --git a/x-pack/plugins/beats_management/server/lib/adapters/database/adapter_types.ts b/x-pack/plugins/beats_management/server/lib/adapters/database/adapter_types.ts deleted file mode 100644 index a1af8e7929635..0000000000000 --- a/x-pack/plugins/beats_management/server/lib/adapters/database/adapter_types.ts +++ /dev/null @@ -1,302 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { FrameworkUser } from '../framework/adapter_types'; - -export interface DatabaseAdapter { - get( - user: FrameworkUser, - params: DatabaseGetParams - ): Promise>; - create( - user: FrameworkUser, - params: DatabaseCreateDocumentParams - ): Promise; - index( - user: FrameworkUser, - params: DatabaseIndexDocumentParams - ): Promise; - delete( - user: FrameworkUser, - params: DatabaseDeleteDocumentParams - ): Promise; - deleteByQuery( - user: FrameworkUser, - params: DatabaseSearchParams - ): Promise; - mget(user: FrameworkUser, params: DatabaseMGetParams): Promise>; - bulk( - user: FrameworkUser, - params: DatabaseBulkIndexDocumentsParams - ): Promise; - search(user: FrameworkUser, params: DatabaseSearchParams): Promise>; - searchAll( - user: FrameworkUser, - params: DatabaseSearchParams - ): Promise>; - putTemplate(name: string, template: any): Promise; -} - -export interface DatabaseSearchParams extends DatabaseGenericParams { - analyzer?: string; - analyzeWildcard?: boolean; - defaultOperator?: DefaultOperator; - df?: string; - explain?: boolean; - storedFields?: DatabaseNameList; - docvalueFields?: DatabaseNameList; - fielddataFields?: DatabaseNameList; - from?: number; - ignoreUnavailable?: boolean; - allowNoIndices?: boolean; - expandWildcards?: ExpandWildcards; - lenient?: boolean; - lowercaseExpandedTerms?: boolean; - preference?: string; - q?: string; - routing?: DatabaseNameList; - scroll?: string; - searchType?: 'query_then_fetch' | 'dfs_query_then_fetch'; - size?: number; - sort?: DatabaseNameList; - _source?: DatabaseNameList; - _sourceExclude?: DatabaseNameList; - _source_includes?: DatabaseNameList; - terminateAfter?: number; - stats?: DatabaseNameList; - suggestField?: string; - suggestMode?: 'missing' | 'popular' | 'always'; - suggestSize?: number; - suggestText?: string; - timeout?: string; - trackScores?: boolean; - version?: boolean; - requestCache?: boolean; - index?: DatabaseNameList; - type?: DatabaseNameList; -} - -export interface DatabaseSearchResponse { - took: number; - timed_out: boolean; - _scroll_id?: string; - _shards: DatabaseShardsResponse; - hits: { - total: number; - max_score: number; - hits: Array<{ - _index: string; - _id: string; - _score: number; - _source: T; - _seq_no?: number; - _primary_term?: number; - _explanation?: DatabaseExplanation; - fields?: any; - highlight?: any; - inner_hits?: any; - sort?: string[]; - }>; - }; - aggregations?: any; -} - -export interface DatabaseExplanation { - value: number; - description: string; - details: DatabaseExplanation[]; -} - -export interface DatabaseShardsResponse { - total: number; - successful: number; - failed: number; - skipped: number; -} - -export interface DatabaseGetDocumentResponse { - _index: string; - _id: string; - _seq_no: number; - _primary_term: number; - found: boolean; - _source: Source; -} - -export interface DatabaseBulkResponse { - took: number; - errors: boolean; - items: Array< - DatabaseDeleteDocumentResponse | DatabaseIndexDocumentResponse | DatabaseUpdateDocumentResponse - >; -} - -export interface DatabaseBulkIndexDocumentsParams extends DatabaseGenericParams { - waitForActiveShards?: string; - refresh?: DatabaseRefresh; - routing?: string; - timeout?: string; - fields?: DatabaseNameList; - _source?: DatabaseNameList; - _sourceExclude?: DatabaseNameList; - _source_includes?: DatabaseNameList; - pipeline?: string; - index?: string; -} - -export interface DatabaseMGetParams extends DatabaseGenericParams { - storedFields?: DatabaseNameList; - preference?: string; - realtime?: boolean; - refresh?: boolean; - _source?: DatabaseNameList; - _sourceExclude?: DatabaseNameList; - _source_includes?: DatabaseNameList; - index: string; -} - -export interface DatabaseMGetResponse { - docs?: Array>; -} - -export interface DatabasePutTemplateParams extends DatabaseGenericParams { - name: string; - body: any; -} - -export interface DatabaseDeleteDocumentParams extends DatabaseGenericParams { - waitForActiveShards?: string; - parent?: string; - refresh?: DatabaseRefresh; - routing?: string; - timeout?: string; - ifSeqNo?: number; - ifPrimaryTerm?: number; - index: string; - id: string; -} - -export interface DatabaseIndexDocumentResponse { - found: boolean; - _index: string; - _id: string; - _seq_no: number; - _primary_term: number; - result: string; -} - -export interface DatabaseUpdateDocumentResponse { - found: boolean; - _index: string; - _id: string; - _seq_no: number; - _primary_term: number; - result: string; -} - -export interface DatabaseDeleteDocumentResponse { - found: boolean; - _index: string; - _id: string; - _seq_no: number; - _primary_term: number; - result: string; -} - -export interface DatabaseIndexDocumentParams extends DatabaseGenericParams { - waitForActiveShards?: string; - opType?: 'index' | 'create'; - parent?: string; - refresh?: string; - routing?: string; - timeout?: string; - timestamp?: Date | number; - ttl?: string; - ifSeqNo?: number; - ifPrimaryTerm?: number; - pipeline?: string; - id?: string; - index: string; - body: T; -} - -export interface DatabaseGetResponse { - found: boolean; - _source: T; -} -export interface DatabaseCreateDocumentParams extends DatabaseGenericParams { - waitForActiveShards?: string; - parent?: string; - refresh?: DatabaseRefresh; - routing?: string; - timeout?: string; - timestamp?: Date | number; - ttl?: string; - ifSeqNo?: number; - ifPrimaryTerm?: number; - pipeline?: string; - id?: string; - index: string; -} - -export interface DatabaseCreateDocumentResponse { - created: boolean; - result: string; -} - -export interface DatabaseDeleteDocumentParams extends DatabaseGenericParams { - waitForActiveShards?: string; - parent?: string; - refresh?: DatabaseRefresh; - routing?: string; - timeout?: string; - ifSeqNo?: number; - ifPrimaryTerm?: number; - index: string; - id: string; -} - -export interface DatabaseGetParams extends DatabaseGenericParams { - storedFields?: DatabaseNameList; - parent?: string; - preference?: string; - realtime?: boolean; - refresh?: boolean; - routing?: string; - _source?: DatabaseNameList; - _sourceExclude?: DatabaseNameList; - _source_includes?: DatabaseNameList; - ifSeqNo?: number; - ifPrimaryTerm?: number; - id: string; - index: string; -} - -export type DatabaseNameList = string | string[] | boolean; -export type DatabaseRefresh = boolean | 'true' | 'false' | 'wait_for' | ''; -export type ExpandWildcards = 'open' | 'closed' | 'none' | 'all'; -export type DefaultOperator = 'AND' | 'OR'; -export type DatabaseConflicts = 'abort' | 'proceed'; - -export interface DatabaseGenericParams { - requestTimeout?: number; - maxRetries?: number; - method?: string; - body?: any; - ignore?: number | number[]; - filterPath?: string | string[]; -} - -export interface DatabaseDeleteDocumentResponse { - found: boolean; - _index: string; - _type: string; - _id: string; - _seq_no: number; - _primary_term: number; - result: string; -} diff --git a/x-pack/plugins/beats_management/server/lib/adapters/database/kibana_database_adapter.ts b/x-pack/plugins/beats_management/server/lib/adapters/database/kibana_database_adapter.ts deleted file mode 100644 index 741668429a3c7..0000000000000 --- a/x-pack/plugins/beats_management/server/lib/adapters/database/kibana_database_adapter.ts +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { ElasticsearchServiceStart, ILegacyClusterClient } from 'src/core/server'; -import { FrameworkUser } from '../framework/adapter_types'; -import { internalAuthData } from './../framework/adapter_types'; -import { - DatabaseAdapter, - DatabaseBulkIndexDocumentsParams, - DatabaseCreateDocumentParams, - DatabaseCreateDocumentResponse, - DatabaseDeleteDocumentParams, - DatabaseDeleteDocumentResponse, - DatabaseGetDocumentResponse, - DatabaseGetParams, - DatabaseIndexDocumentParams, - DatabaseMGetParams, - DatabaseMGetResponse, - DatabaseSearchParams, - DatabaseSearchResponse, -} from './adapter_types'; - -export class KibanaDatabaseAdapter implements DatabaseAdapter { - private es: ILegacyClusterClient; - - constructor(elasticsearch: ElasticsearchServiceStart) { - this.es = elasticsearch.legacy.client; - } - - public async get( - user: FrameworkUser, - params: DatabaseGetParams - ): Promise> { - return await this.callWithUser(user, 'get', params); - } - - public async mget( - user: FrameworkUser, - params: DatabaseMGetParams - ): Promise> { - return await this.callWithUser(user, 'mget', params); - } - - public async bulk(user: FrameworkUser, params: DatabaseBulkIndexDocumentsParams): Promise { - return await this.callWithUser(user, 'bulk', params); - } - - public async create( - user: FrameworkUser, - params: DatabaseCreateDocumentParams - ): Promise { - return await this.callWithUser(user, 'create', params); - } - - public async index(user: FrameworkUser, params: DatabaseIndexDocumentParams): Promise { - return await this.callWithUser(user, 'index', params); - } - - public async delete( - user: FrameworkUser, - params: DatabaseDeleteDocumentParams - ): Promise { - return await this.callWithUser(user, 'delete', params); - } - - public async deleteByQuery( - user: FrameworkUser, - params: DatabaseSearchParams - ): Promise { - return await this.callWithUser(user, 'deleteByQuery', params); - } - - public async search( - user: FrameworkUser, - params: DatabaseSearchParams - ): Promise> { - return await this.callWithUser(user, 'search', params); - } - - public async searchAll( - user: FrameworkUser, - params: DatabaseSearchParams - ): Promise> { - return await this.callWithUser(user, 'search', { - scroll: '1m', - ...params, - body: { - size: 1000, - ...params.body, - }, - }); - } - - public async putTemplate(name: string, template: any): Promise { - return await this.callWithUser({ kind: 'internal' }, 'indices.putTemplate', { - name, - body: template, - }); - } - - private callWithUser(user: FrameworkUser, esMethod: string, options: any = {}): any { - if (user.kind === 'authenticated') { - return this.es - .asScoped({ - headers: user[internalAuthData], - }) - .callAsCurrentUser(esMethod, options); - } else if (user.kind === 'internal') { - return this.es.callAsInternalUser(esMethod, options); - } else { - throw new Error('Invalid user type'); - } - } -} diff --git a/x-pack/plugins/beats_management/server/lib/adapters/framework/adapter_types.ts b/x-pack/plugins/beats_management/server/lib/adapters/framework/adapter_types.ts deleted file mode 100644 index f4102b767c044..0000000000000 --- a/x-pack/plugins/beats_management/server/lib/adapters/framework/adapter_types.ts +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -/* eslint-disable @typescript-eslint/no-empty-interface */ - -import * as t from 'io-ts'; -import { Headers, KibanaRequest } from 'src/core/server'; - -export const internalAuthData = Symbol('internalAuthData'); -export const internalUser: FrameworkInternalUser = { - kind: 'internal', -}; - -export interface BackendFrameworkAdapter { - getUser(request: KibanaRequest): FrameworkUser; - internalUser: FrameworkInternalUser; - info: null | FrameworkInfo; - log(text: string): void; -} - -export const RuntimeFrameworkInfo = t.interface( - { - kibana: t.type({ - version: t.string, - }), - license: t.type({ - type: t.keyof({ - oss: null, - trial: null, - standard: null, - basic: null, - gold: null, - platinum: null, - enterprise: null, - }), - expired: t.boolean, - expiry_date_in_millis: t.number, - }), - security: t.type({ - enabled: t.boolean, - available: t.boolean, - }), - watcher: t.type({ - enabled: t.boolean, - available: t.boolean, - }), - }, - 'FrameworkInfo' -); -export interface FrameworkInfo extends t.TypeOf {} - -export const RuntimeKibanaServerRequest = t.interface( - { - params: t.object, - payload: t.object, - query: t.object, - headers: t.type({ - authorization: t.union([t.string, t.null]), - }), - info: t.type({ - remoteAddress: t.string, - }), - }, - 'KibanaServerRequest' -); -export interface KibanaServerRequest extends t.TypeOf {} - -export const RuntimeKibanaUser = t.interface( - { - username: t.string, - roles: t.readonlyArray(t.string), - full_name: t.union([t.null, t.string]), - email: t.union([t.null, t.string]), - enabled: t.boolean, - }, - 'KibanaUser' -); -export interface KibanaUser extends t.TypeOf {} - -export interface FrameworkAuthenticatedUser { - kind: 'authenticated'; - [internalAuthData]: AuthDataType; - username: string; - roles: readonly string[]; - full_name: string | null; - email: string | null; - enabled: boolean; -} - -export interface FrameworkUnAuthenticatedUser { - kind: 'unauthenticated'; -} - -export interface FrameworkInternalUser { - kind: 'internal'; -} - -export type FrameworkUser = - | FrameworkAuthenticatedUser - | FrameworkUnAuthenticatedUser - | FrameworkInternalUser; -export interface FrameworkRequest< - KibanaServerRequestGenaric extends Partial = any -> { - user: FrameworkUser; - headers: KibanaServerRequestGenaric['headers']; - info: KibanaServerRequest['info']; - payload: KibanaServerRequestGenaric['payload']; - params: KibanaServerRequestGenaric['params']; - query: KibanaServerRequestGenaric['query']; -} diff --git a/x-pack/plugins/beats_management/server/lib/adapters/framework/kibana_framework_adapter.ts b/x-pack/plugins/beats_management/server/lib/adapters/framework/kibana_framework_adapter.ts deleted file mode 100644 index dcacde81ce8b3..0000000000000 --- a/x-pack/plugins/beats_management/server/lib/adapters/framework/kibana_framework_adapter.ts +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { PathReporter } from 'io-ts/lib/PathReporter'; -import { isLeft } from 'fp-ts/lib/Either'; -import { KibanaRequest, Headers, Logger } from 'src/core/server'; -import { - BackendFrameworkAdapter, - FrameworkInfo, - FrameworkUser, - internalAuthData, - internalUser, - RuntimeFrameworkInfo, - RuntimeKibanaUser, -} from './adapter_types'; -import { BeatsManagementConfigType } from '../../../../common'; -import { ILicense, LicensingPluginStart } from '../../../../../licensing/server'; -import { SecurityPluginSetup } from '../../../../../security/server'; - -export class KibanaBackendFrameworkAdapter implements BackendFrameworkAdapter { - public readonly internalUser = internalUser; - public info: null | FrameworkInfo = null; - - constructor( - private readonly PLUGIN_ID: string, - private readonly kibanaVersion: string, - private readonly config: BeatsManagementConfigType, - private readonly logger: Logger, - private readonly licensing: LicensingPluginStart, - private readonly security?: SecurityPluginSetup - ) { - this.licensing.license$.subscribe((license) => this.licenseUpdateHandler(license)); - } - - public log(text: string) { - this.logger.info(text); - } - - getUser(request: KibanaRequest): FrameworkUser { - const user = this.security?.authc.getCurrentUser(request); - if (!user) { - return { - kind: 'unauthenticated', - }; - } - const assertKibanaUser = RuntimeKibanaUser.decode(user); - if (isLeft(assertKibanaUser)) { - throw new Error( - `Error parsing user info in ${this.PLUGIN_ID}, ${ - PathReporter.report(assertKibanaUser)[0] - }` - ); - } - - return { - kind: 'authenticated', - [internalAuthData]: request.headers, - ...user, - }; - } - - private licenseUpdateHandler = (license: ILicense) => { - let xpackInfoUnpacked: FrameworkInfo; - - // If, for some reason, we cannot get the license information - // from Elasticsearch, assume worst case and disable - if (!license.isAvailable) { - this.info = null; - return; - } - - const securityFeature = license.getFeature('security'); - const watcherFeature = license.getFeature('watcher'); - - try { - xpackInfoUnpacked = { - kibana: { - version: this.kibanaVersion, - }, - license: { - type: license.type!, - expired: !license.isActive, - expiry_date_in_millis: license.expiryDateInMillis ?? -1, - }, - security: { - enabled: securityFeature.isEnabled, - available: securityFeature.isAvailable, - }, - watcher: { - enabled: watcherFeature.isEnabled, - available: watcherFeature.isAvailable, - }, - }; - } catch (e) { - this.logger.error(`Error accessing required xPackInfo in ${this.PLUGIN_ID} Kibana adapter`); - throw e; - } - - const assertData = RuntimeFrameworkInfo.decode(xpackInfoUnpacked); - if (isLeft(assertData)) { - throw new Error( - `Error parsing xpack info in ${this.PLUGIN_ID}, ${PathReporter.report(assertData)[0]}` - ); - } - this.info = xpackInfoUnpacked; - - return { - security: xpackInfoUnpacked.security, - settings: { ...this.config }, - }; - }; -} diff --git a/x-pack/plugins/beats_management/server/lib/adapters/tags/adapter_types.ts b/x-pack/plugins/beats_management/server/lib/adapters/tags/adapter_types.ts deleted file mode 100644 index 6e1ad59ce0c71..0000000000000 --- a/x-pack/plugins/beats_management/server/lib/adapters/tags/adapter_types.ts +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { BeatTag } from '../../../../common/domain_types'; -import { FrameworkUser } from '../framework/adapter_types'; - -export interface CMTagsAdapter { - getAll(user: FrameworkUser, ESQuery?: any): Promise; - delete(user: FrameworkUser, tagIds: string[]): Promise; - getTagsWithIds(user: FrameworkUser, tagIds: string[]): Promise; - upsertTag(user: FrameworkUser, tag: BeatTag): Promise; - getWithoutConfigTypes(user: FrameworkUser, blockTypes: string[]): Promise; -} diff --git a/x-pack/plugins/beats_management/server/lib/adapters/tags/elasticsearch_tags_adapter.ts b/x-pack/plugins/beats_management/server/lib/adapters/tags/elasticsearch_tags_adapter.ts deleted file mode 100644 index bfc6993fcb025..0000000000000 --- a/x-pack/plugins/beats_management/server/lib/adapters/tags/elasticsearch_tags_adapter.ts +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { flatten, get } from 'lodash'; -import { INDEX_NAMES } from '../../../../common/constants'; -import { BeatTag } from '../../../../common/domain_types'; -import { DatabaseAdapter } from '../database/adapter_types'; -import { FrameworkUser } from '../framework/adapter_types'; -import { CMTagsAdapter } from './adapter_types'; - -export class ElasticsearchTagsAdapter implements CMTagsAdapter { - private database: DatabaseAdapter; - - constructor(database: DatabaseAdapter) { - this.database = database; - } - - public async getAll(user: FrameworkUser, ESQuery?: any): Promise { - const params = { - ignore: [404], - _source: true, - size: 10000, - index: INDEX_NAMES.BEATS, - body: { - query: { - bool: { - must: { - term: { - type: 'tag', - }, - }, - }, - }, - }, - }; - if (ESQuery) { - params.body.query = { - ...params.body.query, - ...ESQuery, - }; - } - const response = await this.database.search(user, params); - const tags = get(response, 'hits.hits', []) as any; - - return tags.map((tag: any) => ({ hasConfigurationBlocksTypes: [], ...tag._source.tag })); - } - - public async delete(user: FrameworkUser, tagIds: string[]): Promise { - const ids = tagIds.map((tag) => tag); - - const params = { - ignore: [404], - index: INDEX_NAMES.BEATS, - body: { - query: { - terms: { 'beat.tags': tagIds }, - }, - }, - }; - - const beatsResponse = await this.database.search(user, params); - - const beats = (get(beatsResponse, 'hits.hits', []) as BeatTag[]).map( - (beat: any) => beat._source.beat - ); - - const inactiveBeats = beats.filter((beat) => beat.active === false); - const activeBeats = beats.filter((beat) => beat.active === true); - if (activeBeats.length !== 0) { - return false; - } - const beatIds = inactiveBeats.map((beat: BeatTag) => beat.id); - - // While we block tag deletion when on an active beat, we should remove from inactive - const bulkInactiveBeatsUpdates = flatten( - beatIds.map((beatId) => { - const script = ` - def beat = ctx._source.beat; - if (beat.tags != null) { - beat.tags.removeAll([params.tag]); - }`; - - return flatten( - ids.map((tagId) => [ - { update: { _id: `beat:${beatId}` } }, - { script: { source: script.replace(' ', ''), params: { tagId } } }, - ]) - ); - }) - ); - - const bulkTagsDelete = ids.map((tagId) => ({ delete: { _id: `tag:${tagId}` } })); - - await this.database.bulk(user, { - body: flatten([...bulkInactiveBeatsUpdates, ...bulkTagsDelete]), - index: INDEX_NAMES.BEATS, - refresh: 'wait_for', - }); - - return true; - } - - public async getTagsWithIds(user: FrameworkUser, tagIds: string[]): Promise { - if (tagIds.length === 0) { - return []; - } - const ids = tagIds.map((tag) => `tag:${tag}`); - - const params = { - ignore: [404], - _source: true, - body: { - ids, - }, - index: INDEX_NAMES.BEATS, - }; - const response = await this.database.mget(user, params); - - return get(response, 'docs', []) - .filter((b: any) => b.found) - .map((b: any) => ({ - hasConfigurationBlocksTypes: [], - ...b._source.tag, - id: b._id.replace('tag:', ''), - })); - } - - public async upsertTag(user: FrameworkUser, tag: BeatTag): Promise { - const body = { - tag, - type: 'tag', - }; - - const params = { - body, - id: `tag:${tag.id}`, - index: INDEX_NAMES.BEATS, - refresh: 'wait_for', - }; - const response = await this.database.index(user, params); - - return get(response, 'result') as string; - } - - public async getWithoutConfigTypes( - user: FrameworkUser, - blockTypes: string[] - ): Promise { - const body = { - query: { - bool: { - filter: { - match: { - type: 'tag', - }, - }, - must_not: { - terms: { 'tag.hasConfigurationBlocksTypes': blockTypes }, - }, - }, - }, - }; - - const params = { - body, - index: INDEX_NAMES.BEATS, - ignore: [404], - _source: true, - size: 10000, - }; - const response = await this.database.search(user, params); - const tags = get(response, 'hits.hits', []) as any; - - return tags.map((tag: any) => ({ hasConfigurationBlocksTypes: [], ...tag._source.tag })); - } -} diff --git a/x-pack/plugins/beats_management/server/lib/adapters/tokens/adapter_types.ts b/x-pack/plugins/beats_management/server/lib/adapters/tokens/adapter_types.ts deleted file mode 100644 index a7d45490ada38..0000000000000 --- a/x-pack/plugins/beats_management/server/lib/adapters/tokens/adapter_types.ts +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { FrameworkUser } from '../framework/adapter_types'; - -export interface TokenEnrollmentData { - token: string | null; - expires_on: string; -} - -export interface CMTokensAdapter { - deleteEnrollmentToken(user: FrameworkUser, enrollmentToken: string): Promise; - getEnrollmentToken(user: FrameworkUser, enrollmentToken: string): Promise; - insertTokens(user: FrameworkUser, tokens: TokenEnrollmentData[]): Promise; -} diff --git a/x-pack/plugins/beats_management/server/lib/adapters/tokens/elasticsearch_tokens_adapter.ts b/x-pack/plugins/beats_management/server/lib/adapters/tokens/elasticsearch_tokens_adapter.ts deleted file mode 100644 index 849602564347e..0000000000000 --- a/x-pack/plugins/beats_management/server/lib/adapters/tokens/elasticsearch_tokens_adapter.ts +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { flatten, get } from 'lodash'; -import { INDEX_NAMES } from '../../../../common/constants'; -import { DatabaseAdapter } from '../database/adapter_types'; -import { FrameworkUser } from '../framework/adapter_types'; -import { CMTokensAdapter, TokenEnrollmentData } from './adapter_types'; - -export class ElasticsearchTokensAdapter implements CMTokensAdapter { - constructor(private readonly database: DatabaseAdapter) {} - - public async deleteEnrollmentToken(user: FrameworkUser, enrollmentToken: string) { - const params = { - id: `enrollment_token:${enrollmentToken}`, - index: INDEX_NAMES.BEATS, - }; - - await this.database.delete(user, params); - } - - public async getEnrollmentToken( - user: FrameworkUser, - tokenString: string - ): Promise { - const params = { - id: `enrollment_token:${tokenString}`, - ignore: [404], - index: INDEX_NAMES.BEATS, - }; - - const response = await this.database.get(user, params); - - const tokenDetails = get(response, '_source.enrollment_token', { - expires_on: '0', - token: null, - }) as TokenEnrollmentData; - - // Elasticsearch might return fast if the token is not found. OR it might return fast - // if the token *is* found. Either way, an attacker could using a timing attack to figure - // out whether a token is valid or not. So we introduce a random delay in returning from - // this function to obscure the actual time it took for Elasticsearch to find the token. - const randomDelayInMs = 25 + Math.round(Math.random() * 200); // between 25 and 225 ms - return new Promise((resolve) => - setTimeout(() => resolve(tokenDetails), randomDelayInMs) - ); - } - - public async insertTokens(user: FrameworkUser, tokens: TokenEnrollmentData[]) { - const body = flatten( - tokens.map((token) => [ - { index: { _id: `enrollment_token:${token.token}` } }, - { - enrollment_token: token, - type: 'enrollment_token', - }, - ]) - ); - - const result = await this.database.bulk(user, { - body, - index: INDEX_NAMES.BEATS, - refresh: 'wait_for', - }); - - if (result.errors) { - throw new Error(result.items[0].result); - } - - return tokens; - } -} diff --git a/x-pack/plugins/beats_management/server/lib/beat_events.ts b/x-pack/plugins/beats_management/server/lib/beat_events.ts deleted file mode 100644 index ffe77f8d99fff..0000000000000 --- a/x-pack/plugins/beats_management/server/lib/beat_events.ts +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { PathReporter } from 'io-ts/lib/PathReporter'; -import { isLeft } from 'fp-ts/lib/Either'; -import { BeatEvent, RuntimeBeatEvent } from '../../common/domain_types'; -import { FrameworkUser } from './adapters/framework/adapter_types'; -import { CMBeatsDomain } from './beats'; - -export class BeatEventsLib { - constructor(private readonly beats: CMBeatsDomain) {} - - public log = async ( - user: FrameworkUser, - beatId: string, - events: BeatEvent[] - ): Promise> => { - return events.map((event, i) => { - const assertData = RuntimeBeatEvent.decode(event); - if (isLeft(assertData)) { - if (events.length - 1 === i) { - this.beats - .update(user, beatId, { - status: { - ...events[events.length - 2], - timestamp: new Date(events[events.length - 2].timestamp), - }, - }) - .catch((e) => { - // eslint-disable-next-line - console.error('Error inserting event into beats log.', e); - }); - } - return { - success: false, - error: `Error parsing event ${i}, ${PathReporter.report(assertData)[0]}`, - }; - } - if (events.length - 1 === i) { - this.beats - .update(user, beatId, { - status: { - ...events[events.length - 1], - timestamp: new Date(events[events.length - 1].timestamp), - }, - }) - .catch((e) => { - // eslint-disable-next-line - console.error('Error inserting event into beats log.', e); - }); - } - return { success: true }; - }); - }; -} diff --git a/x-pack/plugins/beats_management/server/lib/beats.ts b/x-pack/plugins/beats_management/server/lib/beats.ts deleted file mode 100644 index de3fce4011a3d..0000000000000 --- a/x-pack/plugins/beats_management/server/lib/beats.ts +++ /dev/null @@ -1,260 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { uniq } from 'lodash'; -import moment from 'moment'; -import { CMBeat } from '../../common/domain_types'; -import { - BeatsRemovalReturn, - BeatsTagAssignment, - CMAssignmentReturn, - CMBeatsAdapter, -} from './adapters/beats/adapter_types'; -import { FrameworkUser } from './adapters/framework/adapter_types'; -import { BeatEnrollmentStatus, CMServerLibs, UserOrToken } from './types'; - -export class CMBeatsDomain { - private tags: CMServerLibs['tags']; - private tokens: CMServerLibs['tokens']; - private framework: CMServerLibs['framework']; - - constructor( - private readonly adapter: CMBeatsAdapter, - libs: { - tags: CMServerLibs['tags']; - tokens: CMServerLibs['tokens']; - framework: CMServerLibs['framework']; - } - ) { - this.adapter = adapter; - this.tags = libs.tags; - this.tokens = libs.tokens; - this.framework = libs.framework; - } - - public async getById(user: FrameworkUser, beatId: string): Promise { - const beat = await this.adapter.get(user, beatId); - return beat && beat.active ? beat : null; - } - - public async getByIds(user: FrameworkUser, beatIds: string[]): Promise { - const beats = await this.adapter.getWithIds(user, beatIds); - return beats.filter((beat) => beat.active); - } - - public async getAll(user: FrameworkUser, ESQuery?: any) { - return (await this.adapter.getAll(user, ESQuery)).filter( - (beat: CMBeat) => beat.active === true - ); - } - - public async getAllWithTag(user: FrameworkUser, tagId: string) { - return (await this.adapter.getAllWithTags(user, [tagId])).filter( - (beat: CMBeat) => beat.active === true - ); - } - - public async getByEnrollmentToken(user: FrameworkUser, enrollmentToken: string) { - const beat = await this.adapter.getBeatWithToken(user, enrollmentToken); - return beat && beat.active ? beat : null; - } - - public async update(userOrToken: UserOrToken, beatId: string, beatData: Partial) { - const beat = await this.adapter.get(this.framework.internalUser, beatId); - - // FIXME make return type enum - if (beat === null) { - return 'beat-not-found'; - } - - if (typeof userOrToken === 'string') { - const { verified: isAccessTokenValid } = this.tokens.verifyToken( - beat?.access_token ?? '', - userOrToken - ); - if (!isAccessTokenValid) { - return 'invalid-access-token'; - } - } - - const user = typeof userOrToken === 'string' ? this.framework.internalUser : userOrToken; - await this.adapter.update(user, { - ...beat, - ...beatData, - }); - } - - public async enrollBeat( - enrollmentToken: string, - beatId: string, - remoteAddress: string, - beat: Partial - ): Promise<{ status: string; accessToken?: string }> { - // eslint-disable-next-line @typescript-eslint/naming-convention - const { token, expires_on } = await this.tokens.getEnrollmentToken(enrollmentToken); - if (expires_on && moment(expires_on).isBefore(moment())) { - return { status: BeatEnrollmentStatus.ExpiredEnrollmentToken }; - } - if (!token) { - return { status: BeatEnrollmentStatus.InvalidEnrollmentToken }; - } - - const existingBeat = await this.getById(this.framework.internalUser, beatId); - if (existingBeat) { - return { status: BeatEnrollmentStatus.Success }; - } - - const accessToken = this.tokens.generateAccessToken(); - const verifiedOn = moment().toJSON(); - - await this.adapter.insert(this.framework.internalUser, { - tags: [], - ...beat, - active: true, - enrollment_token: enrollmentToken, - verified_on: verifiedOn, - access_token: accessToken, - host_ip: remoteAddress, - id: beatId, - } as CMBeat); - - await this.tokens.deleteEnrollmentToken(enrollmentToken); - - return { status: BeatEnrollmentStatus.Success, accessToken }; - } - - public async removeTagsFromBeats( - user: FrameworkUser, - removals: BeatsTagAssignment[] - ): Promise { - const beatIds = uniq(removals.map((removal) => removal.beatId)); - const tagIds = uniq(removals.map((removal) => removal.tag)); - - const response = { - removals: removals.map(() => ({ status: null })), - }; - - const beats = await this.adapter.getWithIds(user, beatIds); - const tags = await this.tags.getWithIds(user, tagIds); - - // Handle assignments containing non-existing beat IDs or tags - const nonExistentBeatIds = findNonExistentItems(beats, beatIds); - const nonExistentTags = await findNonExistentItems(tags, tagIds); - - addNonExistentItemToResponse( - response, - removals, - nonExistentBeatIds, - nonExistentTags, - 'removals' - ); - - // FIXME abstract this - const validRemovals = removals - .map((removal, idxInRequest) => ({ - beatId: removal.beatId, - idxInRequest, // so we can add the result of this removal to the correct place in the response - tag: removal.tag, - })) - .filter((removal, idx) => response.removals[idx].status === null); - - if (validRemovals.length > 0) { - const removalResults = await this.adapter.removeTagsFromBeats(user, validRemovals); - return addToResultsToResponse('removals', response, removalResults); - } - return response; - } - - public async assignTagsToBeats( - user: FrameworkUser, - assignments: BeatsTagAssignment[] - ): Promise { - const beatIds = uniq(assignments.map((assignment) => assignment.beatId)); - const tagIds = uniq(assignments.map((assignment) => assignment.tag)); - - const response = { - assignments: assignments.map(() => ({ status: null })), - }; - const beats = await this.adapter.getWithIds(user, beatIds); - const tags = await this.tags.getWithIds(user, tagIds); - // Handle assignments containing non-existing beat IDs or tags - const nonExistentBeatIds = findNonExistentItems(beats, beatIds); - const nonExistentTags = findNonExistentItems(tags, tagIds); - - // FIXME break out back into route / function response - // FIXME causes function to error if a beat or tag does not exist - addNonExistentItemToResponse( - response, - assignments, - nonExistentBeatIds, - nonExistentTags, - 'assignments' - ); - - // FIXME abstract this - const validAssignments = assignments - .map((assignment, idxInRequest) => ({ - beatId: assignment.beatId, - idxInRequest, // so we can add the result of this assignment to the correct place in the response - tag: assignment.tag, - })) - .filter((assignment, idx) => response.assignments[idx].status === null); - - if (validAssignments.length > 0) { - const assignmentResults = await this.adapter.assignTagsToBeats(user, validAssignments); - - // TODO This should prob not mutate - return addToResultsToResponse('assignments', response, assignmentResults); - } - return response; - } -} - -// FIXME abstract to the route, also the key arg is a temp fix -function addNonExistentItemToResponse( - response: any, - assignments: any, - nonExistentBeatIds: any, - nonExistentTags: any, - key: string -) { - assignments.forEach(({ beatId, tag }: BeatsTagAssignment, idx: any) => { - const isBeatNonExistent = nonExistentBeatIds.includes(beatId); - - const isTagNonExistent = nonExistentTags.includes(tag); - - if (isBeatNonExistent && isTagNonExistent) { - response[key][idx].status = 404; - response[key][idx].result = `Beat ${beatId} and tag ${tag} not found`; - } else if (isBeatNonExistent) { - response[key][idx].status = 404; - response[key][idx].result = `Beat ${beatId} not found`; - } else if (isTagNonExistent) { - response[key][idx].status = 404; - response[key][idx].result = `Tag ${tag} not found`; - } - }); -} - -// TODO dont mutate response -function addToResultsToResponse(key: string, response: any, assignmentResults: any) { - assignmentResults.forEach((assignmentResult: any) => { - const { idxInRequest, status, result } = assignmentResult; - response[key][idxInRequest].status = status; - response[key][idxInRequest].result = result; - }); - return response; -} - -export function findNonExistentItems(items: Array<{ id: string }>, requestedItems: string[]) { - return requestedItems.reduce((nonExistentItems: string[], requestedItem: string, idx: number) => { - if (items.findIndex((item) => item && item.id === requestedItem) === -1) { - nonExistentItems.push(requestedItems[idx]); - } - return nonExistentItems; - }, []); -} diff --git a/x-pack/plugins/beats_management/server/lib/compose/kibana.ts b/x-pack/plugins/beats_management/server/lib/compose/kibana.ts deleted file mode 100644 index d3606bf24071d..0000000000000 --- a/x-pack/plugins/beats_management/server/lib/compose/kibana.ts +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { camelCase } from 'lodash'; -import type { ElasticsearchServiceStart, Logger } from 'src/core/server'; -import { SecurityPluginSetup } from '../../../../security/server'; -import { LicensingPluginStart } from '../../../../licensing/server'; -import { PLUGIN } from '../../../common/constants'; -import { BeatsManagementConfigType } from '../../../common'; -import { ElasticsearchBeatsAdapter } from '../adapters/beats/elasticsearch_beats_adapter'; -import { ElasticsearchConfigurationBlockAdapter } from '../adapters/configuration_blocks/elasticsearch_configuration_block_adapter'; -import { KibanaDatabaseAdapter } from '../adapters/database/kibana_database_adapter'; -import { KibanaBackendFrameworkAdapter } from '../adapters/framework/kibana_framework_adapter'; -import { ElasticsearchTagsAdapter } from '../adapters/tags/elasticsearch_tags_adapter'; -import { ElasticsearchTokensAdapter } from '../adapters/tokens/elasticsearch_tokens_adapter'; -import { BeatEventsLib } from '../beat_events'; -import { CMBeatsDomain } from '../beats'; -import { ConfigurationBlocksLib } from '../configuration_blocks'; -import { CMTagsDomain } from '../tags'; -import { CMTokensDomain } from '../tokens'; -import { CMServerLibs } from '../types'; -import { BackendFrameworkLib } from './../framework'; - -interface ComposeOptions { - elasticsearch: ElasticsearchServiceStart; - licensing: LicensingPluginStart; - security?: SecurityPluginSetup; - config: BeatsManagementConfigType; - logger: Logger; - kibanaVersion: string; -} - -export function compose({ - elasticsearch, - config, - kibanaVersion, - logger, - licensing, - security, -}: ComposeOptions): CMServerLibs { - const backendAdapter = new KibanaBackendFrameworkAdapter( - camelCase(PLUGIN.ID), - kibanaVersion, - config, - logger, - licensing, - security - ); - const framework = new BackendFrameworkLib(backendAdapter, config); - const database = new KibanaDatabaseAdapter(elasticsearch); - const beatsAdapter = new ElasticsearchBeatsAdapter(database); - const configAdapter = new ElasticsearchConfigurationBlockAdapter(database); - - const tags = new CMTagsDomain( - new ElasticsearchTagsAdapter(database), - configAdapter, - beatsAdapter - ); - const configurationBlocks = new ConfigurationBlocksLib(configAdapter, tags); - const tokens = new CMTokensDomain(new ElasticsearchTokensAdapter(database), { - framework, - }); - const beats = new CMBeatsDomain(beatsAdapter, { - tags, - tokens, - framework, - }); - const beatEvents = new BeatEventsLib(beats); - - const libs: CMServerLibs = { - beatEvents, - framework, - database, - beats, - tags, - tokens, - configurationBlocks, - }; - - return libs; -} diff --git a/x-pack/plugins/beats_management/server/lib/configuration_blocks.ts b/x-pack/plugins/beats_management/server/lib/configuration_blocks.ts deleted file mode 100644 index 06f1674af93fb..0000000000000 --- a/x-pack/plugins/beats_management/server/lib/configuration_blocks.ts +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { UNIQUENESS_ENFORCING_TYPES } from '../../common/constants/configuration_blocks'; -import { ConfigurationBlock } from '../../common/domain_types'; -import { ConfigurationBlockAdapter } from './adapters/configuration_blocks/adapter_types'; -import { FrameworkUser } from './adapters/framework/adapter_types'; -import { CMTagsDomain } from './tags'; - -export class ConfigurationBlocksLib { - constructor( - private readonly adapter: ConfigurationBlockAdapter, - private readonly tags: CMTagsDomain - ) {} - - public async getForTags( - user: FrameworkUser, - tagIds: string[], - page: number = 0, - size: number = 10 - ) { - if ((page + 1) * size > 10000) { - throw new Error('System error, too many results. To get all results, request page: -1'); - } - - const result = await this.adapter.getForTags(user, tagIds, page, size); - - return { ...result, error: null }; - } - - public async delete(user: FrameworkUser, ids: string[]) { - return await this.adapter.delete(user, ids); - } - - public async save(user: FrameworkUser, block: ConfigurationBlock) { - const tags = await this.tags.getWithIds(user, [block.tag]); - const tag = tags[0]; - - if (!tag) { - return { - error: 'Invalid tag, tag not found', - }; - } - - if (!tag.hasConfigurationBlocksTypes) { - tag.hasConfigurationBlocksTypes = []; - } - - if ( - !block.id && - UNIQUENESS_ENFORCING_TYPES.includes(block.type) && - tag.hasConfigurationBlocksTypes.some((type: string) => - UNIQUENESS_ENFORCING_TYPES.includes(type) - ) - ) { - return { - error: - 'Block is of type that already exists on this tag, and only one config of this type can exist at a time on a beat. Config not saved', - }; - } - - if (UNIQUENESS_ENFORCING_TYPES.includes(block.type)) { - tag.hasConfigurationBlocksTypes.push(block.type); - await this.tags.upsertTag(user, tag); - } - - const ids = await this.adapter.create(user, [block]); - return { - success: true, - blockID: ids[0], - }; - } -} diff --git a/x-pack/plugins/beats_management/server/lib/framework.ts b/x-pack/plugins/beats_management/server/lib/framework.ts deleted file mode 100644 index 072bbae6d46c0..0000000000000 --- a/x-pack/plugins/beats_management/server/lib/framework.ts +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { Headers, KibanaRequest } from 'kibana/server'; -import { BackendFrameworkAdapter, FrameworkUser } from './adapters/framework/adapter_types'; -import { BeatsManagementConfigType } from '../../common'; - -export class BackendFrameworkLib { - public log = this.adapter.log; - public internalUser = this.adapter.internalUser; - - constructor( - private readonly adapter: BackendFrameworkAdapter, - private readonly config: BeatsManagementConfigType - ) { - this.validateConfig(); - } - - public getConfig(): BeatsManagementConfigType { - return this.config; - } - - public getUser(request: KibanaRequest): FrameworkUser { - return this.adapter.getUser(request); - } - - /** - * Expired `null` happens when we have no xpack info - */ - public get license() { - return { - type: this.adapter.info ? this.adapter.info.license.type : 'unknown', - expired: this.adapter.info ? this.adapter.info.license.expired : null, - }; - } - - public get securityIsEnabled() { - return this.adapter.info ? this.adapter.info.security.enabled : false; - } - - private validateConfig() { - const encryptionKey = this.config.encryptionKey; - - if (!encryptionKey) { - this.adapter.log( - 'Using a default encryption key for xpack.beats.encryptionKey. It is recommended that you set xpack.beats.encryptionKey in kibana.yml with a unique token' - ); - } - } -} diff --git a/x-pack/plugins/beats_management/server/lib/tags.ts b/x-pack/plugins/beats_management/server/lib/tags.ts deleted file mode 100644 index 2750e73b898b0..0000000000000 --- a/x-pack/plugins/beats_management/server/lib/tags.ts +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { uniq } from 'lodash'; -import { UNIQUENESS_ENFORCING_TYPES } from '../../common/constants/configuration_blocks'; -import { BeatTag } from '../../common/domain_types'; -import { CMBeatsAdapter } from './adapters/beats/adapter_types'; -import { ConfigurationBlockAdapter } from './adapters/configuration_blocks/adapter_types'; -import { FrameworkUser } from './adapters/framework/adapter_types'; -import { CMTagsAdapter } from './adapters/tags/adapter_types'; - -export class CMTagsDomain { - constructor( - private readonly adapter: CMTagsAdapter, - private readonly configurationBlocksAdapter: ConfigurationBlockAdapter, - private readonly beatsAdabter: CMBeatsAdapter - ) {} - - public async getAll(user: FrameworkUser, ESQuery?: any): Promise { - const tags = await this.adapter.getAll(user, ESQuery); - return tags; - } - - public async getWithIds(user: FrameworkUser, tagIds: string[]): Promise { - const tags = await this.adapter.getTagsWithIds(user, tagIds); - return tags; - } - - public async delete(user: FrameworkUser, tagIds: string[]) { - const beats = await this.beatsAdabter.getAllWithTags(user, tagIds); - if (beats.filter((b) => b.active).length > 0) { - return false; - } - await this.configurationBlocksAdapter.deleteForTags(user, tagIds); - return await this.adapter.delete(user, tagIds); - } - - public async getNonConflictingTags(user: FrameworkUser, existingTagIds: string[]) { - const tags = await this.adapter.getTagsWithIds(user, existingTagIds); - const existingUniqueBlockTypes = uniq( - tags.reduce((existingUniqueTypes, tag) => { - if (tag.hasConfigurationBlocksTypes) { - existingUniqueTypes = existingUniqueTypes.concat(tag.hasConfigurationBlocksTypes); - } - return existingUniqueTypes; - }, [] as string[]) - ).filter((type) => UNIQUENESS_ENFORCING_TYPES.includes(type)); - - const safeTags = await this.adapter.getWithoutConfigTypes(user, existingUniqueBlockTypes); - return safeTags; - } - - public async upsertTag(user: FrameworkUser, tag: BeatTag): Promise { - const tagId = await this.adapter.upsertTag(user, tag); - - return tagId; - } -} diff --git a/x-pack/plugins/beats_management/server/lib/tokens.ts b/x-pack/plugins/beats_management/server/lib/tokens.ts deleted file mode 100644 index 8ff130190f661..0000000000000 --- a/x-pack/plugins/beats_management/server/lib/tokens.ts +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { randomBytes, timingSafeEqual } from 'crypto'; -import { sign as signToken, verify as verifyToken } from 'jsonwebtoken'; -import { chunk } from 'lodash'; -import moment from 'moment'; -import { FrameworkUser } from './adapters/framework/adapter_types'; -import { CMTokensAdapter } from './adapters/tokens/adapter_types'; -import { CMServerLibs } from './types'; - -const RANDOM_TOKEN_1 = 'b48c4bda384a40cb91c6eb9b8849e77f'; -const RANDOM_TOKEN_2 = '80a3819e3cd64f4399f1d4886be7a08b'; - -export class CMTokensDomain { - private adapter: CMTokensAdapter; - private framework: CMServerLibs['framework']; - - constructor(adapter: CMTokensAdapter, libs: { framework: CMServerLibs['framework'] }) { - this.adapter = adapter; - this.framework = libs.framework; - } - - public async getEnrollmentToken(enrollmentToken: string) { - const fullToken = await this.adapter.getEnrollmentToken( - this.framework.internalUser, - enrollmentToken - ); - if (!fullToken) { - return { - token: null, - expired: true, - expires_on: null, - }; - } - - const { verified, expired } = this.verifyToken(enrollmentToken, fullToken.token || '', false); - - if (!verified) { - return { - expired, - token: null, - expires_on: null, - }; - } - - return { ...fullToken, expired }; - } - - public async deleteEnrollmentToken(enrollmentToken: string) { - return await this.adapter.deleteEnrollmentToken(this.framework.internalUser, enrollmentToken); - } - - public verifyToken(recivedToken: string, token2: string, decode = true) { - let tokenDecoded = true; - let expired = false; - - if (decode) { - const enrollmentTokenSecret = this.framework.getConfig().encryptionKey; - - try { - verifyToken(recivedToken, enrollmentTokenSecret); - tokenDecoded = true; - } catch (err) { - if (err.name === 'TokenExpiredError') { - expired = true; - } - tokenDecoded = false; - } - } - - if ( - typeof recivedToken !== 'string' || - typeof token2 !== 'string' || - recivedToken.length !== token2.length - ) { - // This prevents a more subtle timing attack where we know already the tokens aren't going to - // match but still we don't return fast. Instead we compare two pre-generated random tokens using - // the same comparison algorithm that we would use to compare two equal-length tokens. - return { - expired, - verified: - timingSafeEqual( - Buffer.from(RANDOM_TOKEN_1, 'utf8'), - Buffer.from(RANDOM_TOKEN_2, 'utf8') - ) && tokenDecoded, - }; - } - - return { - expired, - verified: - timingSafeEqual(Buffer.from(recivedToken, 'utf8'), Buffer.from(token2, 'utf8')) && - tokenDecoded, - }; - } - - public generateAccessToken() { - const enrollmentTokenSecret = this.framework.getConfig().encryptionKey; - - const tokenData = { - created: moment().toJSON(), - randomHash: randomBytes(26).toString(), - }; - - return signToken(tokenData, enrollmentTokenSecret); - } - - public async createEnrollmentTokens( - user: FrameworkUser, - numTokens: number = 1 - ): Promise { - const tokens = []; - const enrollmentTokensTtlInSeconds = this.framework.getConfig().enrollmentTokensTtlInSeconds; - - const enrollmentTokenExpiration = moment() - .add(enrollmentTokensTtlInSeconds, 'seconds') - .toJSON(); - const enrollmentTokenSecret = this.framework.getConfig().encryptionKey; - - while (tokens.length < numTokens) { - const tokenData = { - created: moment().toJSON(), - expires: enrollmentTokenExpiration, - randomHash: randomBytes(26).toString(), - }; - - tokens.push({ - expires_on: enrollmentTokenExpiration, - token: signToken(tokenData, enrollmentTokenSecret), - }); - } - - await Promise.all( - chunk(tokens, 100).map((tokenChunk) => this.adapter.insertTokens(user, tokenChunk)) - ); - - return tokens.map((token) => token.token); - } -} diff --git a/x-pack/plugins/beats_management/server/lib/types.ts b/x-pack/plugins/beats_management/server/lib/types.ts deleted file mode 100644 index 8342018469450..0000000000000 --- a/x-pack/plugins/beats_management/server/lib/types.ts +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { IRouter, RequestHandlerContext } from 'src/core/server'; -import { DatabaseAdapter } from './adapters/database/adapter_types'; -import { FrameworkUser } from './adapters/framework/adapter_types'; -import { BeatEventsLib } from './beat_events'; -import { CMBeatsDomain } from './beats'; -import { ConfigurationBlocksLib } from './configuration_blocks'; -import { BackendFrameworkLib } from './framework'; -import { CMTagsDomain } from './tags'; -import { CMTokensDomain } from './tokens'; - -export type UserOrToken = FrameworkUser | string; - -export interface CMServerLibs { - framework: BackendFrameworkLib; - database: DatabaseAdapter; - beats: CMBeatsDomain; - tags: CMTagsDomain; - beatEvents: BeatEventsLib; - tokens: CMTokensDomain; - configurationBlocks: ConfigurationBlocksLib; -} - -export enum BeatEnrollmentStatus { - Success = 'Success', - ExpiredEnrollmentToken = 'Expired enrollment token', - InvalidEnrollmentToken = 'Invalid enrollment token', -} - -export interface AsyncResponse { - error: { - code: number | string; - message: string; - }; -} -export interface AsyncResponse { - data: DataType; -} - -/** - * @internal - */ -export type BeatsManagementApiRequestHandlerContext = CMServerLibs; - -/** - * @internal - */ -export interface BeatsManagementRequestHandlerContext extends RequestHandlerContext { - beatsManagement: CMServerLibs; -} - -/** - * @internal - */ -export type BeatsManagementRouter = IRouter; diff --git a/x-pack/plugins/beats_management/server/plugin.ts b/x-pack/plugins/beats_management/server/plugin.ts deleted file mode 100644 index 3093d5d9b8d29..0000000000000 --- a/x-pack/plugins/beats_management/server/plugin.ts +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { CoreSetup, CoreStart, Plugin, PluginInitializerContext, Logger } from 'src/core/server'; -import { PluginSetupContract as FeaturesPluginSetup } from '../../features/server'; -import { SecurityPluginSetup } from '../../security/server'; -import { LicensingPluginStart } from '../../licensing/server'; -import { BeatsManagementConfigType } from '../common'; -import type { BeatsManagementRequestHandlerContext, CMServerLibs } from './lib/types'; -import { registerRoutes } from './routes'; -import { compose } from './lib/compose/kibana'; -import { INDEX_NAMES } from '../common/constants'; -import { beatsIndexTemplate } from './index_templates'; - -interface SetupDeps { - security?: SecurityPluginSetup; - features: FeaturesPluginSetup; -} - -interface StartDeps { - licensing: LicensingPluginStart; -} - -export class BeatsManagementPlugin implements Plugin<{}, {}, SetupDeps, StartDeps> { - private readonly logger: Logger; - private securitySetup?: SecurityPluginSetup; - private beatsLibs?: CMServerLibs; - - constructor( - private readonly initializerContext: PluginInitializerContext - ) { - this.logger = initializerContext.logger.get(); - } - - public setup(core: CoreSetup, { features, security }: SetupDeps) { - this.securitySetup = security; - - const router = core.http.createRouter(); - registerRoutes(router); - - core.http.registerRouteHandlerContext( - 'beatsManagement', - (_, req) => { - return this.beatsLibs!; - } - ); - - features.registerElasticsearchFeature({ - id: 'beats_management', - management: { - ingest: ['beats_management'], - }, - privileges: [ - { - ui: [], - requiredClusterPrivileges: [], - requiredRoles: ['beats_admin'], - }, - ], - }); - - return {}; - } - - public start({ elasticsearch }: CoreStart, { licensing }: StartDeps) { - const config = this.initializerContext.config.get(); - const logger = this.initializerContext.logger.get(); - const kibanaVersion = this.initializerContext.env.packageInfo.version; - - this.beatsLibs = compose({ - elasticsearch, - licensing, - security: this.securitySetup, - config, - logger, - kibanaVersion, - }); - - this.beatsLibs.database.putTemplate(INDEX_NAMES.BEATS, beatsIndexTemplate).catch((e) => { - this.logger.error(`Error create beats template: ${e.message}`); - }); - - return {}; - } -} diff --git a/x-pack/plugins/beats_management/server/routes/beats/configuration.ts b/x-pack/plugins/beats_management/server/routes/beats/configuration.ts deleted file mode 100644 index 2adbe46524c6a..0000000000000 --- a/x-pack/plugins/beats_management/server/routes/beats/configuration.ts +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { schema } from '@kbn/config-schema'; -import type { BeatsManagementRouter } from '../../lib/types'; -import { ConfigurationBlock } from '../../../common/domain_types'; -import { ReturnTypeList } from '../../../common/return_types'; -import { wrapRouteWithSecurity } from '../wrap_route_with_security'; - -export const registerGetBeatConfigurationRoute = (router: BeatsManagementRouter) => { - router.get( - { - path: '/api/beats/agent/{beatId}/configuration', - validate: { - params: schema.object({ - beatId: schema.string(), - }), - }, - options: { - authRequired: false, - }, - }, - wrapRouteWithSecurity({}, async (context, request, response) => { - const beatsManagement = context.beatsManagement!; - const accessToken = request.headers['kbn-beats-access-token']; - if (!accessToken) { - return response.badRequest({ - body: 'beats access token required', - }); - } - const beatId = request.params.beatId; - - let configurationBlocks: ConfigurationBlock[]; - const beat = await beatsManagement.beats.getById( - beatsManagement.framework.internalUser, - beatId - ); - if (beat === null) { - return response.notFound({ - body: { - message: `Beat "${beatId}" not found`, - }, - }); - } - - const isAccessTokenValid = beat.access_token === accessToken; - if (!isAccessTokenValid) { - return response.unauthorized({ - body: { - message: 'Invalid access token', - }, - }); - } - - await beatsManagement.beats.update(beatsManagement.framework.internalUser, beat.id, { - last_checkin: new Date(), - }); - - if (beat.tags) { - const result = await beatsManagement.configurationBlocks.getForTags( - beatsManagement.framework.internalUser, - beat.tags, - -1 - ); - - configurationBlocks = result.blocks; - } else { - configurationBlocks = []; - } - - return response.ok({ - body: { - list: configurationBlocks, - success: true, - } as ReturnTypeList, - }); - }) - ); -}; diff --git a/x-pack/plugins/beats_management/server/routes/beats/enroll.ts b/x-pack/plugins/beats_management/server/routes/beats/enroll.ts deleted file mode 100644 index 8af93a30b61b5..0000000000000 --- a/x-pack/plugins/beats_management/server/routes/beats/enroll.ts +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { schema } from '@kbn/config-schema'; -import type { BeatsManagementRouter } from '../../lib/types'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { ensureRawRequest } from '../../../../../../src/core/server/http/router'; -import { REQUIRED_LICENSES } from '../../../common/constants/security'; -import { BeatEnrollmentStatus } from '../../lib/types'; -import { wrapRouteWithSecurity } from '../wrap_route_with_security'; - -export const registerBeatEnrollmentRoute = (router: BeatsManagementRouter) => { - // TODO: write to Kibana audit log file https://github.com/elastic/kibana/issues/26024 - router.post( - { - path: '/api/beats/agent/{beatId}', - validate: { - params: schema.object({ - beatId: schema.string(), - }), - body: schema.object( - { - host_name: schema.string(), - name: schema.string(), - type: schema.string(), - version: schema.string(), - }, - { unknowns: 'ignore' } - ), - }, - options: { - authRequired: false, - }, - }, - wrapRouteWithSecurity( - { - requiredLicense: REQUIRED_LICENSES, - }, - async (context, request, response) => { - const beatsManagement = context.beatsManagement!; - - const { beatId } = request.params; - const enrollmentToken = request.headers['kbn-beats-enrollment-token'] as string; - if (!enrollmentToken) { - return response.badRequest({ - body: 'beats enrollment token required', - }); - } - - // TODO: fixme eventually, need to access `info.remoteAddress` from KibanaRequest. - const legacyRequest = ensureRawRequest(request); - - const { status, accessToken } = await beatsManagement.beats.enrollBeat( - enrollmentToken, - beatId, - legacyRequest.info.remoteAddress, - request.body - ); - - switch (status) { - case BeatEnrollmentStatus.ExpiredEnrollmentToken: - return response.badRequest({ - body: { - message: BeatEnrollmentStatus.ExpiredEnrollmentToken, - }, - }); - case BeatEnrollmentStatus.InvalidEnrollmentToken: - return response.badRequest({ - body: { - message: BeatEnrollmentStatus.InvalidEnrollmentToken, - }, - }); - case BeatEnrollmentStatus.Success: - default: - return response.ok({ - body: { - item: accessToken, - action: 'created', - success: true, - }, - }); - } - } - ) - ); -}; diff --git a/x-pack/plugins/beats_management/server/routes/beats/events.ts b/x-pack/plugins/beats_management/server/routes/beats/events.ts deleted file mode 100644 index 8df18224845ea..0000000000000 --- a/x-pack/plugins/beats_management/server/routes/beats/events.ts +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { schema } from '@kbn/config-schema'; -import type { BeatsManagementRouter } from '../../lib/types'; -import { ReturnTypeBulkAction } from '../../../common/return_types'; -import { wrapRouteWithSecurity } from '../wrap_route_with_security'; - -export const registerBeatEventsRoute = (router: BeatsManagementRouter) => { - router.post( - { - path: '/api/beats/{beatId}/events', - validate: { - params: schema.object({ - beatId: schema.string(), - }), - body: schema.arrayOf(schema.any(), { defaultValue: [] }), - }, - options: { - authRequired: false, - }, - }, - wrapRouteWithSecurity({}, async (context, request, response) => { - const beatsManagement = context.beatsManagement!; - const accessToken = request.headers['kbn-beats-access-token']; - if (!accessToken) { - return response.badRequest({ - body: 'beats access token required', - }); - } - const beatId = request.params.beatId; - const events = request.body; - const internalUser = beatsManagement.framework.internalUser; - - const beat = await beatsManagement.beats.getById(internalUser, beatId); - if (beat === null) { - return response.badRequest({ - body: { - message: `Beat "${beatId}" not found`, - }, - }); - } - - const isAccessTokenValid = beat.access_token === accessToken; - if (!isAccessTokenValid) { - return response.unauthorized({ - body: { - message: `Invalid access token`, - }, - }); - } - - const results = await beatsManagement.beatEvents.log(internalUser, beat.id, events); - - return response.ok({ - body: { - results, - success: true, - } as ReturnTypeBulkAction, - }); - }) - ); -}; diff --git a/x-pack/plugins/beats_management/server/routes/beats/get.ts b/x-pack/plugins/beats_management/server/routes/beats/get.ts deleted file mode 100644 index e9a3103083143..0000000000000 --- a/x-pack/plugins/beats_management/server/routes/beats/get.ts +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { schema } from '@kbn/config-schema'; -import type { BeatsManagementRouter } from '../../lib/types'; -import { CMBeat } from '../../../common/domain_types'; -import { ReturnTypeGet } from '../../../common/return_types'; -import { wrapRouteWithSecurity } from '../wrap_route_with_security'; - -export const registerGetBeatRoute = (router: BeatsManagementRouter) => { - router.get( - { - path: '/api/beats/agent/{beatId}/{token?}', - validate: { - params: schema.object({ - beatId: schema.string(), - token: schema.string({ defaultValue: '' }), - }), - }, - }, - wrapRouteWithSecurity( - { requiredRoles: ['beats_admin'] }, - async (context, request, response) => { - const beatsManagement = context.beatsManagement!; - const user = beatsManagement.framework.getUser(request); - const beatId = request.params.beatId; - - let beat: CMBeat | null; - if (beatId === 'unknown') { - beat = await beatsManagement.beats.getByEnrollmentToken(user, request.params.token); - if (beat === null) { - return response.ok({ body: { success: false } }); - } - } else { - beat = await beatsManagement.beats.getById(user, beatId); - if (beat === null) { - return response.notFound({ - body: { - message: 'Beat not found', - }, - }); - } - } - - delete beat.access_token; - - return response.ok({ - body: { - item: beat, - success: true, - } as ReturnTypeGet, - }); - } - ) - ); -}; diff --git a/x-pack/plugins/beats_management/server/routes/beats/index.ts b/x-pack/plugins/beats_management/server/routes/beats/index.ts deleted file mode 100644 index c39248b6766ae..0000000000000 --- a/x-pack/plugins/beats_management/server/routes/beats/index.ts +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export { registerGetBeatConfigurationRoute } from './configuration'; -export { registerBeatEnrollmentRoute } from './enroll'; -export { registerBeatEventsRoute } from './events'; -export { registerGetBeatRoute } from './get'; -export { registerListAgentsRoute } from './list'; -export { registerTagAssignmentsRoute } from './tag_assignment'; -export { registerTagRemovalsRoute } from './tag_removal'; -export { registerBeatUpdateRoute } from './update'; diff --git a/x-pack/plugins/beats_management/server/routes/beats/list.ts b/x-pack/plugins/beats_management/server/routes/beats/list.ts deleted file mode 100644 index 549c274bfc1ad..0000000000000 --- a/x-pack/plugins/beats_management/server/routes/beats/list.ts +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { schema } from '@kbn/config-schema'; -import type { BeatsManagementRouter } from '../../lib/types'; -import { REQUIRED_LICENSES } from '../../../common/constants/security'; -import { CMBeat } from '../../../common/domain_types'; -import { ReturnTypeList } from '../../../common/return_types'; -import { wrapRouteWithSecurity } from '../wrap_route_with_security'; - -export const registerListAgentsRoute = (router: BeatsManagementRouter) => { - router.get( - { - path: '/api/beats/agents/{listByAndValue*}', - validate: { - params: schema.object({ - listByAndValue: schema.maybe(schema.string()), - }), - query: schema.object( - { - ESQuery: schema.maybe(schema.string()), - }, - { defaultValue: {} } - ), - }, - }, - wrapRouteWithSecurity( - { - requiredRoles: ['beats_admin'], - requiredLicense: REQUIRED_LICENSES, - }, - async (context, request, response) => { - const beatsManagement = context.beatsManagement; - const user = beatsManagement.framework.getUser(request); - - const listByAndValueParts = request.params.listByAndValue?.split('/') ?? []; - let listBy: string | null = null; - let listByValue: string | null = null; - if (listByAndValueParts.length === 2) { - listBy = listByAndValueParts[0]; - listByValue = listByAndValueParts[1]; - } - - let beats: CMBeat[]; - - switch (listBy) { - case 'tag': - beats = await beatsManagement.beats.getAllWithTag(user, listByValue || ''); - break; - - default: - beats = await beatsManagement.beats.getAll( - user, - request.query.ESQuery ? JSON.parse(request.query.ESQuery) : undefined - ); - - break; - } - - return response.ok({ - body: { list: beats, success: true, page: -1, total: -1 } as ReturnTypeList, - }); - } - ) - ); -}; diff --git a/x-pack/plugins/beats_management/server/routes/beats/tag_assignment.ts b/x-pack/plugins/beats_management/server/routes/beats/tag_assignment.ts deleted file mode 100644 index 44274ac8af401..0000000000000 --- a/x-pack/plugins/beats_management/server/routes/beats/tag_assignment.ts +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { schema } from '@kbn/config-schema'; -import type { BeatsManagementRouter } from '../../lib/types'; -import { REQUIRED_LICENSES } from '../../../common/constants/security'; -import { ReturnTypeBulkAction } from '../../../common/return_types'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import type { BeatsTagAssignment } from '../../../public/lib/adapters/beats/adapter_types'; -import { wrapRouteWithSecurity } from '../wrap_route_with_security'; - -export const registerTagAssignmentsRoute = (router: BeatsManagementRouter) => { - // TODO: write to Kibana audit log file https://github.com/elastic/kibana/issues/26024 - router.post( - { - path: '/api/beats/agents_tags/assignments', - validate: { - body: schema.object({ - assignments: schema.arrayOf( - schema.object({ - beatId: schema.string(), - tag: schema.string(), - }), - { defaultValue: [] } - ), - }), - }, - }, - wrapRouteWithSecurity( - { - requiredLicense: REQUIRED_LICENSES, - requiredRoles: ['beats_admin'], - }, - async (context, request, response) => { - const beatsManagement = context.beatsManagement!; - const user = beatsManagement.framework.getUser(request); - const { assignments }: { assignments: BeatsTagAssignment[] } = request.body; - - const result = await beatsManagement.beats.assignTagsToBeats(user, assignments); - - return response.ok({ - body: { - success: true, - results: result.assignments.map((assignment) => ({ - success: assignment.status && assignment.status >= 200 && assignment.status < 300, - error: - !assignment.status || assignment.status >= 300 - ? { - code: assignment.status || 400, - message: assignment.result, - } - : undefined, - result: - assignment.status && assignment.status >= 200 && assignment.status < 300 - ? { - message: assignment.result, - } - : undefined, - })), - } as ReturnTypeBulkAction, - }); - } - ) - ); -}; diff --git a/x-pack/plugins/beats_management/server/routes/beats/tag_removal.ts b/x-pack/plugins/beats_management/server/routes/beats/tag_removal.ts deleted file mode 100644 index d00b16c4ae176..0000000000000 --- a/x-pack/plugins/beats_management/server/routes/beats/tag_removal.ts +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { schema } from '@kbn/config-schema'; -import type { BeatsManagementRouter } from '../../lib/types'; -import { REQUIRED_LICENSES } from '../../../common/constants/security'; -import { ReturnTypeBulkAction } from '../../../common/return_types'; -import { wrapRouteWithSecurity } from '../wrap_route_with_security'; - -export const registerTagRemovalsRoute = (router: BeatsManagementRouter) => { - // TODO: write to Kibana audit log file https://github.com/elastic/kibana/issues/26024 - router.post( - { - path: '/api/beats/agents_tags/removals', - validate: { - body: schema.object({ - removals: schema.arrayOf( - schema.object({ - beatId: schema.string(), - tag: schema.string(), - }), - { defaultValue: [] } - ), - }), - }, - }, - wrapRouteWithSecurity( - { - requiredLicense: REQUIRED_LICENSES, - requiredRoles: ['beats_admin'], - }, - async (context, request, response) => { - const beatsManagement = context.beatsManagement; - const user = beatsManagement.framework.getUser(request); - const { removals } = request.body; - - const result = await beatsManagement.beats.removeTagsFromBeats(user, removals); - - return response.ok({ - body: { - success: true, - results: result.removals.map((removal) => ({ - success: removal.status && removal.status >= 200 && removal.status < 300, - error: - !removal.status || removal.status >= 300 - ? { - code: removal.status || 400, - message: removal.result, - } - : undefined, - result: - removal.status && removal.status >= 200 && removal.status < 300 - ? { - message: removal.result, - } - : undefined, - })), - } as ReturnTypeBulkAction, - }); - } - ) - ); -}; diff --git a/x-pack/plugins/beats_management/server/routes/beats/update.ts b/x-pack/plugins/beats_management/server/routes/beats/update.ts deleted file mode 100644 index 982005bcf84e9..0000000000000 --- a/x-pack/plugins/beats_management/server/routes/beats/update.ts +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { schema } from '@kbn/config-schema'; -import type { BeatsManagementRouter } from '../../lib/types'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { ensureRawRequest } from '../../../../../../src/core/server/http/router'; -import { REQUIRED_LICENSES } from '../../../common/constants/security'; -import { CMBeat } from '../../../common/domain_types'; -import { ReturnTypeUpdate } from '../../../common/return_types'; -import { internalUser } from '../../lib/adapters/framework/adapter_types'; -import { wrapRouteWithSecurity } from '../wrap_route_with_security'; - -export const registerBeatUpdateRoute = (router: BeatsManagementRouter) => { - // TODO: write to Kibana audit log file (include who did the verification as well) https://github.com/elastic/kibana/issues/26024 - router.put( - { - path: '/api/beats/agent/{beatId}', - validate: { - params: schema.object({ - beatId: schema.string(), - }), - body: schema.object( - { - active: schema.maybe(schema.boolean()), - ephemeral_id: schema.maybe(schema.string()), - host_name: schema.maybe(schema.string()), - local_configuration_yml: schema.maybe(schema.string()), - metadata: schema.maybe(schema.recordOf(schema.string(), schema.any())), - name: schema.maybe(schema.string()), - type: schema.maybe(schema.string()), - version: schema.maybe(schema.string()), - }, - { defaultValue: {} } - ), - }, - }, - wrapRouteWithSecurity( - { - requiredLicense: REQUIRED_LICENSES, - requiredRoles: ['beats_admin'], - }, - async (context, request, response) => { - const beatsManagement = context.beatsManagement; - const accessToken = request.headers['kbn-beats-access-token'] as string; - const { beatId } = request.params; - const user = beatsManagement.framework.getUser(request); - const userOrToken = accessToken || user; - - // TODO: fixme eventually, need to access `info.remoteAddress` from KibanaRequest. - const legacyRequest = ensureRawRequest(request); - const remoteAddress = legacyRequest.info.remoteAddress; - - if (user.kind === 'unauthenticated' && request.body.active !== undefined) { - return response.unauthorized({ - body: { - message: 'access-token is not a valid auth type to change beat status', - }, - }); - } - - const status = await beatsManagement.beats.update(userOrToken, beatId, { - ...request.body, - host_ip: remoteAddress, - }); - - switch (status) { - case 'beat-not-found': - return response.notFound({ - body: { - message: 'Beat not found', - }, - }); - case 'invalid-access-token': - return response.unauthorized({ - body: { - message: 'Invalid access token', - }, - }); - } - - const beat = await beatsManagement.beats.getById(internalUser, beatId); - if (!beat) { - return response.notFound({ - body: { - message: 'Beat not found', - }, - }); - } - - return response.ok({ - body: { - item: beat, - action: 'updated', - success: true, - } as ReturnTypeUpdate, - }); - } - ) - ); -}; diff --git a/x-pack/plugins/beats_management/server/routes/configurations/delete.ts b/x-pack/plugins/beats_management/server/routes/configurations/delete.ts deleted file mode 100644 index 2596204017c11..0000000000000 --- a/x-pack/plugins/beats_management/server/routes/configurations/delete.ts +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { schema } from '@kbn/config-schema'; -import type { BeatsManagementRouter } from '../../lib/types'; -import { wrapRouteWithSecurity } from '../wrap_route_with_security'; -import { REQUIRED_LICENSES } from '../../../common/constants/security'; -import { ReturnTypeBulkDelete } from '../../../common/return_types'; - -export const registerDeleteConfigurationBlocksRoute = (router: BeatsManagementRouter) => { - router.delete( - { - path: '/api/beats/configurations/{ids}', - validate: { - params: schema.object({ - ids: schema.string(), - }), - }, - }, - wrapRouteWithSecurity( - { - requiredLicense: REQUIRED_LICENSES, - requiredRoles: ['beats_admin'], - }, - async (context, request, response) => { - const beatsManagement = context.beatsManagement; - const ids = request.params.ids.split(',').filter((id) => id.length > 0); - const user = beatsManagement.framework.getUser(request); - - const results = await beatsManagement.configurationBlocks.delete(user, ids); - return response.ok({ - body: { - success: true, - results: results.map((result) => ({ - success: result.success, - action: 'deleted', - error: result.success ? undefined : { message: result.reason }, - })), - } as ReturnTypeBulkDelete, - }); - } - ) - ); -}; diff --git a/x-pack/plugins/beats_management/server/routes/configurations/get.ts b/x-pack/plugins/beats_management/server/routes/configurations/get.ts deleted file mode 100644 index 8018420bda773..0000000000000 --- a/x-pack/plugins/beats_management/server/routes/configurations/get.ts +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { schema } from '@kbn/config-schema'; -import type { BeatsManagementRouter } from '../../lib/types'; -import { wrapRouteWithSecurity } from '../wrap_route_with_security'; -import { REQUIRED_LICENSES } from '../../../common/constants/security'; -import { ConfigurationBlock } from '../../../common/domain_types'; -import { ReturnTypeList } from '../../../common/return_types'; - -export const registerGetConfigurationBlocksRoute = (router: BeatsManagementRouter) => { - router.get( - { - path: '/api/beats/configurations/{tagIds}/{page?}', - validate: { - params: schema.object({ - tagIds: schema.string(), - page: schema.maybe(schema.number()), - }), - }, - }, - wrapRouteWithSecurity( - { - requiredLicense: REQUIRED_LICENSES, - requiredRoles: ['beats_admin'], - }, - async (context, request, response) => { - const beatsManagement = context.beatsManagement; - const tagIds = request.params.tagIds.split(',').filter((id) => id.length > 0); - const user = beatsManagement.framework.getUser(request); - const result = await beatsManagement.configurationBlocks.getForTags( - user, - tagIds, - request.params.page, - 5 - ); - - return response.ok({ - body: { - page: result.page, - total: result.total, - list: result.blocks, - success: true, - } as ReturnTypeList, - }); - } - ) - ); -}; diff --git a/x-pack/plugins/beats_management/server/routes/configurations/index.ts b/x-pack/plugins/beats_management/server/routes/configurations/index.ts deleted file mode 100644 index f1e0875c8919d..0000000000000 --- a/x-pack/plugins/beats_management/server/routes/configurations/index.ts +++ /dev/null @@ -1,10 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export { registerGetConfigurationBlocksRoute } from './get'; -export { registerDeleteConfigurationBlocksRoute } from './delete'; -export { registerUpsertConfigurationBlocksRoute } from './upsert'; diff --git a/x-pack/plugins/beats_management/server/routes/configurations/upsert.ts b/x-pack/plugins/beats_management/server/routes/configurations/upsert.ts deleted file mode 100644 index d490cadabf236..0000000000000 --- a/x-pack/plugins/beats_management/server/routes/configurations/upsert.ts +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { PathReporter } from 'io-ts/lib/PathReporter'; -import { isLeft } from 'fp-ts/lib/Either'; -import { schema } from '@kbn/config-schema'; -import type { BeatsManagementRouter } from '../../lib/types'; -import { REQUIRED_LICENSES } from '../../../common/constants'; -import { - ConfigurationBlock, - createConfigurationBlockInterface, -} from '../../../common/domain_types'; -import { ReturnTypeBulkUpsert } from '../../../common/return_types'; -import { wrapRouteWithSecurity } from '../wrap_route_with_security'; - -export const registerUpsertConfigurationBlocksRoute = (router: BeatsManagementRouter) => { - // TODO: write to Kibana audit log file - router.put( - { - path: '/api/beats/configurations', - validate: { - body: schema.arrayOf(schema.recordOf(schema.string(), schema.any()), { defaultValue: [] }), - }, - }, - wrapRouteWithSecurity( - { - requiredLicense: REQUIRED_LICENSES, - requiredRoles: ['beats_admin'], - }, - async (context, request, response) => { - const beatsManagement = context.beatsManagement; - const user = beatsManagement.framework.getUser(request); - const input = request.body as ConfigurationBlock[]; - - const result = await Promise.all( - input.map(async (block: ConfigurationBlock) => { - const assertData = createConfigurationBlockInterface().decode(block); - if (isLeft(assertData)) { - return { - error: `Error parsing block info, ${PathReporter.report(assertData)[0]}`, - }; - } - - const { blockID, success, error } = await beatsManagement.configurationBlocks.save( - user, - block - ); - if (error) { - return { success, error }; - } - - return { success, blockID }; - }) - ); - - return response.ok({ - body: { - results: result.map((r) => ({ - success: r.success as boolean, - // TODO: we need to surface this data, not hard coded - action: 'created' as 'created' | 'updated', - })), - success: true, - } as ReturnTypeBulkUpsert, - }); - } - ) - ); -}; diff --git a/x-pack/plugins/beats_management/server/routes/index.ts b/x-pack/plugins/beats_management/server/routes/index.ts deleted file mode 100644 index 8ea1ca9502959..0000000000000 --- a/x-pack/plugins/beats_management/server/routes/index.ts +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { BeatsManagementRouter } from '../lib/types'; -import { - registerDeleteConfigurationBlocksRoute, - registerGetConfigurationBlocksRoute, - registerUpsertConfigurationBlocksRoute, -} from './configurations'; -import { registerCreateTokenRoute } from './tokens'; -import { - registerSetTagRoute, - registerListTagsRoute, - registerGetTagsWithIdsRoute, - registerDeleteTagsWithIdsRoute, - registerAssignableTagsRoute, -} from './tags'; -import { - registerBeatUpdateRoute, - registerTagRemovalsRoute, - registerTagAssignmentsRoute, - registerListAgentsRoute, - registerGetBeatRoute, - registerBeatEventsRoute, - registerBeatEnrollmentRoute, - registerGetBeatConfigurationRoute, -} from './beats'; - -export const registerRoutes = (router: BeatsManagementRouter) => { - // configurations - registerGetConfigurationBlocksRoute(router); - registerDeleteConfigurationBlocksRoute(router); - registerUpsertConfigurationBlocksRoute(router); - // beats - registerBeatUpdateRoute(router); - registerTagRemovalsRoute(router); - registerTagAssignmentsRoute(router); - registerListAgentsRoute(router); - registerGetBeatRoute(router); - registerBeatEventsRoute(router); - registerBeatEnrollmentRoute(router); - registerGetBeatConfigurationRoute(router); - // tags - registerSetTagRoute(router); - registerListTagsRoute(router); - registerGetTagsWithIdsRoute(router); - registerDeleteTagsWithIdsRoute(router); - registerAssignableTagsRoute(router); - // tokens - registerCreateTokenRoute(router); -}; diff --git a/x-pack/plugins/beats_management/server/routes/tags/assignable.ts b/x-pack/plugins/beats_management/server/routes/tags/assignable.ts deleted file mode 100644 index 9ab89dbcfbcd4..0000000000000 --- a/x-pack/plugins/beats_management/server/routes/tags/assignable.ts +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { schema } from '@kbn/config-schema'; -import { flatten } from 'lodash'; -import type { BeatsManagementRouter } from '../../lib/types'; -import { REQUIRED_LICENSES } from '../../../common/constants/security'; -import { BeatTag } from '../../../common/domain_types'; -import { ReturnTypeBulkGet } from '../../../common/return_types'; -import { wrapRouteWithSecurity } from '../wrap_route_with_security'; - -export const registerAssignableTagsRoute = (router: BeatsManagementRouter) => { - router.get( - { - path: '/api/beats/tags/assignable/{beatIds}', - validate: { - params: schema.object({ - beatIds: schema.string(), - }), - }, - }, - wrapRouteWithSecurity( - { - requiredLicense: REQUIRED_LICENSES, - requiredRoles: ['beats_admin'], - }, - async (context, request, response) => { - const beatsManagement = context.beatsManagement!; - const user = beatsManagement.framework.getUser(request); - const beatIds = request.params.beatIds.split(',').filter((id) => id.length > 0); - - const beats = await beatsManagement.beats.getByIds(user, beatIds); - const tags = await beatsManagement.tags.getNonConflictingTags( - user, - flatten(beats.map((beat) => beat.tags)) - ); - - return response.ok({ - body: { - items: tags, - success: true, - } as ReturnTypeBulkGet, - }); - } - ) - ); -}; diff --git a/x-pack/plugins/beats_management/server/routes/tags/delete.ts b/x-pack/plugins/beats_management/server/routes/tags/delete.ts deleted file mode 100644 index 54b3cf03a08bb..0000000000000 --- a/x-pack/plugins/beats_management/server/routes/tags/delete.ts +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { schema } from '@kbn/config-schema'; -import type { BeatsManagementRouter } from '../../lib/types'; -import { REQUIRED_LICENSES } from '../../../common/constants/security'; -import { ReturnTypeBulkDelete } from '../../../common/return_types'; -import { wrapRouteWithSecurity } from '../wrap_route_with_security'; - -export const registerDeleteTagsWithIdsRoute = (router: BeatsManagementRouter) => { - router.delete( - { - path: '/api/beats/tags/{tagIds}', - validate: { - params: schema.object({ - tagIds: schema.string(), - }), - }, - }, - wrapRouteWithSecurity( - { - requiredLicense: REQUIRED_LICENSES, - requiredRoles: ['beats_admin'], - }, - async (context, request, response) => { - const beatsManagement = context.beatsManagement!; - const user = beatsManagement.framework.getUser(request); - const tagIds = request.params.tagIds.split(',').filter((id) => id.length > 0); - - const success = await beatsManagement.tags.delete(user, tagIds); - - return response.ok({ - body: { - results: tagIds.map(() => ({ - success, - action: 'deleted', - })), - success, - } as ReturnTypeBulkDelete, - }); - } - ) - ); -}; diff --git a/x-pack/plugins/beats_management/server/routes/tags/get.ts b/x-pack/plugins/beats_management/server/routes/tags/get.ts deleted file mode 100644 index 2fe1eb8ab5515..0000000000000 --- a/x-pack/plugins/beats_management/server/routes/tags/get.ts +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { schema } from '@kbn/config-schema'; -import type { BeatsManagementRouter } from '../../lib/types'; -import { REQUIRED_LICENSES } from '../../../common/constants/security'; -import { BeatTag } from '../../../common/domain_types'; -import { ReturnTypeBulkGet } from '../../../common/return_types'; -import { wrapRouteWithSecurity } from '../wrap_route_with_security'; - -export const registerGetTagsWithIdsRoute = (router: BeatsManagementRouter) => { - router.get( - { - path: '/api/beats/tags/{tagIds}', - validate: { - params: schema.object({ - tagIds: schema.string(), - }), - }, - }, - wrapRouteWithSecurity( - { - requiredLicense: REQUIRED_LICENSES, - requiredRoles: ['beats_admin'], - }, - async (context, request, response) => { - const beatsManagement = context.beatsManagement!; - const user = beatsManagement.framework.getUser(request); - const tagIds = request.params.tagIds.split(',').filter((id) => id.length > 0); - - const tags = await beatsManagement.tags.getWithIds(user, tagIds); - - return response.ok({ - body: { - items: tags, - success: true, - } as ReturnTypeBulkGet, - }); - } - ) - ); -}; diff --git a/x-pack/plugins/beats_management/server/routes/tags/index.ts b/x-pack/plugins/beats_management/server/routes/tags/index.ts deleted file mode 100644 index a4208a5679359..0000000000000 --- a/x-pack/plugins/beats_management/server/routes/tags/index.ts +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export { registerAssignableTagsRoute } from './assignable'; -export { registerDeleteTagsWithIdsRoute } from './delete'; -export { registerGetTagsWithIdsRoute } from './get'; -export { registerListTagsRoute } from './list'; -export { registerSetTagRoute } from './set'; diff --git a/x-pack/plugins/beats_management/server/routes/tags/list.ts b/x-pack/plugins/beats_management/server/routes/tags/list.ts deleted file mode 100644 index cee2231808aa6..0000000000000 --- a/x-pack/plugins/beats_management/server/routes/tags/list.ts +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { schema } from '@kbn/config-schema'; -import type { BeatsManagementRouter } from '../../lib/types'; -import { REQUIRED_LICENSES } from '../../../common/constants/security'; -import { BeatTag } from '../../../common/domain_types'; -import { ReturnTypeList } from '../../../common/return_types'; -import { wrapRouteWithSecurity } from '../wrap_route_with_security'; - -export const registerListTagsRoute = (router: BeatsManagementRouter) => { - router.get( - { - path: '/api/beats/tags', - validate: { - query: schema.object( - { - ESQuery: schema.maybe(schema.string()), - }, - { defaultValue: {} } - ), - }, - }, - wrapRouteWithSecurity( - { - requiredLicense: REQUIRED_LICENSES, - requiredRoles: ['beats_admin'], - }, - async (context, request, response) => { - const beatsManagement = context.beatsManagement!; - const user = beatsManagement.framework.getUser(request); - - const tags = await beatsManagement.tags.getAll( - user, - request.query && request.query.ESQuery ? JSON.parse(request.query.ESQuery) : undefined - ); - - return response.ok({ - body: { - list: tags, - success: true, - page: -1, - total: -1, - } as ReturnTypeList, - }); - } - ) - ); -}; diff --git a/x-pack/plugins/beats_management/server/routes/tags/set.ts b/x-pack/plugins/beats_management/server/routes/tags/set.ts deleted file mode 100644 index b556531e8c113..0000000000000 --- a/x-pack/plugins/beats_management/server/routes/tags/set.ts +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { schema } from '@kbn/config-schema'; -import type { BeatsManagementRouter } from '../../lib/types'; -import { REQUIRED_LICENSES } from '../../../common/constants'; -import { BeatTag } from '../../../common/domain_types'; -import { ReturnTypeUpsert } from '../../../common/return_types'; -import { wrapRouteWithSecurity } from '../wrap_route_with_security'; - -export const registerSetTagRoute = (router: BeatsManagementRouter) => { - // TODO: write to Kibana audit log file - router.put( - { - path: '/api/beats/tag/{tagId}', - validate: { - params: schema.object({ - tagId: schema.string(), - }), - body: schema.object( - { - color: schema.maybe(schema.string()), - name: schema.maybe(schema.string()), - }, - { defaultValue: {} } - ), - }, - }, - wrapRouteWithSecurity( - { - requiredLicense: REQUIRED_LICENSES, - requiredRoles: ['beats_admin'], - }, - async (context, request, response) => { - const beatsManagement = context.beatsManagement!; - const user = beatsManagement.framework.getUser(request); - - const config = { - id: request.params.tagId, - name: request.params.tagId, - color: '#DD0A73', - hasConfigurationBlocksTypes: [], - ...request.body, - }; - const id = await beatsManagement.tags.upsertTag(user, config); - const tag = await beatsManagement.tags.getWithIds(user, [id]); - - // TODO the action needs to be surfaced - return response.ok({ - body: { - success: true, - item: tag[0], - action: 'created', - } as ReturnTypeUpsert, - }); - } - ) - ); -}; diff --git a/x-pack/plugins/beats_management/server/routes/tokens/create.ts b/x-pack/plugins/beats_management/server/routes/tokens/create.ts deleted file mode 100644 index c44f9c2dd4e7d..0000000000000 --- a/x-pack/plugins/beats_management/server/routes/tokens/create.ts +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { schema } from '@kbn/config-schema'; -import type { BeatsManagementRouter } from '../../lib/types'; -import { REQUIRED_LICENSES } from '../../../common/constants/security'; -import { ReturnTypeBulkCreate } from '../../../common/return_types'; -import { wrapRouteWithSecurity } from '../wrap_route_with_security'; - -const DEFAULT_NUM_TOKENS = 1; - -export const registerCreateTokenRoute = (router: BeatsManagementRouter) => { - // TODO: write to Kibana audit log file - router.post( - { - path: '/api/beats/enrollment_tokens', - validate: { - body: schema.nullable( - schema.object({ - num_tokens: schema.number({ defaultValue: DEFAULT_NUM_TOKENS, min: 1 }), - }) - ), - }, - }, - wrapRouteWithSecurity( - { - requiredLicense: REQUIRED_LICENSES, - requiredRoles: ['beats_admin'], - }, - async (context, request, response) => { - const beatsManagement = context.beatsManagement!; - const user = beatsManagement.framework.getUser(request); - - const numTokens = request.body?.num_tokens ?? DEFAULT_NUM_TOKENS; - try { - const tokens = await beatsManagement.tokens.createEnrollmentTokens(user, numTokens); - return response.ok({ - body: { - results: tokens.map((token) => ({ - item: token, - success: true, - action: 'created', - })), - success: true, - } as ReturnTypeBulkCreate, - }); - } catch (err) { - beatsManagement.framework.log(err.message); - throw new Error('An error occurred, please check your Kibana logs'); - } - } - ) - ); -}; diff --git a/x-pack/plugins/beats_management/server/routes/tokens/index.ts b/x-pack/plugins/beats_management/server/routes/tokens/index.ts deleted file mode 100644 index f04a8e0d5bc5a..0000000000000 --- a/x-pack/plugins/beats_management/server/routes/tokens/index.ts +++ /dev/null @@ -1,8 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export { registerCreateTokenRoute } from './create'; diff --git a/x-pack/plugins/beats_management/server/routes/wrap_route_with_security.ts b/x-pack/plugins/beats_management/server/routes/wrap_route_with_security.ts deleted file mode 100644 index 327d599ec2703..0000000000000 --- a/x-pack/plugins/beats_management/server/routes/wrap_route_with_security.ts +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { KibanaRequest, KibanaResponseFactory, RequestHandler, RouteMethod } from 'src/core/server'; -import { difference } from 'lodash'; -import type { BeatsManagementRequestHandlerContext } from '../lib/types'; - -export function wrapRouteWithSecurity< - P, - Q, - B, - Context extends BeatsManagementRequestHandlerContext ->( - { - requiredLicense = [], - requiredRoles = [], - }: { requiredLicense?: string[]; requiredRoles?: string[] }, - handler: RequestHandler -): RequestHandler { - return async ( - context: Context, - request: KibanaRequest, - response: KibanaResponseFactory - ) => { - const beatsManagement = context.beatsManagement!; - const license = beatsManagement.framework.license; - const user = beatsManagement.framework.getUser(request); - - if ( - requiredLicense.length > 0 && - (license.expired || !requiredLicense.includes(license.type)) - ) { - return response.forbidden({ - body: { - message: `Your ${license.type} license does not support this API or is expired. Please upgrade your license.`, - }, - }); - } - - if (requiredRoles.length > 0) { - if (user.kind !== 'authenticated') { - return response.forbidden({ - body: { - message: `Request must be authenticated`, - }, - }); - } - - if ( - user.kind === 'authenticated' && - !user.roles.includes('superuser') && - difference(requiredRoles, user.roles).length !== 0 - ) { - return response.forbidden({ - body: { - message: `Request must be authenticated by a user with one of the following user roles: ${requiredRoles.join( - ',' - )}`, - }, - }); - } - } - - return handler(context, request, response); - }; -} diff --git a/x-pack/plugins/beats_management/tsconfig.json b/x-pack/plugins/beats_management/tsconfig.json deleted file mode 100644 index ad68cc900e638..0000000000000 --- a/x-pack/plugins/beats_management/tsconfig.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "extends": "../../../tsconfig.base.json", - "compilerOptions": { - "composite": true, - "outDir": "./target/types", - "emitDeclarationOnly": true, - "declaration": true, - "declarationMap": true - }, - "include": [ - "common/**/*", - "public/**/*", - "server/**/*", - "types/**/*", - "scripts/**/*", - "server/index_templates/*.json", - ], - "references": [ - { "path": "../../../src/core/tsconfig.json" }, - { "path": "../../../src/plugins/data/tsconfig.json" }, - { "path": "../../../src/plugins/management/tsconfig.json" }, - { "path": "../licensing/tsconfig.json" }, - { "path": "../features/tsconfig.json" }, - { "path": "../security/tsconfig.json" } - ] -} diff --git a/x-pack/plugins/beats_management/types/formsy.d.ts b/x-pack/plugins/beats_management/types/formsy.d.ts deleted file mode 100644 index 46231b2385991..0000000000000 --- a/x-pack/plugins/beats_management/types/formsy.d.ts +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -declare module 'formsy-react' { - import React, { FC } from 'react'; - let Formsy: FC; - export interface FormsyInputProps { - getErrorMessage(): any; - getValue(): any; - hasValue(): boolean; - isFormDisabled(): boolean; - isFormSubmitted(): boolean; - isPristine(): boolean; - isRequired(): boolean; - isValid(): boolean; - isValidValue(): boolean; - resetValue(): void; - setValidations(validations: any, required: boolean): void; - setValue(value: any): void; - showError(): boolean; - showRequired(): boolean; - } - - // eslint-disable-next-line import/no-default-export - export default Formsy; - export type FormData = { [fieldName in keyof FormShape]: string }; - export type FieldValue = string | null | undefined; - - type ValidationMethod = ( - values: FormData, - value: string | null | undefined - ) => void; - - export function addValidationRule( - validationName: string, - validationMethod: ValidationMethod - ): void; - export function withFormsy(component: any): any; - - // function withFormsy( - // component: - // | React.Component - // | FC - // ): React.Component; -} diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 66941a8fb591d..845f4b2fb8643 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -6156,185 +6156,6 @@ "xpack.banners.settings.textColor.description": "バナーテキストの色を設定します。{subscriptionLink}", "xpack.banners.settings.textColor.title": "バナーテキスト色", "xpack.banners.settings.textContent.title": "バナーテキスト", - "xpack.beatsManagement.beat.actionSectionTypeLabel": "タイプ:{beatType}。", - "xpack.beatsManagement.beat.actionSectionVersionLabel": "バージョン:{beatVersion}", - "xpack.beatsManagement.beat.beatNameAndIdTitle": "ビート:{nameOrNoName} (ID:{id}) ", - "xpack.beatsManagement.beat.beatNotFoundErrorMessage": "ビートが見つかりません", - "xpack.beatsManagement.beat.beatNotFoundErrorTitle": "ビートが見つかりません", - "xpack.beatsManagement.beat.beatNotFoundMessage": "ビートが見つかりません", - "xpack.beatsManagement.beat.configTabLabel": "構成", - "xpack.beatsManagement.beat.configurationTagsTabLabel": "構成タグ", - "xpack.beatsManagement.beat.detailsConfigurationDescription": "1 つのタグに複数の構成を適用することができます。これらの構成は必要に応じて同じタイプを繰り返したり、タイプを組み合わせることができます。たとえば、3 つの Metricbeat 構成と同時に 1 つのインプットと Filebeat 構成を使用することができます。", - "xpack.beatsManagement.beat.detailsConfigurationTitle": "構成", - "xpack.beatsManagement.beat.lastConfigUpdateMessage": "前回の構成の更新:{lastUpdateTime}。", - "xpack.beatsManagement.beat.loadingTitle": "読み込み中", - "xpack.beatsManagement.beatConfigurations.descriptionColumnName": "説明", - "xpack.beatsManagement.beatConfigurations.moduleColumnName": "モジュール", - "xpack.beatsManagement.beatConfigurations.tagColumnName": "タグ", - "xpack.beatsManagement.beatConfigurations.typeColumnName": "型", - "xpack.beatsManagement.beats.beatDisenrolledNotificationDescription": "ID {firstBeatId} のビートの登録が解除されました。", - "xpack.beatsManagement.beats.beatDisenrolledNotificationTitle": "{firstBeatNameOrId} の登録解除", - "xpack.beatsManagement.beats.configurationTagsTabTitle": "構成タグ", - "xpack.beatsManagement.beats.disenrolledBeatsNotificationTitle": "{beatsLength} 個のビートの登録解除", - "xpack.beatsManagement.beats.enrollBeatsButtonLabel": "ビートを登録", - "xpack.beatsManagement.beats.enrolledBeatsTabTitle": "登録済みのビート", - "xpack.beatsManagement.beats.enrollNewBeatsTitle": "新規ビートの登録", - "xpack.beatsManagement.beats.installBeatsLearningButtonLabel": "ビートのインストール方法", - "xpack.beatsManagement.beatsListAssignmentOptions.setTagsButtonLabel": "タグを設定", - "xpack.beatsManagement.beatsListAssignmentOptions.unenrollBeatsWarninigMessage": "選択されたビートは今後集中管理を使用しません", - "xpack.beatsManagement.beatsListAssignmentOptions.unenrollBeatsWarninigTitle": "選択されたビートの登録を解除しますか?", - "xpack.beatsManagement.beatsListAssignmentOptions.unenrollButtonLabel": "選択項目の登録を解除", - "xpack.beatsManagement.beatsTable.beatNameTitle": "ビート名", - "xpack.beatsManagement.beatsTable.configErrorStatusLabel": "構成エラー", - "xpack.beatsManagement.beatsTable.configStatus.errorTooltip": "このビートにエラーがあります。このホストのログを確認してください。", - "xpack.beatsManagement.beatsTable.configStatus.noConnectionTooltip": "このビートは 10 分以上 Kibana に接続していません", - "xpack.beatsManagement.beatsTable.configStatus.notStartedLabel": "未開始", - "xpack.beatsManagement.beatsTable.configStatus.notStartedTooltip": "このビートはまだ開始していません。", - "xpack.beatsManagement.beatsTable.configStatus.offlineLabel": "オフライン", - "xpack.beatsManagement.beatsTable.configStatus.okLabel": "OK", - "xpack.beatsManagement.beatsTable.configStatus.okTooltip": "最新の構成にビートが適用されました", - "xpack.beatsManagement.beatsTable.configStatus.progressTooltip": "このビートは現在 CM から構成を再読み込み中です。", - "xpack.beatsManagement.beatsTable.configStatus.runningTooltip": "このビートは問題なく動作中です。", - "xpack.beatsManagement.beatsTable.configStatus.startingTooltip": "このビートは開始中です。", - "xpack.beatsManagement.beatsTable.configStatusTitle": "構成ステータス", - "xpack.beatsManagement.beatsTable.disenrollSelectedLabel": "選択項目の登録を解除", - "xpack.beatsManagement.beatsTable.failedStatusLabel": "エラー", - "xpack.beatsManagement.beatsTable.runningStatusLabel": "実行中", - "xpack.beatsManagement.beatsTable.startingStatusLabel": "開始中", - "xpack.beatsManagement.beatsTable.stoppedStatusLabel": "停止中", - "xpack.beatsManagement.beatsTable.tagsTitle": "タグ", - "xpack.beatsManagement.beatsTable.typeLabel": "型", - "xpack.beatsManagement.beatsTable.typeTitle": "型", - "xpack.beatsManagement.beatsTable.updatingStatusLabel": "更新中", - "xpack.beatsManagement.beatTagsTable.addTagLabel": "タグを追加", - "xpack.beatsManagement.beatTagsTable.lastUpdateTitle": "最終更新", - "xpack.beatsManagement.beatTagsTable.removeSelectedLabel": "選択項目を削除", - "xpack.beatsManagement.beatTagsTable.tagNameTitle": "タグ名", - "xpack.beatsManagement.breadcrumb.beatDetails": "{beatId} のビート詳細", - "xpack.beatsManagement.breadcrumb.beatTags": "{beatId} のビートタグ", - "xpack.beatsManagement.breadcrumb.configurationTags": "構成タグ", - "xpack.beatsManagement.breadcrumb.enrolledBeats": "登録済みのビート", - "xpack.beatsManagement.centralManagementLinkLabel": "Beatsの集中管理", - "xpack.beatsManagement.config.other.error": "有効な YAML フォーマットを使用してください", - "xpack.beatsManagement.config.otherConfigDescription": "YAML フォーマットで Filebeat インプットの他の設定を指定します", - "xpack.beatsManagement.config.otherConfigLabel": "他の構成", - "xpack.beatsManagement.confirmModal.cancelButtonLabel": "キャンセル", - "xpack.beatsManagement.confirmModal.confirmButtonLabel": "確認", - "xpack.beatsManagement.confirmModal.confirmWarningTitle": "確認", - "xpack.beatsManagement.createTag.errorSavingTagTitle": "タグの保存中にエラーが発生", - "xpack.beatsManagement.createTag.saveAndContinueButtonLabel": "保存して続行", - "xpack.beatsManagement.disabledSecurityDescription": "ビートの集中管理を使用するには、Kibana と Elasticsearch でセキュリティを有効にする必要があります。", - "xpack.beatsManagement.disabledSecurityTitle": "セキュリティが有効ではありません", - "xpack.beatsManagement.enrollBeat.assignTagToBeatInvalidURLNoTagFoundTitle": "無効な URL、createdTag が見つかりません", - "xpack.beatsManagement.enrollBeat.assignTagToBeatInvalidURLNoTokenFountTitle": "無効な URL、enrollmentToken が見つかりません", - "xpack.beatsManagement.enrollBeat.assignTagToBeatNotEnrolledProperlyTitle": "エラー:ビートは正常に登録されていません", - "xpack.beatsManagement.enrollBeat.beatEnrolledTitle": "このビートは現在集中管理に登録されています:", - "xpack.beatsManagement.enrollBeat.beatsCentralManagementDescription": "一か所で構成を集中管理できます。", - "xpack.beatsManagement.enrollBeat.beatTypeColumnName": "ビートタイプ", - "xpack.beatsManagement.enrollBeat.beatTypeTitle": "ビートタイプ:", - "xpack.beatsManagement.enrollBeat.copyButtonLabel": "コマンドをコピー", - "xpack.beatsManagement.enrollBeat.createTagStepLabel": "タグを作成", - "xpack.beatsManagement.enrollBeat.enrollBeatButtonLabel": "ビートを登録", - "xpack.beatsManagement.enrollBeat.enrollBeatStepLabel": "ビートを登録", - "xpack.beatsManagement.enrollBeat.finishStepLabel": "終了", - "xpack.beatsManagement.enrollBeat.firstBeatEnrollingDoneButtonLabel": "完了", - "xpack.beatsManagement.enrollBeat.getStartedBeatsCentralManagementTitle": "ビートの集中管理を開始", - "xpack.beatsManagement.enrollBeat.hostnameColumnName": "ホスト名", - "xpack.beatsManagement.enrollBeat.nextStepDescription": "ビートを起動して構成エラーを確認し、「完了」をクリックしてください。", - "xpack.beatsManagement.enrollBeat.nextStepTitle": "ビートが登録されました。次のステップ", - "xpack.beatsManagement.enrollBeat.platformTitle": "プラットフォーム:", - "xpack.beatsManagement.enrollBeat.versionColumnName": "バージョン", - "xpack.beatsManagement.enrollBeat.waitingBeatTypeToEnrollTitle": "{beatType} の登録待ち…", - "xpack.beatsManagement.enrollBeat.yourBeatTypeHostTitle": "{beatType} がインストールされているホストでは次を実行:", - "xpack.beatsManagement.filebeatInputConfig.otherConfigDescription": "YAML フォーマットで Filebeat インプットの他の設定を指定します", - "xpack.beatsManagement.filebeatInputConfig.otherConfigErrorMessage": "有効な YAML フォーマットを使用してください", - "xpack.beatsManagement.filebeatInputConfig.otherConfigLabel": "他の構成", - "xpack.beatsManagement.filebeatInputConfig.pathsDescription": "それぞれのパスを別々の行に入力します", - "xpack.beatsManagement.filebeatInputConfig.pathsErrorMessage": "1 行につき 1 つのパスを入力してください", - "xpack.beatsManagement.filebeatInputConfig.pathsLabel": "パス", - "xpack.beatsManagement.filebeatModuleConfig.moduleDescription": "YAML フォーマットで Filebeat モジュールの他の設定を指定します", - "xpack.beatsManagement.filebeatModuleConfig.moduleErrorMessage": "モジュールを選択してください。", - "xpack.beatsManagement.filebeatModuleConfig.moduleLabel": "モジュール", - "xpack.beatsManagement.filebeatModuleConfig.otherConfigErrorMessage": "有効な YAML フォーマットを使用してください", - "xpack.beatsManagement.filebeatModuleConfig.otherConfigLabel": "他の構成", - "xpack.beatsManagement.invalidLicenseDescription": "現在のライセンスは期限切れです。登録されたビートは引き続き動作しますが、ビート管理 UI にアクセスするには有効なライセンスが必要です。", - "xpack.beatsManagement.invalidLicenseTitle": "ライセンスの期限切れ", - "xpack.beatsManagement.management.breadcrumb": "管理", - "xpack.beatsManagement.management.deprecationMessage": "Beats集中管理の開発は中止され、現在はそれに代わる包括的なソリューションを検討しています。ベータ版に参加して、フィードバックを提出していただき、どうもありがとうございます。ご質問や問題点がありましたら、{forumLink}からお問い合わせください。", - "xpack.beatsManagement.management.deprecationTitle": "Beats集中管理は廃止予定です", - "xpack.beatsManagement.management.forumLink": "ディスカッションフォーラム", - "xpack.beatsManagement.metricbeatModuleConfig.hostsDescription": "それぞれのパスを別々の行に入力します", - "xpack.beatsManagement.metricbeatModuleConfig.hostsErrorMessage": "1 行につき 1 つのファイルホストを入力してください", - "xpack.beatsManagement.metricbeatModuleConfig.hostsLabel": "ホスト", - "xpack.beatsManagement.metricbeatModuleConfig.moduleErrorMessage": "モジュールを選択してください。", - "xpack.beatsManagement.metricbeatModuleConfig.moduleLabel": "モジュール", - "xpack.beatsManagement.metricbeatModuleConfig.otherConfigDescription": "YAML フォーマットで Metricbeat モジュールの他の設定を指定します", - "xpack.beatsManagement.metricbeatModuleConfig.otherConfigErrorMessage": "有効な YAML フォーマットを使用してください", - "xpack.beatsManagement.metricbeatModuleConfig.otherConfigLabel": "他の構成", - "xpack.beatsManagement.metricbeatModuleConfig.periodErrorMessage": "無効な期間、10 秒は「10s」というフォーマットを使用してください", - "xpack.beatsManagement.metricbeatModuleConfig.periodLabel": "期間", - "xpack.beatsManagement.noAccess.accessDeniedDescription": "ビート集中管理へのアクセス権がありません。ビート集中管理を使用するには、{beatsAdminRole} ロールから権限が必要です。", - "xpack.beatsManagement.noAccess.accessDeniedTitle": "アクセスが拒否されました", - "xpack.beatsManagement.noContentFoundErrorMessage": "コンテンツがありません", - "xpack.beatsManagement.outputConfig.hostsErrorMessage": "1 行につき 1 つのファイルホストを入力してください", - "xpack.beatsManagement.outputConfig.hostsLabel": "ホスト", - "xpack.beatsManagement.outputConfig.outputTypeErrorMessage": "アウトプットタイプを選択してください", - "xpack.beatsManagement.outputConfig.outputTypeLabel": "アウトプットタイプ", - "xpack.beatsManagement.outputConfig.passwordErrorMessage": "処理不能なパスワードです", - "xpack.beatsManagement.outputConfig.passwordLabel": "パスワード", - "xpack.beatsManagement.outputConfig.usernameErrorMessage": "処理不能なユーザー名です", - "xpack.beatsManagement.outputConfig.usernameLabel": "ユーザー名", - "xpack.beatsManagement.overview.betaBadgeText": "ベータ", - "xpack.beatsManagement.table.filterResultsPlaceholder": "フィルター結果", - "xpack.beatsManagement.table.selectOptionLabel": "オプションを選択してください", - "xpack.beatsManagement.table.selectThisBeatTooltip": "このビートを選択します", - "xpack.beatsManagement.tag.addConfigurationButtonLabel": "構成ブロックを追加", - "xpack.beatsManagement.tag.beatsAssignedToTagTitle": "このタグが付いたビート", - "xpack.beatsManagement.tag.cancelButtonLabel": "キャンセル", - "xpack.beatsManagement.tag.createTagTitle": "タグの作成", - "xpack.beatsManagement.tag.saveButtonLabel": "保存", - "xpack.beatsManagement.tag.tagColorLabel": "タグの色", - "xpack.beatsManagement.tag.tagConfigurationsDescription": "タグには異なるタイプのビートの構成ブロックが使用できます。たとえば、1 つのタグに 2 つの Metricbeat 構成ブロックと 1 つの Filebeat インプット構成ブロックを使用することができます。", - "xpack.beatsManagement.tag.tagConfigurationsTitle": "構成ブロック", - "xpack.beatsManagement.tag.tagDetailsDescription": "タグとは、1 つまたは複数のビートに適用できる構成ブロックのグループです。", - "xpack.beatsManagement.tag.tagDetailsTitle": "タグの詳細", - "xpack.beatsManagement.tag.tagName.validationErrorMessage": "タグ名には文字、数字、ハイフンのみが使用できます。", - "xpack.beatsManagement.tag.tagNameLabel": "タグ名", - "xpack.beatsManagement.tag.tagNamePlaceholder": "タグ名 (必須) ", - "xpack.beatsManagement.tag.updateTagTitle": "タグ {tagId} を更新", - "xpack.beatsManagement.tagConfig.addConfigurationTitle\"": "構成ブロックを追加", - "xpack.beatsManagement.tagConfig.closeButtonLabel": "閉じる", - "xpack.beatsManagement.tagConfig.configurationTypeText": "{configType}‘構成", - "xpack.beatsManagement.tagConfig.descriptionLabel": "説明", - "xpack.beatsManagement.tagConfig.descriptionPlaceholder": "説明 (オプション) ", - "xpack.beatsManagement.tagConfig.editConfigurationTitle": "構成ブロックの編集", - "xpack.beatsManagement.tagConfig.filebeatInputLabel": "Filebeat インプット", - "xpack.beatsManagement.tagConfig.filebeatModuleLabel": "Filebeat モジュール", - "xpack.beatsManagement.tagConfig.invalidSchema": "エラー:この構成は無効です。Beats でサポートされておらず、削除する必要があります", - "xpack.beatsManagement.tagConfig.metricbeatModuleLabel": "Metricbeat モジュール", - "xpack.beatsManagement.tagConfig.outputLabel": "アウトプット", - "xpack.beatsManagement.tagConfig.saveButtonLabel": "保存", - "xpack.beatsManagement.tagConfig.typeLabel": "型", - "xpack.beatsManagement.tagConfig.viewConfigurationTitle\"": "構成ブロックの表示", - "xpack.beatsManagement.tagConfigAssignmentOptions.removeTagsButtonLabel": "タグを削除", - "xpack.beatsManagement.tagConfigAssignmentOptions.removeTagsWarninigMessage": "選択されたビートからタグを削除しますか?", - "xpack.beatsManagement.tagConfigAssignmentOptions.removeTagsWarninigTitle": "タグを削除", - "xpack.beatsManagement.tagListAssignmentOptions.removeTagsButtonLabel": "選択項目を削除", - "xpack.beatsManagement.tagListAssignmentOptions.removeTagsWarninigTitle": "タグを削除", - "xpack.beatsManagement.tagListAssignmentOptions.removeTagWarninigMessage": "タグを削除しますか?", - "xpack.beatsManagement.tags.addTagButtonLabel": "タグを追加", - "xpack.beatsManagement.tags.someTagsMightBeAssignedToBeatsTitle": "これらのタグのいくつかはビートに割り当てられている可能性があります。削除するタグが現在割り当てられていないことを確認してください", - "xpack.beatsManagement.tagsTable.lastUpdateTitle": "最終更新", - "xpack.beatsManagement.tagsTable.removeSelectedLabel": "選択項目を削除", - "xpack.beatsManagement.tagsTable.tagNameTitle": "タグ名", - "xpack.beatsManagement.tagTable.actions.removeButtonAriaLabel": "削除", - "xpack.beatsManagement.tagTable.actions.removeTooltip": "タグからこの構成を削除します", - "xpack.beatsManagement.tagTable.actionsColumnName": "アクション", - "xpack.beatsManagement.tagTable.descriptionColumnName": "説明", - "xpack.beatsManagement.tagTable.moduleColumn.notAvailibaleLabel": "N/A", - "xpack.beatsManagement.tagTable.moduleColumnName": "モジュール", - "xpack.beatsManagement.tagTable.typeColumnName": "型", - "xpack.beatsManagement.walkthrough.initial.betaBadgeText": "ベータ", "xpack.canvas.app.loadErrorMessage": "メッセージ:{error}", "xpack.canvas.app.loadErrorTitle": "Canvas の読み込みに失敗", "xpack.canvas.app.loadingMessage": "Canvas を読み込み中", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 306ac0bf744e2..d223ba08185b4 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -6195,189 +6195,6 @@ "xpack.banners.settings.textColor.description": "设置横幅广告文本的颜色。{subscriptionLink}", "xpack.banners.settings.textColor.title": "横幅广告文本颜色", "xpack.banners.settings.textContent.title": "横幅广告文本", - "xpack.beatsManagement.beat.actionSectionTypeLabel": "类型:{beatType}。", - "xpack.beatsManagement.beat.actionSectionVersionLabel": "版本:{beatVersion}。", - "xpack.beatsManagement.beat.beatNameAndIdTitle": "Beat:{nameOrNoName} (ID:{id}) ", - "xpack.beatsManagement.beat.beatNotFoundErrorMessage": "未找到 Beat", - "xpack.beatsManagement.beat.beatNotFoundErrorTitle": "未找到 Beat", - "xpack.beatsManagement.beat.beatNotFoundMessage": "未找到 Beat", - "xpack.beatsManagement.beat.configTabLabel": "配置", - "xpack.beatsManagement.beat.configurationTagsTabLabel": "配置标签", - "xpack.beatsManagement.beat.detailsConfigurationDescription": "可以将多个配置应用到单个标签。这些配置类型可以根据需要进行重复或混合。例如,您可以同时使用三个 Metricbeat 配置以及一个输入和 Filebeat 配置。", - "xpack.beatsManagement.beat.detailsConfigurationTitle": "配置", - "xpack.beatsManagement.beat.lastConfigUpdateMessage": "上次配置更新:{lastUpdateTime}。", - "xpack.beatsManagement.beat.loadingTitle": "正在加载", - "xpack.beatsManagement.beatConfigurations.descriptionColumnName": "描述", - "xpack.beatsManagement.beatConfigurations.moduleColumnName": "模块", - "xpack.beatsManagement.beatConfigurations.tagColumnName": "标签", - "xpack.beatsManagement.beatConfigurations.typeColumnName": "类型", - "xpack.beatsManagement.beats.addedNotificationDescription": "将标签 {tag} 添加到 {assignmentsLength, plural, one {Beat {beatName}} other {# 个 Beats}}。", - "xpack.beatsManagement.beats.addedNotificationTitle": "{assignmentsLength, plural, other {标签}}已添加", - "xpack.beatsManagement.beats.beatDisenrolledNotificationDescription": "ID 为 {firstBeatId} 的 Beat 已除名。", - "xpack.beatsManagement.beats.beatDisenrolledNotificationTitle": "{firstBeatNameOrId} 已除名", - "xpack.beatsManagement.beats.configurationTagsTabTitle": "配置标签", - "xpack.beatsManagement.beats.disenrolledBeatsNotificationTitle": "{beatsLength} 个 Beats 已除名", - "xpack.beatsManagement.beats.enrollBeatsButtonLabel": "注册 Beats", - "xpack.beatsManagement.beats.enrolledBeatsTabTitle": "已注册 Beats", - "xpack.beatsManagement.beats.enrollNewBeatsTitle": "注册新 Beat", - "xpack.beatsManagement.beats.installBeatsLearningButtonLabel": "了解如何安装 Beats", - "xpack.beatsManagement.beats.removedNotificationDescription": "已从 {assignmentsLength, plural, one {Beat {beatName}} other {# 个 Beat}} 移除标签 {tag}", - "xpack.beatsManagement.beats.removedNotificationTitle": "{assignmentsLength, plural, other {标签}}已删除", - "xpack.beatsManagement.beatsListAssignmentOptions.setTagsButtonLabel": "设置标签", - "xpack.beatsManagement.beatsListAssignmentOptions.unenrollBeatsWarninigMessage": "选定的 Beats 将不再使用集中管理", - "xpack.beatsManagement.beatsListAssignmentOptions.unenrollBeatsWarninigTitle": "取消注册选定的 Beats?", - "xpack.beatsManagement.beatsListAssignmentOptions.unenrollButtonLabel": "取消注册选定", - "xpack.beatsManagement.beatsTable.beatNameTitle": "Beat 名称", - "xpack.beatsManagement.beatsTable.configErrorStatusLabel": "配置错误", - "xpack.beatsManagement.beatsTable.configStatus.errorTooltip": "此 Beat 有错误,请查看此主机的日志。", - "xpack.beatsManagement.beatsTable.configStatus.noConnectionTooltip": "此 Beat 未连接到 Kibana 的时间已超过 10 分钟", - "xpack.beatsManagement.beatsTable.configStatus.notStartedLabel": "未开始", - "xpack.beatsManagement.beatsTable.configStatus.notStartedTooltip": "此 Beat 尚未启动。", - "xpack.beatsManagement.beatsTable.configStatus.offlineLabel": "脱机", - "xpack.beatsManagement.beatsTable.configStatus.okLabel": "确定", - "xpack.beatsManagement.beatsTable.configStatus.okTooltip": "Beat 成功应用最新的配置", - "xpack.beatsManagement.beatsTable.configStatus.progressTooltip": "此 Beat 当前正在从 CM 重新加载配置。", - "xpack.beatsManagement.beatsTable.configStatus.runningTooltip": "此 Beat 正在运行,没有任何问题。", - "xpack.beatsManagement.beatsTable.configStatus.startingTooltip": "此 Beat 正在启动。", - "xpack.beatsManagement.beatsTable.configStatusTitle": "配置状态", - "xpack.beatsManagement.beatsTable.disenrollSelectedLabel": "取消注册选定", - "xpack.beatsManagement.beatsTable.failedStatusLabel": "错误", - "xpack.beatsManagement.beatsTable.runningStatusLabel": "正在运行", - "xpack.beatsManagement.beatsTable.startingStatusLabel": "正在启动", - "xpack.beatsManagement.beatsTable.stoppedStatusLabel": "已停止", - "xpack.beatsManagement.beatsTable.tagsTitle": "标签", - "xpack.beatsManagement.beatsTable.typeLabel": "类型", - "xpack.beatsManagement.beatsTable.typeTitle": "类型", - "xpack.beatsManagement.beatsTable.updatingStatusLabel": "正在更新", - "xpack.beatsManagement.beatTagsTable.addTagLabel": "添加标签", - "xpack.beatsManagement.beatTagsTable.lastUpdateTitle": "上次更新", - "xpack.beatsManagement.beatTagsTable.removeSelectedLabel": "删除选定", - "xpack.beatsManagement.beatTagsTable.tagNameTitle": "标签名称", - "xpack.beatsManagement.breadcrumb.beatDetails": "{beatId} 的 Beat 详情", - "xpack.beatsManagement.breadcrumb.beatTags": "{beatId} 的 Beat 标签", - "xpack.beatsManagement.breadcrumb.configurationTags": "配置标签", - "xpack.beatsManagement.breadcrumb.enrolledBeats": "已注册 Beats", - "xpack.beatsManagement.centralManagementLinkLabel": "Beats 集中管理", - "xpack.beatsManagement.config.other.error": "使用有效的 YAML 格式", - "xpack.beatsManagement.config.otherConfigDescription": "使用 YAML 格式指定 Filebeat 输入的其他设置", - "xpack.beatsManagement.config.otherConfigLabel": "其他配置", - "xpack.beatsManagement.confirmModal.cancelButtonLabel": "取消", - "xpack.beatsManagement.confirmModal.confirmButtonLabel": "确认", - "xpack.beatsManagement.confirmModal.confirmWarningTitle": "确认", - "xpack.beatsManagement.createTag.errorSavingTagTitle": "保存标签时出错", - "xpack.beatsManagement.createTag.saveAndContinueButtonLabel": "保存并继续", - "xpack.beatsManagement.disabledSecurityDescription": "必须在 Kibana 和 Elasticsearch 启用安全性,才能使用 Beats 集中管理。", - "xpack.beatsManagement.disabledSecurityTitle": "安全性未启用", - "xpack.beatsManagement.enrollBeat.assignTagToBeatInvalidURLNoTagFoundTitle": "URL 无效,未找到 createdTag", - "xpack.beatsManagement.enrollBeat.assignTagToBeatInvalidURLNoTokenFountTitle": "URL 无效,未找到 enrollmentToken", - "xpack.beatsManagement.enrollBeat.assignTagToBeatNotEnrolledProperlyTitle": "错误:Beat 未正确注册", - "xpack.beatsManagement.enrollBeat.beatEnrolledTitle": "该 Beat 当前已在集中管理中注册:", - "xpack.beatsManagement.enrollBeat.beatsCentralManagementDescription": "在集中位置管理您的配置。", - "xpack.beatsManagement.enrollBeat.beatTypeColumnName": "Beat 类型", - "xpack.beatsManagement.enrollBeat.beatTypeTitle": "Beat 类型:", - "xpack.beatsManagement.enrollBeat.copyButtonLabel": "复制命令", - "xpack.beatsManagement.enrollBeat.createTagStepLabel": "创建标签", - "xpack.beatsManagement.enrollBeat.enrollBeatButtonLabel": "注册 Beat", - "xpack.beatsManagement.enrollBeat.enrollBeatStepLabel": "注册 Beat", - "xpack.beatsManagement.enrollBeat.finishStepLabel": "完成", - "xpack.beatsManagement.enrollBeat.firstBeatEnrollingDoneButtonLabel": "完成", - "xpack.beatsManagement.enrollBeat.getStartedBeatsCentralManagementTitle": "开始使用 Beats 集中管理", - "xpack.beatsManagement.enrollBeat.hostnameColumnName": "主机名", - "xpack.beatsManagement.enrollBeat.nextStepDescription": "启动您的 Beat 以检查是否有配置错误,然后单击“完成”。", - "xpack.beatsManagement.enrollBeat.nextStepTitle": "您的 Beat 已注册。后续操作", - "xpack.beatsManagement.enrollBeat.platformTitle": "平台:", - "xpack.beatsManagement.enrollBeat.versionColumnName": "版本", - "xpack.beatsManagement.enrollBeat.waitingBeatTypeToEnrollTitle": "正在等待注册 {beatType}……", - "xpack.beatsManagement.enrollBeat.yourBeatTypeHostTitle": "在安装您的 {beatType} 的主机上,运行:", - "xpack.beatsManagement.filebeatInputConfig.otherConfigDescription": "使用 YAML 格式指定 Filebeat 输入的其他设置", - "xpack.beatsManagement.filebeatInputConfig.otherConfigErrorMessage": "使用有效的 YAML 格式", - "xpack.beatsManagement.filebeatInputConfig.otherConfigLabel": "其他配置", - "xpack.beatsManagement.filebeatInputConfig.pathsDescription": "将每个路径放置在单独的行上", - "xpack.beatsManagement.filebeatInputConfig.pathsErrorMessage": "每行一个文件路径", - "xpack.beatsManagement.filebeatInputConfig.pathsLabel": "路径", - "xpack.beatsManagement.filebeatModuleConfig.moduleDescription": "使用 YAML 格式指定 Filebeat 模块的其他设置", - "xpack.beatsManagement.filebeatModuleConfig.moduleErrorMessage": "请选择模块", - "xpack.beatsManagement.filebeatModuleConfig.moduleLabel": "模块", - "xpack.beatsManagement.filebeatModuleConfig.otherConfigErrorMessage": "使用有效的 YAML 格式", - "xpack.beatsManagement.filebeatModuleConfig.otherConfigLabel": "其他配置", - "xpack.beatsManagement.invalidLicenseDescription": "您当前的许可证已过期。已注册的 Beats 将继续工作,但您需要有效的许可,才能访问 Beats 管理 UI。", - "xpack.beatsManagement.invalidLicenseTitle": "已过期许可证", - "xpack.beatsManagement.management.breadcrumb": "管理", - "xpack.beatsManagement.management.deprecationMessage": "我们已停止开发 Beats 集中管理,正开发一款全面的解决方案来替代它。感谢您参与公测版测试并提供反馈。如果您有任何问题或顾虑,请在 {forumLink} 上联系我们。", - "xpack.beatsManagement.management.deprecationTitle": "Beats 集中管理已弃用", - "xpack.beatsManagement.management.forumLink": "讨论论坛", - "xpack.beatsManagement.metricbeatModuleConfig.hostsDescription": "将每个路径放置在单独的行上", - "xpack.beatsManagement.metricbeatModuleConfig.hostsErrorMessage": "每行一个文件主机", - "xpack.beatsManagement.metricbeatModuleConfig.hostsLabel": "主机", - "xpack.beatsManagement.metricbeatModuleConfig.moduleErrorMessage": "请选择模块", - "xpack.beatsManagement.metricbeatModuleConfig.moduleLabel": "模块", - "xpack.beatsManagement.metricbeatModuleConfig.otherConfigDescription": "使用 YAML 格式指定 Metricbeat 模块的其他设置", - "xpack.beatsManagement.metricbeatModuleConfig.otherConfigErrorMessage": "使用有效的 YAML 格式", - "xpack.beatsManagement.metricbeatModuleConfig.otherConfigLabel": "其他配置", - "xpack.beatsManagement.metricbeatModuleConfig.periodErrorMessage": "期间无效,10 秒的格式必须为 `10s`。", - "xpack.beatsManagement.metricbeatModuleConfig.periodLabel": "期间", - "xpack.beatsManagement.noAccess.accessDeniedDescription": "您无权访问 Beats 集中管理。要使用 Beats 集中管理,您需要 {beatsAdminRole} 角色授予的权限。", - "xpack.beatsManagement.noAccess.accessDeniedTitle": "访问被拒绝", - "xpack.beatsManagement.noContentFoundErrorMessage": "未找到任何内容", - "xpack.beatsManagement.outputConfig.hostsErrorMessage": "每行一个文件主机", - "xpack.beatsManagement.outputConfig.hostsLabel": "主机", - "xpack.beatsManagement.outputConfig.outputTypeErrorMessage": "请选择输出类型", - "xpack.beatsManagement.outputConfig.outputTypeLabel": "输出类型", - "xpack.beatsManagement.outputConfig.passwordErrorMessage": "无法处理的密码", - "xpack.beatsManagement.outputConfig.passwordLabel": "密码", - "xpack.beatsManagement.outputConfig.usernameErrorMessage": "无法处理的用户名", - "xpack.beatsManagement.outputConfig.usernameLabel": "用户名", - "xpack.beatsManagement.overview.betaBadgeText": "公测版", - "xpack.beatsManagement.table.filterResultsPlaceholder": "筛选结果", - "xpack.beatsManagement.table.selectOptionLabel": "请选择选项", - "xpack.beatsManagement.table.selectThisBeatTooltip": "选择此 Beat", - "xpack.beatsManagement.tag.addConfigurationButtonLabel": "添加配置块", - "xpack.beatsManagement.tag.beatsAssignedToTagTitle": "具有此标签的 Beats", - "xpack.beatsManagement.tag.cancelButtonLabel": "取消", - "xpack.beatsManagement.tag.createTagTitle": "创建标签", - "xpack.beatsManagement.tag.saveButtonLabel": "保存", - "xpack.beatsManagement.tag.tagColorLabel": "标签颜色", - "xpack.beatsManagement.tag.tagConfigurationsDescription": "标签可以有不同类型 Beats 的配置块。例如,标签可以有两个 Metricbeat 配置块和一个 Filebeat 输入配置块。", - "xpack.beatsManagement.tag.tagConfigurationsTitle": "配置块", - "xpack.beatsManagement.tag.tagDetailsDescription": "标签是可以应用到一个或多个 Beats 的一组配置块。", - "xpack.beatsManagement.tag.tagDetailsTitle": "标签详情", - "xpack.beatsManagement.tag.tagName.validationErrorMessage": "标签名称只能由字母、数字和短划线构成", - "xpack.beatsManagement.tag.tagNameLabel": "标签名称", - "xpack.beatsManagement.tag.tagNamePlaceholder": "标签名称 (必填) ", - "xpack.beatsManagement.tag.updateTagTitle": "创建标签:{tagId}", - "xpack.beatsManagement.tagConfig.addConfigurationTitle\"": "添加配置块", - "xpack.beatsManagement.tagConfig.closeButtonLabel": "关闭", - "xpack.beatsManagement.tagConfig.configurationTypeText": "{configType} 配置", - "xpack.beatsManagement.tagConfig.descriptionLabel": "描述", - "xpack.beatsManagement.tagConfig.descriptionPlaceholder": "描述 (可选) ", - "xpack.beatsManagement.tagConfig.editConfigurationTitle": "编辑配置块", - "xpack.beatsManagement.tagConfig.filebeatInputLabel": "Filebeat 输入", - "xpack.beatsManagement.tagConfig.filebeatModuleLabel": "Filebeat 模块", - "xpack.beatsManagement.tagConfig.invalidSchema": "错误:此配置无效,其不受 Beats 支持,应移除", - "xpack.beatsManagement.tagConfig.metricbeatModuleLabel": "Metricbeat 模块", - "xpack.beatsManagement.tagConfig.outputLabel": "输出", - "xpack.beatsManagement.tagConfig.saveButtonLabel": "保存", - "xpack.beatsManagement.tagConfig.typeLabel": "类型", - "xpack.beatsManagement.tagConfig.viewConfigurationTitle\"": "查看配置块", - "xpack.beatsManagement.tagConfigAssignmentOptions.removeTagsButtonLabel": "删除标签", - "xpack.beatsManagement.tagConfigAssignmentOptions.removeTagsWarninigMessage": "从选定 Beats 删除该标签?", - "xpack.beatsManagement.tagConfigAssignmentOptions.removeTagsWarninigTitle": "删除标签", - "xpack.beatsManagement.tagListAssignmentOptions.removeTagsButtonLabel": "删除选定", - "xpack.beatsManagement.tagListAssignmentOptions.removeTagsWarninigTitle": "删除标签", - "xpack.beatsManagement.tagListAssignmentOptions.removeTagWarninigMessage": "删除标签?", - "xpack.beatsManagement.tags.addTagButtonLabel": "添加标签", - "xpack.beatsManagement.tags.someTagsMightBeAssignedToBeatsTitle": "以下部分标签可能已分配给 Beats。请确保正要删除的标签当前未被分配", - "xpack.beatsManagement.tagsTable.lastUpdateTitle": "上次更新", - "xpack.beatsManagement.tagsTable.removeSelectedLabel": "删除选定", - "xpack.beatsManagement.tagsTable.tagNameTitle": "标签名称", - "xpack.beatsManagement.tagTable.actions.removeButtonAriaLabel": "移除", - "xpack.beatsManagement.tagTable.actions.removeTooltip": "从标签删除此配置", - "xpack.beatsManagement.tagTable.actionsColumnName": "操作", - "xpack.beatsManagement.tagTable.descriptionColumnName": "描述", - "xpack.beatsManagement.tagTable.moduleColumn.notAvailibaleLabel": "不可用", - "xpack.beatsManagement.tagTable.moduleColumnName": "模块", - "xpack.beatsManagement.tagTable.typeColumnName": "类型", - "xpack.beatsManagement.walkthrough.initial.betaBadgeText": "公测版", "xpack.canvas.app.loadErrorMessage": "消息:{error}", "xpack.canvas.app.loadErrorTitle": "Canvas 加载失败", "xpack.canvas.app.loadingMessage": "Canvas 正在加载", diff --git a/x-pack/test/api_integration/apis/beats/assign_tags_to_beats.js b/x-pack/test/api_integration/apis/beats/assign_tags_to_beats.js deleted file mode 100644 index c11bdb7112640..0000000000000 --- a/x-pack/test/api_integration/apis/beats/assign_tags_to_beats.js +++ /dev/null @@ -1,254 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import expect from '@kbn/expect'; -import { ES_INDEX_NAME } from './constants'; - -export default function ({ getService }) { - const supertest = getService('supertest'); - const esArchiver = getService('esArchiver'); - const es = getService('legacyEs'); - const randomness = getService('randomness'); - - describe('assign_tags_to_beats', () => { - const archive = 'beats/list'; - - beforeEach('load beats archive', () => esArchiver.load(archive)); - afterEach('unload beats archive', () => esArchiver.unload(archive)); - - it('should add a single tag to a single beat', async () => { - const { body: apiResponse } = await supertest - .post('/api/beats/agents_tags/assignments') - .set('kbn-xsrf', 'xxx') - .send({ - assignments: [{ beatId: 'bar', tag: 'production' }], - }) - .expect(200); - - expect(apiResponse.results).to.eql([{ success: true, result: { message: 'updated' } }]); - - const esResponse = await es.get({ - index: ES_INDEX_NAME, - id: `beat:bar`, - }); - - const beat = esResponse._source.beat; - expect(beat.tags).to.eql(['production']); - }); - - it('should not re-add an existing tag to a beat', async () => { - const tags = ['production']; - - let esResponse; - let beat; - - // Before adding the existing tag - esResponse = await es.get({ - index: ES_INDEX_NAME, - id: `beat:foo`, - }); - - beat = esResponse._source.beat; - expect(beat.tags).to.eql([...tags, 'qa']); - - // Adding the existing tag - const { body: apiResponse } = await supertest - .post('/api/beats/agents_tags/assignments') - .set('kbn-xsrf', 'xxx') - .send({ - assignments: [{ beatId: 'foo', tag: 'production' }], - }) - .expect(200); - - expect(apiResponse.results).to.eql([{ success: true, result: { message: 'updated' } }]); - - // After adding the existing tag - esResponse = await es.get({ - index: ES_INDEX_NAME, - id: `beat:foo`, - }); - - beat = esResponse._source.beat; - expect(beat.tags).to.eql([...tags, 'qa']); - }); - - it('should add a single tag to a multiple beats', async () => { - const { body: apiResponse } = await supertest - .post('/api/beats/agents_tags/assignments') - .set('kbn-xsrf', 'xxx') - .send({ - assignments: [ - { beatId: 'foo', tag: 'development' }, - { beatId: 'bar', tag: 'development' }, - ], - }) - .expect(200); - - expect(apiResponse.results).to.eql([ - { success: true, result: { message: 'updated' } }, - { success: true, result: { message: 'updated' } }, - ]); - - let esResponse; - let beat; - - // Beat foo - esResponse = await es.get({ - index: ES_INDEX_NAME, - id: `beat:foo`, - }); - - beat = esResponse._source.beat; - expect(beat.tags).to.eql(['production', 'qa', 'development']); // as beat 'foo' already had 'production' and 'qa' tags attached to it - - // Beat bar - esResponse = await es.get({ - index: ES_INDEX_NAME, - id: `beat:bar`, - }); - - beat = esResponse._source.beat; - expect(beat.tags).to.eql(['development']); - }); - - it('should add multiple tags to a single beat', async () => { - const { body: apiResponse } = await supertest - .post('/api/beats/agents_tags/assignments') - .set('kbn-xsrf', 'xxx') - .send({ - assignments: [ - { beatId: 'bar', tag: 'development' }, - { beatId: 'bar', tag: 'production' }, - ], - }) - .expect(200); - - expect(apiResponse.results).to.eql([ - { success: true, result: { message: 'updated' } }, - { success: true, result: { message: 'updated' } }, - ]); - - const esResponse = await es.get({ - index: ES_INDEX_NAME, - id: `beat:bar`, - }); - - const beat = esResponse._source.beat; - expect(beat.tags).to.eql(['development', 'production']); - }); - - it('should add multiple tags to a multiple beats', async () => { - const { body: apiResponse } = await supertest - .post('/api/beats/agents_tags/assignments') - .set('kbn-xsrf', 'xxx') - .send({ - assignments: [ - { beatId: 'foo', tag: 'development' }, - { beatId: 'bar', tag: 'production' }, - ], - }) - .expect(200); - - expect(apiResponse.results).to.eql([ - { success: true, result: { message: 'updated' } }, - { success: true, result: { message: 'updated' } }, - ]); - - let esResponse; - let beat; - - // Beat foo - esResponse = await es.get({ - index: ES_INDEX_NAME, - id: `beat:foo`, - }); - - beat = esResponse._source.beat; - expect(beat.tags).to.eql(['production', 'qa', 'development']); // as beat 'foo' already had 'production' and 'qa' tags attached to it - - // Beat bar - esResponse = await es.get({ - index: ES_INDEX_NAME, - id: `beat:bar`, - }); - - beat = esResponse._source.beat; - expect(beat.tags).to.eql(['production']); - }); - - it('should return errors for non-existent beats', async () => { - const nonExistentBeatId = randomness.word(); - - const { body: apiResponse } = await supertest - .post('/api/beats/agents_tags/assignments') - .set('kbn-xsrf', 'xxx') - .send({ - assignments: [{ beatId: nonExistentBeatId, tag: 'production' }], - }) - .expect(200); - - expect(apiResponse.results).to.eql([ - { success: false, error: { code: 404, message: `Beat ${nonExistentBeatId} not found` } }, - ]); - }); - - it('should return errors for non-existent tags', async () => { - const nonExistentTag = randomness.word(); - - const { body: apiResponse } = await supertest - .post('/api/beats/agents_tags/assignments') - .set('kbn-xsrf', 'xxx') - .send({ - assignments: [{ beatId: 'bar', tag: nonExistentTag }], - }) - .expect(200); - - expect(apiResponse.results).to.eql([ - { success: false, error: { code: 404, message: `Tag ${nonExistentTag} not found` } }, - ]); - - const esResponse = await es.get({ - index: ES_INDEX_NAME, - id: `beat:bar`, - }); - - const beat = esResponse._source.beat; - expect(beat).to.not.have.property('tags'); - }); - - it('should return errors for non-existent beats and tags', async () => { - const nonExistentBeatId = randomness.word(); - const nonExistentTag = randomness.word(); - - const { body: apiResponse } = await supertest - .post('/api/beats/agents_tags/assignments') - .set('kbn-xsrf', 'xxx') - .send({ - assignments: [{ beatId: nonExistentBeatId, tag: nonExistentTag }], - }) - .expect(200); - - expect(apiResponse.results).to.eql([ - { - success: false, - error: { - code: 404, - message: `Beat ${nonExistentBeatId} and tag ${nonExistentTag} not found`, - }, - }, - ]); - - const esResponse = await es.get({ - index: ES_INDEX_NAME, - id: `beat:bar`, - }); - - const beat = esResponse._source.beat; - expect(beat).to.not.have.property('tags'); - }); - }); -} diff --git a/x-pack/test/api_integration/apis/beats/constants.js b/x-pack/test/api_integration/apis/beats/constants.js deleted file mode 100644 index 9e8064f4d1b5b..0000000000000 --- a/x-pack/test/api_integration/apis/beats/constants.js +++ /dev/null @@ -1,8 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export const ES_INDEX_NAME = '.management-beats'; diff --git a/x-pack/test/api_integration/apis/beats/create_enrollment_tokens.js b/x-pack/test/api_integration/apis/beats/create_enrollment_tokens.js deleted file mode 100644 index 5ac59b690465f..0000000000000 --- a/x-pack/test/api_integration/apis/beats/create_enrollment_tokens.js +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import expect from '@kbn/expect'; -import moment from 'moment'; -import { ES_INDEX_NAME } from './constants'; - -export default function ({ getService }) { - const supertest = getService('supertest'); - const es = getService('legacyEs'); - - describe('create_enrollment_token', () => { - it('should create one token by default', async () => { - const { body: apiResponse } = await supertest - .post('/api/beats/enrollment_tokens') - .set('kbn-xsrf', 'xxx') - .send() - .expect(200); - - const tokensFromApi = apiResponse.results.map((r) => r.item); - - const esResponse = await es.search({ - index: ES_INDEX_NAME, - q: 'type:enrollment_token', - }); - - const tokensInEs = esResponse.hits.hits.map((hit) => hit._source.enrollment_token.token); - - expect(tokensFromApi.length).to.eql(1); - expect(tokensFromApi).to.eql(tokensInEs); - }); - - it('should create the specified number of tokens', async () => { - const numTokens = 1000; - - const { body: apiResponse } = await supertest - .post('/api/beats/enrollment_tokens') - .set('kbn-xsrf', 'xxx') - .send({ - num_tokens: numTokens, - }) - .expect(200); - - const tokensFromApi = apiResponse.results.map((r) => r.item); - - const esResponse = await es.search({ - index: ES_INDEX_NAME, - q: 'type:enrollment_token', - size: numTokens, - }); - - const tokensInEs = esResponse.hits.hits.map((hit) => hit._source.enrollment_token.token); - - expect(tokensFromApi).to.be.an('array'); - expect(tokensFromApi.length).to.eql(numTokens); - expect(tokensInEs.length).to.eql(numTokens); - expect(tokensFromApi.sort()).to.eql(tokensInEs.sort()); - }); - - it('should set token expiration to 10 minutes from now by default', async () => { - await supertest - .post('/api/beats/enrollment_tokens') - .set('kbn-xsrf', 'xxx') - .send() - .expect(200); - - const esResponse = await es.search({ - index: ES_INDEX_NAME, - q: 'type:enrollment_token', - }); - - const tokenInEs = esResponse.hits.hits[0]._source.enrollment_token; - - // We do a fuzzy check to see if the token expires between 9 and 10 minutes - // from now because a bit of time has elapsed been the creation of the - // tokens and this check. - const tokenExpiresOn = moment(tokenInEs.expires_on).valueOf(); - const tenMinutesFromNow = moment().add('10', 'minutes').valueOf(); - const almostTenMinutesFromNow = moment(tenMinutesFromNow).subtract('2', 'seconds').valueOf(); - expect(tokenExpiresOn).to.be.lessThan(tenMinutesFromNow); - expect(tokenExpiresOn).to.be.greaterThan(almostTenMinutesFromNow); - }); - }); -} diff --git a/x-pack/test/api_integration/apis/beats/enroll_beat.js b/x-pack/test/api_integration/apis/beats/enroll_beat.js deleted file mode 100644 index a1ac449e7fcb8..0000000000000 --- a/x-pack/test/api_integration/apis/beats/enroll_beat.js +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import expect from '@kbn/expect'; -import moment from 'moment'; - -import { ES_INDEX_NAME } from './constants'; - -export default function ({ getService }) { - const supertest = getService('supertest'); - const randomness = getService('randomness'); - const es = getService('legacyEs'); - - describe('enroll_beat', () => { - let validEnrollmentToken; - let beatId; - let beat; - - beforeEach(async () => { - validEnrollmentToken = randomness.word(); - - beatId = randomness.word(); - const version = - randomness.integer({ min: 1, max: 10 }) + - '.' + - randomness.integer({ min: 1, max: 10 }) + - '.' + - randomness.integer({ min: 1, max: 10 }); - - beat = { - type: 'filebeat', - host_name: 'foo.bar.com', - name: randomness.word(), - version, - }; - - await es.index({ - index: ES_INDEX_NAME, - id: `enrollment_token:${validEnrollmentToken}`, - body: { - type: 'enrollment_token', - enrollment_token: { - token: validEnrollmentToken, - expires_on: moment().add(4, 'hours').toJSON(), - }, - }, - }); - }); - - it('should enroll beat in a verified state', async () => { - await supertest - .post(`/api/beats/agent/${beatId}`) - .set('kbn-xsrf', 'xxx') - .set('kbn-beats-enrollment-token', validEnrollmentToken) - .send(beat) - .expect(200); - - const esResponse = await es.get({ - index: ES_INDEX_NAME, - id: `beat:${beatId}`, - }); - - expect(esResponse._source.beat).to.have.property('verified_on'); - expect(esResponse._source.beat).to.have.property('host_ip'); - }); - - it('should contain an access token in the response', async () => { - const { body: apiResponse } = await supertest - .post(`/api/beats/agent/${beatId}`) - .set('kbn-xsrf', 'xxx') - .set('kbn-beats-enrollment-token', validEnrollmentToken) - .send(beat) - .expect(200); - - const accessTokenFromApi = apiResponse.item; - - const esResponse = await es.get({ - index: ES_INDEX_NAME, - id: `beat:${beatId}`, - }); - - const accessTokenInEs = esResponse._source.beat.access_token; - - expect(accessTokenFromApi.length).to.be.greaterThan(0); - expect(accessTokenFromApi).to.eql(accessTokenInEs); - }); - - it('should reject an invalid enrollment token', async () => { - const { body: apiResponse } = await supertest - .post(`/api/beats/agent/${beatId}`) - .set('kbn-xsrf', 'xxx') - .set('kbn-beats-enrollment-token', randomness.word()) - .send(beat) - .expect(400); - - expect(apiResponse).to.eql({ - statusCode: 400, - error: 'Bad Request', - message: 'Invalid enrollment token', - }); - }); - - it('should reject an expired enrollment token', async () => { - const expiredEnrollmentToken = - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.' + - 'eyJjcmVhdGVkIjoiMjAxOC0wNi0zMFQwMzo0MjoxNS4yMzBaIiwiaWF0IjoxNTMwMzMwMTM1LCJleHAiOjE1MzAzMzAxMzV9.' + - 'Azf4czAwWZEflR7Pf8pi-DUTcve9xyxWyViNYeUSGog'; - - await es.index({ - index: ES_INDEX_NAME, - id: `enrollment_token:${expiredEnrollmentToken}`, - body: { - type: 'enrollment_token', - enrollment_token: { - token: expiredEnrollmentToken, - expires_on: moment().subtract(1, 'minute').toJSON(), - }, - }, - }); - - const { body: apiResponse } = await supertest - .post(`/api/beats/agent/${beatId}`) - .set('kbn-xsrf', 'xxx') - .set('kbn-beats-enrollment-token', expiredEnrollmentToken) - .send(beat) - .expect(400); - - expect(apiResponse).to.eql({ - statusCode: 400, - error: 'Bad Request', - message: 'Expired enrollment token', - }); - }); - - it('should delete the given enrollment token so it may not be reused', async () => { - await supertest - .post(`/api/beats/agent/${beatId}`) - .set('kbn-xsrf', 'xxx') - .set('kbn-beats-enrollment-token', validEnrollmentToken) - .send(beat) - .expect(200); - - const esResponse = await es.get({ - index: ES_INDEX_NAME, - id: `enrollment_token:${validEnrollmentToken}`, - ignore: [404], - }); - - expect(esResponse.found).to.be(false); - }); - - it('should fail if the beat with the same ID is enrolled twice', async () => { - await supertest - .post(`/api/beats/agent/${beatId}`) - .set('kbn-xsrf', 'xxx') - .set('kbn-beats-enrollment-token', validEnrollmentToken) - .send(beat) - .expect(200); - - await es.index({ - index: ES_INDEX_NAME, - id: `enrollment_token:${validEnrollmentToken}`, - body: { - type: 'enrollment_token', - enrollment_token: { - token: validEnrollmentToken, - expires_on: moment().add(4, 'hours').toJSON(), - }, - }, - }); - - await supertest - .post(`/api/beats/agent/${beatId}`) - .set('kbn-xsrf', 'xxx') - .set('kbn-beats-enrollment-token', validEnrollmentToken) - .send(beat) - .expect(200); - }); - }); -} diff --git a/x-pack/test/api_integration/apis/beats/get_beat.js b/x-pack/test/api_integration/apis/beats/get_beat.js deleted file mode 100644 index 610ea72bb3d42..0000000000000 --- a/x-pack/test/api_integration/apis/beats/get_beat.js +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import expect from '@kbn/expect'; -import { ES_INDEX_NAME } from './constants'; - -export default function ({ getService }) { - const supertest = getService('supertest'); - const esArchiver = getService('esArchiver'); - const es = getService('legacyEs'); - - describe('get_beat_configuration', () => { - const archive = 'beats/list'; - - beforeEach('load beats archive', () => esArchiver.load(archive)); - afterEach('unload beats archive', () => esArchiver.unload(archive)); - - it('should return no configurations for the beat without tags', async () => { - await es.index({ - index: ES_INDEX_NAME, - id: `beat:empty`, - body: { - type: 'beat', - beat: { - type: 'filebeat', - active: true, - host_ip: '1.2.3.4', - host_name: 'empty.com', - id: 'empty', - name: 'empty_filebeat', - access_token: - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjcmVhdGVkIjoiMjAxOC0wNi0zMFQwMzo0MjoxNS4yMzBaIiwiaWF0IjoxNTMwMzMwMTM1fQ.SSsX2Byyo1B1bGxV8C3G4QldhE5iH87EY_1r21-bwbI', // eslint-disable-line - }, - }, - }); - - const { body: apiResponse } = await supertest - .get('/api/beats/agent/empty/configuration') - .set( - 'kbn-beats-access-token', - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.' + - 'eyJjcmVhdGVkIjoiMjAxOC0wNi0zMFQwMzo0MjoxNS4yMzBaIiwiaWF0IjoxNTMwMzMwMTM1fQ.' + - 'SSsX2Byyo1B1bGxV8C3G4QldhE5iH87EY_1r21-bwbI' - ) - .expect(200); - - const configurationBlocks = apiResponse.list; - - expect(configurationBlocks).to.be.an(Array); - expect(configurationBlocks.length).to.be(0); - }); - - it('should return merged configuration for the beat', async () => { - const { body: apiResponse } = await supertest - .get('/api/beats/agent/foo/configuration') - .set( - 'kbn-beats-access-token', - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.' + - 'eyJjcmVhdGVkIjoiMjAxOC0wNi0zMFQwMzo0MjoxNS4yMzBaIiwiaWF0IjoxNTMwMzMwMTM1fQ.' + - 'SSsX2Byyo1B1bGxV8C3G4QldhE5iH87EY_1r21-bwbI' - ) - .expect(200); - - const configurationBlocks = apiResponse.list; - - expect(configurationBlocks).to.be.an(Array); - expect(configurationBlocks.length).to.be(3); - - expect(configurationBlocks[1].type).to.be('metricbeat.modules'); - expect(configurationBlocks[1].config).to.eql({ - module: 'memcached', - hosts: ['localhost:11211'], - }); - - expect(configurationBlocks[2].type).to.be('metricbeat.modules'); - expect(configurationBlocks[2].config).to.eql({ - module: 'memcached', - hosts: ['localhost:4949'], - 'node.namespace': 'node', - }); - }); - }); -} diff --git a/x-pack/test/api_integration/apis/beats/index.js b/x-pack/test/api_integration/apis/beats/index.js deleted file mode 100644 index b490ddd24da38..0000000000000 --- a/x-pack/test/api_integration/apis/beats/index.js +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { ES_INDEX_NAME } from './constants'; - -export default function ({ getService, loadTestFile }) { - const es = getService('legacyEs'); - - describe('beats', () => { - const cleanup = () => - es.indices.delete({ - index: ES_INDEX_NAME, - ignore: [404], - }); - - beforeEach(cleanup); - - loadTestFile(require.resolve('./create_enrollment_tokens')); - loadTestFile(require.resolve('./enroll_beat')); - loadTestFile(require.resolve('./list_beats')); - loadTestFile(require.resolve('./update_beat')); - loadTestFile(require.resolve('./set_tag')); - loadTestFile(require.resolve('./assign_tags_to_beats')); - loadTestFile(require.resolve('./remove_tags_from_beats')); - loadTestFile(require.resolve('./get_beat')); - }); -} diff --git a/x-pack/test/api_integration/apis/beats/list_beats.js b/x-pack/test/api_integration/apis/beats/list_beats.js deleted file mode 100644 index a844b814f7ca8..0000000000000 --- a/x-pack/test/api_integration/apis/beats/list_beats.js +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import expect from '@kbn/expect'; - -export default function ({ getService }) { - const supertest = getService('supertest'); - const esArchiver = getService('esArchiver'); - - describe('list_beats', () => { - const archive = 'beats/list'; - - beforeEach('load beats archive', () => esArchiver.load(archive)); - afterEach('unload beats archive', () => esArchiver.unload(archive)); - - it('should return all beats', async () => { - const { body: apiResponse } = await supertest.get('/api/beats/agents').expect(200); - - const beatsFromApi = apiResponse.list; - - expect(beatsFromApi.length).to.be(4); - expect(beatsFromApi.filter((beat) => beat.hasOwnProperty('verified_on')).length).to.be(1); - expect(beatsFromApi.find((beat) => beat.hasOwnProperty('verified_on')).id).to.be('foo'); - }); - - it('should not return access tokens', async () => { - const { body: apiResponse } = await supertest.get('/api/beats/agents').expect(200); - - const beatsFromApi = apiResponse.list; - - expect(beatsFromApi.length).to.be(4); - expect(beatsFromApi.filter((beat) => beat.hasOwnProperty('access_token')).length).to.be(0); - }); - }); -} diff --git a/x-pack/test/api_integration/apis/beats/remove_tags_from_beats.js b/x-pack/test/api_integration/apis/beats/remove_tags_from_beats.js deleted file mode 100644 index 1c9ce2ffb7d48..0000000000000 --- a/x-pack/test/api_integration/apis/beats/remove_tags_from_beats.js +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import expect from '@kbn/expect'; -import { ES_INDEX_NAME } from './constants'; - -export default function ({ getService }) { - const supertest = getService('supertest'); - const esArchiver = getService('esArchiver'); - const es = getService('legacyEs'); - const randomness = getService('randomness'); - - describe('remove_tags_from_beats', () => { - const archive = 'beats/list'; - - beforeEach('load beats archive', () => esArchiver.load(archive)); - afterEach('unload beats archive', () => esArchiver.unload(archive)); - - it('should remove a single tag from a single beat', async () => { - const { body: apiResponse } = await supertest - .post('/api/beats/agents_tags/removals') - .set('kbn-xsrf', 'xxx') - .send({ - removals: [{ beatId: 'foo', tag: 'production' }], - }) - .expect(200); - - expect(apiResponse.results).to.eql([{ success: true, result: { message: 'updated' } }]); - - const esResponse = await es.get({ - index: ES_INDEX_NAME, - id: `beat:foo`, - }); - - const beat = esResponse._source.beat; - expect(beat.tags).to.eql(['qa']); - }); - - it('should remove a single tag from a multiple beats', async () => { - const { body: apiResponse } = await supertest - .post('/api/beats/agents_tags/removals') - .set('kbn-xsrf', 'xxx') - .send({ - removals: [ - { beatId: 'foo', tag: 'development' }, - { beatId: 'bar', tag: 'development' }, - ], - }) - .expect(200); - - expect(apiResponse.results).to.eql([ - { success: true, result: { message: 'updated' } }, - { success: true, result: { message: 'updated' } }, - ]); - - let esResponse; - let beat; - - // Beat foo - esResponse = await es.get({ - index: ES_INDEX_NAME, - id: `beat:foo`, - }); - - beat = esResponse._source.beat; - expect(beat.tags).to.eql(['production', 'qa']); // as beat 'foo' already had 'production' and 'qa' tags attached to it - - // Beat bar - esResponse = await es.get({ - index: ES_INDEX_NAME, - id: `beat:bar`, - }); - - beat = esResponse._source.beat; - expect(beat).to.not.have.property('tags'); - }); - - it('should remove multiple tags from a single beat', async () => { - const { body: apiResponse } = await supertest - .post('/api/beats/agents_tags/removals') - .set('kbn-xsrf', 'xxx') - .send({ - removals: [ - { beatId: 'foo', tag: 'development' }, - { beatId: 'foo', tag: 'production' }, - ], - }) - .expect(200); - - expect(apiResponse.results).to.eql([ - { success: true, result: { message: 'updated' } }, - { success: true, result: { message: 'updated' } }, - ]); - - const esResponse = await es.get({ - index: ES_INDEX_NAME, - id: `beat:foo`, - }); - - const beat = esResponse._source.beat; - expect(beat.tags).to.eql(['qa']); // as beat 'foo' already had 'production' and 'qa' tags attached to it - }); - - it('should remove multiple tags from a multiple beats', async () => { - const { body: apiResponse } = await supertest - .post('/api/beats/agents_tags/removals') - .set('kbn-xsrf', 'xxx') - .send({ - removals: [ - { beatId: 'foo', tag: 'production' }, - { beatId: 'bar', tag: 'development' }, - ], - }) - .expect(200); - - expect(apiResponse.results).to.eql([ - { success: true, result: { message: 'updated' } }, - { success: true, result: { message: 'updated' } }, - ]); - - let esResponse; - let beat; - - // Beat foo - esResponse = await es.get({ - index: ES_INDEX_NAME, - id: `beat:foo`, - }); - - beat = esResponse._source.beat; - expect(beat.tags).to.eql(['qa']); // as beat 'foo' already had 'production' and 'qa' tags attached to it - - // Beat bar - esResponse = await es.get({ - index: ES_INDEX_NAME, - id: `beat:bar`, - }); - - beat = esResponse._source.beat; - expect(beat).to.not.have.property('tags'); - }); - - it('should return errors for non-existent beats', async () => { - const nonExistentBeatId = randomness.word(); - - const { body: apiResponse } = await supertest - .post('/api/beats/agents_tags/removals') - .set('kbn-xsrf', 'xxx') - .send({ - removals: [{ beatId: nonExistentBeatId, tag: 'production' }], - }) - .expect(200); - - expect(apiResponse.results).to.eql([ - { success: false, error: { code: 404, message: `Beat ${nonExistentBeatId} not found` } }, - ]); - }); - - it('should return errors for non-existent tags', async () => { - const nonExistentTag = randomness.word(); - - const { body: apiResponse } = await supertest - .post('/api/beats/agents_tags/removals') - .set('kbn-xsrf', 'xxx') - .send({ - removals: [{ beatId: 'bar', tag: nonExistentTag }], - }) - .expect(200); - - expect(apiResponse.results).to.eql([ - { success: false, error: { code: 404, message: `Tag ${nonExistentTag} not found` } }, - ]); - - const esResponse = await es.get({ - index: ES_INDEX_NAME, - id: `beat:bar`, - }); - - const beat = esResponse._source.beat; - expect(beat).to.not.have.property('tags'); - }); - - it('should return errors for non-existent beats and tags', async () => { - const nonExistentBeatId = randomness.word(); - const nonExistentTag = randomness.word(); - - const { body: apiResponse } = await supertest - .post('/api/beats/agents_tags/removals') - .set('kbn-xsrf', 'xxx') - .send({ - removals: [{ beatId: nonExistentBeatId, tag: nonExistentTag }], - }) - .expect(200); - - expect(apiResponse.results).to.eql([ - { - success: false, - error: { - code: 404, - message: `Beat ${nonExistentBeatId} and tag ${nonExistentTag} not found`, - }, - }, - ]); - - const esResponse = await es.get({ - index: ES_INDEX_NAME, - id: `beat:bar`, - }); - - const beat = esResponse._source.beat; - expect(beat).to.not.have.property('tags'); - }); - }); -} diff --git a/x-pack/test/api_integration/apis/beats/set_config.js b/x-pack/test/api_integration/apis/beats/set_config.js deleted file mode 100644 index fbc3db30313bf..0000000000000 --- a/x-pack/test/api_integration/apis/beats/set_config.js +++ /dev/null @@ -1,246 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import expect from '@kbn/expect'; -import { ES_INDEX_NAME } from './constants'; - -export default function ({ getService }) { - const supertest = getService('supertest'); - const es = getService('legacyEs'); - const esArchiver = getService('esArchiver'); - - describe('set_config', () => { - const archive = 'beats/list'; - - beforeEach('load archive', () => esArchiver.load(archive)); - afterEach('unload archive', () => esArchiver.unload(archive)); - - it('should create a configuration block', async () => { - const tagId = 'qa'; - await supertest - .put(`/api/beats/configurations`) - .set('kbn-xsrf', 'xxx') - .send([ - { - type: 'output', - description: 'smething', - config: { elasticsearch: { hosts: ['localhost:9200'], username: 'foo' } }, - }, - ]) - .expect(200); - const esResponse = await es.get({ - index: ES_INDEX_NAME, - id: `tag:${tagId}`, - }); - - const tagInEs = esResponse._source; - - expect(tagInEs.type).to.be('tag'); - expect(tagInEs.tag.id).to.be(tagId); - expect(tagInEs.tag.configuration_blocks).to.be.an(Array); - expect(tagInEs.tag.configuration_blocks.length).to.be(1); - expect(tagInEs.tag.configuration_blocks[0].type).to.be('output'); - expect(tagInEs.tag.configuration_blocks[0].configs).to.eql([ - { - elasticsearch: { - hosts: ['localhost:9200'], - username: 'foo', - }, - }, - ]); - }); - - // it('should create a tag with two configuration blocks', async () => { - // const tagId = 'production'; - // await supertest - // .put(`/api/beats/tag/${tagId}`) - // .set('kbn-xsrf', 'xxx') - // .send({ - // configuration_blocks: [ - // { - // type: 'filebeat.inputs', - // configs: [ - // { - // paths: ['./foo'], - // }, - // ], - // }, - // { - // type: 'output', - // configs: [ - // { - // elasticsearch: { - // hosts: ['localhost:9200'], - // username: 'foo', - // }, - // }, - // ], - // }, - // ], - // }) - // .expect(201); - - // const esResponse = await es.get({ - // index: ES_INDEX_NAME, - // type: ES_TYPE_NAME, - // id: `tag:${tagId}`, - // }); - - // const tagInEs = esResponse._source; - - // expect(tagInEs.type).to.be('tag'); - // expect(tagInEs.tag.id).to.be(tagId); - // expect(tagInEs.tag.configuration_blocks).to.be.an(Array); - // expect(tagInEs.tag.configuration_blocks.length).to.be(2); - // expect(tagInEs.tag.configuration_blocks[0].type).to.be('filebeat.inputs'); - // expect(tagInEs.tag.configuration_blocks[0].configs).to.eql([ - // { - // paths: ['./foo'], - // }, - // ]); - // expect(tagInEs.tag.configuration_blocks[1].type).to.be('output'); - // expect(tagInEs.tag.configuration_blocks[1].configs).to.eql([ - // { - // elasticsearch: { - // hosts: ['localhost:9200'], - // username: 'foo', - // }, - // }, - // ]); - // }); - - // it('should fail when creating a tag with two configuration blocks of type output', async () => { - // const tagId = 'production'; - // await supertest - // .put(`/api/beats/tag/${tagId}`) - // .set('kbn-xsrf', 'xxx') - // .send({ - // configuration_blocks: [ - // { - // type: 'output', - // configs: [ - // { - // elasticsearch: { - // hosts: ['localhost:9200'], - // username: 'foo', - // }, - // }, - // ], - // }, - // { - // type: 'output', - // configs: [ - // { - // elasticsearch: { - // hosts: ['localhost:9200'], - // username: 'foo', - // }, - // }, - // ], - // }, - // ], - // }) - // .expect(400); - // }); - - // it('should fail when creating a tag with an invalid configuration block type', async () => { - // const tagId = 'production'; - // await supertest - // .put(`/api/beats/tag/${tagId}`) - // .set('kbn-xsrf', 'xxx') - // .send({ - // configuration_blocks: [ - // { - // type: chance.word(), - // configs: [ - // { - // elasticsearch: { - // hosts: ['localhost:9200'], - // username: 'foo', - // }, - // }, - // ], - // }, - // ], - // }) - // .expect(400); - // }); - - // it('should update an existing tag', async () => { - // const tagId = 'production'; - // await supertest - // .put(`/api/beats/tag/${tagId}`) - // .set('kbn-xsrf', 'xxx') - // .send({ - // configuration_blocks: [ - // { - // type: 'filebeat.inputs', - // configs: [ - // { - // paths: ['./test'], - // }, - // ], - // }, - // { - // type: 'output', - // configs: [ - // { - // elasticsearch: { - // hosts: ['localhost:9200'], - // username: 'foo', - // }, - // }, - // ], - // }, - // ], - // }) - // .expect(201); - - // await supertest - // .put(`/api/beats/tag/${tagId}`) - // .set('kbn-xsrf', 'xxx') - // .send({ - // configuration_blocks: [ - // { - // type: 'output', - // configs: [ - // { - // elasticsearch: { - // hosts: ['localhost:9000'], - // username: 'foo', - // }, - // }, - // ], - // }, - // ], - // }) - // .expect(200); - - // const esResponse = await es.get({ - // index: ES_INDEX_NAME, - // type: ES_TYPE_NAME, - // id: `tag:${tagId}`, - // }); - - // const tagInEs = esResponse._source; - - // expect(tagInEs.type).to.be('tag'); - // expect(tagInEs.tag.id).to.be(tagId); - // expect(tagInEs.tag.configuration_blocks).to.be.an(Array); - // expect(tagInEs.tag.configuration_blocks.length).to.be(1); - // expect(tagInEs.tag.configuration_blocks[0].type).to.be('output'); - // expect(tagInEs.tag.configuration_blocks[0].configs).to.eql([ - // { - // elasticsearch: { - // hosts: ['localhost:9000'], - // username: 'foo', - // }, - // }, - // ]); - // }); - }); -} diff --git a/x-pack/test/api_integration/apis/beats/set_tag.js b/x-pack/test/api_integration/apis/beats/set_tag.js deleted file mode 100644 index 742fe9db251bd..0000000000000 --- a/x-pack/test/api_integration/apis/beats/set_tag.js +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import expect from '@kbn/expect'; -import { ES_INDEX_NAME } from './constants'; - -export default function ({ getService }) { - const supertest = getService('supertest'); - const es = getService('legacyEs'); - - describe('set_tag', () => { - it('should create a tag', async () => { - const tagId = 'production'; - await supertest - .put(`/api/beats/tag/${tagId}`) - .set('kbn-xsrf', 'xxx') - .send({ - color: 'green', - }) - .expect(200); - - const esResponse = await es.get({ - index: ES_INDEX_NAME, - id: `tag:${tagId}`, - }); - - const tagInEs = esResponse._source; - - expect(tagInEs.type).to.be('tag'); - expect(tagInEs.tag.id).to.be(tagId); - }); - - it('should update an existing tag', async () => { - const tagId = 'production'; - await supertest - .put(`/api/beats/tag/${tagId}`) - .set('kbn-xsrf', 'xxx') - .send({ - color: 'blue', - }) - .expect(200); - - await supertest - .put(`/api/beats/tag/${tagId}`) - .set('kbn-xsrf', 'xxx') - .send({ - color: 'yellow', - }) - .expect(200); - - const esResponse = await es.get({ - index: ES_INDEX_NAME, - id: `tag:${tagId}`, - }); - - const tagInEs = esResponse._source; - - expect(tagInEs.type).to.be('tag'); - expect(tagInEs.tag.id).to.be(tagId); - expect(tagInEs.tag.color).to.be('yellow'); - }); - }); -} diff --git a/x-pack/test/api_integration/apis/beats/update_beat.js b/x-pack/test/api_integration/apis/beats/update_beat.js deleted file mode 100644 index 8c67f43839fcc..0000000000000 --- a/x-pack/test/api_integration/apis/beats/update_beat.js +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import expect from '@kbn/expect'; -import { ES_INDEX_NAME } from './constants'; -import moment from 'moment'; - -export default function ({ getService }) { - const supertest = getService('supertest'); - const randomness = getService('randomness'); - const es = getService('legacyEs'); - const esArchiver = getService('esArchiver'); - - describe('update_beat', () => { - let validEnrollmentToken; - let beat; - const archive = 'beats/list'; - - beforeEach('load beats archive', () => esArchiver.load(archive)); - beforeEach(async () => { - validEnrollmentToken = - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.' + - 'eyJjcmVhdGVkIjoiMjAxOC0wNi0zMFQwMzo0MjoxNS4yMzBaIiwiaWF0IjoxNTMwMzMwMTM1fQ.' + - 'SSsX2Byyo1B1bGxV8C3G4QldhE5iH87EY_1r21-bwbI'; - - const version = - randomness.integer({ min: 1, max: 10 }) + - '.' + - randomness.integer({ min: 1, max: 10 }) + - '.' + - randomness.integer({ min: 1, max: 10 }); - - beat = { - type: `${randomness.word()}beat`, - host_name: `www.${randomness.word()}.net`, - name: randomness.word(), - version, - ephemeral_id: randomness.word(), - }; - - await es.index({ - index: ES_INDEX_NAME, - id: `enrollment_token:${validEnrollmentToken}`, - body: { - type: 'enrollment_token', - enrollment_token: { - token: validEnrollmentToken, - expires_on: moment().add(4, 'hours').toJSON(), - }, - }, - }); - }); - - afterEach('unload beats archive', () => esArchiver.unload(archive)); - - it('should update an existing verified beat', async () => { - const beatId = 'foo'; - await supertest - .put(`/api/beats/agent/${beatId}`) - .set('kbn-xsrf', 'xxx') - .set( - 'kbn-beats-access-token', - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.' + - 'eyJjcmVhdGVkIjoiMjAxOC0wNi0zMFQwMzo0MjoxNS4yMzBaIiwiaWF0IjoxNTMwMzMwMTM1fQ.' + - 'SSsX2Byyo1B1bGxV8C3G4QldhE5iH87EY_1r21-bwbI' - ) - .send(beat) - .expect(200); - - const beatInEs = await es.get({ - index: ES_INDEX_NAME, - id: `beat:${beatId}`, - }); - - expect(beatInEs._source.beat.id).to.be(beatId); - expect(beatInEs._source.beat.type).to.be(beat.type); - expect(beatInEs._source.beat.host_name).to.be(beat.host_name); - expect(beatInEs._source.beat.version).to.be(beat.version); - expect(beatInEs._source.beat.ephemeral_id).to.be(beat.ephemeral_id); - expect(beatInEs._source.beat.name).to.be(beat.name); - }); - - it('should return an error for an invalid access token', async () => { - const beatId = 'foo'; - const { body } = await supertest - .put(`/api/beats/agent/${beatId}`) - .set('kbn-xsrf', 'xxx') - .set('kbn-beats-access-token', randomness.word()) - .send(beat) - .expect(401); - - expect(body.message).to.be('Invalid access token'); - - const beatInEs = await es.get({ - index: ES_INDEX_NAME, - id: `beat:${beatId}`, - }); - - expect(beatInEs._source.beat.id).to.be(beatId); - expect(beatInEs._source.beat.type).to.not.be(beat.type); - expect(beatInEs._source.beat.host_name).to.not.be(beat.host_name); - expect(beatInEs._source.beat.version).to.not.be(beat.version); - expect(beatInEs._source.beat.ephemeral_id).to.not.be(beat.ephemeral_id); - }); - - it('should return an error for a non-existent beat', async () => { - const beatId = randomness.word(); - const { body } = await supertest - .put(`/api/beats/agent/${beatId}`) - .set('kbn-xsrf', 'xxx') - .set('kbn-beats-access-token', validEnrollmentToken) - .send(beat) - .expect(404); - - expect(body.message).to.be('Beat not found'); - }); - }); -} diff --git a/x-pack/test/api_integration/apis/index.ts b/x-pack/test/api_integration/apis/index.ts index e032844470177..0d345db58d24f 100644 --- a/x-pack/test/api_integration/apis/index.ts +++ b/x-pack/test/api_integration/apis/index.ts @@ -22,7 +22,6 @@ export default function ({ loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./logstash')); loadTestFile(require.resolve('./kibana')); loadTestFile(require.resolve('./metrics_ui')); - loadTestFile(require.resolve('./beats')); loadTestFile(require.resolve('./console')); loadTestFile(require.resolve('./management')); loadTestFile(require.resolve('./uptime')); diff --git a/x-pack/test/tsconfig.json b/x-pack/test/tsconfig.json index 63a9f8998a99d..7c95a53b75ee7 100644 --- a/x-pack/test/tsconfig.json +++ b/x-pack/test/tsconfig.json @@ -41,7 +41,6 @@ { "path": "../plugins/alerting/tsconfig.json" }, { "path": "../plugins/apm/tsconfig.json" }, { "path": "../plugins/banners/tsconfig.json" }, - { "path": "../plugins/beats_management/tsconfig.json" }, { "path": "../plugins/cases/tsconfig.json" }, { "path": "../plugins/cloud/tsconfig.json" }, { "path": "../plugins/console_extensions/tsconfig.json" }, From 77452e686be6a3b202e3a9e7bcf0fe0174a07ee9 Mon Sep 17 00:00:00 2001 From: Spencer Date: Thu, 27 May 2021 04:16:02 -0700 Subject: [PATCH 19/77] [ftr] migrate "comboBox" service to FtrService class (#100592) Co-authored-by: spalger --- test/functional/services/combo_box.ts | 518 +++++++++++++------------- test/functional/services/index.ts | 4 +- 2 files changed, 261 insertions(+), 261 deletions(-) diff --git a/test/functional/services/combo_box.ts b/test/functional/services/combo_box.ts index 4615a7378415c..a198aec1d1696 100644 --- a/test/functional/services/combo_box.ts +++ b/test/functional/services/combo_box.ts @@ -6,301 +6,301 @@ * Side Public License, v 1. */ -import { FtrProviderContext } from '../ftr_provider_context'; +import { FtrService } from '../ftr_provider_context'; import { WebElementWrapper } from './lib/web_element_wrapper'; // @ts-ignore not supported yet import { scrollIntoViewIfNecessary } from './lib/web_element_wrapper/scroll_into_view_if_necessary'; -export function ComboBoxProvider({ getService, getPageObjects }: FtrProviderContext) { - const config = getService('config'); - const testSubjects = getService('testSubjects'); - const find = getService('find'); - const log = getService('log'); - const retry = getService('retry'); - const browser = getService('browser'); - const PageObjects = getPageObjects(['common']); +/** + * wrapper around EuiComboBox interactions + */ +export class ComboBoxService extends FtrService { + private readonly config = this.ctx.getService('config'); + private readonly testSubjects = this.ctx.getService('testSubjects'); + private readonly find = this.ctx.getService('find'); + private readonly log = this.ctx.getService('log'); + private readonly retry = this.ctx.getService('retry'); + private readonly browser = this.ctx.getService('browser'); + private readonly PageObjects = this.ctx.getPageObjects(['common']); - const WAIT_FOR_EXISTS_TIME: number = config.get('timeouts.waitForExists'); + private readonly WAIT_FOR_EXISTS_TIME: number = this.config.get('timeouts.waitForExists'); - // wrapper around EuiComboBox interactions - class ComboBox { - /** - * Finds combobox element and sets specified value - * - * @param comboBoxSelector data-test-subj selector - * @param value option text - */ + /** + * Finds combobox element and sets specified value + * + * @param comboBoxSelector data-test-subj selector + * @param value option text + */ - public async set(comboBoxSelector: string, value: string): Promise { - log.debug(`comboBox.set, comboBoxSelector: ${comboBoxSelector}`); - const comboBox = await testSubjects.find(comboBoxSelector); - await this.setElement(comboBox, value); - } + public async set(comboBoxSelector: string, value: string): Promise { + this.log.debug(`comboBox.set, comboBoxSelector: ${comboBoxSelector}`); + const comboBox = await this.testSubjects.find(comboBoxSelector); + await this.setElement(comboBox, value); + } - /** - * Clicks option in combobox dropdown - * - * @param isMouseClick if 'true', click will be done with mouse - * @param element element that wraps up option - */ - private async clickOption(isMouseClick: boolean, element: WebElementWrapper): Promise { - // element.click causes scrollIntoView which causes combobox to close, using _webElement.click instead - return isMouseClick ? await element.clickMouseButton() : await element._webElement.click(); - } + /** + * Clicks option in combobox dropdown + * + * @param isMouseClick if 'true', click will be done with mouse + * @param element element that wraps up option + */ + private async clickOption(isMouseClick: boolean, element: WebElementWrapper): Promise { + // element.click causes scrollIntoView which causes combobox to close, using _webElement.click instead + return isMouseClick ? await element.clickMouseButton() : await element._webElement.click(); + } - /** - * Finds combobox element options - * - * @param comboBoxSelector data-test-subj selector - */ - public async getOptions(comboBoxSelector: string) { - const comboBoxElement = await testSubjects.find(comboBoxSelector); - await this.openOptionsList(comboBoxElement); - return await find.allByCssSelector('.euiFilterSelectItem', WAIT_FOR_EXISTS_TIME); - } + /** + * Finds combobox element options + * + * @param comboBoxSelector data-test-subj selector + */ + public async getOptions(comboBoxSelector: string) { + const comboBoxElement = await this.testSubjects.find(comboBoxSelector); + await this.openOptionsList(comboBoxElement); + return await this.find.allByCssSelector('.euiFilterSelectItem', this.WAIT_FOR_EXISTS_TIME); + } - /** - * Sets value for specified combobox element - * - * @param comboBoxElement element that wraps up EuiComboBox - * @param value - */ - public async setElement( - comboBoxElement: WebElementWrapper, - value: string, - options = { clickWithMouse: false } - ): Promise { - log.debug(`comboBox.setElement, value: ${value}`); - const isOptionSelected = await this.isOptionSelected(comboBoxElement, value); + /** + * Sets value for specified combobox element + * + * @param comboBoxElement element that wraps up EuiComboBox + * @param value + */ + public async setElement( + comboBoxElement: WebElementWrapper, + value: string, + options = { clickWithMouse: false } + ): Promise { + this.log.debug(`comboBox.setElement, value: ${value}`); + const isOptionSelected = await this.isOptionSelected(comboBoxElement, value); - if (isOptionSelected) { - return; - } + if (isOptionSelected) { + return; + } - await comboBoxElement.scrollIntoViewIfNecessary(); - await this.setFilterValue(comboBoxElement, value); - await this.openOptionsList(comboBoxElement); + await comboBoxElement.scrollIntoViewIfNecessary(); + await this.setFilterValue(comboBoxElement, value); + await this.openOptionsList(comboBoxElement); - if (value !== undefined) { - const selectOptions = await find.allByCssSelector( - `.euiFilterSelectItem[title^="${value.toString().trim()}"]`, - WAIT_FOR_EXISTS_TIME - ); + if (value !== undefined) { + const selectOptions = await this.find.allByCssSelector( + `.euiFilterSelectItem[title^="${value.toString().trim()}"]`, + this.WAIT_FOR_EXISTS_TIME + ); - if (selectOptions.length > 0) { - await this.clickOption(options.clickWithMouse, selectOptions[0]); - } else { - // if it doesn't find the item which text starts with value, it will choose the first option - const firstOption = await find.byCssSelector('.euiFilterSelectItem', 5000); - await this.clickOption(options.clickWithMouse, firstOption); - } + if (selectOptions.length > 0) { + await this.clickOption(options.clickWithMouse, selectOptions[0]); } else { - const firstOption = await find.byCssSelector('.euiFilterSelectItem'); + // if it doesn't find the item which text starts with value, it will choose the first option + const firstOption = await this.find.byCssSelector('.euiFilterSelectItem', 5000); await this.clickOption(options.clickWithMouse, firstOption); } - await this.closeOptionsList(comboBoxElement); - } - - /** - * Finds combobox element and sets custom value - * It applies changes by pressing Enter key. Sometimes it may lead to auto-submitting a form. - * - * @param comboBoxSelector data-test-subj selector - * @param value option text - */ - public async setCustom(comboBoxSelector: string, value: string): Promise { - log.debug(`comboBox.setCustom, comboBoxSelector: ${comboBoxSelector}, value: ${value}`); - const comboBoxElement = await testSubjects.find(comboBoxSelector); - await this.setFilterValue(comboBoxElement, value); - await PageObjects.common.pressEnterKey(); - await this.closeOptionsList(comboBoxElement); + } else { + const firstOption = await this.find.byCssSelector('.euiFilterSelectItem'); + await this.clickOption(options.clickWithMouse, firstOption); } + await this.closeOptionsList(comboBoxElement); + } - /** - * Finds combobox element and sets filter value - * - * @param comboBoxSelector data-test-subj selector - * @param filterValue text - */ - public async filterOptionsList(comboBoxSelector: string, filterValue: string): Promise { - log.debug( - `comboBox.filterOptionsList, comboBoxSelector: ${comboBoxSelector}, filter: ${filterValue}` - ); - const comboBox = await testSubjects.find(comboBoxSelector); - await this.setFilterValue(comboBox, filterValue); - await this.closeOptionsList(comboBox); - } + /** + * Finds combobox element and sets custom value + * It applies changes by pressing Enter key. Sometimes it may lead to auto-submitting a form. + * + * @param comboBoxSelector data-test-subj selector + * @param value option text + */ + public async setCustom(comboBoxSelector: string, value: string): Promise { + this.log.debug(`comboBox.setCustom, comboBoxSelector: ${comboBoxSelector}, value: ${value}`); + const comboBoxElement = await this.testSubjects.find(comboBoxSelector); + await this.setFilterValue(comboBoxElement, value); + await this.PageObjects.common.pressEnterKey(); + await this.closeOptionsList(comboBoxElement); + } - /** - * Sets new filter value in specified combobox element - * - * @param comboBoxElement element that wraps up EuiComboBox - * @param filterValue text - */ - private async setFilterValue( - comboBoxElement: WebElementWrapper, - filterValue: string - ): Promise { - const input = await comboBoxElement.findByTagName('input'); - await input.clearValue(); - await this.waitForOptionsListLoading(comboBoxElement); - await input.type(filterValue); - await this.waitForOptionsListLoading(comboBoxElement); - } + /** + * Finds combobox element and sets filter value + * + * @param comboBoxSelector data-test-subj selector + * @param filterValue text + */ + public async filterOptionsList(comboBoxSelector: string, filterValue: string): Promise { + this.log.debug( + `comboBox.filterOptionsList, comboBoxSelector: ${comboBoxSelector}, filter: ${filterValue}` + ); + const comboBox = await this.testSubjects.find(comboBoxSelector); + await this.setFilterValue(comboBox, filterValue); + await this.closeOptionsList(comboBox); + } - /** - * Waits options list to be loaded - * - * @param comboBoxElement element that wraps up EuiComboBox - */ - private async waitForOptionsListLoading(comboBoxElement: WebElementWrapper): Promise { - await comboBoxElement.waitForDeletedByCssSelector('.euiLoadingSpinner'); - } + /** + * Sets new filter value in specified combobox element + * + * @param comboBoxElement element that wraps up EuiComboBox + * @param filterValue text + */ + private async setFilterValue( + comboBoxElement: WebElementWrapper, + filterValue: string + ): Promise { + const input = await comboBoxElement.findByTagName('input'); + await input.clearValue(); + await this.waitForOptionsListLoading(comboBoxElement); + await input.type(filterValue); + await this.waitForOptionsListLoading(comboBoxElement); + } - /** - * Returns options list as a single string - * - * @param comboBoxSelector data-test-subj selector - */ - public async getOptionsList(comboBoxSelector: string): Promise { - log.debug(`comboBox.getOptionsList, comboBoxSelector: ${comboBoxSelector}`); - const comboBox = await testSubjects.find(comboBoxSelector); - const menu = await retry.try(async () => { - await testSubjects.click(comboBoxSelector); - await this.waitForOptionsListLoading(comboBox); - const isOptionsListOpen = await testSubjects.exists('~comboBoxOptionsList'); - if (!isOptionsListOpen) { - throw new Error('Combo box options list did not open on click'); - } - return await testSubjects.find('~comboBoxOptionsList'); - }); - const optionsText = await menu.getVisibleText(); - await this.closeOptionsList(comboBox); - return optionsText; - } + /** + * Waits options list to be loaded + * + * @param comboBoxElement element that wraps up EuiComboBox + */ + private async waitForOptionsListLoading(comboBoxElement: WebElementWrapper): Promise { + await comboBoxElement.waitForDeletedByCssSelector('.euiLoadingSpinner'); + } - /** - * Finds combobox element and checks if it has selected options - * - * @param comboBoxSelector data-test-subj selector - */ - public async doesComboBoxHaveSelectedOptions(comboBoxSelector: string): Promise { - log.debug(`comboBox.doesComboBoxHaveSelectedOptions, comboBoxSelector: ${comboBoxSelector}`); - const comboBox = await testSubjects.find(comboBoxSelector); - const $ = await comboBox.parseDomContent(); - return $('.euiComboBoxPill').toArray().length > 0; - } + /** + * Returns options list as a single string + * + * @param comboBoxSelector data-test-subj selector + */ + public async getOptionsList(comboBoxSelector: string): Promise { + this.log.debug(`comboBox.getOptionsList, comboBoxSelector: ${comboBoxSelector}`); + const comboBox = await this.testSubjects.find(comboBoxSelector); + const menu = await this.retry.try(async () => { + await this.testSubjects.click(comboBoxSelector); + await this.waitForOptionsListLoading(comboBox); + const isOptionsListOpen = await this.testSubjects.exists('~comboBoxOptionsList'); + if (!isOptionsListOpen) { + throw new Error('Combo box options list did not open on click'); + } + return await this.testSubjects.find('~comboBoxOptionsList'); + }); + const optionsText = await menu.getVisibleText(); + await this.closeOptionsList(comboBox); + return optionsText; + } - /** - * Returns selected options - * @param comboBoxSelector data-test-subj selector - */ - public async getComboBoxSelectedOptions(comboBoxSelector: string): Promise { - log.debug(`comboBox.getComboBoxSelectedOptions, comboBoxSelector: ${comboBoxSelector}`); - const comboBox = await testSubjects.find(comboBoxSelector); - const $ = await comboBox.parseDomContent(); - return $('.euiComboBoxPill') - .toArray() - .map((option) => $(option).text()); - } + /** + * Finds combobox element and checks if it has selected options + * + * @param comboBoxSelector data-test-subj selector + */ + public async doesComboBoxHaveSelectedOptions(comboBoxSelector: string): Promise { + this.log.debug( + `comboBox.doesComboBoxHaveSelectedOptions, comboBoxSelector: ${comboBoxSelector}` + ); + const comboBox = await this.testSubjects.find(comboBoxSelector); + const $ = await comboBox.parseDomContent(); + return $('.euiComboBoxPill').toArray().length > 0; + } - /** - * Finds combobox element and clears value in the input field by clicking clear button - * - * @param comboBoxSelector data-test-subj selector - */ - public async clear(comboBoxSelector: string): Promise { - log.debug(`comboBox.clear, comboBoxSelector:${comboBoxSelector}`); - const comboBox = await testSubjects.find(comboBoxSelector); - await retry.try(async () => { - const clearButtonExists = await this.doesClearButtonExist(comboBox); - if (!clearButtonExists) { - log.debug('Unable to clear comboBox, comboBoxClearButton does not exist'); - return; - } + /** + * Returns selected options + * @param comboBoxSelector data-test-subj selector + */ + public async getComboBoxSelectedOptions(comboBoxSelector: string): Promise { + this.log.debug(`comboBox.getComboBoxSelectedOptions, comboBoxSelector: ${comboBoxSelector}`); + const comboBox = await this.testSubjects.find(comboBoxSelector); + const $ = await comboBox.parseDomContent(); + return $('.euiComboBoxPill') + .toArray() + .map((option) => $(option).text()); + } - const clearBtn = await comboBox.findByTestSubject('comboBoxClearButton'); - await clearBtn.click(); + /** + * Finds combobox element and clears value in the input field by clicking clear button + * + * @param comboBoxSelector data-test-subj selector + */ + public async clear(comboBoxSelector: string): Promise { + this.log.debug(`comboBox.clear, comboBoxSelector:${comboBoxSelector}`); + const comboBox = await this.testSubjects.find(comboBoxSelector); + await this.retry.try(async () => { + const clearButtonExists = await this.doesClearButtonExist(comboBox); + if (!clearButtonExists) { + this.log.debug('Unable to clear comboBox, comboBoxClearButton does not exist'); + return; + } - const clearButtonStillExists = await this.doesClearButtonExist(comboBox); - if (clearButtonStillExists) { - throw new Error('Failed to clear comboBox'); - } - }); - await this.closeOptionsList(comboBox); - } + const clearBtn = await comboBox.findByTestSubject('comboBoxClearButton'); + await clearBtn.click(); - public async doesClearButtonExist(comboBoxElement: WebElementWrapper): Promise { - const found = await comboBoxElement.findAllByTestSubject( - 'comboBoxClearButton', - WAIT_FOR_EXISTS_TIME - ); - return found.length > 0; - } + const clearButtonStillExists = await this.doesClearButtonExist(comboBox); + if (clearButtonStillExists) { + throw new Error('Failed to clear comboBox'); + } + }); + await this.closeOptionsList(comboBox); + } - public async checkValidity(comboBoxElement: WebElementWrapper): Promise { - const invalidClassName = 'euiComboBox-isInvalid'; + public async doesClearButtonExist(comboBoxElement: WebElementWrapper): Promise { + const found = await comboBoxElement.findAllByTestSubject( + 'comboBoxClearButton', + this.WAIT_FOR_EXISTS_TIME + ); + return found.length > 0; + } - return !(await comboBoxElement.elementHasClass(invalidClassName)); - } + public async checkValidity(comboBoxElement: WebElementWrapper): Promise { + const invalidClassName = 'euiComboBox-isInvalid'; - /** - * Closes options list - * - * @param comboBoxElement element that wraps up EuiComboBox - */ - public async closeOptionsList(comboBoxElement: WebElementWrapper): Promise { - const isOptionsListOpen = await testSubjects.exists('~comboBoxOptionsList'); - if (isOptionsListOpen) { - const input = await comboBoxElement.findByTagName('input'); - await input.pressKeys(browser.keys.ESCAPE); - } - } + return !(await comboBoxElement.elementHasClass(invalidClassName)); + } - /** - * Opens options list - * - * @param comboBoxElement element that wraps up EuiComboBox - */ - public async openOptionsList(comboBoxElement: WebElementWrapper): Promise { - const isOptionsListOpen = await testSubjects.exists('~comboBoxOptionsList'); - if (!isOptionsListOpen) { - await retry.try(async () => { - const toggleBtn = await comboBoxElement.findByTestSubject('comboBoxInput'); - await toggleBtn.click(); - }); - } + /** + * Closes options list + * + * @param comboBoxElement element that wraps up EuiComboBox + */ + public async closeOptionsList(comboBoxElement: WebElementWrapper): Promise { + const isOptionsListOpen = await this.testSubjects.exists('~comboBoxOptionsList'); + if (isOptionsListOpen) { + const input = await comboBoxElement.findByTagName('input'); + await input.pressKeys(this.browser.keys.ESCAPE); } + } - /** - * Checks if specified option is already selected - * - * @param comboBoxElement element that wraps up EuiComboBox - * @param value option text - */ - public async isOptionSelected( - comboBoxElement: WebElementWrapper, - value: string - ): Promise { - log.debug(`comboBox.isOptionSelected, value: ${value}`); - const $ = await comboBoxElement.parseDomContent(); - const selectedOptions = $('.euiComboBoxPill') - .toArray() - .map((option) => $(option).text()); - return selectedOptions.length === 1 && selectedOptions[0] === value; + /** + * Opens options list + * + * @param comboBoxElement element that wraps up EuiComboBox + */ + public async openOptionsList(comboBoxElement: WebElementWrapper): Promise { + const isOptionsListOpen = await this.testSubjects.exists('~comboBoxOptionsList'); + if (!isOptionsListOpen) { + await this.retry.try(async () => { + const toggleBtn = await comboBoxElement.findByTestSubject('comboBoxInput'); + await toggleBtn.click(); + }); } + } - /** - * Clears input field - * @param comboBoxSelector data-test-subj selector - */ - public async clearInputField(comboBoxSelector: string): Promise { - log.debug(`comboBox.clearInputField, comboBoxSelector:${comboBoxSelector}`); - const comboBoxElement = await testSubjects.find(comboBoxSelector); - const input = await comboBoxElement.findByTagName('input'); - await input.clearValueWithKeyboard(); - } + /** + * Checks if specified option is already selected + * + * @param comboBoxElement element that wraps up EuiComboBox + * @param value option text + */ + public async isOptionSelected( + comboBoxElement: WebElementWrapper, + value: string + ): Promise { + this.log.debug(`comboBox.isOptionSelected, value: ${value}`); + const $ = await comboBoxElement.parseDomContent(); + const selectedOptions = $('.euiComboBoxPill') + .toArray() + .map((option) => $(option).text()); + return selectedOptions.length === 1 && selectedOptions[0] === value; } - return new ComboBox(); + /** + * Clears input field + * @param comboBoxSelector data-test-subj selector + */ + public async clearInputField(comboBoxSelector: string): Promise { + this.log.debug(`comboBox.clearInputField, comboBoxSelector:${comboBoxSelector}`); + const comboBoxElement = await this.testSubjects.find(comboBoxSelector); + const input = await comboBoxElement.findByTagName('input'); + await input.clearValueWithKeyboard(); + } } diff --git a/test/functional/services/index.ts b/test/functional/services/index.ts index 294b68c548865..03c43ffc30214 100644 --- a/test/functional/services/index.ts +++ b/test/functional/services/index.ts @@ -17,7 +17,7 @@ import { SnapshotsService, TestSubjects, } from './common'; -import { ComboBoxProvider } from './combo_box'; +import { ComboBoxService } from './combo_box'; import { DashboardAddPanelService, DashboardReplacePanelService, @@ -68,7 +68,7 @@ export const services = { dashboardReplacePanel: DashboardReplacePanelService, dashboardPanelActions: DashboardPanelActionsService, flyout: FlyoutService, - comboBox: ComboBoxProvider, + comboBox: ComboBoxService, dataGrid: DataGridService, embedding: EmbeddingProvider, renderable: RenderableProvider, From 11b3ab167d931652d55aa95070c1be98146c8fc9 Mon Sep 17 00:00:00 2001 From: Patrick Mueller Date: Thu, 27 May 2021 09:17:12 -0400 Subject: [PATCH 20/77] [alerting] add ignore_above to alerts params mappings to handle immense params (#100726) resolves https://github.com/elastic/kibana/issues/100607 This fixes a problem when very large parameters (over 32K bytes) are saved with an alert. Before this fix, an error from elasticsearch would be thrown with the following message, and a 400 returned from create (and presumably update). Document contains at least one immense term in field=\"alert.params\" (whose UTF8 encoding is longer than the max length 32766), all of which were skipped. After the fix, alerts with immense params can be saved and executed. Note that the immense params will not be searchable, since they won't be indexed, but that seems both unavoidable, and not a severe issue. --- .../server/saved_objects/mappings.json | 3 +- .../spaces_only/tests/alerting/create.ts | 47 +++++++++++++++++++ 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/alerting/server/saved_objects/mappings.json b/x-pack/plugins/alerting/server/saved_objects/mappings.json index 136dc530aa119..43292c6a54346 100644 --- a/x-pack/plugins/alerting/server/saved_objects/mappings.json +++ b/x-pack/plugins/alerting/server/saved_objects/mappings.json @@ -47,7 +47,8 @@ } }, "params": { - "type": "flattened" + "type": "flattened", + "ignore_above": 4096 }, "scheduledTaskId": { "type": "keyword" diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/create.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/create.ts index 9033b1f303943..96534c192d67c 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/create.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/create.ts @@ -112,6 +112,53 @@ export default function createAlertTests({ getService }: FtrProviderContext) { }); }); + // see: https://github.com/elastic/kibana/issues/100607 + // note this fails when the mappings for `params` does not have ignore_above + it('should handle alerts with immense params', async () => { + const { body: createdAction } = await supertest + .post(`${getUrlPrefix(Spaces.space1.id)}/api/actions/connector`) + .set('kbn-xsrf', 'foo') + .send({ + name: 'MY action', + connector_type_id: 'test.noop', + config: {}, + secrets: {}, + }) + .expect(200); + + const lotsOfSpaces = ''.padEnd(100 * 1000); // 100K space chars + const response = await supertest + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) + .set('kbn-xsrf', 'foo') + .send( + getTestAlertData({ + params: { + ignoredButPersisted: lotsOfSpaces, + }, + actions: [ + { + id: createdAction.id, + group: 'default', + params: {}, + }, + ], + }) + ); + + expect(response.status).to.eql(200); + objectRemover.add(Spaces.space1.id, response.body.id, 'rule', 'alerting'); + + expect(response.body.params.ignoredButPersisted).to.eql(lotsOfSpaces); + + // Ensure AAD isn't broken + await checkAAD({ + supertest, + spaceId: Spaces.space1.id, + type: 'alert', + id: response.body.id, + }); + }); + it('should allow providing custom saved object ids (uuid v1)', async () => { const customId = '09570bb0-6299-11eb-8fde-9fe5ce6ea450'; const response = await supertest From 7cfa0d2b061106ee764702a1cd3806c6bbfaab21 Mon Sep 17 00:00:00 2001 From: Stratoula Kalafateli Date: Thu, 27 May 2021 16:18:15 +0300 Subject: [PATCH 21/77] [TSVB] Support triggers only for timeseries chart (#100323) * [TSVB] Support triggers only for timeseries chart * fix the type * Fix type falure Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- src/plugins/vis_type_timeseries/public/metrics_type.ts | 7 +++++-- .../public/embeddable/visualize_embeddable.ts | 2 +- src/plugins/visualizations/public/vis_types/types.ts | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/plugins/vis_type_timeseries/public/metrics_type.ts b/src/plugins/vis_type_timeseries/public/metrics_type.ts index 3cb4faaacf25b..a2efe39b2c7f0 100644 --- a/src/plugins/vis_type_timeseries/public/metrics_type.ts +++ b/src/plugins/vis_type_timeseries/public/metrics_type.ts @@ -74,8 +74,11 @@ export const metricsVisDefinition = { showIndexSelection: false, }, toExpressionAst, - getSupportedTriggers: () => { - return [VIS_EVENT_TO_TRIGGER.filter, VIS_EVENT_TO_TRIGGER.brush]; + getSupportedTriggers: (params?: VisParams) => { + if (params?.type === PANEL_TYPES.TIMESERIES) { + return [VIS_EVENT_TO_TRIGGER.filter, VIS_EVENT_TO_TRIGGER.brush]; + } + return []; }, inspectorAdapters: {}, getUsedIndexPattern: async (params: VisParams) => { diff --git a/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts b/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts index f5bf6b59aa0ae..03fa8d415aca2 100644 --- a/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts +++ b/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts @@ -420,7 +420,7 @@ export class VisualizeEmbeddable }; public supportedTriggers(): string[] { - return this.vis.type.getSupportedTriggers?.() ?? []; + return this.vis.type.getSupportedTriggers?.(this.vis.params) ?? []; } inputIsRefType = (input: VisualizeInput): input is VisualizeByReferenceInput => { diff --git a/src/plugins/visualizations/public/vis_types/types.ts b/src/plugins/visualizations/public/vis_types/types.ts index 7cfa31adfca4a..77654c8a157e3 100644 --- a/src/plugins/visualizations/public/vis_types/types.ts +++ b/src/plugins/visualizations/public/vis_types/types.ts @@ -91,7 +91,7 @@ export interface VisTypeDefinition { /** * If given, it will return the supported triggers for this vis. */ - readonly getSupportedTriggers?: () => string[]; + readonly getSupportedTriggers?: (params?: VisParams) => string[]; /** * Some visualizations are created without SearchSource and may change the used indexes during the visualization configuration. From f6266c431b604d667242d3c3db9f74cdcd0e0909 Mon Sep 17 00:00:00 2001 From: Joe Reuter Date: Thu, 27 May 2021 15:25:10 +0200 Subject: [PATCH 22/77] [Lens] Improve caching with more stable Elasticsearch requests (#100414) --- .../indexpattern.test.ts | 20 +++++++++---------- .../definitions/date_histogram.test.tsx | 6 ++++-- .../operations/definitions/index.ts | 3 ++- .../definitions/last_value.test.tsx | 3 ++- .../definitions/percentile.test.tsx | 3 ++- .../definitions/ranges/ranges.test.tsx | 12 +++++++---- .../operations/definitions/terms/index.tsx | 6 ++++-- .../definitions/terms/terms.test.tsx | 6 ++++-- .../indexpattern_datasource/to_expression.ts | 14 +++++++------ 9 files changed, 44 insertions(+), 29 deletions(-) diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.test.ts b/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.test.ts index c0a502df14234..81dff1da57809 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.test.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.test.ts @@ -359,7 +359,7 @@ describe('IndexPattern Data Source', () => { true, ], "id": Array [ - "col1", + "0", ], "schema": Array [ "metric", @@ -388,7 +388,7 @@ describe('IndexPattern Data Source', () => { "timestamp", ], "id": Array [ - "col2", + "1", ], "interval": Array [ "1d", @@ -442,7 +442,7 @@ describe('IndexPattern Data Source', () => { Object { "arguments": Object { "idMap": Array [ - "{\\"col-0-col1\\":{\\"label\\":\\"Count of records\\",\\"dataType\\":\\"number\\",\\"isBucketed\\":false,\\"sourceField\\":\\"Records\\",\\"operationType\\":\\"count\\",\\"id\\":\\"col1\\"},\\"col-1-col2\\":{\\"label\\":\\"Date\\",\\"dataType\\":\\"date\\",\\"isBucketed\\":true,\\"operationType\\":\\"date_histogram\\",\\"sourceField\\":\\"timestamp\\",\\"params\\":{\\"interval\\":\\"1d\\"},\\"id\\":\\"col2\\"}}", + "{\\"col-0-0\\":{\\"label\\":\\"Count of records\\",\\"dataType\\":\\"number\\",\\"isBucketed\\":false,\\"sourceField\\":\\"Records\\",\\"operationType\\":\\"count\\",\\"id\\":\\"col1\\"},\\"col-1-1\\":{\\"label\\":\\"Date\\",\\"dataType\\":\\"date\\",\\"isBucketed\\":true,\\"operationType\\":\\"date_histogram\\",\\"sourceField\\":\\"timestamp\\",\\"params\\":{\\"interval\\":\\"1d\\"},\\"id\\":\\"col2\\"}}", ], }, "function": "lens_rename_columns", @@ -563,7 +563,7 @@ describe('IndexPattern Data Source', () => { "{\\"language\\":\\"kuery\\",\\"query\\":\\"bytes > 5\\"}", ], "id": Array [ - "col1-filter", + "0-filter", ], "schema": Array [ "bucket", @@ -585,7 +585,7 @@ describe('IndexPattern Data Source', () => { true, ], "id": Array [ - "col1-metric", + "0-metric", ], "schema": Array [ "metric", @@ -602,7 +602,7 @@ describe('IndexPattern Data Source', () => { true, ], "id": Array [ - "col1", + "0", ], "schema": Array [ "metric", @@ -795,9 +795,9 @@ describe('IndexPattern Data Source', () => { const ast = indexPatternDatasource.toExpression(state, 'first') as Ast; expect(ast.chain[0].arguments.metricsAtAllLevels).toEqual([false]); expect(JSON.parse(ast.chain[1].arguments.idMap[0] as string)).toEqual({ - 'col-0-bucket1': expect.any(Object), - 'col-1-bucket2': expect.any(Object), - 'col-2-metric': expect.any(Object), + 'col-0-0': expect.objectContaining({ id: 'bucket1' }), + 'col-1-1': expect.objectContaining({ id: 'bucket2' }), + 'col-2-2': expect.objectContaining({ id: 'metric' }), }); }); @@ -919,7 +919,7 @@ describe('IndexPattern Data Source', () => { const ast = indexPatternDatasource.toExpression(state, 'first') as Ast; expect(JSON.parse(ast.chain[1].arguments.idMap[0] as string)).toEqual({ - 'col-0-col1': expect.objectContaining({ + 'col-0-0': expect.objectContaining({ id: 'col1', }), }); diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/date_histogram.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/date_histogram.test.tsx index eaaf13171124b..92741b9b5ed09 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/date_histogram.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/date_histogram.test.tsx @@ -205,7 +205,8 @@ describe('date_histogram', () => { 'col1', indexPattern1, layer, - uiSettingsMock + uiSettingsMock, + [] ); expect(esAggsFn).toEqual( expect.objectContaining({ @@ -258,7 +259,8 @@ describe('date_histogram', () => { ]), }, layer, - uiSettingsMock + uiSettingsMock, + [] ); expect(esAggsFn).toEqual( expect.objectContaining({ diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/index.ts b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/index.ts index a7402bc13c0a8..6772432664d8c 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/index.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/index.ts @@ -355,7 +355,8 @@ interface FieldBasedOperationDefinition { columnId: string, indexPattern: IndexPattern, layer: IndexPatternLayer, - uiSettings: IUiSettingsClient + uiSettings: IUiSettingsClient, + orderedColumnIds: string[] ) => ExpressionAstFunction; /** * Validate that the operation has the right preconditions in the state. For example: diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/last_value.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/last_value.test.tsx index 280cfe9471c9d..15ce3bdcd0b0f 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/last_value.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/last_value.test.tsx @@ -75,7 +75,8 @@ describe('last_value', () => { 'col1', {} as IndexPattern, layer, - uiSettingsMock + uiSettingsMock, + [] ); expect(esAggsFn).toEqual( expect.objectContaining({ diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/percentile.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/percentile.test.tsx index 59da0f6f7bcde..2b7104112d63e 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/percentile.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/percentile.test.tsx @@ -123,7 +123,8 @@ describe('percentile', () => { 'col1', {} as IndexPattern, layer, - uiSettingsMock + uiSettingsMock, + [] ); expect(esAggsFn).toEqual( expect.objectContaining({ diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/ranges.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/ranges.test.tsx index cfbe0f8903daf..295f988c6e390 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/ranges.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/ranges.test.tsx @@ -172,7 +172,8 @@ describe('ranges', () => { 'col1', {} as IndexPattern, layer, - uiSettingsMock + uiSettingsMock, + [] ); expect(esAggsFn).toMatchInlineSnapshot(` Object { @@ -219,7 +220,8 @@ describe('ranges', () => { 'col1', {} as IndexPattern, layer, - uiSettingsMock + uiSettingsMock, + [] ); expect(esAggsFn).toEqual( @@ -240,7 +242,8 @@ describe('ranges', () => { 'col1', {} as IndexPattern, layer, - uiSettingsMock + uiSettingsMock, + [] ); expect(esAggsFn).toEqual( @@ -261,7 +264,8 @@ describe('ranges', () => { 'col1', {} as IndexPattern, layer, - uiSettingsMock + uiSettingsMock, + [] ); expect((esAggsFn as { arguments: unknown }).arguments).toEqual( diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/index.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/index.tsx index d226fe6f2a745..52adf83752363 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/index.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/index.tsx @@ -132,14 +132,16 @@ export const termsOperation: OperationDefinition { + toEsAggsFn: (column, columnId, _indexPattern, layer, uiSettings, orderedColumnIds) => { return buildExpressionFunction('aggTerms', { id: columnId, enabled: true, schema: 'segment', field: column.sourceField, orderBy: - column.params.orderBy.type === 'alphabetical' ? '_key' : column.params.orderBy.columnId, + column.params.orderBy.type === 'alphabetical' + ? '_key' + : String(orderedColumnIds.indexOf(column.params.orderBy.columnId)), order: column.params.orderDirection, size: column.params.size, otherBucket: Boolean(column.params.otherBucket), diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/terms.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/terms.test.tsx index b094d3f0ff5cd..aab957c8ecebe 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/terms.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/terms.test.tsx @@ -71,7 +71,8 @@ describe('terms', () => { 'col1', {} as IndexPattern, layer, - uiSettingsMock + uiSettingsMock, + [] ); expect(esAggsFn).toEqual( expect.objectContaining({ @@ -95,7 +96,8 @@ describe('terms', () => { 'col1', {} as IndexPattern, layer, - uiSettingsMock + uiSettingsMock, + [] ); expect(esAggsFn).toEqual( expect.objectContaining({ diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/to_expression.ts b/x-pack/plugins/lens/public/indexpattern_datasource/to_expression.ts index 4905bd75d6498..430e139a85cca 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/to_expression.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/to_expression.ts @@ -77,27 +77,29 @@ function getExpressionForLayer( } }); - esAggEntries.forEach(([colId, col]) => { + const orderedColumnIds = esAggEntries.map(([colId]) => colId); + esAggEntries.forEach(([colId, col], index) => { const def = operationDefinitionMap[col.operationType]; if (def.input !== 'fullReference' && def.input !== 'managedReference') { const wrapInFilter = Boolean(def.filterable && col.filter); let aggAst = def.toEsAggsFn( col, - wrapInFilter ? `${colId}-metric` : colId, + wrapInFilter ? `${index}-metric` : String(index), indexPattern, layer, - uiSettings + uiSettings, + orderedColumnIds ); if (wrapInFilter) { aggAst = buildExpressionFunction( 'aggFilteredMetric', { - id: colId, + id: String(index), enabled: true, schema: 'metric', customBucket: buildExpression([ buildExpressionFunction('aggFilter', { - id: `${colId}-filter`, + id: `${index}-filter`, enabled: true, schema: 'bucket', filter: JSON.stringify(col.filter), @@ -121,7 +123,7 @@ function getExpressionForLayer( return null; } const idMap = esAggEntries.reduce((currentIdMap, [colId, column], index) => { - const esAggsId = `col-${index}-${colId}`; + const esAggsId = `col-${index}-${index}`; return { ...currentIdMap, [esAggsId]: { From 1c4d338668186073827cf0230da68598d0f78c8d Mon Sep 17 00:00:00 2001 From: Candace Park <56409205+parkiino@users.noreply.github.com> Date: Thu, 27 May 2021 09:32:32 -0400 Subject: [PATCH 23/77] [Security Solution][Endpoint][Host Isolation] User can unisolate host from alert details (#100401) --- .../common/endpoint/actions.ts | 14 ++ .../common/endpoint/constants.ts | 3 + .../common/endpoint/types/index.ts | 2 +- .../endpoint/host_isolation/index.ts | 1 + .../host_isolation/isolate_success.tsx | 37 +++-- .../endpoint/host_isolation/translations.ts | 29 +++- .../host_isolation/unisolate_form.tsx | 81 ++++++++++ .../hooks/endpoint/use_isolate_privileges.ts | 40 +++++ .../components/host_isolation/index.tsx | 148 ++++++------------ .../components/host_isolation/isolate.tsx | 113 +++++++++++++ .../host_isolation/take_action_dropdown.tsx | 48 ++++-- .../components/host_isolation/translations.ts | 9 +- .../components/host_isolation/unisolate.tsx | 113 +++++++++++++ .../containers/detection_engine/alerts/api.ts | 45 +++++- .../detection_engine/alerts/translations.ts | 5 + .../alerts/use_host_isolation_status.tsx | 64 ++++++++ .../alerts/use_host_unisolation.tsx | 45 ++++++ .../pages/endpoint_hosts/store/middleware.ts | 15 +- .../side_panel/event_details/index.tsx | 52 ++++-- .../endpoint/routes/actions/isolation.ts | 9 +- .../endpoint/routes/metadata/handlers.ts | 4 +- 21 files changed, 714 insertions(+), 163 deletions(-) create mode 100644 x-pack/plugins/security_solution/common/endpoint/actions.ts create mode 100644 x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/unisolate_form.tsx create mode 100644 x-pack/plugins/security_solution/public/common/hooks/endpoint/use_isolate_privileges.ts create mode 100644 x-pack/plugins/security_solution/public/detections/components/host_isolation/isolate.tsx create mode 100644 x-pack/plugins/security_solution/public/detections/components/host_isolation/unisolate.tsx create mode 100644 x-pack/plugins/security_solution/public/detections/containers/detection_engine/alerts/use_host_isolation_status.tsx create mode 100644 x-pack/plugins/security_solution/public/detections/containers/detection_engine/alerts/use_host_unisolation.tsx diff --git a/x-pack/plugins/security_solution/common/endpoint/actions.ts b/x-pack/plugins/security_solution/common/endpoint/actions.ts new file mode 100644 index 0000000000000..287ebddacad9a --- /dev/null +++ b/x-pack/plugins/security_solution/common/endpoint/actions.ts @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const userCanIsolate = (roles: readonly string[] | undefined): boolean => { + // only superusers can write to the fleet index (or look up endpoint data to convert endp ID to agent ID) + if (!roles || roles.length === 0) { + return false; + } + return roles.includes('superuser'); +}; diff --git a/x-pack/plugins/security_solution/common/endpoint/constants.ts b/x-pack/plugins/security_solution/common/endpoint/constants.ts index a5718af1d42c5..1c0b09a4648e5 100644 --- a/x-pack/plugins/security_solution/common/endpoint/constants.ts +++ b/x-pack/plugins/security_solution/common/endpoint/constants.ts @@ -15,6 +15,9 @@ export const telemetryIndexPattern = 'metrics-endpoint.telemetry-*'; export const LIMITED_CONCURRENCY_ENDPOINT_ROUTE_TAG = 'endpoint:limited-concurrency'; export const LIMITED_CONCURRENCY_ENDPOINT_COUNT = 100; +export const HOST_METADATA_LIST_API = '/api/endpoint/metadata'; +export const HOST_METADATA_GET_API = '/api/endpoint/metadata/{id}'; + export const TRUSTED_APPS_GET_API = '/api/endpoint/trusted_apps/{id}'; export const TRUSTED_APPS_LIST_API = '/api/endpoint/trusted_apps'; export const TRUSTED_APPS_CREATE_API = '/api/endpoint/trusted_apps'; 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 512adffc70eef..dd0ff540cb4af 100644 --- a/x-pack/plugins/security_solution/common/endpoint/types/index.ts +++ b/x-pack/plugins/security_solution/common/endpoint/types/index.ts @@ -414,7 +414,7 @@ export type PolicyInfo = Immutable<{ id: string; }>; -export interface HostMetaDataInfo { +export interface HostMetadataInfo { metadata: HostMetadata; query_strategy_version: MetadataQueryStrategyVersions; } diff --git a/x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/index.ts b/x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/index.ts index de51df283251d..f5387a1b1a99c 100644 --- a/x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/index.ts +++ b/x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/index.ts @@ -7,3 +7,4 @@ export * from './isolate_success'; export * from './isolate_form'; +export * from './unisolate_form'; diff --git a/x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/isolate_success.tsx b/x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/isolate_success.tsx index 32ac1177d6e80..f822b3c287a02 100644 --- a/x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/isolate_success.tsx +++ b/x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/isolate_success.tsx @@ -7,27 +7,44 @@ import React, { memo, ReactNode } from 'react'; import { EuiButtonEmpty, EuiCallOut, EuiFlexGroup, EuiFlexItem, EuiText } from '@elastic/eui'; -import { GET_SUCCESS_MESSAGE } from './translations'; +import { GET_ISOLATION_SUCCESS_MESSAGE, GET_UNISOLATION_SUCCESS_MESSAGE } from './translations'; export interface EndpointIsolateSuccessProps { hostName: string; + isolateAction?: 'isolateHost' | 'unisolateHost'; completeButtonLabel: string; onComplete: () => void; additionalInfo?: ReactNode; } export const EndpointIsolateSuccess = memo( - ({ hostName, onComplete, completeButtonLabel, additionalInfo }) => { + ({ + hostName, + isolateAction = 'isolateHost', + onComplete, + completeButtonLabel, + additionalInfo, + }) => { return ( <> - - {additionalInfo} - + {isolateAction === 'isolateHost' ? ( + + {additionalInfo} + + ) : ( + + {additionalInfo} + + )} diff --git a/x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/translations.ts b/x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/translations.ts index baeced2a7a69f..790c951f61ccd 100644 --- a/x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/translations.ts +++ b/x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/translations.ts @@ -24,8 +24,33 @@ export const COMMENT_PLACEHOLDER = i18n.translate( { defaultMessage: 'You may leave an optional note here.' } ); -export const GET_SUCCESS_MESSAGE = (hostName: string) => - i18n.translate('xpack.securitySolution.endpoint.hostIsolation.successfulMessage', { +export const GET_ISOLATION_SUCCESS_MESSAGE = (hostName: string) => + i18n.translate('xpack.securitySolution.endpoint.hostIsolation.isolation.successfulMessage', { defaultMessage: 'Host Isolation on {hostName} successfully submitted', values: { hostName }, }); + +export const GET_UNISOLATION_SUCCESS_MESSAGE = (hostName: string) => + i18n.translate('xpack.securitySolution.endpoint.hostIsolation.unisolate.successfulMessage', { + defaultMessage: 'Host Unisolation on {hostName} successfully submitted', + values: { hostName }, + }); + +export const ISOLATE = i18n.translate('xpack.securitySolution.endpoint.hostisolation.isolate', { + defaultMessage: 'isolate', +}); + +export const UNISOLATE = i18n.translate('xpack.securitySolution.endpoint.hostisolation.unisolate', { + defaultMessage: 'unisolate', +}); + +export const NOT_ISOLATED = i18n.translate( + 'xpack.securitySolution.endpoint.hostIsolation.notIsolated', + { + defaultMessage: 'not isolated', + } +); + +export const ISOLATED = i18n.translate('xpack.securitySolution.endpoint.hostIsolation.isolated', { + defaultMessage: 'isolated', +}); diff --git a/x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/unisolate_form.tsx b/x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/unisolate_form.tsx new file mode 100644 index 0000000000000..98006524844c4 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/unisolate_form.tsx @@ -0,0 +1,81 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { ChangeEventHandler, memo, useCallback } from 'react'; +import { + EuiButton, + EuiButtonEmpty, + EuiFlexGroup, + EuiFlexItem, + EuiSpacer, + EuiText, + EuiTextArea, + EuiTitle, +} from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { CANCEL, COMMENT, COMMENT_PLACEHOLDER, CONFIRM, UNISOLATE, ISOLATED } from './translations'; +import { EndpointIsolatedFormProps } from './isolate_form'; + +export const EndpointUnisolateForm = memo( + ({ hostName, onCancel, onConfirm, onChange, comment = '', messageAppend, isLoading = false }) => { + const handleCommentChange: ChangeEventHandler = useCallback( + (event) => { + onChange({ comment: event.target.value }); + }, + [onChange] + ); + + return ( + <> + +

+ {hostName}, + isolated: {ISOLATED}, + unisolate: {UNISOLATE}, + }} + />{' '} + {messageAppend} +

+
+ + + + +

{COMMENT}

+
+ + + + + + + + {CANCEL} + + + + + {CONFIRM} + + + + + ); + } +); + +EndpointUnisolateForm.displayName = 'EndpointUnisolateForm'; diff --git a/x-pack/plugins/security_solution/public/common/hooks/endpoint/use_isolate_privileges.ts b/x-pack/plugins/security_solution/public/common/hooks/endpoint/use_isolate_privileges.ts new file mode 100644 index 0000000000000..23ef6d586adc5 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/hooks/endpoint/use_isolate_privileges.ts @@ -0,0 +1,40 @@ +/* + * 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 { useEffect, useState } from 'react'; +import { userCanIsolate } from '../../../../common/endpoint/actions'; +import { useKibana } from '../../lib/kibana'; +import { useLicense } from '../use_license'; + +interface IsolationPriviledgesStatus { + isLoading: boolean; + isAllowed: boolean; +} + +/* + * Host isolation requires superuser privileges and at least a platinum license + */ +export const useIsolationPrivileges = (): IsolationPriviledgesStatus => { + const [isLoading, setIsLoading] = useState(false); + const [canIsolate, setCanIsolate] = useState(false); + + const isPlatinumPlus = useLicense().isPlatinumPlus(); + const services = useKibana().services; + + useEffect(() => { + setIsLoading(true); + const user = services.security.authc.getCurrentUser(); + if (user) { + user.then((authenticatedUser) => { + setCanIsolate(userCanIsolate(authenticatedUser.roles)); + setIsLoading(false); + }); + } + }, [services.security.authc]); + + return { isLoading, isAllowed: canIsolate && isPlatinumPlus ? true : false }; +}; diff --git a/x-pack/plugins/security_solution/public/detections/components/host_isolation/index.tsx b/x-pack/plugins/security_solution/public/detections/components/host_isolation/index.tsx index e6fd3a8459f76..bb1585b5392bd 100644 --- a/x-pack/plugins/security_solution/public/detections/components/host_isolation/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/host_isolation/index.tsx @@ -5,33 +5,27 @@ * 2.0. */ -import React, { useMemo, useState, useCallback } from 'react'; +import React, { useMemo } from 'react'; import { find } from 'lodash/fp'; -import { EuiText, EuiSpacer } from '@elastic/eui'; +import { EuiText } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; -import { useHostIsolation } from '../../containers/detection_engine/alerts/use_host_isolation'; -import { CASES_ASSOCIATED_WITH_ALERT, RETURN_TO_ALERT_DETAILS } from './translations'; import { Maybe } from '../../../../../observability/common/typings'; import { useCasesFromAlerts } from '../../containers/detection_engine/alerts/use_cases_from_alerts'; import { CaseDetailsLink } from '../../../common/components/links'; import { TimelineEventsDetailsItem } from '../../../../common/search_strategy'; -import { - EndpointIsolatedFormProps, - EndpointIsolateForm, - EndpointIsolateSuccess, -} from '../../../common/components/endpoint/host_isolation'; +import { IsolateHost } from './isolate'; +import { UnisolateHost } from './unisolate'; export const HostIsolationPanel = React.memo( ({ details, cancelCallback, + isolateAction, }: { details: Maybe; cancelCallback: () => void; + isolateAction: string; }) => { - const [comment, setComment] = useState(''); - const [isIsolated, setIsIsolated] = useState(false); - const agentId = useMemo(() => { const findAgentId = find({ category: 'agent', field: 'agent.id' }, details)?.values; return findAgentId ? findAgentId[0] : ''; @@ -54,25 +48,15 @@ export const HostIsolationPanel = React.memo( }, [details]); const { caseIds } = useCasesFromAlerts({ alertId }); - const { loading, isolateHost } = useHostIsolation({ agentId, comment, caseIds }); - - const confirmHostIsolation = useCallback(async () => { - const hostIsolated = await isolateHost(); - setIsIsolated(hostIsolated); - }, [isolateHost]); - - const backToAlertDetails = useCallback(() => cancelCallback(), [cancelCallback]); - const handleIsolateFormChange: EndpointIsolatedFormProps['onChange'] = useCallback( - ({ comment: newComment }) => setComment(newComment), - [] - ); + // Cases related components to be used in both isolate and unisolate actions from the alert details flyout entry point + const caseCount: number = useMemo(() => caseIds.length, [caseIds]); const casesList = useMemo( () => caseIds.map((id, index) => { return ( -
  • +
  • caseIds.length, [caseIds]); - - const hostIsolated = useMemo(() => { - return ( - <> - - 0 && ( - <> - -

    - -

    -
    - -
      {casesList}
    -
    - - ) - } - /> - - ); - }, [backToAlertDetails, hostName, caseCount, casesList]); - - const hostNotIsolated = useMemo(() => { - return ( - <> - - - {caseCount} - {CASES_ASSOCIATED_WITH_ALERT(caseCount)} - {alertRule} - - ), - }} - /> - } - /> - - ); - }, [ - hostName, - backToAlertDetails, - confirmHostIsolation, - handleIsolateFormChange, - comment, - loading, - caseCount, - alertRule, - ]); - - return isIsolated ? hostIsolated : hostNotIsolated; + const associatedCases = useMemo(() => { + if (caseCount > 0) { + return ( + <> + +

    + +

    +
    + +
      {casesList}
    +
    + + ); + } + }, [caseCount, casesList]); + + return isolateAction === 'isolateHost' ? ( + + ) : ( + + ); } ); diff --git a/x-pack/plugins/security_solution/public/detections/components/host_isolation/isolate.tsx b/x-pack/plugins/security_solution/public/detections/components/host_isolation/isolate.tsx new file mode 100644 index 0000000000000..10c9082976a0e --- /dev/null +++ b/x-pack/plugins/security_solution/public/detections/components/host_isolation/isolate.tsx @@ -0,0 +1,113 @@ +/* + * 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, { useMemo, useState, useCallback, ReactNode } from 'react'; +import { EuiSpacer } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { useHostIsolation } from '../../containers/detection_engine/alerts/use_host_isolation'; +import { CASES_ASSOCIATED_WITH_ALERT, RETURN_TO_ALERT_DETAILS } from './translations'; +import { + EndpointIsolatedFormProps, + EndpointIsolateForm, + EndpointIsolateSuccess, +} from '../../../common/components/endpoint/host_isolation'; + +export const IsolateHost = React.memo( + ({ + agentId, + hostName, + alertRule, + cases, + caseIds, + cancelCallback, + }: { + agentId: string; + hostName: string; + alertRule: string; + cases: ReactNode; + caseIds: string[]; + cancelCallback: () => void; + }) => { + const [comment, setComment] = useState(''); + const [isIsolated, setIsIsolated] = useState(false); + + const { loading, isolateHost } = useHostIsolation({ agentId, comment, caseIds }); + + const confirmHostIsolation = useCallback(async () => { + const hostIsolated = await isolateHost(); + setIsIsolated(hostIsolated); + }, [isolateHost]); + + const backToAlertDetails = useCallback(() => cancelCallback(), [cancelCallback]); + + const handleIsolateFormChange: EndpointIsolatedFormProps['onChange'] = useCallback( + ({ comment: newComment }) => setComment(newComment), + [] + ); + + const caseCount: number = useMemo(() => caseIds.length, [caseIds]); + + const hostIsolatedSuccess = useMemo(() => { + return ( + <> + + + + ); + }, [backToAlertDetails, hostName, cases]); + + const hostNotIsolated = useMemo(() => { + return ( + <> + + + {caseCount} + {CASES_ASSOCIATED_WITH_ALERT(caseCount)} + {alertRule} + + ), + }} + /> + } + /> + + ); + }, [ + hostName, + backToAlertDetails, + confirmHostIsolation, + handleIsolateFormChange, + comment, + loading, + caseCount, + alertRule, + ]); + + return isIsolated ? hostIsolatedSuccess : hostNotIsolated; + } +); + +IsolateHost.displayName = 'IsolateHost'; diff --git a/x-pack/plugins/security_solution/public/detections/components/host_isolation/take_action_dropdown.tsx b/x-pack/plugins/security_solution/public/detections/components/host_isolation/take_action_dropdown.tsx index 36f2553e1b927..a10ad901441ea 100644 --- a/x-pack/plugins/security_solution/public/detections/components/host_isolation/take_action_dropdown.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/host_isolation/take_action_dropdown.tsx @@ -7,30 +7,33 @@ import React, { useState, useCallback, useMemo } from 'react'; import { EuiContextMenuItem, EuiContextMenuPanel, EuiButton, EuiPopover } from '@elastic/eui'; -import { ISOLATE_HOST } from './translations'; +import { ISOLATE_HOST, UNISOLATE_HOST } from './translations'; import { TAKE_ACTION } from '../alerts_table/alerts_utility_bar/translations'; +import { useHostIsolationStatus } from '../../containers/detection_engine/alerts/use_host_isolation_status'; export const TakeActionDropdown = React.memo( - ({ onChange }: { onChange: (action: 'isolateHost') => void }) => { + ({ + onChange, + agentId, + }: { + onChange: (action: 'isolateHost' | 'unisolateHost') => void; + agentId: string; + }) => { + const { loading, isIsolated: isolationStatus } = useHostIsolationStatus({ agentId }); const [isPopoverOpen, setIsPopoverOpen] = useState(false); const closePopoverHandler = useCallback(() => { setIsPopoverOpen(false); }, []); - const takeActionItems = useMemo(() => { - return [ - { - setIsPopoverOpen(false); - onChange('isolateHost'); - }} - > - {ISOLATE_HOST} - , - ]; - }, [onChange]); + const isolateHostHandler = useCallback(() => { + setIsPopoverOpen(false); + if (isolationStatus === false) { + onChange('isolateHost'); + } else { + onChange('unisolateHost'); + } + }, [onChange, isolationStatus]); const takeActionButton = useMemo(() => { return ( @@ -38,6 +41,7 @@ export const TakeActionDropdown = React.memo( iconSide="right" fill iconType="arrowDown" + disabled={loading} onClick={() => { setIsPopoverOpen(!isPopoverOpen); }} @@ -45,7 +49,7 @@ export const TakeActionDropdown = React.memo( {TAKE_ACTION} ); - }, [isPopoverOpen]); + }, [isPopoverOpen, loading]); return ( - + + {isolationStatus === false ? ( + + {ISOLATE_HOST} + + ) : ( + + {UNISOLATE_HOST} + + )} + ); } diff --git a/x-pack/plugins/security_solution/public/detections/components/host_isolation/translations.ts b/x-pack/plugins/security_solution/public/detections/components/host_isolation/translations.ts index 027a97cc3846e..449a09b932cd3 100644 --- a/x-pack/plugins/security_solution/public/detections/components/host_isolation/translations.ts +++ b/x-pack/plugins/security_solution/public/detections/components/host_isolation/translations.ts @@ -8,12 +8,19 @@ import { i18n } from '@kbn/i18n'; export const ISOLATE_HOST = i18n.translate( - 'xpack.securitySolution.endpoint.hostIsolation.isolateHost.isolateHost', + 'xpack.securitySolution.endpoint.hostIsolation.isolateHost', { defaultMessage: 'Isolate host', } ); +export const UNISOLATE_HOST = i18n.translate( + 'xpack.securitySolution.endpoint.hostIsolation.unisolateHost', + { + defaultMessage: 'Unisolate host', + } +); + export const CASES_ASSOCIATED_WITH_ALERT = (caseCount: number): string => i18n.translate( 'xpack.securitySolution.endpoint.hostIsolation.isolateHost.casesAssociatedWithAlert', diff --git a/x-pack/plugins/security_solution/public/detections/components/host_isolation/unisolate.tsx b/x-pack/plugins/security_solution/public/detections/components/host_isolation/unisolate.tsx new file mode 100644 index 0000000000000..74149f2a692d3 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detections/components/host_isolation/unisolate.tsx @@ -0,0 +1,113 @@ +/* + * 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, { useMemo, useState, useCallback, ReactNode } from 'react'; +import { EuiSpacer } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { CASES_ASSOCIATED_WITH_ALERT, RETURN_TO_ALERT_DETAILS } from './translations'; +import { + EndpointIsolatedFormProps, + EndpointIsolateSuccess, + EndpointUnisolateForm, +} from '../../../common/components/endpoint/host_isolation'; +import { useHostUnisolation } from '../../containers/detection_engine/alerts/use_host_unisolation'; + +export const UnisolateHost = React.memo( + ({ + agentId, + hostName, + alertRule, + cases, + caseIds, + cancelCallback, + }: { + agentId: string; + hostName: string; + alertRule: string; + cases: ReactNode; + caseIds: string[]; + cancelCallback: () => void; + }) => { + const [comment, setComment] = useState(''); + const [isUnIsolated, setIsUnIsolated] = useState(false); + + const { loading, unIsolateHost } = useHostUnisolation({ agentId, comment, caseIds }); + + const confirmHostUnIsolation = useCallback(async () => { + const hostIsolated = await unIsolateHost(); + setIsUnIsolated(hostIsolated); + }, [unIsolateHost]); + + const backToAlertDetails = useCallback(() => cancelCallback(), [cancelCallback]); + + const handleIsolateFormChange: EndpointIsolatedFormProps['onChange'] = useCallback( + ({ comment: newComment }) => setComment(newComment), + [] + ); + + const caseCount: number = useMemo(() => caseIds.length, [caseIds]); + + const hostUnisolatedSuccess = useMemo(() => { + return ( + <> + + + + ); + }, [backToAlertDetails, hostName, cases]); + + const hostNotUnisolated = useMemo(() => { + return ( + <> + + + {caseCount} + {CASES_ASSOCIATED_WITH_ALERT(caseCount)} + {alertRule} + + ), + }} + /> + } + /> + + ); + }, [ + hostName, + backToAlertDetails, + confirmHostUnIsolation, + handleIsolateFormChange, + comment, + loading, + caseCount, + alertRule, + ]); + + return isUnIsolated ? hostUnisolatedSuccess : hostNotUnisolated; + } +); + +UnisolateHost.displayName = 'UnisolateHost'; diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/alerts/api.ts b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/alerts/api.ts index 28a6076421e83..65185b4d05135 100644 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/alerts/api.ts +++ b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/alerts/api.ts @@ -7,13 +7,14 @@ import { UpdateDocumentByQueryResponse } from 'elasticsearch'; import { getCasesFromAlertsUrl } from '../../../../../../cases/common'; -import { HostIsolationResponse } from '../../../../../common/endpoint/types'; +import { HostIsolationResponse, HostMetadataInfo } from '../../../../../common/endpoint/types'; import { DETECTION_ENGINE_QUERY_SIGNALS_URL, DETECTION_ENGINE_SIGNALS_STATUS_URL, DETECTION_ENGINE_INDEX_URL, DETECTION_ENGINE_PRIVILEGES_URL, } from '../../../../../common/constants'; +import { HOST_METADATA_GET_API } from '../../../../../common/endpoint/constants'; import { KibanaServices } from '../../../../common/lib/kibana'; import { BasicSignals, @@ -24,7 +25,8 @@ import { UpdateAlertStatusProps, CasesFromAlertsResponse, } from './types'; -import { isolateHost } from '../../../../common/lib/host_isolation'; +import { resolvePathVariables } from '../../../../management/pages/trusted_apps/service/utils'; +import { isolateHost, unIsolateHost } from '../../../../common/lib/host_isolation'; /** * Fetch Alerts by providing a query @@ -130,6 +132,30 @@ export const createHostIsolation = async ({ case_ids: caseIds, }); +/** + * Unisolate a host + * + * @param agent id + * @param optional comment for the unisolation action + * @param optional case ids if associated with an alert on the host + * + * @throws An error if response is not OK + */ +export const createHostUnIsolation = async ({ + agentId, + comment = '', + caseIds, +}: { + agentId: string; + comment?: string; + caseIds?: string[]; +}): Promise => + unIsolateHost({ + agent_ids: [agentId], + comment, + case_ids: caseIds, + }); + /** * Get list of associated case ids from alert id * @@ -143,3 +169,18 @@ export const getCaseIdsFromAlertId = async ({ KibanaServices.get().http.fetch(getCasesFromAlertsUrl(alertId), { method: 'get', }); + +/** + * Get Host metadata + * + * @param host id + */ +export const getHostMetadata = async ({ + agentId, +}: { + agentId: string; +}): Promise => + KibanaServices.get().http.fetch( + resolvePathVariables(HOST_METADATA_GET_API, { id: agentId }), + { method: 'get' } + ); diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/alerts/translations.ts b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/alerts/translations.ts index ed6a22375a776..9e4497f2f096b 100644 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/alerts/translations.ts +++ b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/alerts/translations.ts @@ -37,3 +37,8 @@ export const CASES_FROM_ALERTS_FAILURE = i18n.translate( 'xpack.securitySolution.endpoint.hostIsolation.casesFromAlerts.title', { defaultMessage: 'Failed to find associated cases' } ); + +export const ISOLATION_STATUS_FAILURE = i18n.translate( + 'xpack.securitySolution.endpoint.hostIsolation.isolationStatus.title', + { defaultMessage: 'Failed to retrieve current isolation status' } +); diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/alerts/use_host_isolation_status.tsx b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/alerts/use_host_isolation_status.tsx new file mode 100644 index 0000000000000..adc6d3a6b054b --- /dev/null +++ b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/alerts/use_host_isolation_status.tsx @@ -0,0 +1,64 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { isEmpty } from 'lodash'; +import { useEffect, useState } from 'react'; +import { Maybe } from '../../../../../../observability/common/typings'; +import { useAppToasts } from '../../../../common/hooks/use_app_toasts'; +import { getHostMetadata } from './api'; +import { ISOLATION_STATUS_FAILURE } from './translations'; + +interface HostIsolationStatusResponse { + loading: boolean; + isIsolated: Maybe; +} + +/* + * Retrieves the current isolation status of a host */ +export const useHostIsolationStatus = ({ + agentId, +}: { + agentId: string; +}): HostIsolationStatusResponse => { + const [isIsolated, setIsIsolated] = useState>(); + const [loading, setLoading] = useState(false); + + const { addError } = useAppToasts(); + + useEffect(() => { + // isMounted tracks if a component is mounted before changing state + let isMounted = true; + const fetchData = async () => { + try { + const metadataResponse = await getHostMetadata({ agentId }); + if (isMounted) { + setIsIsolated(Boolean(metadataResponse.metadata.Endpoint.state.isolation)); + } + } catch (error) { + addError(error.message, { title: ISOLATION_STATUS_FAILURE }); + } + if (isMounted) { + setLoading(false); + } + }; + + setLoading((prevState) => { + if (prevState) { + return prevState; + } + if (!isEmpty(agentId)) { + fetchData(); + } + return true; + }); + return () => { + // updates to show component is unmounted + isMounted = false; + }; + }, [addError, agentId]); + return { loading, isIsolated }; +}; diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/alerts/use_host_unisolation.tsx b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/alerts/use_host_unisolation.tsx new file mode 100644 index 0000000000000..1a0ecb0d15878 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/alerts/use_host_unisolation.tsx @@ -0,0 +1,45 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { useCallback, useState } from 'react'; +import { useAppToasts } from '../../../../common/hooks/use_app_toasts'; +import { HOST_ISOLATION_FAILURE } from './translations'; +import { createHostUnIsolation } from './api'; + +interface HostUnisolationStatus { + loading: boolean; + unIsolateHost: () => Promise; +} + +interface UseHostIsolationProps { + agentId: string; + comment: string; + caseIds?: string[]; +} + +export const useHostUnisolation = ({ + agentId, + comment, + caseIds, +}: UseHostIsolationProps): HostUnisolationStatus => { + const [loading, setLoading] = useState(false); + const { addError } = useAppToasts(); + + const unIsolateHost = useCallback(async () => { + try { + setLoading(true); + const isolationStatus = await createHostUnIsolation({ agentId, comment, caseIds }); + setLoading(false); + return isolationStatus.action ? true : false; + } catch (error) { + setLoading(false); + addError(error.message, { title: HOST_ISOLATION_FAILURE }); + return false; + } + }, [agentId, comment, caseIds, addError]); + return { loading, unIsolateHost }; +}; diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts index ffde8b0931752..9db9932dd4387 100644 --- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts @@ -36,8 +36,13 @@ import { sendGetFleetAgentsWithEndpoint, } from '../../policy/store/services/ingest'; import { AGENT_POLICY_SAVED_OBJECT_TYPE } from '../../../../../../fleet/common'; -import { metadataCurrentIndexPattern } from '../../../../../common/endpoint/constants'; +import { + HOST_METADATA_GET_API, + HOST_METADATA_LIST_API, + metadataCurrentIndexPattern, +} from '../../../../../common/endpoint/constants'; import { IIndexPattern, Query } from '../../../../../../../../src/plugins/data/public'; +import { resolvePathVariables } from '../../trusted_apps/service/utils'; import { createFailedResourceState, createLoadedResourceState, @@ -95,7 +100,7 @@ export const endpointMiddlewareFactory: ImmutableMiddlewareFactory('/api/endpoint/metadata', { + endpointResponse = await coreStart.http.post(HOST_METADATA_LIST_API, { body: JSON.stringify({ paging_properties: [{ page_index: pageIndex }, { page_size: pageSize }], filters: { kql: decodedQuery.query }, @@ -244,7 +249,7 @@ export const endpointMiddlewareFactory: ImmutableMiddlewareFactory( - `/api/endpoint/metadata/${selectedEndpoint}` + resolvePathVariables(HOST_METADATA_GET_API, { id: selectedEndpoint as string }) ); dispatch({ type: 'serverReturnedEndpointDetails', @@ -426,7 +431,7 @@ const getAgentAndPoliciesForEndpointsList = async ( const endpointsTotal = async (http: HttpStart): Promise => { try { return ( - await http.post('/api/endpoint/metadata', { + await http.post(HOST_METADATA_LIST_API, { body: JSON.stringify({ paging_properties: [{ page_index: 0 }, { page_size: 1 }], }), diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/index.tsx index de4795869f4b4..341397da09e1d 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/index.tsx @@ -26,9 +26,13 @@ import { useTimelineEventsDetails } from '../../../containers/details'; import { TimelineTabs } from '../../../../../common/types/timeline'; import { HostIsolationPanel } from '../../../../detections/components/host_isolation'; import { TakeActionDropdown } from '../../../../detections/components/host_isolation/take_action_dropdown'; -import { ISOLATE_HOST } from '../../../../detections/components/host_isolation/translations'; +import { + ISOLATE_HOST, + UNISOLATE_HOST, +} from '../../../../detections/components/host_isolation/translations'; import { ALERT_DETAILS } from './translations'; import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features'; +import { useIsolationPrivileges } from '../../../../common/hooks/endpoint/use_isolate_privileges'; const StyledEuiFlyoutBody = styled(EuiFlyoutBody)` .euiFlyoutBody__overflow { @@ -74,13 +78,17 @@ const EventDetailsPanelComponent: React.FC = ({ const [isHostIsolationPanelOpen, setIsHostIsolationPanel] = useState(false); + const [isolateAction, setIsolateAction] = useState('isolateHost'); + const showAlertDetails = useCallback(() => { setIsHostIsolationPanel(false); }, []); + const { isAllowed: isIsolationAllowed } = useIsolationPrivileges(); const showHostIsolationPanel = useCallback((action) => { - if (action === 'isolateHost') { + if (action === 'isolateHost' || action === 'unisolateHost') { setIsHostIsolationPanel(true); + setIsolateAction(action); } }, []); @@ -91,6 +99,11 @@ const EventDetailsPanelComponent: React.FC = ({ return findEndpointAlert ? findEndpointAlert[0] === 'endpoint' : false; }, [detailsData]); + const agentId = useMemo(() => { + const findAgentId = find({ category: 'agent', field: 'agent.id' }, detailsData)?.values; + return findAgentId ? findAgentId[0] : ''; + }, [detailsData]); + const backToAlertDetailsLink = useMemo(() => { return ( <> @@ -105,11 +118,11 @@ const EventDetailsPanelComponent: React.FC = ({ -

    {ISOLATE_HOST}

    +

    {isolateAction === 'isolateHost' ? ISOLATE_HOST : UNISOLATE_HOST}

    ); - }, [showAlertDetails]); + }, [showAlertDetails, isolateAction]); if (!expandedEvent?.eventId) { return null; @@ -126,7 +139,11 @@ const EventDetailsPanelComponent: React.FC = ({ {isHostIsolationPanelOpen ? ( - + ) : ( = ({ /> )} - {isHostIsolationEnabled && isEndpointAlert && isHostIsolationPanelOpen === false && ( - - - - - - - - - - )} + {isIsolationAllowed && + isHostIsolationEnabled && + isEndpointAlert && + isHostIsolationPanelOpen === false && ( + + + + + + + + + + )} ) : ( <> diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/actions/isolation.ts b/x-pack/plugins/security_solution/server/endpoint/routes/actions/isolation.ts index 09d26a20f1095..6842041128465 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/actions/isolation.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/actions/isolation.ts @@ -20,14 +20,7 @@ import { } from '../../../types'; import { getAgentIDsForEndpoints } from '../../services'; import { EndpointAppContext } from '../../types'; - -export const userCanIsolate = (roles: readonly string[] | undefined): boolean => { - // only superusers can write to the fleet index (or look up endpoint data to convert endp ID to agent ID) - if (!roles || roles.length === 0) { - return false; - } - return roles.includes('superuser'); -}; +import { userCanIsolate } from '../../../../common/endpoint/actions'; /** * Registers the Host-(un-)isolation routes diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/handlers.ts b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/handlers.ts index 104383f398646..98610c2e84c02 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/handlers.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/handlers.ts @@ -17,7 +17,7 @@ import { import { HostInfo, HostMetadata, - HostMetaDataInfo, + HostMetadataInfo, HostResultList, HostStatus, MetadataQueryStrategyVersions, @@ -182,7 +182,7 @@ export async function getHostMetaData( metadataRequestContext: MetadataRequestContext, id: string, queryStrategyVersion?: MetadataQueryStrategyVersions -): Promise { +): Promise { if ( !metadataRequestContext.esClient && !metadataRequestContext.requestHandlerContext?.core.elasticsearch.client From 806566c62ecb4577ea73d622dcd45fec94787841 Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Thu, 27 May 2021 15:47:30 +0200 Subject: [PATCH 24/77] [Index Patterns] Migrate tests to the new es client (#100760) --- .../apis/index_patterns/es_errors/errors.js | 14 ++++++-------- .../index_patterns/es_errors/lib/get_es_errors.js | 4 ++-- .../management/_create_index_pattern_wizard.js | 2 +- test/functional/apps/management/_handle_alias.js | 2 +- .../apps/management/_handle_version_conflict.js | 6 +++--- .../apps/management/_index_patterns_empty.ts | 6 ++---- .../apps/management/create_index_pattern_wizard.js | 2 +- 7 files changed, 16 insertions(+), 20 deletions(-) diff --git a/test/api_integration/apis/index_patterns/es_errors/errors.js b/test/api_integration/apis/index_patterns/es_errors/errors.js index 3b5b4628f0f20..fab59ef256a05 100644 --- a/test/api_integration/apis/index_patterns/es_errors/errors.js +++ b/test/api_integration/apis/index_patterns/es_errors/errors.js @@ -7,7 +7,7 @@ */ import expect from '@kbn/expect'; -import { errors as esErrors } from 'elasticsearch'; +import { errors as esErrors } from '@elastic/elasticsearch'; import Boom from '@hapi/boom'; import { @@ -20,7 +20,7 @@ import { import { getIndexNotFoundError, getDocNotFoundError } from './lib'; export default function ({ getService }) { - const es = getService('legacyEs'); + const es = getService('es'); const esArchiver = getService('esArchiver'); describe('index_patterns/* error handler', () => { @@ -98,8 +98,8 @@ export default function ({ getService }) { }); it('wraps other errors in Boom', async () => { - const error = new esErrors.AuthenticationException( - { + const error = new esErrors.ResponseError({ + body: { root_cause: [ { type: 'security_exception', @@ -109,10 +109,8 @@ export default function ({ getService }) { type: 'security_exception', reason: 'action [indices:data/read/field_caps] is unauthorized for user [standard]', }, - { - statusCode: 403, - } - ); + statusCode: 403, + }); expect(error).to.not.have.property('isBoom'); const converted = convertEsError(indices, error); diff --git a/test/api_integration/apis/index_patterns/es_errors/lib/get_es_errors.js b/test/api_integration/apis/index_patterns/es_errors/lib/get_es_errors.js index 047d9f781421e..c55f8dd8d6d83 100644 --- a/test/api_integration/apis/index_patterns/es_errors/lib/get_es_errors.js +++ b/test/api_integration/apis/index_patterns/es_errors/lib/get_es_errors.js @@ -14,7 +14,7 @@ export async function getIndexNotFoundError(es) { index: 'SHOULD NOT EXIST', }); } catch (err) { - expect(err).to.have.property('status', 404); // sanity check + expect(err).to.have.property('statusCode', 404); // sanity check return err; } @@ -28,7 +28,7 @@ export async function getDocNotFoundError(es) { id: '1234', }); } catch (err) { - expect(err).to.have.property('status', 404); // sanity check + expect(err).to.have.property('statusCode', 404); // sanity check return err; } diff --git a/test/functional/apps/management/_create_index_pattern_wizard.js b/test/functional/apps/management/_create_index_pattern_wizard.js index 306d251629396..d4b49d74d1b90 100644 --- a/test/functional/apps/management/_create_index_pattern_wizard.js +++ b/test/functional/apps/management/_create_index_pattern_wizard.js @@ -11,7 +11,7 @@ import expect from '@kbn/expect'; export default function ({ getService, getPageObjects }) { const kibanaServer = getService('kibanaServer'); const testSubjects = getService('testSubjects'); - const es = getService('legacyEs'); + const es = getService('es'); const PageObjects = getPageObjects(['settings', 'common', 'header']); const security = getService('security'); diff --git a/test/functional/apps/management/_handle_alias.js b/test/functional/apps/management/_handle_alias.js index b88dfe0f25524..6c90556d77cf0 100644 --- a/test/functional/apps/management/_handle_alias.js +++ b/test/functional/apps/management/_handle_alias.js @@ -10,7 +10,7 @@ import expect from '@kbn/expect'; export default function ({ getService, getPageObjects }) { const esArchiver = getService('esArchiver'); - const es = getService('legacyEs'); + const es = getService('es'); const retry = getService('retry'); const security = getService('security'); const PageObjects = getPageObjects(['common', 'home', 'settings', 'discover', 'timePicker']); diff --git a/test/functional/apps/management/_handle_version_conflict.js b/test/functional/apps/management/_handle_version_conflict.js index 16c427e9bbe20..2daad1e457a6b 100644 --- a/test/functional/apps/management/_handle_version_conflict.js +++ b/test/functional/apps/management/_handle_version_conflict.js @@ -21,7 +21,7 @@ export default function ({ getService, getPageObjects }) { const testSubjects = getService('testSubjects'); const esArchiver = getService('esArchiver'); const browser = getService('browser'); - const es = getService('legacyEs'); + const es = getService('es'); const retry = getService('retry'); const scriptedFiledName = 'versionConflictScript'; const PageObjects = getPageObjects(['common', 'home', 'settings', 'discover', 'header']); @@ -49,7 +49,7 @@ export default function ({ getService, getPageObjects }) { }, }); log.debug(JSON.stringify(response)); - expect(response.result).to.be('updated'); + expect(response.body.result).to.be('updated'); await PageObjects.settings.setFieldFormat('url'); await PageObjects.settings.clickSaveScriptedField(); await retry.try(async function () { @@ -80,7 +80,7 @@ export default function ({ getService, getPageObjects }) { }, }); log.debug(JSON.stringify(response)); - expect(response.result).to.be('updated'); + expect(response.body.result).to.be('updated'); await PageObjects.settings.controlChangeSave(); await retry.try(async function () { //await PageObjects.common.sleep(2000); diff --git a/test/functional/apps/management/_index_patterns_empty.ts b/test/functional/apps/management/_index_patterns_empty.ts index 90dd8cdc35c30..3a09340f06ba0 100644 --- a/test/functional/apps/management/_index_patterns_empty.ts +++ b/test/functional/apps/management/_index_patterns_empty.ts @@ -15,7 +15,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { const PageObjects = getPageObjects(['common', 'settings']); const testSubjects = getService('testSubjects'); const globalNav = getService('globalNav'); - const es = getService('legacyEs'); + const es = getService('es'); describe('index pattern empty view', () => { before(async () => { @@ -28,7 +28,6 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { after(async () => { await esArchiver.loadIfNeeded('makelogs'); - // @ts-expect-error await es.transport.request({ path: '/logstash-a', method: 'DELETE', @@ -42,14 +41,13 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { `\n\nNOTE: If this test fails make sure there aren't any non-system indices in the _cat/indices output (use esArchiver.unload on them)` ); log.debug( - // @ts-expect-error await es.transport.request({ path: '/_cat/indices', method: 'GET', }) ); await testSubjects.existOrFail('createAnyway'); - // @ts-expect-error + await es.transport.request({ path: '/logstash-a/_doc', method: 'POST', diff --git a/x-pack/test/functional/apps/management/create_index_pattern_wizard.js b/x-pack/test/functional/apps/management/create_index_pattern_wizard.js index 149c0fd09c097..246256cb4c2a1 100644 --- a/x-pack/test/functional/apps/management/create_index_pattern_wizard.js +++ b/x-pack/test/functional/apps/management/create_index_pattern_wizard.js @@ -7,7 +7,7 @@ export default function ({ getService, getPageObjects }) { const kibanaServer = getService('kibanaServer'); - const es = getService('legacyEs'); + const es = getService('es'); const PageObjects = getPageObjects(['settings', 'common']); describe('"Create Index Pattern" wizard', function () { From 4272bfb9720ac68fe7638128836697a578863c18 Mon Sep 17 00:00:00 2001 From: spalger Date: Thu, 27 May 2021 07:33:11 -0700 Subject: [PATCH 25/77] save --- .../src/lib/docs/index_doc_records_stream.ts | 2 ++ .../src/lib/indices/create_index_stream.ts | 15 +++++++++++++++ .../src/lib/indices/delete_index.ts | 13 ++++++++++++- packages/kbn-es-archiver/src/lib/stats.ts | 2 ++ 4 files changed, 31 insertions(+), 1 deletion(-) diff --git a/packages/kbn-es-archiver/src/lib/docs/index_doc_records_stream.ts b/packages/kbn-es-archiver/src/lib/docs/index_doc_records_stream.ts index 028ff16c9afb2..99fb31a8c942a 100644 --- a/packages/kbn-es-archiver/src/lib/docs/index_doc_records_stream.ts +++ b/packages/kbn-es-archiver/src/lib/docs/index_doc_records_stream.ts @@ -66,6 +66,8 @@ export function createIndexDocRecordsStream( async write(record, enc, callback) { try { + stats.log.info('index doc records stream write()', record); + await indexDocs([record.value]); progress.addToComplete(1); callback(null); diff --git a/packages/kbn-es-archiver/src/lib/indices/create_index_stream.ts b/packages/kbn-es-archiver/src/lib/indices/create_index_stream.ts index b45a8b18a5776..4cbec1488104e 100644 --- a/packages/kbn-es-archiver/src/lib/indices/create_index_stream.ts +++ b/packages/kbn-es-archiver/src/lib/indices/create_index_stream.ts @@ -62,6 +62,13 @@ export function createCreateIndexStream({ kibanaIndexAlreadyDeleted = true; } + await new Promise((resolve) => setTimeout(resolve, 6000)); + + stats.log.info('calling client.indices.create', { + index, + body: { settings, mappings, aliases }, + }); + await client.indices.create( { index, @@ -95,6 +102,10 @@ export function createCreateIndexStream({ err?.meta?.body?.error?.type !== 'resource_already_exists_exception' || attemptNumber >= 3 ) { + stats.log.info('throwing error', { + message: err.message, + meta: err.meta, + }); throw err; } @@ -104,6 +115,10 @@ export function createCreateIndexStream({ return; } + stats.log.info('trying to delete existing index', { + message: err.message, + meta: err.meta, + }); await deleteIndex({ client, stats, index, log }); await attemptToCreate(attemptNumber + 1); return; diff --git a/packages/kbn-es-archiver/src/lib/indices/delete_index.ts b/packages/kbn-es-archiver/src/lib/indices/delete_index.ts index 2a42d52e2ca80..f0ad76435eeef 100644 --- a/packages/kbn-es-archiver/src/lib/indices/delete_index.ts +++ b/packages/kbn-es-archiver/src/lib/indices/delete_index.ts @@ -35,21 +35,32 @@ export async function deleteIndex(options: { } ); + stats.log.info('attempt to get aliases for', indices, resp); + return resp.statusCode === 404 ? indices : Object.keys(resp.body); }; try { const indicesToDelete = await getIndicesToDelete(); - await client.indices.delete( + + stats.log.info('indices to delete', indicesToDelete); + + const resp = await client.indices.delete( { index: indicesToDelete }, { headers: ES_CLIENT_HEADERS, } ); + stats.log.info('deleted indices with response', resp.body); for (const index of indices) { stats.deletedIndex(index); } } catch (error) { + stats.log.info('error while deleting indices', { + message: error.message, + meta: error.meta, + }); + if (retryIfSnapshottingCount > 0 && isDeleteWhileSnapshotInProgressError(error)) { for (const index of indices) { stats.waitingForInProgressSnapshot(index); diff --git a/packages/kbn-es-archiver/src/lib/stats.ts b/packages/kbn-es-archiver/src/lib/stats.ts index 64dd6a9273efe..9f8c1b6fa99ef 100644 --- a/packages/kbn-es-archiver/src/lib/stats.ts +++ b/packages/kbn-es-archiver/src/lib/stats.ts @@ -56,6 +56,8 @@ export function createStats(name: string, log: ToolingLog) { }; return new (class Stats { + public readonly log = log; + /** * Record that an index was not restored because it already existed * @param index From 7fc4a1f80f69dfbb4b7ace3922328c840838e339 Mon Sep 17 00:00:00 2001 From: Nathan L Smith Date: Thu, 27 May 2021 09:43:12 -0500 Subject: [PATCH 26/77] Add kibana.yml configuration for cases (#100583) Make it so `xpack.observability.unsafe.alertingExperience.enabled` only shows and hides the Alerts page, and `xpack.observability.unsafe.cases.enabled` show and hides the Cases page. --- .../resources/base/bin/kibana-docker | 1 + x-pack/plugins/observability/README.md | 12 ++++++++++-- .../public/application/application.test.tsx | 2 +- .../public/components/app/section/apm/index.test.tsx | 2 +- .../public/components/app/section/ux/index.test.tsx | 2 +- .../public/hooks/use_time_range.test.ts | 4 ++-- x-pack/plugins/observability/public/index.ts | 2 +- .../public/pages/overview/overview.stories.tsx | 2 +- x-pack/plugins/observability/public/plugin.ts | 2 ++ .../observability/public/utils/test_helper.tsx | 2 +- x-pack/plugins/observability/server/index.ts | 3 ++- 11 files changed, 23 insertions(+), 11 deletions(-) diff --git a/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker b/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker index 2f54bd1d818b5..47b5888da4ce8 100755 --- a/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker +++ b/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker @@ -231,6 +231,7 @@ kibana_vars=( xpack.maps.showMapVisualizationTypes xpack.ml.enabled xpack.observability.unsafe.alertingExperience.enabled + xpack.observability.unsafe.cases.enabled xpack.reporting.capture.browser.autoDownload xpack.reporting.capture.browser.chromium.disableSandbox xpack.reporting.capture.browser.chromium.inspect diff --git a/x-pack/plugins/observability/README.md b/x-pack/plugins/observability/README.md index 943a7482a25ee..cfa1331573415 100644 --- a/x-pack/plugins/observability/README.md +++ b/x-pack/plugins/observability/README.md @@ -9,13 +9,21 @@ case management. If you have: +```yaml +xpack.observability.unsafe.cases.enabled: true +``` + +In your Kibana configuration, the Cases page will be available. + +If you have: + ```yaml xpack.observability.unsafe.alertingExperience.enabled: true ``` -In your Kibana configuration, the Alerts and Cases pages will be available. +In your Kibana configuration, the Alerts page will be available. -This will only enable the UI for these pages. In order to have alert data indexed +This will only enable the UI for this page when. In order to have alert data indexed you'll need to enable writing in the [Rule Registry plugin](../rule_registry/README.md): ```yaml diff --git a/x-pack/plugins/observability/public/application/application.test.tsx b/x-pack/plugins/observability/public/application/application.test.tsx index 9182a0e8196c8..76b8eb5c7fd08 100644 --- a/x-pack/plugins/observability/public/application/application.test.tsx +++ b/x-pack/plugins/observability/public/application/application.test.tsx @@ -45,7 +45,7 @@ describe('renderApp', () => { uiSettings: { get: () => false }, http: { basePath: { prepend: (path: string) => path } }, } as unknown) as CoreStart; - const config = { unsafe: { alertingExperience: { enabled: true } } }; + const config = { unsafe: { alertingExperience: { enabled: true }, cases: { enabled: true } } }; const params = ({ element: window.document.createElement('div'), history: createMemoryHistory(), diff --git a/x-pack/plugins/observability/public/components/app/section/apm/index.test.tsx b/x-pack/plugins/observability/public/components/app/section/apm/index.test.tsx index 67fede05f3ced..aa83c49c9f52a 100644 --- a/x-pack/plugins/observability/public/components/app/section/apm/index.test.tsx +++ b/x-pack/plugins/observability/public/components/app/section/apm/index.test.tsx @@ -41,7 +41,7 @@ describe('APMSection', () => { http: { basePath: { prepend: jest.fn() } }, } as unknown) as CoreStart, appMountParameters: {} as AppMountParameters, - config: { unsafe: { alertingExperience: { enabled: true } } }, + config: { unsafe: { alertingExperience: { enabled: true }, cases: { enabled: true } } }, observabilityRuleTypeRegistry: createObservabilityRuleTypeRegistryMock(), plugins: ({ data: { diff --git a/x-pack/plugins/observability/public/components/app/section/ux/index.test.tsx b/x-pack/plugins/observability/public/components/app/section/ux/index.test.tsx index b4227cc122dde..5c237bfbc31ec 100644 --- a/x-pack/plugins/observability/public/components/app/section/ux/index.test.tsx +++ b/x-pack/plugins/observability/public/components/app/section/ux/index.test.tsx @@ -40,7 +40,7 @@ describe('UXSection', () => { http: { basePath: { prepend: jest.fn() } }, } as unknown) as CoreStart, appMountParameters: {} as AppMountParameters, - config: { unsafe: { alertingExperience: { enabled: true } } }, + config: { unsafe: { alertingExperience: { enabled: true }, cases: { enabled: true } } }, plugins: ({ data: { query: { diff --git a/x-pack/plugins/observability/public/hooks/use_time_range.test.ts b/x-pack/plugins/observability/public/hooks/use_time_range.test.ts index 8808d6390e365..3b0bdb8dc9603 100644 --- a/x-pack/plugins/observability/public/hooks/use_time_range.test.ts +++ b/x-pack/plugins/observability/public/hooks/use_time_range.test.ts @@ -24,7 +24,7 @@ describe('useTimeRange', () => { jest.spyOn(pluginContext, 'usePluginContext').mockImplementation(() => ({ core: {} as CoreStart, appMountParameters: {} as AppMountParameters, - config: { unsafe: { alertingExperience: { enabled: true } } }, + config: { unsafe: { alertingExperience: { enabled: true }, cases: { enabled: true } } }, plugins: ({ data: { query: { @@ -66,7 +66,7 @@ describe('useTimeRange', () => { jest.spyOn(pluginContext, 'usePluginContext').mockImplementation(() => ({ core: {} as CoreStart, appMountParameters: {} as AppMountParameters, - config: { unsafe: { alertingExperience: { enabled: true } } }, + config: { unsafe: { alertingExperience: { enabled: true }, cases: { enabled: true } } }, plugins: ({ data: { query: { diff --git a/x-pack/plugins/observability/public/index.ts b/x-pack/plugins/observability/public/index.ts index 8dd2f6a57eefe..a49d3461529c2 100644 --- a/x-pack/plugins/observability/public/index.ts +++ b/x-pack/plugins/observability/public/index.ts @@ -22,7 +22,7 @@ export type { export { enableInspectEsQueries } from '../common/ui_settings_keys'; export interface ConfigSchema { - unsafe: { alertingExperience: { enabled: boolean } }; + unsafe: { alertingExperience: { enabled: boolean }; cases: { enabled: boolean } }; } export const plugin: PluginInitializer< diff --git a/x-pack/plugins/observability/public/pages/overview/overview.stories.tsx b/x-pack/plugins/observability/public/pages/overview/overview.stories.tsx index ebd1c73859169..12f8900034eb2 100644 --- a/x-pack/plugins/observability/public/pages/overview/overview.stories.tsx +++ b/x-pack/plugins/observability/public/pages/overview/overview.stories.tsx @@ -45,7 +45,7 @@ const withCore = makeDecorator({ appMountParameters: ({ setHeaderActionMenu: () => {}, } as unknown) as AppMountParameters, - config: { unsafe: { alertingExperience: { enabled: true } } }, + config: { unsafe: { alertingExperience: { enabled: true }, cases: { enabled: true } } }, core: options as CoreStart, plugins: ({ data: { diff --git a/x-pack/plugins/observability/public/plugin.ts b/x-pack/plugins/observability/public/plugin.ts index 6856bc97b4a36..16363d4181c5b 100644 --- a/x-pack/plugins/observability/public/plugin.ts +++ b/x-pack/plugins/observability/public/plugin.ts @@ -119,7 +119,9 @@ export class Plugin mount, updater$, }); + } + if (config.unsafe.cases.enabled) { coreSetup.application.register({ id: 'observability-cases', title: 'Cases', diff --git a/x-pack/plugins/observability/public/utils/test_helper.tsx b/x-pack/plugins/observability/public/utils/test_helper.tsx index ef7c62a143f25..2434f0eec10ed 100644 --- a/x-pack/plugins/observability/public/utils/test_helper.tsx +++ b/x-pack/plugins/observability/public/utils/test_helper.tsx @@ -31,7 +31,7 @@ export const core = ({ }, } as unknown) as CoreStart; -const config = { unsafe: { alertingExperience: { enabled: true } } }; +const config = { unsafe: { alertingExperience: { enabled: true }, cases: { enabled: true } } }; const plugins = ({ data: { query: { timefilter: { timefilter: { setTime: jest.fn() } } } }, diff --git a/x-pack/plugins/observability/server/index.ts b/x-pack/plugins/observability/server/index.ts index ec471df164fe1..52a60a92f5b95 100644 --- a/x-pack/plugins/observability/server/index.ts +++ b/x-pack/plugins/observability/server/index.ts @@ -17,7 +17,7 @@ export * from './types'; export const config = { exposeToBrowser: { - unsafe: { alertingExperience: { enabled: true } }, + unsafe: { alertingExperience: { enabled: true }, cases: { enabled: true } }, }, schema: schema.object({ enabled: schema.boolean({ defaultValue: true }), @@ -27,6 +27,7 @@ export const config = { }), unsafe: schema.object({ alertingExperience: schema.object({ enabled: schema.boolean({ defaultValue: false }) }), + cases: schema.object({ enabled: schema.boolean({ defaultValue: false }) }), }), }), }; From 06d276e06054229010f43ff51a2c7e5d3afb3307 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20St=C3=BCrmer?= Date: Thu, 27 May 2021 16:58:15 +0200 Subject: [PATCH 27/77] [Logs UI] Add shared observability page template and navigation (#99380) Co-authored-by: Kerry Gallagher <471693+Kerry350@users.noreply.github.com> Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- x-pack/plugins/observability/README.md | 4 + .../public/application/application.test.tsx | 2 + .../public/application/index.tsx | 19 ++- .../components/app/header/header_menu.tsx | 41 ++++++ .../components/app/header/index.test.tsx | 18 --- .../public/components/app/header/index.tsx | 79 +---------- .../components/app/layout/with_header.tsx | 48 ------- .../components/app/section/apm/index.test.tsx | 2 + .../components/app/section/ux/index.test.tsx | 2 + .../public/components/shared/index.tsx | 2 + .../components/shared/page_template/README.md | 104 +++++++++++++++ .../components/shared/page_template/index.ts | 8 ++ .../page_template/lazy_page_template.tsx | 26 ++++ .../shared/page_template/page_template.png | Bin 0 -> 311243 bytes .../page_template/page_template.test.tsx | 112 ++++++++++++++++ .../shared/page_template/page_template.tsx | 125 ++++++++++++++++++ .../public/context/plugin_context.tsx | 4 +- .../public/hooks/use_time_range.test.ts | 2 + .../public/pages/alerts/index.tsx | 17 +-- .../public/pages/cases/index.tsx | 8 +- .../public/pages/landing/index.tsx | 13 +- .../public/pages/overview/index.tsx | 39 +++--- .../pages/overview/loading_observability.tsx | 58 +++----- .../pages/overview/overview.stories.tsx | 2 + x-pack/plugins/observability/public/plugin.ts | 38 +++++- .../services/navigation_registry.test.ts | 74 +++++++++++ .../public/services/navigation_registry.ts | 51 +++++++ .../public/utils/test_helper.tsx | 14 +- .../translations/translations/ja-JP.json | 1 - .../translations/translations/zh-CN.json | 1 - 30 files changed, 680 insertions(+), 234 deletions(-) create mode 100644 x-pack/plugins/observability/public/components/app/header/header_menu.tsx delete mode 100644 x-pack/plugins/observability/public/components/app/header/index.test.tsx delete mode 100644 x-pack/plugins/observability/public/components/app/layout/with_header.tsx create mode 100644 x-pack/plugins/observability/public/components/shared/page_template/README.md create mode 100644 x-pack/plugins/observability/public/components/shared/page_template/index.ts create mode 100644 x-pack/plugins/observability/public/components/shared/page_template/lazy_page_template.tsx create mode 100644 x-pack/plugins/observability/public/components/shared/page_template/page_template.png create mode 100644 x-pack/plugins/observability/public/components/shared/page_template/page_template.test.tsx create mode 100644 x-pack/plugins/observability/public/components/shared/page_template/page_template.tsx create mode 100644 x-pack/plugins/observability/public/services/navigation_registry.test.ts create mode 100644 x-pack/plugins/observability/public/services/navigation_registry.ts diff --git a/x-pack/plugins/observability/README.md b/x-pack/plugins/observability/README.md index cfa1331573415..8d87bacc431e0 100644 --- a/x-pack/plugins/observability/README.md +++ b/x-pack/plugins/observability/README.md @@ -32,6 +32,10 @@ xpack.ruleRegistry.write.enabled: true When both of the these are set to `true`, your alerts should show on the alerts page. +## Shared navigation + +The Observability plugin maintains a navigation registry for Observability solutions, and exposes a shared page template component. Please refer to the docs in [the component directory](./components/shared/page_template/README.md) for more information on registering your solution's navigation structure, and rendering the navigation via the shared component. + ## Unit testing Note: Run the following commands from `kibana/x-pack/plugins/observability`. diff --git a/x-pack/plugins/observability/public/application/application.test.tsx b/x-pack/plugins/observability/public/application/application.test.tsx index 76b8eb5c7fd08..3b276df08e5af 100644 --- a/x-pack/plugins/observability/public/application/application.test.tsx +++ b/x-pack/plugins/observability/public/application/application.test.tsx @@ -9,6 +9,7 @@ import { createMemoryHistory } from 'history'; import React from 'react'; import { Observable } from 'rxjs'; import { AppMountParameters, CoreStart } from 'src/core/public'; +import { KibanaPageTemplate } from '../../../../../src/plugins/kibana_react/public'; import { ObservabilityPublicPluginsStart } from '../plugin'; import { createObservabilityRuleTypeRegistryMock } from '../rules/observability_rule_type_registry_mock'; import { renderApp } from './'; @@ -59,6 +60,7 @@ describe('renderApp', () => { plugins, appMountParameters: params, observabilityRuleTypeRegistry: createObservabilityRuleTypeRegistryMock(), + ObservabilityPageTemplate: KibanaPageTemplate, }); unmount(); }).not.toThrowError(); diff --git a/x-pack/plugins/observability/public/application/index.tsx b/x-pack/plugins/observability/public/application/index.tsx index 460aa6c35bdb8..f8dce3ce1d487 100644 --- a/x-pack/plugins/observability/public/application/index.tsx +++ b/x-pack/plugins/observability/public/application/index.tsx @@ -10,7 +10,7 @@ import React, { MouseEvent, useEffect } from 'react'; import ReactDOM from 'react-dom'; import { Route, Router, Switch } from 'react-router-dom'; import { EuiThemeProvider } from '../../../../../src/plugins/kibana_react/common'; -import { AppMountParameters, CoreStart } from '../../../../../src/core/public'; +import { AppMountParameters, APP_WRAPPER_CLASS, CoreStart } from '../../../../../src/core/public'; import { KibanaContextProvider, RedirectAppLinks, @@ -19,6 +19,7 @@ import { PluginContext } from '../context/plugin_context'; import { usePluginContext } from '../hooks/use_plugin_context'; import { useRouteParams } from '../hooks/use_route_params'; import { ObservabilityPublicPluginsStart } from '../plugin'; +import type { LazyObservabilityPageTemplateProps } from '../components/shared/page_template/lazy_page_template'; import { HasDataContextProvider } from '../context/has_data_context'; import { Breadcrumbs, routes } from '../routes'; import { Storage } from '../../../../../src/plugins/kibana_utils/public'; @@ -74,12 +75,14 @@ export const renderApp = ({ plugins, appMountParameters, observabilityRuleTypeRegistry, + ObservabilityPageTemplate, }: { config: ConfigSchema; core: CoreStart; plugins: ObservabilityPublicPluginsStart; observabilityRuleTypeRegistry: ObservabilityRuleTypeRegistry; appMountParameters: AppMountParameters; + ObservabilityPageTemplate: React.ComponentType; }) => { const { element, history } = appMountParameters; const i18nCore = core.i18n; @@ -92,15 +95,25 @@ export const renderApp = ({ links: [{ linkType: 'discuss', href: 'https://ela.st/observability-discuss' }], }); + // ensure all divs are .kbnAppWrappers + element.classList.add(APP_WRAPPER_CLASS); + ReactDOM.render( - + diff --git a/x-pack/plugins/observability/public/components/app/header/header_menu.tsx b/x-pack/plugins/observability/public/components/app/header/header_menu.tsx new file mode 100644 index 0000000000000..707cb241501fd --- /dev/null +++ b/x-pack/plugins/observability/public/components/app/header/header_menu.tsx @@ -0,0 +1,41 @@ +/* + * 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 { EuiHeaderLink, EuiHeaderLinks } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import React from 'react'; +import { usePluginContext } from '../../../hooks/use_plugin_context'; +import HeaderMenuPortal from '../../shared/header_menu_portal'; + +export function ObservabilityHeaderMenu(): React.ReactElement | null { + const { + appMountParameters: { setHeaderActionMenu }, + core: { + http: { + basePath: { prepend }, + }, + }, + } = usePluginContext(); + + return ( + + + + {addDataLinkText} + + + + ); +} + +const addDataLinkText = i18n.translate('xpack.observability.home.addData', { + defaultMessage: 'Add data', +}); diff --git a/x-pack/plugins/observability/public/components/app/header/index.test.tsx b/x-pack/plugins/observability/public/components/app/header/index.test.tsx deleted file mode 100644 index 65724dd74598d..0000000000000 --- a/x-pack/plugins/observability/public/components/app/header/index.test.tsx +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import { render } from '../../../utils/test_helper'; -import { Header } from './'; - -describe('Header', () => { - it('renders', () => { - const { getByText, getByTestId } = render(
    ); - expect(getByTestId('observability-logo')).toBeInTheDocument(); - expect(getByText('Observability')).toBeInTheDocument(); - }); -}); diff --git a/x-pack/plugins/observability/public/components/app/header/index.tsx b/x-pack/plugins/observability/public/components/app/header/index.tsx index 8b86e0b25379b..f7f69c22173fc 100644 --- a/x-pack/plugins/observability/public/components/app/header/index.tsx +++ b/x-pack/plugins/observability/public/components/app/header/index.tsx @@ -5,81 +5,4 @@ * 2.0. */ -import { - EuiFlexGroup, - EuiFlexItem, - EuiHeaderLink, - EuiHeaderLinks, - EuiIcon, - EuiSpacer, - EuiTitle, -} from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import React, { ReactNode } from 'react'; -import styled from 'styled-components'; -import { usePluginContext } from '../../../hooks/use_plugin_context'; -import HeaderMenuPortal from '../../shared/header_menu_portal'; - -const Container = styled.div<{ color: string }>` - background: ${(props) => props.color}; - border-bottom: ${(props) => props.theme.eui.euiBorderThin}; -`; - -const Wrapper = styled.div<{ restrictWidth?: number }>` - width: 100%; - max-width: ${(props) => `${props.restrictWidth}px`}; - margin: 0 auto; - overflow: hidden; - padding: 0 16px; -`; - -interface Props { - color: string; - datePicker?: ReactNode; - restrictWidth?: number; -} - -export function Header({ color, datePicker = null, restrictWidth }: Props) { - const { appMountParameters, core } = usePluginContext(); - const { setHeaderActionMenu } = appMountParameters; - const { prepend } = core.http.basePath; - - return ( - - - - - {i18n.translate('xpack.observability.home.addData', { defaultMessage: 'Add data' })} - - - - - - - - - - - - - -

    - {i18n.translate('xpack.observability.home.title', { - defaultMessage: 'Observability', - })} -

    -
    -
    -
    -
    - {datePicker} -
    - -
    -
    - ); -} +export * from './header_menu'; diff --git a/x-pack/plugins/observability/public/components/app/layout/with_header.tsx b/x-pack/plugins/observability/public/components/app/layout/with_header.tsx deleted file mode 100644 index f2d50539395bd..0000000000000 --- a/x-pack/plugins/observability/public/components/app/layout/with_header.tsx +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { EuiPage, EuiPageBody, EuiPageProps } from '@elastic/eui'; -import React, { ReactNode } from 'react'; -import styled from 'styled-components'; -import { Header } from '../header/index'; - -const Page = styled(EuiPage)` - background: transparent; -`; - -const Container = styled.div<{ color?: string }>` - overflow-y: hidden; - min-height: calc( - 100vh - ${(props) => props.theme.eui.euiHeaderHeight + props.theme.eui.euiHeaderHeight} - ); - background: ${(props) => props.color}; -`; - -interface Props { - datePicker?: ReactNode; - headerColor: string; - bodyColor: string; - children?: ReactNode; - restrictWidth?: number; -} - -export function WithHeaderLayout({ - datePicker, - headerColor, - bodyColor, - children, - restrictWidth, -}: Props) { - return ( - -
    - - {children} - - - ); -} diff --git a/x-pack/plugins/observability/public/components/app/section/apm/index.test.tsx b/x-pack/plugins/observability/public/components/app/section/apm/index.test.tsx index aa83c49c9f52a..ad3ecd2740802 100644 --- a/x-pack/plugins/observability/public/components/app/section/apm/index.test.tsx +++ b/x-pack/plugins/observability/public/components/app/section/apm/index.test.tsx @@ -16,6 +16,7 @@ import { HasDataContextValue } from '../../../../context/has_data_context'; import { AppMountParameters, CoreStart } from 'kibana/public'; import { ObservabilityPublicPluginsStart } from '../../../../plugin'; import { createObservabilityRuleTypeRegistryMock } from '../../../../rules/observability_rule_type_registry_mock'; +import { KibanaPageTemplate } from '../../../../../../../../src/plugins/kibana_react/public'; jest.mock('react-router-dom', () => ({ useLocation: () => ({ @@ -57,6 +58,7 @@ describe('APMSection', () => { }, }, } as unknown) as ObservabilityPublicPluginsStart, + ObservabilityPageTemplate: KibanaPageTemplate, })); }); diff --git a/x-pack/plugins/observability/public/components/app/section/ux/index.test.tsx b/x-pack/plugins/observability/public/components/app/section/ux/index.test.tsx index 5c237bfbc31ec..fab461476e713 100644 --- a/x-pack/plugins/observability/public/components/app/section/ux/index.test.tsx +++ b/x-pack/plugins/observability/public/components/app/section/ux/index.test.tsx @@ -16,6 +16,7 @@ import { render } from '../../../../utils/test_helper'; import { UXSection } from './'; import { response } from './mock_data/ux.mock'; import { createObservabilityRuleTypeRegistryMock } from '../../../../rules/observability_rule_type_registry_mock'; +import { KibanaPageTemplate } from '../../../../../../../../src/plugins/kibana_react/public'; jest.mock('react-router-dom', () => ({ useLocation: () => ({ @@ -56,6 +57,7 @@ describe('UXSection', () => { }, } as unknown) as ObservabilityPublicPluginsStart, observabilityRuleTypeRegistry: createObservabilityRuleTypeRegistryMock(), + ObservabilityPageTemplate: KibanaPageTemplate, })); }); it('renders with core web vitals', () => { diff --git a/x-pack/plugins/observability/public/components/shared/index.tsx b/x-pack/plugins/observability/public/components/shared/index.tsx index d4d7521a6b096..f04ca5b857916 100644 --- a/x-pack/plugins/observability/public/components/shared/index.tsx +++ b/x-pack/plugins/observability/public/components/shared/index.tsx @@ -9,6 +9,8 @@ import React, { lazy, Suspense } from 'react'; import type { CoreVitalProps, HeaderMenuPortalProps } from './types'; import type { FieldValueSuggestionsProps } from './field_value_suggestions/types'; +export { createLazyObservabilityPageTemplate } from './page_template'; + const CoreVitalsLazy = lazy(() => import('./core_web_vitals/index')); export function getCoreVitalsComponent(props: CoreVitalProps) { diff --git a/x-pack/plugins/observability/public/components/shared/page_template/README.md b/x-pack/plugins/observability/public/components/shared/page_template/README.md new file mode 100644 index 0000000000000..e360e6d95a9d8 --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/page_template/README.md @@ -0,0 +1,104 @@ +## Overview + +Observability solutions can register their navigation structures via the Observability plugin, this ensures that these navigation options display in the Observability page template component. This is a two part process, A) register your navigation structure and B) consume and render the shared page template component. These two elements are documented below. + +## Navigation registration + +To register a solution's navigation structure you'll first need to ensure your solution has the observability plugin specified as a dependency in your `kibana.json` file, e.g. + +```json +"requiredPlugins": [ + "observability" +], +``` + +Now within your solution's **public** plugin `setup` lifecycle method you can call the `registerSections` method, this will register your solution's specific navigation structure with the overall Observability navigation registry. E.g. + +```typescript +// x-pack/plugins/example_plugin/public/plugin.ts + +export class Plugin implements PluginClass { + constructor(_context: PluginInitializerContext) {} + + setup(core: CoreSetup, plugins: PluginsSetup) { + plugins.observability.navigation.registerSections( + of([ + { + label: 'A solution section', + sortKey: 200, + entries: [ + { label: 'Example Page', app: 'exampleA', path: '/example' }, + { label: 'Another Example Page', app: 'exampleA', path: '/another-example' }, + ], + }, + { + label: 'Another solution section', + sortKey: 300, + entries: [ + { label: 'Example page', app: 'exampleB', path: '/example' }, + ], + }, + ]) + ); + } + + start() {} + + stop() {} +} +``` + +Here `app` would match your solution - e.g. logs, metrics, APM, uptime etc. The registry is fully typed so please refer to the types for specific options. + +Observables are used to facilitate changes over time, for example within the lifetime of your application a license type or set of user permissions may change and as such you may wish to change the navigation structure. If your navigation needs are simple you can pass a value and forget about it. **Solutions are expected to handle their own permissions, and what should or should not be displayed at any time**, the Observability plugin will not add and remove items for you. + +The Observability navigation registry is now aware of your solution's navigation needs ✅ + +## Page template component + +The shared page template component can be used to actually display and render all of the registered navigation structures within your solution. + +The `start` contract of the public Observability plugin exposes a React component, under `navigation.PageTemplate`. + +This can be accessed like so: + +``` +const [coreStart, pluginsStart] = await core.getStartServices(); +const pageTemplateComponent = pluginsStart.observability.navigation.PageTemplate; +``` + +Now that you have access to the component you can render your solution's content using it. + +```jsx + , + ], + }} + > + // Render anything you like here, this is just an example. + + + // Content + + + + // Content + + + +``` + +The `` component is a wrapper around the `` component (which in turn is a wrapper around the `` component). As such the props mostly reflect those available on the wrapped components, again everything is fully typed so please refer to the types for specific options. The `pageSideBar` prop is handled by the component, and will take care of rendering out and managing the items from the registry. + +After these two steps we should see something like the following (note the navigation on the left): + +![Page template rendered example](./page_template.png) \ No newline at end of file diff --git a/x-pack/plugins/observability/public/components/shared/page_template/index.ts b/x-pack/plugins/observability/public/components/shared/page_template/index.ts new file mode 100644 index 0000000000000..14793ba402251 --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/page_template/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { createLazyObservabilityPageTemplate } from './lazy_page_template'; diff --git a/x-pack/plugins/observability/public/components/shared/page_template/lazy_page_template.tsx b/x-pack/plugins/observability/public/components/shared/page_template/lazy_page_template.tsx new file mode 100644 index 0000000000000..7c61cae4f2c73 --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/page_template/lazy_page_template.tsx @@ -0,0 +1,26 @@ +/* + * 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 type { + ObservabilityPageTemplateDependencies, + WrappedPageTemplateProps, +} from './page_template'; + +export const LazyObservabilityPageTemplate = React.lazy(() => import('./page_template')); + +export type LazyObservabilityPageTemplateProps = WrappedPageTemplateProps; + +export function createLazyObservabilityPageTemplate( + injectedDeps: ObservabilityPageTemplateDependencies +) { + return (pageTemplateProps: LazyObservabilityPageTemplateProps) => ( + + + + ); +} diff --git a/x-pack/plugins/observability/public/components/shared/page_template/page_template.png b/x-pack/plugins/observability/public/components/shared/page_template/page_template.png new file mode 100644 index 0000000000000000000000000000000000000000..7dc88b937c27bf2bb43851d641b4b11213b71045 GIT binary patch literal 311243 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 VXno#evIG2GSGf6~>_3bj{U5)Ckh=f? literal 0 HcmV?d00001 diff --git a/x-pack/plugins/observability/public/components/shared/page_template/page_template.test.tsx b/x-pack/plugins/observability/public/components/shared/page_template/page_template.test.tsx new file mode 100644 index 0000000000000..42d520786afcf --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/page_template/page_template.test.tsx @@ -0,0 +1,112 @@ +/* + * 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 { I18nProvider } from '@kbn/i18n/react'; +import { render } from '@testing-library/react'; +import { shallow } from 'enzyme'; +import React from 'react'; +import { of } from 'rxjs'; +import { createNavigationRegistry } from '../../../services/navigation_registry'; +import { createLazyObservabilityPageTemplate } from './lazy_page_template'; +import { ObservabilityPageTemplate } from './page_template'; + +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useLocation: () => ({ + pathname: '/test-path', + }), +})); + +const navigationRegistry = createNavigationRegistry(); + +navigationRegistry.registerSections( + of([ + { + label: 'Test A', + sortKey: 100, + entries: [ + { label: 'Section A Url A', app: 'TestA', path: '/url-a' }, + { label: 'Section A Url B', app: 'TestA', path: '/url-b' }, + ], + }, + { + label: 'Test B', + sortKey: 200, + entries: [ + { label: 'Section B Url A', app: 'TestB', path: '/url-a' }, + { label: 'Section B Url B', app: 'TestB', path: '/url-b' }, + ], + }, + ]) +); + +describe('Page template', () => { + it('Provides a working lazy wrapper', () => { + const LazyObservabilityPageTemplate = createLazyObservabilityPageTemplate({ + currentAppId$: of('Test app ID'), + getUrlForApp: () => '/test-url', + navigateToApp: async () => {}, + navigationSections$: navigationRegistry.sections$, + }); + + const component = shallow( + Test side item], + }} + > +
    Test structure
    +
    + ); + + expect(component.exists('lazy')).toBe(true); + }); + + it('Utilises the KibanaPageTemplate for rendering', () => { + const component = shallow( + '/test-url'} + navigateToApp={async () => {}} + navigationSections$={navigationRegistry.sections$} + pageHeader={{ + pageTitle: 'Test title', + rightSideItems: [Test side item], + }} + > +
    Test structure
    +
    + ); + + expect(component.is('KibanaPageTemplate')); + }); + + it('Handles outputting the registered navigation structures within a side nav', () => { + const { container } = render( + + '/test-url'} + navigateToApp={async () => {}} + navigationSections$={navigationRegistry.sections$} + pageHeader={{ + pageTitle: 'Test title', + rightSideItems: [Test side item], + }} + > +
    Test structure
    +
    +
    + ); + + expect(container).toHaveTextContent('Section A Url A'); + expect(container).toHaveTextContent('Section A Url B'); + expect(container).toHaveTextContent('Section B Url A'); + expect(container).toHaveTextContent('Section B Url B'); + }); +}); diff --git a/x-pack/plugins/observability/public/components/shared/page_template/page_template.tsx b/x-pack/plugins/observability/public/components/shared/page_template/page_template.tsx new file mode 100644 index 0000000000000..8025c6d658692 --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/page_template/page_template.tsx @@ -0,0 +1,125 @@ +/* + * 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 { EuiSideNavItemType, ExclusiveUnion } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import React, { useMemo } from 'react'; +import { matchPath, useLocation } from 'react-router-dom'; +import useObservable from 'react-use/lib/useObservable'; +import type { Observable } from 'rxjs'; +import type { ApplicationStart } from '../../../../../../../src/core/public'; +import { + KibanaPageTemplate, + KibanaPageTemplateProps, +} from '../../../../../../../src/plugins/kibana_react/public'; +import type { NavigationSection } from '../../../services/navigation_registry'; + +export type WrappedPageTemplateProps = Pick< + KibanaPageTemplateProps, + | 'children' + | 'data-test-subj' + | 'paddingSize' + | 'pageBodyProps' + | 'pageContentBodyProps' + | 'pageContentProps' + | 'pageHeader' + | 'restrictWidth' +> & + // recreate the exclusivity of bottomBar-related props + ExclusiveUnion< + { template?: 'default' } & Pick, + { template: KibanaPageTemplateProps['template'] } + >; + +export interface ObservabilityPageTemplateDependencies { + currentAppId$: Observable; + getUrlForApp: ApplicationStart['getUrlForApp']; + navigateToApp: ApplicationStart['navigateToApp']; + navigationSections$: Observable; +} + +export type ObservabilityPageTemplateProps = ObservabilityPageTemplateDependencies & + WrappedPageTemplateProps; + +export function ObservabilityPageTemplate({ + children, + currentAppId$, + getUrlForApp, + navigateToApp, + navigationSections$, + ...pageTemplateProps +}: ObservabilityPageTemplateProps): React.ReactElement | null { + const sections = useObservable(navigationSections$, []); + const currentAppId = useObservable(currentAppId$, undefined); + const { pathname: currentPath } = useLocation(); + + const sideNavItems = useMemo>>( + () => + sections.map(({ label, entries }, sectionIndex) => ({ + id: `${sectionIndex}`, + name: label, + items: entries.map((entry, entryIndex) => { + const href = getUrlForApp(entry.app, { + path: entry.path, + }); + + const isSelected = + entry.app === currentAppId && + matchPath(currentPath, { + path: entry.path, + }) != null; + + return { + id: `${sectionIndex}.${entryIndex}`, + name: entry.label, + href, + isSelected, + onClick: (event) => { + if ( + event.button !== 0 || + event.defaultPrevented || + event.metaKey || + event.altKey || + event.ctrlKey || + event.shiftKey + ) { + return; + } + + event.preventDefault(); + navigateToApp(entry.app, { + path: entry.path, + }); + }, + }; + }), + })), + [currentAppId, currentPath, getUrlForApp, navigateToApp, sections] + ); + + return ( + + {children} + + ); +} + +// for lazy import +// eslint-disable-next-line import/no-default-export +export default ObservabilityPageTemplate; + +const sideNavTitle = i18n.translate('xpack.observability.pageLayout.sideNavTitle', { + defaultMessage: 'Observability', +}); diff --git a/x-pack/plugins/observability/public/context/plugin_context.tsx b/x-pack/plugins/observability/public/context/plugin_context.tsx index 9b0bacc4c1174..7c710d1d84c3d 100644 --- a/x-pack/plugins/observability/public/context/plugin_context.tsx +++ b/x-pack/plugins/observability/public/context/plugin_context.tsx @@ -5,11 +5,12 @@ * 2.0. */ -import { createContext } from 'react'; import { AppMountParameters, CoreStart } from 'kibana/public'; +import { createContext } from 'react'; import { ObservabilityPublicPluginsStart } from '../plugin'; import { ConfigSchema } from '..'; import { ObservabilityRuleTypeRegistry } from '../rules/create_observability_rule_type_registry'; +import type { LazyObservabilityPageTemplateProps } from '../components/shared/page_template/lazy_page_template'; export interface PluginContextValue { appMountParameters: AppMountParameters; @@ -17,6 +18,7 @@ export interface PluginContextValue { core: CoreStart; plugins: ObservabilityPublicPluginsStart; observabilityRuleTypeRegistry: ObservabilityRuleTypeRegistry; + ObservabilityPageTemplate: React.ComponentType; } export const PluginContext = createContext({} as PluginContextValue); diff --git a/x-pack/plugins/observability/public/hooks/use_time_range.test.ts b/x-pack/plugins/observability/public/hooks/use_time_range.test.ts index 3b0bdb8dc9603..7a241401722cf 100644 --- a/x-pack/plugins/observability/public/hooks/use_time_range.test.ts +++ b/x-pack/plugins/observability/public/hooks/use_time_range.test.ts @@ -40,6 +40,7 @@ describe('useTimeRange', () => { }, } as unknown) as ObservabilityPublicPluginsStart, observabilityRuleTypeRegistry: createObservabilityRuleTypeRegistryMock(), + ObservabilityPageTemplate: () => null, })); jest.spyOn(kibanaUISettings, 'useKibanaUISettings').mockImplementation(() => ({ from: '2020-10-08T05:00:00.000Z', @@ -82,6 +83,7 @@ describe('useTimeRange', () => { }, } as unknown) as ObservabilityPublicPluginsStart, observabilityRuleTypeRegistry: createObservabilityRuleTypeRegistryMock(), + ObservabilityPageTemplate: () => null, })); }); it('returns ranges and absolute times from kibana default settings', () => { diff --git a/x-pack/plugins/observability/public/pages/alerts/index.tsx b/x-pack/plugins/observability/public/pages/alerts/index.tsx index 7b8055c82f071..b76e9f82d8dfe 100644 --- a/x-pack/plugins/observability/public/pages/alerts/index.tsx +++ b/x-pack/plugins/observability/public/pages/alerts/index.tsx @@ -5,15 +5,7 @@ * 2.0. */ -import { - EuiButton, - EuiCallOut, - EuiFlexGroup, - EuiFlexItem, - EuiLink, - EuiPageTemplate, - EuiSpacer, -} from '@elastic/eui'; +import { EuiButton, EuiCallOut, EuiFlexGroup, EuiFlexItem, EuiLink, EuiSpacer } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { ALERT_START, @@ -56,7 +48,7 @@ interface AlertsPageProps { } export function AlertsPage({ routeParams }: AlertsPageProps) { - const { core, observabilityRuleTypeRegistry } = usePluginContext(); + const { core, observabilityRuleTypeRegistry, ObservabilityPageTemplate } = usePluginContext(); const { prepend } = core.http.basePath; const history = useHistory(); const { @@ -131,7 +123,7 @@ export function AlertsPage({ routeParams }: AlertsPageProps) { } return ( - @@ -139,7 +131,6 @@ export function AlertsPage({ routeParams }: AlertsPageProps) { ), - rightSideItems: [ {i18n.translate('xpack.observability.alerts.manageDetectionRulesButtonLabel', { @@ -206,6 +197,6 @@ export function AlertsPage({ routeParams }: AlertsPageProps) { - +
    ); } diff --git a/x-pack/plugins/observability/public/pages/cases/index.tsx b/x-pack/plugins/observability/public/pages/cases/index.tsx index dd7f7875b568e..7f6bce7d486f3 100644 --- a/x-pack/plugins/observability/public/pages/cases/index.tsx +++ b/x-pack/plugins/observability/public/pages/cases/index.tsx @@ -5,19 +5,21 @@ * 2.0. */ -import { EuiCallOut, EuiFlexGroup, EuiFlexItem, EuiPageTemplate } from '@elastic/eui'; +import { EuiCallOut, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import React from 'react'; import { ExperimentalBadge } from '../../components/shared/experimental_badge'; import { RouteParams } from '../../routes'; +import { usePluginContext } from '../../hooks/use_plugin_context'; interface CasesProps { routeParams: RouteParams<'/cases'>; } export function CasesPage(props: CasesProps) { + const { ObservabilityPageTemplate } = usePluginContext(); return ( - @@ -44,6 +46,6 @@ export function CasesPage(props: CasesProps) { - + ); } diff --git a/x-pack/plugins/observability/public/pages/landing/index.tsx b/x-pack/plugins/observability/public/pages/landing/index.tsx index 73693e14d6ac1..46c99bffbcc69 100644 --- a/x-pack/plugins/observability/public/pages/landing/index.tsx +++ b/x-pack/plugins/observability/public/pages/landing/index.tsx @@ -20,7 +20,7 @@ import { i18n } from '@kbn/i18n'; import React, { useContext } from 'react'; import styled, { ThemeContext } from 'styled-components'; import { FleetPanel } from '../../components/app/fleet_panel'; -import { WithHeaderLayout } from '../../components/app/layout/with_header'; +import { ObservabilityHeaderMenu } from '../../components/app/header'; import { usePluginContext } from '../../hooks/use_plugin_context'; import { useTrackPageview } from '../../hooks/use_track_metric'; import { appsSection } from '../home/section'; @@ -34,15 +34,12 @@ export function LandingPage() { useTrackPageview({ app: 'observability-overview', path: 'landing' }); useTrackPageview({ app: 'observability-overview', path: 'landing', delay: 15000 }); - const { core } = usePluginContext(); + const { core, ObservabilityPageTemplate } = usePluginContext(); const theme = useContext(ThemeContext); return ( - + + {/* title and description */} @@ -128,6 +125,6 @@ export function LandingPage() { - + ); } diff --git a/x-pack/plugins/observability/public/pages/overview/index.tsx b/x-pack/plugins/observability/public/pages/overview/index.tsx index 7aa473d0ebee9..4cb6792d50195 100644 --- a/x-pack/plugins/observability/public/pages/overview/index.tsx +++ b/x-pack/plugins/observability/public/pages/overview/index.tsx @@ -6,12 +6,12 @@ */ import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; -import React, { useContext } from 'react'; -import { ThemeContext } from 'styled-components'; +import { i18n } from '@kbn/i18n'; +import React from 'react'; import { useTrackPageview } from '../..'; import { Alert } from '../../../../alerting/common'; import { EmptySections } from '../../components/app/empty_sections'; -import { WithHeaderLayout } from '../../components/app/layout/with_header'; +import { ObservabilityHeaderMenu } from '../../components/app/header'; import { NewsFeed } from '../../components/app/news_feed'; import { Resources } from '../../components/app/resources'; import { AlertsSection } from '../../components/app/section/alerts'; @@ -39,8 +39,7 @@ function calculateBucketSize({ start, end }: { start?: number; end?: number }) { export function OverviewPage({ routeParams }: Props) { useTrackPageview({ app: 'observability-overview', path: 'overview' }); useTrackPageview({ app: 'observability-overview', path: 'overview', delay: 15000 }); - const { core } = usePluginContext(); - const theme = useContext(ThemeContext); + const { core, ObservabilityPageTemplate } = usePluginContext(); const { relativeStart, relativeEnd, absoluteStart, absoluteEnd } = useTimeRange(); @@ -65,18 +64,20 @@ export function OverviewPage({ routeParams }: Props) { }); return ( - - } + , + ], + }} > + {/* Data sections */} @@ -107,6 +108,10 @@ export function OverviewPage({ routeParams }: Props) { - + ); } + +const overviewPageTitle = i18n.translate('xpack.observability.overview.pageTitle', { + defaultMessage: 'Overview', +}); diff --git a/x-pack/plugins/observability/public/pages/overview/loading_observability.tsx b/x-pack/plugins/observability/public/pages/overview/loading_observability.tsx index 36c9589e7e169..e2d691c647acc 100644 --- a/x-pack/plugins/observability/public/pages/overview/loading_observability.tsx +++ b/x-pack/plugins/observability/public/pages/overview/loading_observability.tsx @@ -5,49 +5,33 @@ * 2.0. */ -import React, { useContext } from 'react'; -import styled, { ThemeContext } from 'styled-components'; -import { EuiFlexItem } from '@elastic/eui'; -import { EuiPanel } from '@elastic/eui'; -import { EuiFlexGroup } from '@elastic/eui'; -import { EuiLoadingSpinner } from '@elastic/eui'; -import { EuiText } from '@elastic/eui'; +import { EuiFlexGroup, EuiFlexItem, EuiLoadingSpinner, EuiText } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { WithHeaderLayout } from '../../components/app/layout/with_header'; - -const CentralizedFlexGroup = styled(EuiFlexGroup)` - justify-content: center; - align-items: center; - // place the element in the center of the page - min-height: calc(100vh - ${(props) => props.theme.eui.euiHeaderChildSize}); -`; +import React from 'react'; +import { ObservabilityHeaderMenu } from '../../components/app/header'; +import { usePluginContext } from '../../hooks/use_plugin_context'; export function LoadingObservability() { - const theme = useContext(ThemeContext); + const { ObservabilityPageTemplate } = usePluginContext(); return ( - - + + + - - - - - - - - {i18n.translate('xpack.observability.overview.loadingObservability', { - defaultMessage: 'Loading Observability', - })} - - - - + + + + {observabilityLoadingMessage} - - + + ); } + +const observabilityLoadingMessage = i18n.translate( + 'xpack.observability.overview.loadingObservability', + { + defaultMessage: 'Loading Observability', + } +); diff --git a/x-pack/plugins/observability/public/pages/overview/overview.stories.tsx b/x-pack/plugins/observability/public/pages/overview/overview.stories.tsx index 12f8900034eb2..2482ae7a8e7ab 100644 --- a/x-pack/plugins/observability/public/pages/overview/overview.stories.tsx +++ b/x-pack/plugins/observability/public/pages/overview/overview.stories.tsx @@ -24,6 +24,7 @@ import { emptyResponse as emptyMetricsResponse, fetchMetricsData } from './mock/ import { newsFeedFetchData } from './mock/news_feed.mock'; import { emptyResponse as emptyUptimeResponse, fetchUptimeData } from './mock/uptime.mock'; import { createObservabilityRuleTypeRegistryMock } from '../../rules/observability_rule_type_registry_mock'; +import { KibanaPageTemplate } from '../../../../../../src/plugins/kibana_react/public'; function unregisterAll() { unregisterDataHandler({ appName: 'apm' }); @@ -55,6 +56,7 @@ const withCore = makeDecorator({ }, } as unknown) as ObservabilityPublicPluginsStart, observabilityRuleTypeRegistry: createObservabilityRuleTypeRegistryMock(), + ObservabilityPageTemplate: KibanaPageTemplate, }} > diff --git a/x-pack/plugins/observability/public/plugin.ts b/x-pack/plugins/observability/public/plugin.ts index 16363d4181c5b..c1b18e37faee8 100644 --- a/x-pack/plugins/observability/public/plugin.ts +++ b/x-pack/plugins/observability/public/plugin.ts @@ -6,7 +6,7 @@ */ import { i18n } from '@kbn/i18n'; -import { BehaviorSubject } from 'rxjs'; +import { BehaviorSubject, of } from 'rxjs'; import { TriggersAndActionsUIPublicPluginSetup, TriggersAndActionsUIPublicPluginStart, @@ -31,9 +31,11 @@ import type { import type { LensPublicStart } from '../../lens/public'; import { registerDataHandler } from './data_handler'; import { createCallObservabilityApi } from './services/call_observability_api'; +import { createNavigationRegistry } from './services/navigation_registry'; import { toggleOverviewLinkInNav } from './toggle_overview_link_in_nav'; import { ConfigSchema } from '.'; import { createObservabilityRuleTypeRegistry } from './rules/create_observability_rule_type_registry'; +import { createLazyObservabilityPageTemplate } from './components/shared'; export type ObservabilityPublicSetup = ReturnType; @@ -50,7 +52,7 @@ export interface ObservabilityPublicPluginsStart { lens: LensPublicStart; } -export type ObservabilityPublicStart = void; +export type ObservabilityPublicStart = ReturnType; export class Plugin implements @@ -61,13 +63,14 @@ export class Plugin ObservabilityPublicPluginsStart > { private readonly appUpdater$ = new BehaviorSubject(() => ({})); + private readonly navigationRegistry = createNavigationRegistry(); constructor(private readonly initializerContext: PluginInitializerContext) { this.initializerContext = initializerContext; } public setup( - coreSetup: CoreSetup, + coreSetup: CoreSetup, pluginsSetup: ObservabilityPublicPluginsSetup ) { const category = DEFAULT_APP_CATEGORIES.observability; @@ -84,7 +87,7 @@ export class Plugin // Load application bundle const { renderApp } = await import('./application'); // Get start services - const [coreStart, pluginsStart] = await coreSetup.getStartServices(); + const [coreStart, pluginsStart, { navigation }] = await coreSetup.getStartServices(); return renderApp({ config, @@ -92,6 +95,7 @@ export class Plugin plugins: pluginsStart, appMountParameters: params, observabilityRuleTypeRegistry, + ObservabilityPageTemplate: navigation.PageTemplate, }); }; @@ -164,13 +168,39 @@ export class Plugin }); } + this.navigationRegistry.registerSections( + of([ + { + label: '', + sortKey: 100, + entries: [{ label: 'Overview', app: 'observability-overview', path: '/overview' }], + }, + ]) + ); + return { dashboard: { register: registerDataHandler }, observabilityRuleTypeRegistry, isAlertingExperienceEnabled: () => config.unsafe.alertingExperience.enabled, + navigation: { + registerSections: this.navigationRegistry.registerSections, + }, }; } public start({ application }: CoreStart) { toggleOverviewLinkInNav(this.appUpdater$, application); + + const PageTemplate = createLazyObservabilityPageTemplate({ + currentAppId$: application.currentAppId$, + getUrlForApp: application.getUrlForApp, + navigateToApp: application.navigateToApp, + navigationSections$: this.navigationRegistry.sections$, + }); + + return { + navigation: { + PageTemplate, + }, + }; } } diff --git a/x-pack/plugins/observability/public/services/navigation_registry.test.ts b/x-pack/plugins/observability/public/services/navigation_registry.test.ts new file mode 100644 index 0000000000000..8e46ed8aacabe --- /dev/null +++ b/x-pack/plugins/observability/public/services/navigation_registry.test.ts @@ -0,0 +1,74 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { firstValueFrom } from '@kbn/std'; +import { of } from 'rxjs'; +import { createNavigationRegistry } from './navigation_registry'; + +describe('Navigation registry', () => { + it('Allows the registration of, and access to, navigation sections', async () => { + const navigationRegistry = createNavigationRegistry(); + + navigationRegistry.registerSections( + of([ + { + label: 'Test A', + sortKey: 100, + entries: [ + { label: 'Url A', app: 'TestA', path: '/url-a' }, + { label: 'Url B', app: 'TestA', path: '/url-b' }, + ], + }, + { + label: 'Test B', + sortKey: 200, + entries: [ + { label: 'Url A', app: 'TestB', path: '/url-a' }, + { label: 'Url B', app: 'TestB', path: '/url-b' }, + ], + }, + ]) + ); + + const sections = await firstValueFrom(navigationRegistry.sections$); + + expect(sections).toEqual([ + { + label: 'Test A', + sortKey: 100, + entries: [ + { + label: 'Url A', + app: 'TestA', + path: '/url-a', + }, + { + label: 'Url B', + app: 'TestA', + path: '/url-b', + }, + ], + }, + { + label: 'Test B', + sortKey: 200, + entries: [ + { + label: 'Url A', + app: 'TestB', + path: '/url-a', + }, + { + label: 'Url B', + app: 'TestB', + path: '/url-b', + }, + ], + }, + ]); + }); +}); diff --git a/x-pack/plugins/observability/public/services/navigation_registry.ts b/x-pack/plugins/observability/public/services/navigation_registry.ts new file mode 100644 index 0000000000000..f42f34fcfe9bb --- /dev/null +++ b/x-pack/plugins/observability/public/services/navigation_registry.ts @@ -0,0 +1,51 @@ +/* + * 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 { combineLatest, Observable, ReplaySubject } from 'rxjs'; +import { map, scan, shareReplay, switchMap } from 'rxjs/operators'; + +export interface NavigationSection { + label: string | undefined; + sortKey: number; + entries: NavigationEntry[]; +} + +export interface NavigationEntry { + label: string; + app: string; + path: string; +} + +export interface NavigationRegistry { + registerSections: (sections$: Observable) => void; + sections$: Observable; +} + +export const createNavigationRegistry = (): NavigationRegistry => { + const registeredSections$ = new ReplaySubject>(); + + const registerSections = (sections$: Observable) => { + registeredSections$.next(sections$); + }; + + const sections$: Observable = registeredSections$.pipe( + scan( + (accumulatedSections$, newSections) => accumulatedSections$.add(newSections), + new Set>() + ), + switchMap((registeredSections) => combineLatest([...registeredSections])), + map((registeredSections) => + registeredSections.flat().sort((first, second) => first.sortKey - second.sortKey) + ), + shareReplay(1) + ); + + return { + registerSections, + sections$, + }; +}; diff --git a/x-pack/plugins/observability/public/utils/test_helper.tsx b/x-pack/plugins/observability/public/utils/test_helper.tsx index 2434f0eec10ed..feacb011e0701 100644 --- a/x-pack/plugins/observability/public/utils/test_helper.tsx +++ b/x-pack/plugins/observability/public/utils/test_helper.tsx @@ -10,7 +10,10 @@ import { AppMountParameters, CoreStart } from 'kibana/public'; import React from 'react'; import { IntlProvider } from 'react-intl'; import { of } from 'rxjs'; -import { KibanaContextProvider } from '../../../../../src/plugins/kibana_react/public'; +import { + KibanaContextProvider, + KibanaPageTemplate, +} from '../../../../../src/plugins/kibana_react/public'; import translations from '../../../translations/translations/ja-JP.json'; import { PluginContext } from '../context/plugin_context'; import { ObservabilityPublicPluginsStart } from '../plugin'; @@ -44,7 +47,14 @@ export const render = (component: React.ReactNode) => { {component} diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 845f4b2fb8643..f694b2b39c605 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -17657,7 +17657,6 @@ "xpack.observability.home.getStatedButton": "使ってみる", "xpack.observability.home.sectionsubtitle": "ログ、メトリック、トレースを大規模に、1つのスタックにまとめて、環境内のあらゆる場所で生じるイベントの監視、分析、対応を行います。", "xpack.observability.home.sectionTitle": "エコシステム全体の一元的な可視性", - "xpack.observability.home.title": "オブザーバビリティ", "xpack.observability.landing.breadcrumb": "はじめて使う", "xpack.observability.news.readFullStory": "詳細なストーリーを読む", "xpack.observability.news.title": "新機能", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index d223ba08185b4..36985a729ec2f 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -17894,7 +17894,6 @@ "xpack.observability.home.getStatedButton": "开始使用", "xpack.observability.home.sectionsubtitle": "通过根据需要将日志、指标和跟踪都置于单个堆栈上,来监测、分析和响应环境中任何位置发生的事件。", "xpack.observability.home.sectionTitle": "整个生态系统的统一可见性", - "xpack.observability.home.title": "可观测性", "xpack.observability.landing.breadcrumb": "入门", "xpack.observability.news.readFullStory": "详细了解", "xpack.observability.news.title": "最新动态", From 413132008bf52682d5998c6d7f11fe75ae2714e1 Mon Sep 17 00:00:00 2001 From: Shahzad Date: Thu, 27 May 2021 17:01:52 +0200 Subject: [PATCH 28/77] [Uptime] Waterfall use different styling for number (#97216) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../waterfall_chart_wrapper.test.tsx | 18 +++-- .../waterfall/waterfall_chart_wrapper.tsx | 5 +- .../waterfall/waterfall_flyout.tsx | 10 ++- ...st.tsx => waterfall_sidebar_item.test.tsx} | 23 ++++-- .../waterfall/waterfall_sidebar_item.tsx | 9 ++- .../components/middle_truncated_text.test.tsx | 34 ++++++-- .../components/middle_truncated_text.tsx | 77 ++++++++++++++++--- .../synthetics/waterfall/components/styles.ts | 4 +- 8 files changed, 141 insertions(+), 39 deletions(-) rename x-pack/plugins/uptime/public/components/monitor/synthetics/step_detail/waterfall/{waterfalll_sidebar_item.test.tsx => waterfall_sidebar_item.test.tsx} (73%) diff --git a/x-pack/plugins/uptime/public/components/monitor/synthetics/step_detail/waterfall/waterfall_chart_wrapper.test.tsx b/x-pack/plugins/uptime/public/components/monitor/synthetics/step_detail/waterfall/waterfall_chart_wrapper.test.tsx index 3a0a30980ab52..da7ccd3679f57 100644 --- a/x-pack/plugins/uptime/public/components/monitor/synthetics/step_detail/waterfall/waterfall_chart_wrapper.test.tsx +++ b/x-pack/plugins/uptime/public/components/monitor/synthetics/step_detail/waterfall/waterfall_chart_wrapper.test.tsx @@ -131,17 +131,18 @@ describe('WaterfallChartWrapper', () => { }); it('opens flyout on sidebar click and closes on flyout close button', async () => { - const { getByText, getAllByText, getByTestId, queryByText, getByRole } = render( + const { getByText, getByTestId, queryByText, getByRole } = render( ); - expect(getByText(`1. ${mockNetworkItems[0].url}`)).toBeInTheDocument(); + expect(getByText(`${mockNetworkItems[0].url}`)).toBeInTheDocument(); + expect(getByText(`1.`)).toBeInTheDocument(); expect(queryByText('Content type')).not.toBeInTheDocument(); expect(queryByText(`${mockNetworkItems[0]?.mimeType}`)).not.toBeInTheDocument(); // open flyout - // selecter matches both button and accessible text. Button is the second element in the array; - const sidebarButton = getAllByText(/1./)[1]; + // selector matches both button and accessible text. Button is the second element in the array; + const sidebarButton = getByTestId(`middleTruncatedTextButton1`); fireEvent.click(sidebarButton); // check for sample flyout items @@ -163,17 +164,18 @@ describe('WaterfallChartWrapper', () => { }); it('opens flyout on sidebar click and closes on second sidebar click', async () => { - const { getByText, getAllByText, getByTestId, queryByText } = render( + const { getByText, getByTestId, queryByText } = render( ); - expect(getByText(`1. ${mockNetworkItems[0].url}`)).toBeInTheDocument(); + expect(getByText(`${mockNetworkItems[0].url}`)).toBeInTheDocument(); + expect(getByText(`1.`)).toBeInTheDocument(); expect(queryByText('Content type')).not.toBeInTheDocument(); expect(queryByText(`${mockNetworkItems[0]?.mimeType}`)).not.toBeInTheDocument(); // open flyout - // selecter matches both button and accessible text. Button is the second element in the array; - const sidebarButton = getAllByText(/1./)[1]; + // selector matches both button and accessible text. Button is the second element in the array; + const sidebarButton = getByTestId(`middleTruncatedTextButton1`); fireEvent.click(sidebarButton); // check for sample flyout items and that the flyout is focused diff --git a/x-pack/plugins/uptime/public/components/monitor/synthetics/step_detail/waterfall/waterfall_chart_wrapper.tsx b/x-pack/plugins/uptime/public/components/monitor/synthetics/step_detail/waterfall/waterfall_chart_wrapper.tsx index e4c08236e49de..0cb44bce26848 100644 --- a/x-pack/plugins/uptime/public/components/monitor/synthetics/step_detail/waterfall/waterfall_chart_wrapper.tsx +++ b/x-pack/plugins/uptime/public/components/monitor/synthetics/step_detail/waterfall/waterfall_chart_wrapper.tsx @@ -81,6 +81,8 @@ export const WaterfallChartWrapper: React.FC = ({ data, total }) => { ); }, [flyoutData, isFlyoutVisible, onFlyoutClose]); + const highestSideBarIndex = Math.max(...series.map((sr) => sr.x)); + const renderSidebarItem: RenderItem = useCallback( (item) => { return ( @@ -88,10 +90,11 @@ export const WaterfallChartWrapper: React.FC = ({ data, total }) => { item={item} renderFilterScreenReaderText={hasFilters && !onlyHighlighted} onClick={onSidebarClick} + highestIndex={highestSideBarIndex} /> ); }, - [hasFilters, onlyHighlighted, onSidebarClick] + [hasFilters, onlyHighlighted, onSidebarClick, highestSideBarIndex] ); useTrackMetric({ app: 'uptime', metric: 'waterfall_chart_view', metricType: METRIC_TYPE.COUNT }); diff --git a/x-pack/plugins/uptime/public/components/monitor/synthetics/step_detail/waterfall/waterfall_flyout.tsx b/x-pack/plugins/uptime/public/components/monitor/synthetics/step_detail/waterfall/waterfall_flyout.tsx index 4f92c882340b9..53e6583e00cc2 100644 --- a/x-pack/plugins/uptime/public/components/monitor/synthetics/step_detail/waterfall/waterfall_flyout.tsx +++ b/x-pack/plugins/uptime/public/components/monitor/synthetics/step_detail/waterfall/waterfall_flyout.tsx @@ -77,7 +77,7 @@ export const WaterfallFlyout = ({ return null; } - const { url, details, certificates, requestHeaders, responseHeaders } = flyoutData; + const { x, url, details, certificates, requestHeaders, responseHeaders } = flyoutData; trackMetric({ metric: 'waterfall_flyout', metricType: METRIC_TYPE.CLICK }); @@ -93,7 +93,13 @@ export const WaterfallFlyout = ({

    - +

    diff --git a/x-pack/plugins/uptime/public/components/monitor/synthetics/step_detail/waterfall/waterfalll_sidebar_item.test.tsx b/x-pack/plugins/uptime/public/components/monitor/synthetics/step_detail/waterfall/waterfall_sidebar_item.test.tsx similarity index 73% rename from x-pack/plugins/uptime/public/components/monitor/synthetics/step_detail/waterfall/waterfalll_sidebar_item.test.tsx rename to x-pack/plugins/uptime/public/components/monitor/synthetics/step_detail/waterfall/waterfall_sidebar_item.test.tsx index 7f32cac92bd9f..2d08bbbadfbe4 100644 --- a/x-pack/plugins/uptime/public/components/monitor/synthetics/step_detail/waterfall/waterfalll_sidebar_item.test.tsx +++ b/x-pack/plugins/uptime/public/components/monitor/synthetics/step_detail/waterfall/waterfall_sidebar_item.test.tsx @@ -13,9 +13,10 @@ import { SidebarItem } from '../waterfall/types'; import { render } from '../../../../../lib/helper/rtl_helpers'; import { WaterfallSidebarItem } from './waterfall_sidebar_item'; import { SIDEBAR_FILTER_MATCHES_SCREENREADER_LABEL } from '../../waterfall/components/translations'; +import { getChunks } from '../../waterfall/components/middle_truncated_text'; describe('waterfall filter', () => { - const url = 'http://www.elastic.co'; + const url = 'http://www.elastic.co/observability/uptime'; const index = 0; const offsetIndex = index + 1; const item: SidebarItem = { @@ -25,26 +26,34 @@ describe('waterfall filter', () => { offsetIndex, }; - it('renders sidbar item', () => { - const { getByText } = render(); + it('renders sidebar item', () => { + const { getByText } = render(); - expect(getByText(`${offsetIndex}. ${url}`)); + const chunks = getChunks(url.replace('http://www.', '')); + + expect(getByText(`${offsetIndex}. ${chunks.first}`)); + expect(getByText(`${chunks.last}`)); }); it('render screen reader text when renderFilterScreenReaderText is true', () => { const { getByLabelText } = render( - + ); expect( - getByLabelText(`${SIDEBAR_FILTER_MATCHES_SCREENREADER_LABEL} ${offsetIndex}. ${url}`) + getByLabelText(`${SIDEBAR_FILTER_MATCHES_SCREENREADER_LABEL} ${url}`) ).toBeInTheDocument(); }); it('does not render screen reader text when renderFilterScreenReaderText is false', () => { const onClick = jest.fn(); const { getByRole } = render( - + ); const button = getByRole('button'); fireEvent.click(button); diff --git a/x-pack/plugins/uptime/public/components/monitor/synthetics/step_detail/waterfall/waterfall_sidebar_item.tsx b/x-pack/plugins/uptime/public/components/monitor/synthetics/step_detail/waterfall/waterfall_sidebar_item.tsx index be624352cd1e4..1aea9d9e69db7 100644 --- a/x-pack/plugins/uptime/public/components/monitor/synthetics/step_detail/waterfall/waterfall_sidebar_item.tsx +++ b/x-pack/plugins/uptime/public/components/monitor/synthetics/step_detail/waterfall/waterfall_sidebar_item.tsx @@ -17,10 +17,12 @@ interface SidebarItemProps { item: SidebarItem; renderFilterScreenReaderText?: boolean; onClick?: OnSidebarClick; + highestIndex: number; } export const WaterfallSidebarItem = ({ item, + highestIndex, renderFilterScreenReaderText, onClick, }: SidebarItemProps) => { @@ -42,7 +44,8 @@ export const WaterfallSidebarItem = ({ return is400 || is500 || isSpecific300; }; - const text = `${offsetIndex}. ${item.url}`; + const text = item.url; + const ariaLabel = `${ isHighlighted && renderFilterScreenReaderText ? `${SIDEBAR_FILTER_MATCHES_SCREENREADER_LABEL} ` @@ -58,11 +61,13 @@ export const WaterfallSidebarItem = ({ @@ -70,11 +75,13 @@ export const WaterfallSidebarItem = ({ diff --git a/x-pack/plugins/uptime/public/components/monitor/synthetics/waterfall/components/middle_truncated_text.test.tsx b/x-pack/plugins/uptime/public/components/monitor/synthetics/waterfall/components/middle_truncated_text.test.tsx index de352186e26fd..5006ad927f313 100644 --- a/x-pack/plugins/uptime/public/components/monitor/synthetics/waterfall/components/middle_truncated_text.test.tsx +++ b/x-pack/plugins/uptime/public/components/monitor/synthetics/waterfall/components/middle_truncated_text.test.tsx @@ -5,9 +5,10 @@ * 2.0. */ -import { getChunks, MiddleTruncatedText } from './middle_truncated_text'; -import { render, within, fireEvent, waitFor } from '@testing-library/react'; import React from 'react'; +import { within, fireEvent, waitFor } from '@testing-library/react'; +import { getChunks, MiddleTruncatedText } from './middle_truncated_text'; +import { render } from '../../../../../lib/helper/rtl_helpers'; const longString = 'this-is-a-really-really-really-really-really-really-really-really-long-string.madeup.extension'; @@ -28,7 +29,14 @@ describe('Component', () => { const url = 'http://www.elastic.co'; it('renders truncated text and aria label', () => { const { getByText, getByLabelText } = render( - + ); expect(getByText(first)).toBeInTheDocument(); @@ -39,7 +47,13 @@ describe('Component', () => { it('renders screen reader only text', () => { const { getByTestId } = render( - + ); const { getByText } = within(getByTestId('middleTruncatedTextSROnly')); @@ -49,7 +63,13 @@ describe('Component', () => { it('renders external link', () => { const { getByText } = render( - + ); const link = getByText('Open resource in new tab').closest('a'); @@ -61,13 +81,15 @@ describe('Component', () => { const handleClick = jest.fn(); const { getByTestId } = render( ); - const button = getByTestId('middleTruncatedTextButton'); + const button = getByTestId('middleTruncatedTextButton1'); fireEvent.click(button); await waitFor(() => { diff --git a/x-pack/plugins/uptime/public/components/monitor/synthetics/waterfall/components/middle_truncated_text.tsx b/x-pack/plugins/uptime/public/components/monitor/synthetics/waterfall/components/middle_truncated_text.tsx index 6a9d6660c901c..cb7159485856c 100644 --- a/x-pack/plugins/uptime/public/components/monitor/synthetics/waterfall/components/middle_truncated_text.tsx +++ b/x-pack/plugins/uptime/public/components/monitor/synthetics/waterfall/components/middle_truncated_text.tsx @@ -6,12 +6,22 @@ */ import React, { useMemo } from 'react'; -import styled from 'styled-components'; import { FormattedMessage } from '@kbn/i18n/react'; -import { EuiScreenReaderOnly, EuiToolTip, EuiButtonEmpty, EuiLink } from '@elastic/eui'; +import { + EuiScreenReaderOnly, + EuiToolTip, + EuiButtonEmpty, + EuiLink, + EuiText, + EuiIcon, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import { FIXED_AXIS_HEIGHT } from './constants'; +import { euiStyled } from '../../../../../../../../../src/plugins/kibana_react/common'; interface Props { + index: number; + highestIndex: number; ariaLabel: string; text: string; onClick?: (event: React.MouseEvent) => void; @@ -19,7 +29,7 @@ interface Props { url: string; } -const OuterContainer = styled.span` +const OuterContainer = euiStyled.span` position: relative; display: inline-flex; align-items: center; @@ -28,13 +38,21 @@ const OuterContainer = styled.span` } `; // NOTE: min-width: 0 ensures flexbox and no-wrap children can co-exist -const InnerContainer = styled.span` +const InnerContainer = euiStyled.span` overflow: hidden; display: flex; align-items: center; `; -const FirstChunk = styled.span` +const IndexNumber = euiStyled(EuiText)` + font-family: ${(props) => props.theme.eui.euiCodeFontFamily}; + margin-right: ${(props) => props.theme.eui.euiSizeXS}; + line-height: ${FIXED_AXIS_HEIGHT}px; + text-align: right; + background-color: ${(props) => props.theme.eui.euiColorLightestShade}; +`; + +const FirstChunk = euiStyled.span` text-overflow: ellipsis; white-space: nowrap; overflow: hidden; @@ -42,13 +60,13 @@ const FirstChunk = styled.span` text-align: left; `; // safari doesn't auto align text left in some cases -const LastChunk = styled.span` +const LastChunk = euiStyled.span` flex-shrink: 0; line-height: ${FIXED_AXIS_HEIGHT}px; text-align: left; `; // safari doesn't auto align text left in some cases -const StyledButton = styled(EuiButtonEmpty)` +const StyledButton = euiStyled(EuiButtonEmpty)` &&& { border: none; @@ -59,6 +77,10 @@ const StyledButton = styled(EuiButtonEmpty)` } `; +const SecureIcon = euiStyled(EuiIcon)` + margin-right: ${(props) => props.theme.eui.euiSizeXS}; +`; + export const getChunks = (text: string = '') => { const END_CHARS = 12; const chars = text.split(''); @@ -70,7 +92,18 @@ export const getChunks = (text: string = '') => { // Helper component for adding middle text truncation, e.g. // really-really-really-long....ompressed.js // Can be used to accomodate content in sidebar item rendering. -export const MiddleTruncatedText = ({ ariaLabel, text, onClick, setButtonRef, url }: Props) => { +export const MiddleTruncatedText = ({ + index, + ariaLabel, + text: fullText, + onClick, + setButtonRef, + url, + highestIndex, +}: Props) => { + const secureHttps = fullText.startsWith('https://'); + const text = fullText.replace(/https:\/\/www.|http:\/\/www.|http:\/\/|https:\/\//, ''); + const chunks = useMemo(() => { return getChunks(text); }, [text]); @@ -78,24 +111,44 @@ export const MiddleTruncatedText = ({ ariaLabel, text, onClick, setButtonRef, ur return ( - {text} + {fullText} - + <> {onClick ? ( + + {index + '.'} + + {secureHttps && ( + + )} {chunks.first} {chunks.last} ) : ( - {chunks.first} + + {index}. {chunks.first} + {chunks.last} )} diff --git a/x-pack/plugins/uptime/public/components/monitor/synthetics/waterfall/components/styles.ts b/x-pack/plugins/uptime/public/components/monitor/synthetics/waterfall/components/styles.ts index e8125ebcf30cb..9a884c6824284 100644 --- a/x-pack/plugins/uptime/public/components/monitor/synthetics/waterfall/components/styles.ts +++ b/x-pack/plugins/uptime/public/components/monitor/synthetics/waterfall/components/styles.ts @@ -90,6 +90,7 @@ export const WaterfallChartSidebarWrapper = euiStyled(EuiFlexItem)` export const WaterfallChartSidebarContainer = euiStyled.div` height: ${(props) => `${props.height}px`}; overflow-y: hidden; + overflow-x: hidden; `; export const WaterfallChartSidebarContainerInnerPanel: StyledComponent< @@ -107,8 +108,7 @@ export const WaterfallChartSidebarContainerFlexGroup = euiStyled(EuiFlexGroup)` // Ensures flex items honour no-wrap of children, rather than trying to extend to the full width of children. export const WaterfallChartSidebarFlexItem = euiStyled(EuiFlexItem)` min-width: 0; - padding-left: ${(props) => props.theme.eui.paddingSizes.m}; - padding-right: ${(props) => props.theme.eui.paddingSizes.m}; + padding-right: ${(props) => props.theme.eui.paddingSizes.s}; justify-content: space-around; `; From c298efe6103d0c1ab015c86bea5a37480401801f Mon Sep 17 00:00:00 2001 From: Thomas Neirynck Date: Thu, 27 May 2021 11:25:28 -0400 Subject: [PATCH 29/77] [Maps] Add package to codeowners (#100786) --- .github/CODEOWNERS | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index df7dc1040907c..9c9200ce33e7a 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -147,6 +147,7 @@ #CC# /x-pack/plugins/file_upload @elastic/kibana-gis /src/plugins/tile_map/ @elastic/kibana-gis /src/plugins/region_map/ @elastic/kibana-gis +/packages/kbn-mapbox-gl @elastic/kibana-gis # Operations /src/dev/ @elastic/kibana-operations From 7fd6539dcaa0aa4119abd2ee4f0462fd57de16d4 Mon Sep 17 00:00:00 2001 From: Georgii Gorbachev Date: Thu, 27 May 2021 18:28:19 +0300 Subject: [PATCH 30/77] [RAC] Rule monitoring: Event Log for Rule Registry (#98353) **Needed for:** rule execution log for Security https://github.com/elastic/kibana/pull/94143 **Related to:** - alerts-as-data: https://github.com/elastic/kibana/issues/93728, https://github.com/elastic/kibana/issues/93729, https://github.com/elastic/kibana/issues/93730 - RFC for index naming https://github.com/elastic/kibana/issues/98912 ## Summary This PR adds a mechanism for writing to / reading from / bootstrapping indices for RAC project into the `rule_registry` plugin. Particularly, indices for alerts-as-data and rule execution events. This implementation is similar to existing implementations like `event_log` plugin (see https://github.com/elastic/kibana/pull/98353#issuecomment-833045980 for historical perspective), but we're going to converge all of them into 1 or 2 implementations. At least we should have a single one in `rule_registry` itself. In this PR I tried to incorporate most of the feedback received in the RFC (https://github.com/elastic/kibana/issues/98912), but if you notice I missed/forgot something, please let me know in the comments. Done in this PR: - [x] Schema-agnostic APIs for working with Elasticsearch. - [x] Schema-aware log definition and bootstrapping API (creating hierarchical logs). - [x] Schema-aware write API (logging events). - [x] Schema-aware read API (searching logs, filtering, sorting, pagination, aggregation). - [x] Support for Kibana spaces, space-aware index bootstrapping (either at rule creation or rule execution time). As for reviewing this PR, perhaps it might be easier to start with: - checking description of https://github.com/elastic/kibana/issues/98912 - checking usage examples https://github.com/elastic/kibana/pull/98353/files#diff-c049ff2198cc69bd50a69e92d29e88da7e10b9a152bdaceaf3d41826e712c12b - checking public api https://github.com/elastic/kibana/pull/98353/files#diff-8e9ef0dbcbc60b1861d492a03865b2ae76a56ec38ada61898c991d3a74bd6268 ## Next steps Next steps towards rule execution log in Security (https://github.com/elastic/kibana/pull/94143): - define actual schema for rule execution events - inject instance of rule execution log into Security rule executors and route handlers - implement actual execution logging in rule executors - update route handlers to start fetching execution events and metrics from the log instead of custom saved objects Next steps in the context of RAC and unified implementation: - converge this implementation with `RuleDataService` implementation - implement robust index bootstrapping - reconsider using FieldMap as a generic type parameter - implement validation for documents being indexed - cover the final implementation with tests - write comprehensive docs: update plugin README, add JSDoc comments to all public interfaces --- x-pack/plugins/apm/server/plugin.ts | 19 +- x-pack/plugins/observability/server/plugin.ts | 2 +- x-pack/plugins/rule_registry/kibana.json | 2 + x-pack/plugins/rule_registry/server/config.ts | 20 +++ .../server/event_log/elasticsearch/index.ts | 14 ++ .../elasticsearch/index_bootstrapper.ts | 107 ++++++++++++ .../elasticsearch/index_management_gateway.ts | 139 +++++++++++++++ .../event_log/elasticsearch/index_reader.ts | 44 +++++ .../event_log/elasticsearch/index_writer.ts | 94 ++++++++++ .../elasticsearch/resources/ilm_policy.ts | 33 ++++ .../elasticsearch/resources/index_mappings.ts | 12 ++ .../elasticsearch/resources/index_names.ts | 84 +++++++++ .../elasticsearch/resources/index_template.ts | 51 ++++++ .../elasticsearch/utils/buffered_stream.ts | 52 ++++++ .../server/event_log/event_schema/index.ts | 9 + .../server/event_log/event_schema/schema.ts | 51 ++++++ .../event_log/event_schema/schema_types.ts | 20 +++ .../rule_registry/server/event_log/index.ts | 10 ++ .../server/event_log/log/event_log.ts | 51 ++++++ .../event_log/log/event_log_bootstrapper.ts | 51 ++++++ .../event_log/log/event_log_definition.ts | 37 ++++ .../event_log/log/event_log_provider.ts | 33 ++++ .../event_log/log/event_log_registry.ts | 56 ++++++ .../event_log/log/event_log_resolver.ts | 162 ++++++++++++++++++ .../server/event_log/log/event_log_service.ts | 67 ++++++++ .../server/event_log/log/event_logger.ts | 36 ++++ .../event_log/log/event_logger_template.ts | 55 ++++++ .../server/event_log/log/event_query.ts | 27 +++ .../event_log/log/event_query_builder.ts | 110 ++++++++++++ .../server/event_log/log/index.ts | 10 ++ .../server/event_log/log/internal_api.ts | 46 +++++ .../server/event_log/log/public_api.ts | 113 ++++++++++++ .../log/utils/mapping_from_field_map.ts | 33 ++++ .../server/event_log/utils/fields.ts | 18 ++ .../server/event_log/utils/predicates.ts | 16 ++ .../event_log/utils/ready_signal.test.ts | 22 +++ .../server/event_log/utils/ready_signal.ts | 29 ++++ .../server/event_log/utils/utility_types.ts | 12 ++ x-pack/plugins/rule_registry/server/index.ts | 14 +- x-pack/plugins/rule_registry/server/plugin.ts | 86 ++++++++-- x-pack/plugins/rule_registry/tsconfig.json | 2 + 41 files changed, 1809 insertions(+), 40 deletions(-) create mode 100644 x-pack/plugins/rule_registry/server/config.ts create mode 100644 x-pack/plugins/rule_registry/server/event_log/elasticsearch/index.ts create mode 100644 x-pack/plugins/rule_registry/server/event_log/elasticsearch/index_bootstrapper.ts create mode 100644 x-pack/plugins/rule_registry/server/event_log/elasticsearch/index_management_gateway.ts create mode 100644 x-pack/plugins/rule_registry/server/event_log/elasticsearch/index_reader.ts create mode 100644 x-pack/plugins/rule_registry/server/event_log/elasticsearch/index_writer.ts create mode 100644 x-pack/plugins/rule_registry/server/event_log/elasticsearch/resources/ilm_policy.ts create mode 100644 x-pack/plugins/rule_registry/server/event_log/elasticsearch/resources/index_mappings.ts create mode 100644 x-pack/plugins/rule_registry/server/event_log/elasticsearch/resources/index_names.ts create mode 100644 x-pack/plugins/rule_registry/server/event_log/elasticsearch/resources/index_template.ts create mode 100644 x-pack/plugins/rule_registry/server/event_log/elasticsearch/utils/buffered_stream.ts create mode 100644 x-pack/plugins/rule_registry/server/event_log/event_schema/index.ts create mode 100644 x-pack/plugins/rule_registry/server/event_log/event_schema/schema.ts create mode 100644 x-pack/plugins/rule_registry/server/event_log/event_schema/schema_types.ts create mode 100644 x-pack/plugins/rule_registry/server/event_log/index.ts create mode 100644 x-pack/plugins/rule_registry/server/event_log/log/event_log.ts create mode 100644 x-pack/plugins/rule_registry/server/event_log/log/event_log_bootstrapper.ts create mode 100644 x-pack/plugins/rule_registry/server/event_log/log/event_log_definition.ts create mode 100644 x-pack/plugins/rule_registry/server/event_log/log/event_log_provider.ts create mode 100644 x-pack/plugins/rule_registry/server/event_log/log/event_log_registry.ts create mode 100644 x-pack/plugins/rule_registry/server/event_log/log/event_log_resolver.ts create mode 100644 x-pack/plugins/rule_registry/server/event_log/log/event_log_service.ts create mode 100644 x-pack/plugins/rule_registry/server/event_log/log/event_logger.ts create mode 100644 x-pack/plugins/rule_registry/server/event_log/log/event_logger_template.ts create mode 100644 x-pack/plugins/rule_registry/server/event_log/log/event_query.ts create mode 100644 x-pack/plugins/rule_registry/server/event_log/log/event_query_builder.ts create mode 100644 x-pack/plugins/rule_registry/server/event_log/log/index.ts create mode 100644 x-pack/plugins/rule_registry/server/event_log/log/internal_api.ts create mode 100644 x-pack/plugins/rule_registry/server/event_log/log/public_api.ts create mode 100644 x-pack/plugins/rule_registry/server/event_log/log/utils/mapping_from_field_map.ts create mode 100644 x-pack/plugins/rule_registry/server/event_log/utils/fields.ts create mode 100644 x-pack/plugins/rule_registry/server/event_log/utils/predicates.ts create mode 100644 x-pack/plugins/rule_registry/server/event_log/utils/ready_signal.test.ts create mode 100644 x-pack/plugins/rule_registry/server/event_log/utils/ready_signal.ts create mode 100644 x-pack/plugins/rule_registry/server/event_log/utils/utility_types.ts diff --git a/x-pack/plugins/apm/server/plugin.ts b/x-pack/plugins/apm/server/plugin.ts index cf5be4369f79e..8d83f762e2023 100644 --- a/x-pack/plugins/apm/server/plugin.ts +++ b/x-pack/plugins/apm/server/plugin.ts @@ -130,19 +130,20 @@ export class APMPlugin registerFeaturesUsage({ licensingPlugin: plugins.licensing }); + const { ruleDataService } = plugins.ruleRegistry; const getCoreStart = () => core.getStartServices().then(([coreStart]) => coreStart); const ready = once(async () => { - const componentTemplateName = plugins.ruleRegistry.getFullAssetName( + const componentTemplateName = ruleDataService.getFullAssetName( 'apm-mappings' ); - if (!plugins.ruleRegistry.isWriteEnabled()) { + if (!ruleDataService.isWriteEnabled()) { return; } - await plugins.ruleRegistry.createOrUpdateComponentTemplate({ + await ruleDataService.createOrUpdateComponentTemplate({ name: componentTemplateName, body: { template: { @@ -167,16 +168,14 @@ export class APMPlugin }, }); - await plugins.ruleRegistry.createOrUpdateIndexTemplate({ - name: plugins.ruleRegistry.getFullAssetName('apm-index-template'), + await ruleDataService.createOrUpdateIndexTemplate({ + name: ruleDataService.getFullAssetName('apm-index-template'), body: { index_patterns: [ - plugins.ruleRegistry.getFullAssetName('observability-apm*'), + ruleDataService.getFullAssetName('observability-apm*'), ], composed_of: [ - plugins.ruleRegistry.getFullAssetName( - TECHNICAL_COMPONENT_TEMPLATE_NAME - ), + ruleDataService.getFullAssetName(TECHNICAL_COMPONENT_TEMPLATE_NAME), componentTemplateName, ], }, @@ -188,7 +187,7 @@ export class APMPlugin }); const ruleDataClient = new RuleDataClient({ - alias: plugins.ruleRegistry.getFullAssetName('observability-apm'), + alias: ruleDataService.getFullAssetName('observability-apm'), getClusterClient: async () => { const coreStart = await getCoreStart(); return coreStart.elasticsearch.client.asInternalUser; diff --git a/x-pack/plugins/observability/server/plugin.ts b/x-pack/plugins/observability/server/plugin.ts index 046a9a62d5fa7..9eff1b08cead9 100644 --- a/x-pack/plugins/observability/server/plugin.ts +++ b/x-pack/plugins/observability/server/plugin.ts @@ -57,7 +57,7 @@ export class ObservabilityPlugin implements Plugin { return coreStart.elasticsearch.client.asInternalUser; }, ready: () => Promise.resolve(), - alias: plugins.ruleRegistry.getFullAssetName(), + alias: plugins.ruleRegistry.ruleDataService.getFullAssetName(), }); registerRoutes({ diff --git a/x-pack/plugins/rule_registry/kibana.json b/x-pack/plugins/rule_registry/kibana.json index 7e3f8bf6afb72..8c1e8d0f5e40e 100644 --- a/x-pack/plugins/rule_registry/kibana.json +++ b/x-pack/plugins/rule_registry/kibana.json @@ -8,6 +8,8 @@ ], "requiredPlugins": [ "alerting", + "data", + "spaces", "triggersActionsUi" ], "server": true diff --git a/x-pack/plugins/rule_registry/server/config.ts b/x-pack/plugins/rule_registry/server/config.ts new file mode 100644 index 0000000000000..498b6d16a6fda --- /dev/null +++ b/x-pack/plugins/rule_registry/server/config.ts @@ -0,0 +1,20 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { schema, TypeOf } from '@kbn/config-schema'; + +export const config = { + schema: schema.object({ + enabled: schema.boolean({ defaultValue: true }), + write: schema.object({ + enabled: schema.boolean({ defaultValue: true }), + }), + index: schema.string({ defaultValue: '.alerts' }), + }), +}; + +export type RuleRegistryPluginConfig = TypeOf; diff --git a/x-pack/plugins/rule_registry/server/event_log/elasticsearch/index.ts b/x-pack/plugins/rule_registry/server/event_log/elasticsearch/index.ts new file mode 100644 index 0000000000000..1941208ed07cd --- /dev/null +++ b/x-pack/plugins/rule_registry/server/event_log/elasticsearch/index.ts @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export * from './index_bootstrapper'; +export * from './index_management_gateway'; +export * from './index_reader'; +export * from './index_writer'; +export * from './resources/ilm_policy'; +export * from './resources/index_mappings'; +export * from './resources/index_names'; diff --git a/x-pack/plugins/rule_registry/server/event_log/elasticsearch/index_bootstrapper.ts b/x-pack/plugins/rule_registry/server/event_log/elasticsearch/index_bootstrapper.ts new file mode 100644 index 0000000000000..b0c3927cd7dfe --- /dev/null +++ b/x-pack/plugins/rule_registry/server/event_log/elasticsearch/index_bootstrapper.ts @@ -0,0 +1,107 @@ +/* + * 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 type { PublicMethodsOf } from '@kbn/utility-types'; +import { Logger } from 'src/core/server'; + +import { IndexNames } from './resources/index_names'; +import { IndexMappings } from './resources/index_mappings'; +import { createIndexTemplate } from './resources/index_template'; +import { IlmPolicy, defaultIlmPolicy } from './resources/ilm_policy'; +import { IIndexManagementGateway } from './index_management_gateway'; + +interface ConstructorParams { + gateway: IIndexManagementGateway; + logger: Logger; +} + +export interface IndexSpecification { + indexNames: IndexNames; + indexMappings: IndexMappings; + ilmPolicy?: IlmPolicy; +} + +export type IIndexBootstrapper = PublicMethodsOf; + +// TODO: Converge with the logic of .siem-signals index bootstrapping +// x-pack/plugins/security_solution/server/lib/detection_engine/routes/index/create_index_route.ts + +// TODO: Handle race conditions and potential errors between multiple instances of Kibana +// trying to bootstrap the same index. Possible options: +// - robust idempotent logic with error handling +// - leveraging task_manager to make sure bootstrapping is run only once at a time +// - using some sort of distributed lock +// Maybe we can check how Saved Objects service bootstraps .kibana index + +export class IndexBootstrapper { + private readonly gateway: IIndexManagementGateway; + private readonly logger: Logger; + + constructor(params: ConstructorParams) { + this.gateway = params.gateway; + this.logger = params.logger.get('IndexBootstrapper'); + } + + public async run(indexSpec: IndexSpecification): Promise { + this.logger.debug('bootstrapping elasticsearch resources starting'); + + try { + const { indexNames, indexMappings, ilmPolicy } = indexSpec; + await this.createIlmPolicyIfNotExists(indexNames, ilmPolicy); + await this.createIndexTemplateIfNotExists(indexNames, indexMappings); + await this.createInitialIndexIfNotExists(indexNames); + } catch (err) { + this.logger.error(`error bootstrapping elasticsearch resources: ${err.message}`); + return false; + } + + this.logger.debug('bootstrapping elasticsearch resources complete'); + return true; + } + + private async createIlmPolicyIfNotExists(names: IndexNames, policy?: IlmPolicy): Promise { + const { indexIlmPolicyName } = names; + + const exists = await this.gateway.doesIlmPolicyExist(indexIlmPolicyName); + if (!exists) { + const ilmPolicy = policy ?? defaultIlmPolicy; + await this.gateway.createIlmPolicy(indexIlmPolicyName, ilmPolicy); + } + } + + private async createIndexTemplateIfNotExists( + names: IndexNames, + mappings: IndexMappings + ): Promise { + const { indexTemplateName } = names; + + const templateVersion = 1; // TODO: get from EventSchema definition + const template = createIndexTemplate(names, mappings, templateVersion); + + const exists = await this.gateway.doesIndexTemplateExist(indexTemplateName); + if (!exists) { + await this.gateway.createIndexTemplate(indexTemplateName, template); + } else { + await this.gateway.updateIndexTemplate(indexTemplateName, template); + } + } + + private async createInitialIndexIfNotExists(names: IndexNames): Promise { + const { indexAliasName, indexInitialName } = names; + + const exists = await this.gateway.doesAliasExist(indexAliasName); + if (!exists) { + await this.gateway.createIndex(indexInitialName, { + aliases: { + [indexAliasName]: { + is_write_index: true, + }, + }, + }); + } + } +} diff --git a/x-pack/plugins/rule_registry/server/event_log/elasticsearch/index_management_gateway.ts b/x-pack/plugins/rule_registry/server/event_log/elasticsearch/index_management_gateway.ts new file mode 100644 index 0000000000000..96b5860e143ee --- /dev/null +++ b/x-pack/plugins/rule_registry/server/event_log/elasticsearch/index_management_gateway.ts @@ -0,0 +1,139 @@ +/* + * 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 type { PublicMethodsOf } from '@kbn/utility-types'; +import { ElasticsearchClient, Logger } from 'src/core/server'; +import { IlmPolicy } from './resources/ilm_policy'; +import { IndexTemplate } from './resources/index_template'; + +interface ConstructorParams { + elasticsearch: Promise; + logger: Logger; +} + +export type IIndexManagementGateway = PublicMethodsOf; + +export class IndexManagementGateway { + private readonly elasticsearch: Promise; + private readonly logger: Logger; + + constructor(params: ConstructorParams) { + this.elasticsearch = params.elasticsearch; + this.logger = params.logger.get('IndexManagementGateway'); + } + + public async doesIlmPolicyExist(policyName: string): Promise { + this.logger.debug(`Checking if ILM policy exists; name="${policyName}"`); + + try { + const es = await this.elasticsearch; + await es.transport.request({ + method: 'GET', + path: `/_ilm/policy/${policyName}`, + }); + } catch (e) { + if (e.statusCode === 404) return false; + throw new Error(`Error checking existence of ILM policy: ${e.message}`); + } + return true; + } + + public async createIlmPolicy(policyName: string, policy: IlmPolicy): Promise { + this.logger.debug(`Creating ILM policy; name="${policyName}"`); + + try { + const es = await this.elasticsearch; + await es.transport.request({ + method: 'PUT', + path: `/_ilm/policy/${policyName}`, + body: policy, + }); + } catch (e) { + throw new Error(`Error creating ILM policy: ${e.message}`); + } + } + + public async doesIndexTemplateExist(templateName: string): Promise { + this.logger.debug(`Checking if index template exists; name="${templateName}"`); + + try { + const es = await this.elasticsearch; + const { body } = await es.indices.existsTemplate({ name: templateName }); + return body as boolean; + } catch (e) { + throw new Error(`Error checking existence of index template: ${e.message}`); + } + } + + public async createIndexTemplate(templateName: string, template: IndexTemplate): Promise { + this.logger.debug(`Creating index template; name="${templateName}"`); + + try { + const es = await this.elasticsearch; + await es.indices.putTemplate({ create: true, name: templateName, body: template }); + } catch (e) { + // The error message doesn't have a type attribute we can look to guarantee it's due + // to the template already existing (only long message) so we'll check ourselves to see + // if the template now exists. This scenario would happen if you startup multiple Kibana + // instances at the same time. + const existsNow = await this.doesIndexTemplateExist(templateName); + if (!existsNow) { + const error = new Error(`Error creating index template: ${e.message}`); + Object.assign(error, { wrapped: e }); + throw error; + } + } + } + + public async updateIndexTemplate(templateName: string, template: IndexTemplate): Promise { + this.logger.debug(`Updating index template; name="${templateName}"`); + + try { + const { settings, ...templateWithoutSettings } = template; + + const es = await this.elasticsearch; + await es.indices.putTemplate({ + create: false, + name: templateName, + body: templateWithoutSettings, + }); + } catch (e) { + throw new Error(`Error updating index template: ${e.message}`); + } + } + + public async doesAliasExist(aliasName: string): Promise { + this.logger.debug(`Checking if index alias exists; name="${aliasName}"`); + + try { + const es = await this.elasticsearch; + const { body } = await es.indices.existsAlias({ name: aliasName }); + return body as boolean; + } catch (e) { + throw new Error(`Error checking existence of initial index: ${e.message}`); + } + } + + public async createIndex(indexName: string, body: Record = {}): Promise { + this.logger.debug(`Creating index; name="${indexName}"`); + this.logger.debug(JSON.stringify(body, null, 2)); + + try { + const es = await this.elasticsearch; + await es.indices.create({ + index: indexName, + body, + }); + } catch (e) { + if (e.body?.error?.type !== 'resource_already_exists_exception') { + this.logger.error(e); + this.logger.error(JSON.stringify(e.meta, null, 2)); + throw new Error(`Error creating initial index: ${e.message}`); + } + } + } +} diff --git a/x-pack/plugins/rule_registry/server/event_log/elasticsearch/index_reader.ts b/x-pack/plugins/rule_registry/server/event_log/elasticsearch/index_reader.ts new file mode 100644 index 0000000000000..84c0b41f7e1a0 --- /dev/null +++ b/x-pack/plugins/rule_registry/server/event_log/elasticsearch/index_reader.ts @@ -0,0 +1,44 @@ +/* + * 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 type { PublicMethodsOf } from '@kbn/utility-types'; +import { estypes } from '@elastic/elasticsearch'; +import { Logger, ElasticsearchClient } from 'src/core/server'; + +interface ConstructorParams { + indexName: string; + elasticsearch: Promise; + logger: Logger; +} + +export type IIndexReader = PublicMethodsOf; + +export class IndexReader { + private readonly indexName: string; + private readonly elasticsearch: Promise; + private readonly logger: Logger; + + constructor(params: ConstructorParams) { + this.indexName = params.indexName; + this.elasticsearch = params.elasticsearch; + this.logger = params.logger.get('IndexReader'); + } + + public async search(request: estypes.SearchRequest) { + const requestToSend: estypes.SearchRequest = { + ...request, + index: this.indexName, + }; + + this.logger.debug(`Searching; request: ${JSON.stringify(requestToSend, null)}`); + + const esClient = await this.elasticsearch; + const response = await esClient.search(requestToSend); + + return response; + } +} diff --git a/x-pack/plugins/rule_registry/server/event_log/elasticsearch/index_writer.ts b/x-pack/plugins/rule_registry/server/event_log/elasticsearch/index_writer.ts new file mode 100644 index 0000000000000..7f83421ec80d8 --- /dev/null +++ b/x-pack/plugins/rule_registry/server/event_log/elasticsearch/index_writer.ts @@ -0,0 +1,94 @@ +/* + * 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 type { PublicMethodsOf } from '@kbn/utility-types'; +import util from 'util'; +import { Logger, ElasticsearchClient } from 'src/core/server'; +import { BufferedStream } from './utils/buffered_stream'; + +type Document = Record; + +interface BufferItem { + index: string; + doc: Document; +} + +interface ConstructorParams { + indexName: string; + elasticsearch: Promise; + isWriteEnabled: boolean; + logger: Logger; +} + +export type IIndexWriter = PublicMethodsOf; + +export class IndexWriter { + private readonly indexName: string; + private readonly elasticsearch: Promise; + private readonly isWriteEnabled: boolean; + private readonly logger: Logger; + private readonly buffer: BufferedStream; + + constructor(params: ConstructorParams) { + this.indexName = params.indexName; + this.elasticsearch = params.elasticsearch; + this.isWriteEnabled = params.isWriteEnabled; + this.logger = params.logger.get('IndexWriter'); + + this.buffer = new BufferedStream({ + flush: (items) => this.bulkIndex(items), + }); + } + + public indexOne(doc: Document): void { + if (this.isWriteEnabled) { + this.logger.debug('Buffering 1 document'); + this.buffer.enqueue({ index: this.indexName, doc }); + } + } + + public indexMany(docs: Document[]): void { + if (this.isWriteEnabled) { + this.logger.debug(`Buffering ${docs.length} documents`); + docs.forEach((doc) => { + this.buffer.enqueue({ index: this.indexName, doc }); + }); + } + } + + public async close(): Promise { + await this.buffer.closeAndWaitUntilFlushed(); + } + + private async bulkIndex(items: BufferItem[]): Promise { + this.logger.debug(`Indexing ${items.length} documents`); + + const bulkBody: Array> = []; + + for (const item of items) { + if (item.doc === undefined) continue; + + bulkBody.push({ create: { _index: item.index } }); + bulkBody.push(item.doc); + } + + try { + const es = await this.elasticsearch; + const response = await es.bulk({ body: bulkBody }); + + if (response.body.errors) { + const error = new Error('Error writing some bulk events'); + error.stack += '\n' + util.inspect(response.body.items, { depth: null }); + this.logger.error(error); + } + } catch (e) { + this.logger.error( + `error writing bulk events: "${e.message}"; docs: ${JSON.stringify(bulkBody)}` + ); + } + } +} diff --git a/x-pack/plugins/rule_registry/server/event_log/elasticsearch/resources/ilm_policy.ts b/x-pack/plugins/rule_registry/server/event_log/elasticsearch/resources/ilm_policy.ts new file mode 100644 index 0000000000000..00fc9131523ac --- /dev/null +++ b/x-pack/plugins/rule_registry/server/event_log/elasticsearch/resources/ilm_policy.ts @@ -0,0 +1,33 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { estypes } from '@elastic/elasticsearch'; + +export interface IlmPolicy { + policy: estypes.Policy; +} + +export const defaultIlmPolicy: IlmPolicy = { + policy: { + phases: { + hot: { + min_age: '0ms', + actions: { + rollover: { + max_age: '90d', + max_size: '50gb', + }, + }, + }, + delete: { + actions: { + delete: {}, + }, + }, + }, + }, +}; diff --git a/x-pack/plugins/rule_registry/server/event_log/elasticsearch/resources/index_mappings.ts b/x-pack/plugins/rule_registry/server/event_log/elasticsearch/resources/index_mappings.ts new file mode 100644 index 0000000000000..064bde5001f7b --- /dev/null +++ b/x-pack/plugins/rule_registry/server/event_log/elasticsearch/resources/index_mappings.ts @@ -0,0 +1,12 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export interface IndexMappings { + dynamic: 'strict' | boolean; + properties: Record; + _meta?: Record; +} diff --git a/x-pack/plugins/rule_registry/server/event_log/elasticsearch/resources/index_names.ts b/x-pack/plugins/rule_registry/server/event_log/elasticsearch/resources/index_names.ts new file mode 100644 index 0000000000000..1082c62b95e70 --- /dev/null +++ b/x-pack/plugins/rule_registry/server/event_log/elasticsearch/resources/index_names.ts @@ -0,0 +1,84 @@ +/* + * 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. + */ + +export interface IndexParams { + /** @example '.alerts' */ + indexPrefix: string; + + /** @example 'security', 'security.alerts', 'observability.events' */ + logName: string; + + /** @example 'default' */ + kibanaSpaceId: string; +} + +export interface IndexNames extends IndexParams { + /** @example '.alerts-security.alerts' */ + indexBaseName: string; + + /** @example '.alerts-security.alerts-*' */ + indexBasePattern: string; + + /** @example '.alerts-security.alerts-default' */ + indexAliasName: string; + + /** @example '.alerts-security.alerts-default-*' */ + indexAliasPattern: string; + + /** @example '.alerts-security.alerts-default-policy' */ + indexIlmPolicyName: string; + + /** @example '.alerts-security.alerts-default-template' */ + indexTemplateName: string; + + /** @example '.alerts-security.alerts-default-000001' */ + indexInitialName: string; +} + +export abstract class IndexNames { + public static create(params: IndexParams): IndexNames { + const { indexPrefix, logName, kibanaSpaceId } = params; + + // TODO: validate params + + const indexBaseName = joinWithDash(indexPrefix, logName); + const indexBasePattern = joinWithDash(indexPrefix, logName, '*'); + const indexAliasName = joinWithDash(indexPrefix, logName, kibanaSpaceId); + const indexAliasPattern = joinWithDash(indexPrefix, logName, kibanaSpaceId, '*'); + const indexIlmPolicyName = joinWithDash(indexPrefix, logName, kibanaSpaceId, 'policy'); + const indexTemplateName = joinWithDash(indexPrefix, logName, kibanaSpaceId, 'template'); + const indexInitialName = joinWithDash(indexPrefix, logName, kibanaSpaceId, '000001'); + + return { + indexPrefix, + logName, + kibanaSpaceId, + indexBaseName, + indexBasePattern, + indexAliasName, + indexAliasPattern, + indexIlmPolicyName, + indexTemplateName, + indexInitialName, + }; + } + + public static createChild(parent: IndexNames, logName: string): IndexNames { + return this.create({ + indexPrefix: parent.indexPrefix, + logName: this.createChildLogName(parent.logName, logName), + kibanaSpaceId: parent.kibanaSpaceId, + }); + } + + public static createChildLogName(parentLogName: string, logName: string): string { + return joinWithDot(parentLogName, logName); + } +} + +const joinWithDash = (...names: string[]): string => names.join('-'); +const joinWithDot = (...names: string[]): string => names.join('.'); diff --git a/x-pack/plugins/rule_registry/server/event_log/elasticsearch/resources/index_template.ts b/x-pack/plugins/rule_registry/server/event_log/elasticsearch/resources/index_template.ts new file mode 100644 index 0000000000000..caf71dadf6e1e --- /dev/null +++ b/x-pack/plugins/rule_registry/server/event_log/elasticsearch/resources/index_template.ts @@ -0,0 +1,51 @@ +/* + * 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 { estypes } from '@elastic/elasticsearch'; +import { IndexNames } from './index_names'; +import { IndexMappings } from './index_mappings'; + +export type IndexTemplate = estypes.PutIndexTemplateRequest['body']; + +export const createIndexTemplate = ( + names: IndexNames, + mappings: IndexMappings, + version: number +): IndexTemplate => { + const { indexAliasName, indexAliasPattern, indexIlmPolicyName } = names; + + return { + index_patterns: [indexAliasPattern], + settings: { + number_of_shards: 1, // TODO: do we need to set this? + auto_expand_replicas: '0-1', // TODO: do we need to set? + index: { + lifecycle: { + name: indexIlmPolicyName, + rollover_alias: indexAliasName, + }, + }, + mapping: { + total_fields: { + limit: 10000, + }, + }, + sort: { + field: '@timestamp', + order: 'desc', + }, + }, + mappings: { + ...mappings, + _meta: { + ...mappings._meta, + version, + }, + }, + version, + }; +}; diff --git a/x-pack/plugins/rule_registry/server/event_log/elasticsearch/utils/buffered_stream.ts b/x-pack/plugins/rule_registry/server/event_log/elasticsearch/utils/buffered_stream.ts new file mode 100644 index 0000000000000..d968cd5a0ac68 --- /dev/null +++ b/x-pack/plugins/rule_registry/server/event_log/elasticsearch/utils/buffered_stream.ts @@ -0,0 +1,52 @@ +/* + * 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 { Subject } from 'rxjs'; +import { bufferTime, filter as rxFilter, switchMap } from 'rxjs/operators'; + +export const DEFAULT_BUFFER_TIME_MS = 1000; +export const DEFAULT_BUFFER_SIZE = 100; + +interface ConstructorParams { + maxBufferTimeMs?: number; + maxBufferSize?: number; + flush: (items: TItem[]) => Promise; +} + +// TODO: handle possible exceptions in flush and maybe add retry logic + +export class BufferedStream { + private readonly buffer$: Subject; + private readonly whenBufferCompleteAndFlushed: Promise; + + constructor(params: ConstructorParams) { + const maxBufferTime = params.maxBufferTimeMs ?? DEFAULT_BUFFER_TIME_MS; + const maxBufferSize = params.maxBufferSize ?? DEFAULT_BUFFER_SIZE; + + this.buffer$ = new Subject(); + + // Buffer items for time/buffer length, ignore empty buffers, + // then flush the buffered items; kick things off with a promise + // on the observable, which we'll wait on in shutdown + this.whenBufferCompleteAndFlushed = this.buffer$ + .pipe( + bufferTime(maxBufferTime, null, maxBufferSize), + rxFilter((docs) => docs.length > 0), + switchMap(async (docs) => await params.flush(docs)) + ) + .toPromise(); + } + + public enqueue(item: TItem): void { + this.buffer$.next(item); + } + + public async closeAndWaitUntilFlushed(): Promise { + this.buffer$.complete(); + await this.whenBufferCompleteAndFlushed; + } +} diff --git a/x-pack/plugins/rule_registry/server/event_log/event_schema/index.ts b/x-pack/plugins/rule_registry/server/event_log/event_schema/index.ts new file mode 100644 index 0000000000000..77c041a4059b5 --- /dev/null +++ b/x-pack/plugins/rule_registry/server/event_log/event_schema/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export * from './schema_types'; +export * from './schema'; diff --git a/x-pack/plugins/rule_registry/server/event_log/event_schema/schema.ts b/x-pack/plugins/rule_registry/server/event_log/event_schema/schema.ts new file mode 100644 index 0000000000000..9b5d94918a83f --- /dev/null +++ b/x-pack/plugins/rule_registry/server/event_log/event_schema/schema.ts @@ -0,0 +1,51 @@ +/* + * 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 { EventSchema, Event } from './schema_types'; +import { FieldMap, runtimeTypeFromFieldMap, mergeFieldMaps } from '../../../common/field_map'; +import { + TechnicalRuleFieldMaps, + technicalRuleFieldMap, +} from '../../../common/assets/field_maps/technical_rule_field_map'; + +const baseSchema = createSchema(technicalRuleFieldMap); + +export abstract class Schema { + public static create(fields: TMap): EventSchema { + return createSchema(fields); + } + + public static combine( + s1: EventSchema, + s2: EventSchema + ): EventSchema { + const combinedFields = mergeFieldMaps(s1.objectFields, s2.objectFields); + return createSchema(combinedFields); + } + + public static getBase(): EventSchema { + return baseSchema; + } + + public static extendBase( + fields: TMap + ): EventSchema { + const extensionSchema = createSchema(fields); + return this.combine(baseSchema, extensionSchema); + } +} + +function createSchema(fields: TMap): EventSchema { + const objectType: Event = ({} as unknown) as Event; + const runtimeType = runtimeTypeFromFieldMap(fields); + + return { + objectFields: fields, + objectType, + runtimeType, + }; +} diff --git a/x-pack/plugins/rule_registry/server/event_log/event_schema/schema_types.ts b/x-pack/plugins/rule_registry/server/event_log/event_schema/schema_types.ts new file mode 100644 index 0000000000000..e5c665652fe97 --- /dev/null +++ b/x-pack/plugins/rule_registry/server/event_log/event_schema/schema_types.ts @@ -0,0 +1,20 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FieldMap, FieldMapType, TypeOfFieldMap } from '../../../common/field_map'; + +export interface EventSchema { + objectFields: TMap; + objectType: Event; + runtimeType: EventRuntimeType; +} + +export type Event = TypeOfFieldMap; + +export type EventRuntimeType = FieldMapType; + +export { FieldMap }; diff --git a/x-pack/plugins/rule_registry/server/event_log/index.ts b/x-pack/plugins/rule_registry/server/event_log/index.ts new file mode 100644 index 0000000000000..cf7467588c22f --- /dev/null +++ b/x-pack/plugins/rule_registry/server/event_log/index.ts @@ -0,0 +1,10 @@ +/* + * 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. + */ + +export * from './elasticsearch'; +export * from './event_schema'; +export * from './log'; diff --git a/x-pack/plugins/rule_registry/server/event_log/log/event_log.ts b/x-pack/plugins/rule_registry/server/event_log/log/event_log.ts new file mode 100644 index 0000000000000..2b1ecde48d2db --- /dev/null +++ b/x-pack/plugins/rule_registry/server/event_log/log/event_log.ts @@ -0,0 +1,51 @@ +/* + * 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 { estypes } from '@elastic/elasticsearch'; +import { DeepPartial } from '../utils/utility_types'; +import { IndexNames } from '../elasticsearch'; +import { IEventLog, IEventLogger, IEventLoggerTemplate, IEventQueryBuilder } from './public_api'; +import { EventLogParams } from './internal_api'; +import { EventLoggerTemplate } from './event_logger_template'; +import { EventQueryBuilder } from './event_query_builder'; + +export class EventLog implements IEventLog { + private readonly params: EventLogParams; + private readonly initialTemplate: IEventLoggerTemplate; + + constructor(params: EventLogParams) { + this.params = params; + this.initialTemplate = new EventLoggerTemplate({ + ...params, + eventLoggerName: '', + eventFields: {}, + }); + } + + public getNames(): IndexNames { + return this.params.indexNames; + } + + public getLoggerTemplate(fields: DeepPartial): IEventLoggerTemplate { + return this.initialTemplate.getLoggerTemplate(fields); + } + + public getLogger(loggerName: string, fields?: DeepPartial): IEventLogger { + return this.initialTemplate.getLogger(loggerName, fields); + } + + public getQueryBuilder(): IEventQueryBuilder { + return new EventQueryBuilder(this.params); + } + + public async search( + request: estypes.SearchRequest + ): Promise> { + const response = await this.params.indexReader.search(request); + return response.body; + } +} diff --git a/x-pack/plugins/rule_registry/server/event_log/log/event_log_bootstrapper.ts b/x-pack/plugins/rule_registry/server/event_log/log/event_log_bootstrapper.ts new file mode 100644 index 0000000000000..0498a7cd97b2f --- /dev/null +++ b/x-pack/plugins/rule_registry/server/event_log/log/event_log_bootstrapper.ts @@ -0,0 +1,51 @@ +/* + * 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 { Logger } from 'kibana/server'; +import { IIndexBootstrapper, IndexSpecification } from '../elasticsearch'; + +interface ConstructorParams { + indexSpec: IndexSpecification; + indexBootstrapper: IIndexBootstrapper; + isWriteEnabled: boolean; + logger: Logger; +} + +export class EventLogBootstrapper { + private readonly indexSpec: IndexSpecification; + private readonly indexBootstrapper: IIndexBootstrapper; + private readonly logger: Logger; + private readonly isWriteEnabled: boolean; + private isIndexBootstrapped: boolean; + + constructor(params: ConstructorParams) { + this.indexSpec = params.indexSpec; + this.indexBootstrapper = params.indexBootstrapper; + this.logger = params.logger.get('EventLogBootstrapper'); + this.isWriteEnabled = params.isWriteEnabled; + this.isIndexBootstrapped = false; + } + + public async run(): Promise { + if (this.isIndexBootstrapped || !this.isWriteEnabled) { + return; + } + + const { logName, indexAliasName } = this.indexSpec.indexNames; + const logInfo = `log="${logName}" index="${indexAliasName}"`; + + this.logger.debug(`Bootstrapping started, ${logInfo}`); + this.isIndexBootstrapped = await this.indexBootstrapper.run(this.indexSpec); + this.logger.debug( + `Bootstrapping ${this.isIndexBootstrapped ? 'succeeded' : 'failed'}, ${logInfo}` + ); + + if (!this.isIndexBootstrapped) { + throw new Error(`Event log bootstrapping failed, ${logInfo}`); + } + } +} diff --git a/x-pack/plugins/rule_registry/server/event_log/log/event_log_definition.ts b/x-pack/plugins/rule_registry/server/event_log/log/event_log_definition.ts new file mode 100644 index 0000000000000..124664d5578b0 --- /dev/null +++ b/x-pack/plugins/rule_registry/server/event_log/log/event_log_definition.ts @@ -0,0 +1,37 @@ +/* + * 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 { IlmPolicy, defaultIlmPolicy, IndexNames } from '../elasticsearch'; +import { EventSchema, FieldMap, Schema } from '../event_schema'; +import { EventLogOptions, IEventLogDefinition } from './public_api'; + +export class EventLogDefinition implements IEventLogDefinition { + public readonly eventLogName: string; + public readonly eventSchema: EventSchema; + public readonly ilmPolicy: IlmPolicy; + + constructor(options: EventLogOptions) { + // TODO: validate options; options.name should not contain "-" and "." + this.eventLogName = options.name; + this.eventSchema = options.schema; + this.ilmPolicy = options.ilmPolicy ?? defaultIlmPolicy; + } + + public defineChild( + options: EventLogOptions + ): IEventLogDefinition { + const childName = IndexNames.createChildLogName(this.eventLogName, options.name); + const childSchema = Schema.combine(this.eventSchema, options.schema); + const childPolicy = options.ilmPolicy ?? this.ilmPolicy; + + return new EventLogDefinition({ + name: childName, + schema: childSchema, + ilmPolicy: childPolicy, + }); + } +} diff --git a/x-pack/plugins/rule_registry/server/event_log/log/event_log_provider.ts b/x-pack/plugins/rule_registry/server/event_log/log/event_log_provider.ts new file mode 100644 index 0000000000000..d1ecd6a977a08 --- /dev/null +++ b/x-pack/plugins/rule_registry/server/event_log/log/event_log_provider.ts @@ -0,0 +1,33 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { IIndexWriter } from '../elasticsearch'; +import { IEventLog } from './public_api'; +import { IEventLogProvider } from './internal_api'; +import { EventLogBootstrapper } from './event_log_bootstrapper'; + +interface ConstructorParams { + log: IEventLog; + logBootstrapper: EventLogBootstrapper; + indexWriter: IIndexWriter; +} + +export class EventLogProvider implements IEventLogProvider { + constructor(private readonly params: ConstructorParams) {} + + public getLog(): IEventLog { + return this.params.log; + } + + public async bootstrapLog(): Promise { + await this.params.logBootstrapper.run(); + } + + public async shutdownLog(): Promise { + await this.params.indexWriter.close(); + } +} diff --git a/x-pack/plugins/rule_registry/server/event_log/log/event_log_registry.ts b/x-pack/plugins/rule_registry/server/event_log/log/event_log_registry.ts new file mode 100644 index 0000000000000..52f6c6bd918d4 --- /dev/null +++ b/x-pack/plugins/rule_registry/server/event_log/log/event_log_registry.ts @@ -0,0 +1,56 @@ +/* + * 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 { Event, FieldMap } from '../event_schema'; +import { IEventLogDefinition } from './public_api'; +import { IEventLogRegistry, IEventLogProvider } from './internal_api'; + +const getRegistryKey = (definition: IEventLogDefinition, spaceId: string) => + `${definition.eventLogName}-${spaceId}`; + +interface RegistryEntry { + definition: IEventLogDefinition; + spaceId: string; + provider: IEventLogProvider; +} + +export class EventLogRegistry implements IEventLogRegistry { + private readonly map = new Map(); + + public get( + definition: IEventLogDefinition, + spaceId: string + ): IEventLogProvider> | null { + const key = getRegistryKey(definition, spaceId); + const entry = this.map.get(key); + return entry != null ? (entry.provider as IEventLogProvider>) : null; + } + + public add( + definition: IEventLogDefinition, + spaceId: string, + provider: IEventLogProvider> + ): void { + const key = getRegistryKey(definition, spaceId); + + if (this.map.has(key)) { + throw new Error(`Event log already registered, key="${key}"`); + } + + this.map.set(key, { + definition, + spaceId, + provider, + }); + } + + public async shutdown(): Promise { + const entries = Array.from(this.map.values()); + const promises = entries.map(({ provider }) => provider.shutdownLog()); + await Promise.all(promises); + } +} diff --git a/x-pack/plugins/rule_registry/server/event_log/log/event_log_resolver.ts b/x-pack/plugins/rule_registry/server/event_log/log/event_log_resolver.ts new file mode 100644 index 0000000000000..8440f55432304 --- /dev/null +++ b/x-pack/plugins/rule_registry/server/event_log/log/event_log_resolver.ts @@ -0,0 +1,162 @@ +/* + * 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 { + IndexBootstrapper, + IndexManagementGateway, + IndexNames, + IndexReader, + IndexSpecification, + IndexWriter, +} from '../elasticsearch'; + +import { Event, FieldMap } from '../event_schema'; +import { IEventLogRegistry, IEventLogProvider } from './internal_api'; +import { + EventLogServiceConfig, + EventLogServiceDependencies, + IEventLog, + IEventLogDefinition, + IEventLogResolver, +} from './public_api'; + +import { EventLog } from './event_log'; +import { EventLogBootstrapper } from './event_log_bootstrapper'; +import { EventLogProvider } from './event_log_provider'; +import { mappingFromFieldMap } from './utils/mapping_from_field_map'; + +export class EventLogResolver implements IEventLogResolver { + private readonly indexBootstrapper: IndexBootstrapper; + + constructor( + private readonly config: EventLogServiceConfig, + private readonly deps: EventLogServiceDependencies, + private readonly registry: IEventLogRegistry, + private readonly bootstrapLog: boolean + ) { + this.indexBootstrapper = this.createIndexBootstrapper(); + } + + public async resolve( + definition: IEventLogDefinition, + kibanaSpaceId: string + ): Promise>> { + const provider = this.resolveLogProvider(definition, kibanaSpaceId); + + if (this.bootstrapLog) { + await provider.bootstrapLog(); + } + + return provider.getLog(); + } + + private resolveLogProvider( + definition: IEventLogDefinition, + kibanaSpaceId: string + ): IEventLogProvider> { + const existingProvider = this.registry.get(definition, kibanaSpaceId); + if (existingProvider) { + return existingProvider; + } + + const indexSpec = this.createIndexSpec(definition, kibanaSpaceId); + const indexReader = this.createIndexReader(indexSpec); + const indexWriter = this.createIndexWriter(indexSpec); + const logBootstrapper = this.createEventLogBootstrapper(indexSpec); + const log = this.createEventLog(indexSpec, indexReader, indexWriter); + const logProvider = new EventLogProvider({ + log, + logBootstrapper, + indexWriter, + }); + + this.registry.add(definition, kibanaSpaceId, logProvider); + + return logProvider; + } + + private createIndexSpec( + definition: IEventLogDefinition, + kibanaSpaceId: string + ): IndexSpecification { + const { indexPrefix } = this.config; + const { eventLogName, eventSchema, ilmPolicy } = definition; + + const indexNames = IndexNames.create({ + indexPrefix, + logName: eventLogName, + kibanaSpaceId, + }); + + const indexMappings = mappingFromFieldMap(eventSchema.objectFields); + + return { indexNames, indexMappings, ilmPolicy }; + } + + private createIndexBootstrapper(): IndexBootstrapper { + const { clusterClient, logger } = this.deps; + + return new IndexBootstrapper({ + gateway: new IndexManagementGateway({ + elasticsearch: clusterClient.then((c) => c.asInternalUser), + logger, + }), + logger, + }); + } + + private createIndexReader(indexSpec: IndexSpecification): IndexReader { + const { clusterClient, logger } = this.deps; + const { indexNames } = indexSpec; + + return new IndexReader({ + indexName: indexNames.indexAliasPattern, + elasticsearch: clusterClient.then((c) => c.asInternalUser), // TODO: internal or current? + logger, + }); + } + + private createIndexWriter(indexSpec: IndexSpecification): IndexWriter { + const { clusterClient, logger } = this.deps; + const { isWriteEnabled } = this.config; + const { indexNames } = indexSpec; + + return new IndexWriter({ + indexName: indexNames.indexAliasName, + elasticsearch: clusterClient.then((c) => c.asInternalUser), // TODO: internal or current? + isWriteEnabled, + logger, + }); + } + + private createEventLogBootstrapper(indexSpec: IndexSpecification): EventLogBootstrapper { + const { logger } = this.deps; + const { isWriteEnabled } = this.config; + + return new EventLogBootstrapper({ + indexSpec, + indexBootstrapper: this.indexBootstrapper, + isWriteEnabled, + logger, + }); + } + + private createEventLog( + indexSpec: IndexSpecification, + indexReader: IndexReader, + indexWriter: IndexWriter + ): IEventLog> { + const { logger } = this.deps; + + return new EventLog>({ + indexNames: indexSpec.indexNames, + indexReader, + indexWriter, + logger, + }); + } +} diff --git a/x-pack/plugins/rule_registry/server/event_log/log/event_log_service.ts b/x-pack/plugins/rule_registry/server/event_log/log/event_log_service.ts new file mode 100644 index 0000000000000..b5b1d23f2e215 --- /dev/null +++ b/x-pack/plugins/rule_registry/server/event_log/log/event_log_service.ts @@ -0,0 +1,67 @@ +/* + * 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 { KibanaRequest } from 'kibana/server'; + +import { Event, FieldMap } from '../event_schema'; +import { + EventLogServiceConfig, + EventLogServiceDependencies, + IEventLog, + IEventLogDefinition, + IEventLogResolver, + IEventLogService, + IScopedEventLogResolver, +} from './public_api'; + +import { EventLogRegistry } from './event_log_registry'; +import { EventLogResolver } from './event_log_resolver'; + +const BOOTSTRAP_BY_DEFAULT = true; + +interface ConstructorParams { + config: EventLogServiceConfig; + dependencies: EventLogServiceDependencies; +} + +export class EventLogService implements IEventLogService { + private readonly registry: EventLogRegistry; + + constructor(private readonly params: ConstructorParams) { + this.registry = new EventLogRegistry(); + } + + public getResolver(bootstrapLog = BOOTSTRAP_BY_DEFAULT): IEventLogResolver { + const { params, registry } = this; + const { config, dependencies } = params; + + return new EventLogResolver(config, dependencies, registry, bootstrapLog); + } + + public getScopedResolver( + request: KibanaRequest, + bootstrapLog = BOOTSTRAP_BY_DEFAULT + ): IScopedEventLogResolver { + const resolver = this.getResolver(bootstrapLog); + + return { + resolve: async ( + definition: IEventLogDefinition + ): Promise>> => { + const spaces = await this.params.dependencies.spacesService; + const spaceId = spaces.getSpaceId(request); + + const log = await resolver.resolve(definition, spaceId); + return log; + }, + }; + } + + public async stop(): Promise { + await this.registry.shutdown(); + } +} diff --git a/x-pack/plugins/rule_registry/server/event_log/log/event_logger.ts b/x-pack/plugins/rule_registry/server/event_log/log/event_logger.ts new file mode 100644 index 0000000000000..c6f88f49835d7 --- /dev/null +++ b/x-pack/plugins/rule_registry/server/event_log/log/event_logger.ts @@ -0,0 +1,36 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { DeepPartial } from '../utils/utility_types'; +import { mergeFields } from '../utils/fields'; +import { EventLoggerParams } from './internal_api'; +import { IEventLogger, IEventLoggerTemplate } from './public_api'; + +export class EventLogger implements IEventLogger { + private readonly params: EventLoggerParams; + private readonly ownTemplate: IEventLoggerTemplate; + + constructor(params: EventLoggerParams, template: IEventLoggerTemplate) { + this.params = params; + this.ownTemplate = template; + } + + public getLoggerTemplate(fields: DeepPartial): IEventLoggerTemplate { + return this.ownTemplate.getLoggerTemplate(fields); + } + + public getLogger(name: string, fields?: DeepPartial): IEventLogger { + return this.ownTemplate.getLogger(name, fields); + } + + public logEvent(fields: DeepPartial): void { + const { eventFields, indexWriter } = this.params; + + const event = mergeFields(eventFields, fields); + indexWriter.indexOne(event); + } +} diff --git a/x-pack/plugins/rule_registry/server/event_log/log/event_logger_template.ts b/x-pack/plugins/rule_registry/server/event_log/log/event_logger_template.ts new file mode 100644 index 0000000000000..3872a5c744269 --- /dev/null +++ b/x-pack/plugins/rule_registry/server/event_log/log/event_logger_template.ts @@ -0,0 +1,55 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { DeepPartial } from '../utils/utility_types'; +import { mergeFields } from '../utils/fields'; +import { IEventLogger, IEventLoggerTemplate } from './public_api'; +import { EventLoggerParams } from './internal_api'; +import { EventLogger } from './event_logger'; + +export class EventLoggerTemplate implements IEventLoggerTemplate { + private readonly params: EventLoggerParams; + + constructor(params: EventLoggerParams) { + this.params = params; + } + + public getLoggerTemplate(fields: DeepPartial): IEventLoggerTemplate { + const nextParams = this.getNextParams('', fields); + return new EventLoggerTemplate(nextParams); + } + + public getLogger(name: string, fields?: DeepPartial): IEventLogger { + const nextParams = this.getNextParams(name, fields); + const nextTemplate = new EventLoggerTemplate(nextParams); + return new EventLogger(nextParams, nextTemplate); + } + + private getNextParams( + extName: string, + extFields?: DeepPartial + ): EventLoggerParams { + const { indexNames, eventLoggerName, eventFields } = this.params; + + const baseName = eventLoggerName; + const nextName = [baseName, extName].filter(Boolean).join('.'); + + const baseFields = eventFields; + const nextFields = mergeFields(baseFields, extFields, { + // TODO: Define a schema for own fields used/set by event log. Add it to the base schema. + // Then maybe introduce a base type for TEvent. + 'kibana.rac.event_log.log_name': indexNames.logName, + 'kibana.rac.event_log.logger_name': nextName, + } as any); + + return { + ...this.params, + eventLoggerName: nextName, + eventFields: nextFields, + }; + } +} diff --git a/x-pack/plugins/rule_registry/server/event_log/log/event_query.ts b/x-pack/plugins/rule_registry/server/event_log/log/event_query.ts new file mode 100644 index 0000000000000..0eabe4be64837 --- /dev/null +++ b/x-pack/plugins/rule_registry/server/event_log/log/event_query.ts @@ -0,0 +1,27 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { estypes } from '@elastic/elasticsearch'; +import { IIndexReader } from '../elasticsearch'; +import { truthy } from '../utils/predicates'; +import { IEventQuery } from './public_api'; + +export interface EventQueryParams { + indexReader: IIndexReader; + request: estypes.SearchRequest; +} + +export class EventQuery implements IEventQuery { + constructor(private readonly params: EventQueryParams) {} + + public async execute(): Promise { + const { indexReader, request } = this.params; + + const response = await indexReader.search(request); + return response.body.hits.hits.map((hit) => hit._source).filter(truthy); + } +} diff --git a/x-pack/plugins/rule_registry/server/event_log/log/event_query_builder.ts b/x-pack/plugins/rule_registry/server/event_log/log/event_query_builder.ts new file mode 100644 index 0000000000000..48228ce5352b7 --- /dev/null +++ b/x-pack/plugins/rule_registry/server/event_log/log/event_query_builder.ts @@ -0,0 +1,110 @@ +/* + * 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 { getFlattenedObject } from '@kbn/std'; +import { estypes } from '@elastic/elasticsearch'; +import { esKuery } from '../../../../../../src/plugins/data/server'; + +import { DeepPartial } from '../utils/utility_types'; +import { mergeFields } from '../utils/fields'; +import { EventLogParams } from './internal_api'; +import { IEventQueryBuilder, IEventQuery, SortingParams, PaginationParams } from './public_api'; +import { EventQuery } from './event_query'; + +export class EventQueryBuilder implements IEventQueryBuilder { + private readonly params: EventLogParams; + private loggerName: string; + private fields: DeepPartial | null; + private kql: string; + private sorting: SortingParams; + private pagination: PaginationParams; + + constructor(params: EventLogParams) { + this.params = params; + this.loggerName = ''; + this.fields = null; + this.kql = ''; + this.sorting = [{ '@timestamp': { order: 'desc' } }, { 'event.sequence': { order: 'desc' } }]; + this.pagination = { page: 1, perPage: 20 }; + } + + public filterByLogger(loggerName: string): IEventQueryBuilder { + this.loggerName = loggerName; + return this; + } + + public filterByFields(fields: DeepPartial): IEventQueryBuilder { + this.fields = mergeFields(this.fields ?? {}, fields); + return this; + } + + public filterByKql(kql: string): IEventQueryBuilder { + this.kql = kql; + return this; + } + + public sortBy(params: SortingParams): IEventQueryBuilder { + this.sorting = params; + return this; + } + + public paginate(params: PaginationParams): IEventQueryBuilder { + this.pagination = params; + return this; + } + + public buildQuery(): IEventQuery { + const { indexReader } = this.params; + const { page, perPage } = this.pagination; + + const request: estypes.SearchRequest = { + track_total_hits: true, + body: { + from: (page - 1) * perPage, + size: perPage, + sort: this.sorting, + query: { + bool: { + filter: this.buildFilter(), + }, + }, + }, + }; + + return new EventQuery({ indexReader, request }); + } + + private buildFilter(): estypes.QueryContainer[] { + const result: estypes.QueryContainer[] = []; + + if (this.loggerName) { + result.push({ + term: { 'kibana.rac.event_log.logger_name': this.loggerName }, + }); + } + + if (this.fields) { + const flatFields = getFlattenedObject(this.fields); + Object.entries(flatFields) + .map(([key, value]) => { + const queryName = Array.isArray(value) ? 'terms' : 'term'; + return { [queryName]: { [key]: value } }; + }) + .forEach((query) => { + result.push(query); + }); + } + + if (this.kql) { + const dsl = esKuery.toElasticsearchQuery(esKuery.fromKueryExpression(this.kql)); + const queries = Array.isArray(dsl) ? dsl : [dsl]; + result.push(...queries); + } + + return result; + } +} diff --git a/x-pack/plugins/rule_registry/server/event_log/log/index.ts b/x-pack/plugins/rule_registry/server/event_log/log/index.ts new file mode 100644 index 0000000000000..e5593390733e4 --- /dev/null +++ b/x-pack/plugins/rule_registry/server/event_log/log/index.ts @@ -0,0 +1,10 @@ +/* + * 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. + */ + +export * from './event_log_definition'; +export * from './event_log_service'; +export * from './public_api'; diff --git a/x-pack/plugins/rule_registry/server/event_log/log/internal_api.ts b/x-pack/plugins/rule_registry/server/event_log/log/internal_api.ts new file mode 100644 index 0000000000000..8db931b35912d --- /dev/null +++ b/x-pack/plugins/rule_registry/server/event_log/log/internal_api.ts @@ -0,0 +1,46 @@ +/* + * 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 { Logger } from 'kibana/server'; + +import { IIndexReader, IIndexWriter, IndexNames } from '../elasticsearch'; +import { Event, FieldMap } from '../event_schema'; +import { DeepPartial } from '../utils/utility_types'; +import { IEventLogDefinition, IEventLog } from './public_api'; + +export interface IEventLogRegistry { + get( + definition: IEventLogDefinition, + spaceId: string + ): IEventLogProvider> | null; + + add( + definition: IEventLogDefinition, + spaceId: string, + provider: IEventLogProvider> + ): void; + + shutdown(): Promise; +} + +export interface IEventLogProvider { + getLog(): IEventLog; + bootstrapLog(): Promise; + shutdownLog(): Promise; +} + +export interface EventLogParams { + indexNames: IndexNames; + indexReader: IIndexReader; + indexWriter: IIndexWriter; + logger: Logger; +} + +export interface EventLoggerParams extends EventLogParams { + eventLoggerName: string; + eventFields: DeepPartial; +} diff --git a/x-pack/plugins/rule_registry/server/event_log/log/public_api.ts b/x-pack/plugins/rule_registry/server/event_log/log/public_api.ts new file mode 100644 index 0000000000000..7807dd9ca6b36 --- /dev/null +++ b/x-pack/plugins/rule_registry/server/event_log/log/public_api.ts @@ -0,0 +1,113 @@ +/* + * 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 { estypes } from '@elastic/elasticsearch'; +import { IClusterClient, KibanaRequest, Logger } from 'kibana/server'; +import { SpacesServiceStart } from '../../../../spaces/server'; + +import { IlmPolicy, IndexNames, IndexSpecification } from '../elasticsearch'; +import { FieldMap, Event, EventSchema } from '../event_schema'; +import { DeepPartial } from '../utils/utility_types'; + +export { IlmPolicy, IndexSpecification }; + +// ------------------------------------------------------------------------------------------------- +// Definition API (defining log hierarchies as simple objects) + +export interface EventLogOptions { + name: string; + schema: EventSchema; + ilmPolicy?: IlmPolicy; +} + +export interface IEventLogDefinition { + eventLogName: string; + eventSchema: EventSchema; + ilmPolicy: IlmPolicy; + + defineChild( + options: EventLogOptions + ): IEventLogDefinition; +} + +// ------------------------------------------------------------------------------------------------- +// Resolving and bootstrapping API (creating runtime objects representing logs, bootstrapping indices) + +export interface EventLogServiceConfig { + indexPrefix: string; + isWriteEnabled: boolean; +} + +export interface EventLogServiceDependencies { + clusterClient: Promise; + spacesService: Promise; + logger: Logger; +} + +export interface IEventLogService { + getResolver(bootstrapLog?: boolean): IEventLogResolver; + getScopedResolver(request: KibanaRequest, bootstrapLog?: boolean): IScopedEventLogResolver; +} + +export interface IEventLogResolver { + resolve( + definition: IEventLogDefinition, + spaceId: string + ): Promise>>; +} + +export interface IScopedEventLogResolver { + resolve( + definition: IEventLogDefinition + ): Promise>>; +} + +export interface IEventLog extends IEventLoggerTemplate { + getNames(): IndexNames; + + getQueryBuilder(): IEventQueryBuilder; + + search( + request: estypes.SearchRequest + ): Promise>; +} + +// ------------------------------------------------------------------------------------------------- +// Write API (logging events) + +export interface IEventLoggerTemplate { + getLoggerTemplate(fields: DeepPartial): IEventLoggerTemplate; + getLogger(name: string, fields?: DeepPartial): IEventLogger; +} + +export interface IEventLogger extends IEventLoggerTemplate { + logEvent(fields: DeepPartial): void; +} + +// ------------------------------------------------------------------------------------------------- +// Read API (searching, filtering, sorting, pagination, aggregation over events) + +export interface IEventQueryBuilder { + filterByLogger(loggerName: string): IEventQueryBuilder; + filterByFields(fields: DeepPartial): IEventQueryBuilder; + filterByKql(kql: string): IEventQueryBuilder; + sortBy(params: SortingParams): IEventQueryBuilder; + paginate(params: PaginationParams): IEventQueryBuilder; + + buildQuery(): IEventQuery; +} + +export type SortingParams = estypes.Sort; + +export interface PaginationParams { + page: number; + perPage: number; +} + +export interface IEventQuery { + execute(): Promise; +} diff --git a/x-pack/plugins/rule_registry/server/event_log/log/utils/mapping_from_field_map.ts b/x-pack/plugins/rule_registry/server/event_log/log/utils/mapping_from_field_map.ts new file mode 100644 index 0000000000000..fd5dc3ae02288 --- /dev/null +++ b/x-pack/plugins/rule_registry/server/event_log/log/utils/mapping_from_field_map.ts @@ -0,0 +1,33 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { set } from '@elastic/safer-lodash-set'; +import { FieldMap } from '../../../../common/field_map'; +import { IndexMappings } from '../../elasticsearch'; + +export function mappingFromFieldMap(fieldMap: FieldMap): IndexMappings { + const mappings = { + dynamic: 'strict' as const, + properties: {}, + }; + + const fields = Object.keys(fieldMap).map((key) => { + const field = fieldMap[key]; + return { + name: key, + ...field, + }; + }); + + fields.forEach((field) => { + const { name, required, array, ...rest } = field; + + set(mappings.properties, field.name.split('.').join('.properties.'), rest); + }); + + return mappings; +} diff --git a/x-pack/plugins/rule_registry/server/event_log/utils/fields.ts b/x-pack/plugins/rule_registry/server/event_log/utils/fields.ts new file mode 100644 index 0000000000000..4f140cfb3434f --- /dev/null +++ b/x-pack/plugins/rule_registry/server/event_log/utils/fields.ts @@ -0,0 +1,18 @@ +/* + * 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 { merge } from 'lodash'; +import { DeepPartial } from './utility_types'; + +export const mergeFields = ( + base: DeepPartial, + ext1?: DeepPartial, + ext2?: DeepPartial, + ext3?: DeepPartial +): DeepPartial => { + return merge({}, base, ext1 ?? {}, ext2 ?? {}, ext3 ?? {}); +}; diff --git a/x-pack/plugins/rule_registry/server/event_log/utils/predicates.ts b/x-pack/plugins/rule_registry/server/event_log/utils/predicates.ts new file mode 100644 index 0000000000000..40daac1fedcc6 --- /dev/null +++ b/x-pack/plugins/rule_registry/server/event_log/utils/predicates.ts @@ -0,0 +1,16 @@ +/* + * 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. + */ + +export function nonNullable(value: T): value is NonNullable { + return value !== null && value !== undefined; +} + +export type Truthy = T extends false | '' | 0 | null | undefined ? never : T; // from lodash + +export function truthy(value: T): value is Truthy { + return Boolean(value); +} diff --git a/x-pack/plugins/rule_registry/server/event_log/utils/ready_signal.test.ts b/x-pack/plugins/rule_registry/server/event_log/utils/ready_signal.test.ts new file mode 100644 index 0000000000000..f01d438ce79a0 --- /dev/null +++ b/x-pack/plugins/rule_registry/server/event_log/utils/ready_signal.test.ts @@ -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 { createReadySignal, ReadySignal } from './ready_signal'; + +describe('ReadySignal', () => { + let readySignal: ReadySignal; + + beforeEach(() => { + readySignal = createReadySignal(); + }); + + test('works as expected', async () => { + readySignal.signal(42); + const ready = await readySignal.wait(); + expect(ready).toBe(42); + }); +}); diff --git a/x-pack/plugins/rule_registry/server/event_log/utils/ready_signal.ts b/x-pack/plugins/rule_registry/server/event_log/utils/ready_signal.ts new file mode 100644 index 0000000000000..0512def2b5977 --- /dev/null +++ b/x-pack/plugins/rule_registry/server/event_log/utils/ready_signal.ts @@ -0,0 +1,29 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export interface ReadySignal { + wait(): Promise; + signal(value: T): void; +} + +export function createReadySignal(): ReadySignal { + let resolver: (value: T) => void; + + const promise = new Promise((resolve) => { + resolver = resolve; + }); + + async function wait(): Promise { + return await promise; + } + + function signal(value: T) { + resolver(value); + } + + return { wait, signal }; +} diff --git a/x-pack/plugins/rule_registry/server/event_log/utils/utility_types.ts b/x-pack/plugins/rule_registry/server/event_log/utils/utility_types.ts new file mode 100644 index 0000000000000..78e145740da54 --- /dev/null +++ b/x-pack/plugins/rule_registry/server/event_log/utils/utility_types.ts @@ -0,0 +1,12 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export type DeepWriteable = { -readonly [P in keyof T]: DeepWriteable }; + +export type DeepPartial = { + [P in keyof T]?: T[P] extends Array ? Array> : DeepPartial; +}; diff --git a/x-pack/plugins/rule_registry/server/index.ts b/x-pack/plugins/rule_registry/server/index.ts index b51ba3e10f91a..9547f165cd705 100644 --- a/x-pack/plugins/rule_registry/server/index.ts +++ b/x-pack/plugins/rule_registry/server/index.ts @@ -5,27 +5,15 @@ * 2.0. */ -import { schema, TypeOf } from '@kbn/config-schema'; import { PluginInitializerContext } from 'src/core/server'; import { RuleRegistryPlugin } from './plugin'; +export * from './config'; export type { RuleRegistryPluginSetupContract, RuleRegistryPluginStartContract } from './plugin'; export { RuleDataClient } from './rule_data_client'; export { IRuleDataClient } from './rule_data_client/types'; export { getRuleExecutorData, RuleExecutorData } from './utils/get_rule_executor_data'; export { createLifecycleRuleTypeFactory } from './utils/create_lifecycle_rule_type_factory'; -export const config = { - schema: schema.object({ - enabled: schema.boolean({ defaultValue: true }), - write: schema.object({ - enabled: schema.boolean({ defaultValue: true }), - }), - index: schema.string({ defaultValue: '.alerts' }), - }), -}; - -export type RuleRegistryPluginConfig = TypeOf; - export const plugin = (initContext: PluginInitializerContext) => new RuleRegistryPlugin(initContext); diff --git a/x-pack/plugins/rule_registry/server/plugin.ts b/x-pack/plugins/rule_registry/server/plugin.ts index 3c645f98f5c71..043b07f9d67c1 100644 --- a/x-pack/plugins/rule_registry/server/plugin.ts +++ b/x-pack/plugins/rule_registry/server/plugin.ts @@ -5,45 +5,99 @@ * 2.0. */ -import { PluginInitializerContext, Plugin, CoreSetup } from 'src/core/server'; +import { PluginInitializerContext, Plugin, CoreSetup, Logger } from 'src/core/server'; +import { SpacesPluginStart } from '../../spaces/server'; + +import { RuleRegistryPluginConfig } from './config'; import { RuleDataPluginService } from './rule_data_plugin_service'; -import { RuleRegistryPluginConfig } from '.'; +import { EventLogService, IEventLogService } from './event_log'; + +// eslint-disable-next-line @typescript-eslint/no-empty-interface +interface RuleRegistryPluginSetupDependencies {} + +interface RuleRegistryPluginStartDependencies { + spaces: SpacesPluginStart; +} + +export interface RuleRegistryPluginSetupContract { + ruleDataService: RuleDataPluginService; + eventLogService: IEventLogService; +} -export type RuleRegistryPluginSetupContract = RuleDataPluginService; export type RuleRegistryPluginStartContract = void; -export class RuleRegistryPlugin implements Plugin { - constructor(private readonly initContext: PluginInitializerContext) { - this.initContext = initContext; +export class RuleRegistryPlugin + implements + Plugin< + RuleRegistryPluginSetupContract, + RuleRegistryPluginStartContract, + RuleRegistryPluginSetupDependencies, + RuleRegistryPluginStartDependencies + > { + private readonly config: RuleRegistryPluginConfig; + private readonly logger: Logger; + private eventLogService: EventLogService | null; + + constructor(initContext: PluginInitializerContext) { + this.config = initContext.config.get(); + this.logger = initContext.logger.get(); + this.eventLogService = null; } - public setup(core: CoreSetup): RuleRegistryPluginSetupContract { - const config = this.initContext.config.get(); + public setup( + core: CoreSetup + ): RuleRegistryPluginSetupContract { + const { config, logger } = this; - const logger = this.initContext.logger.get(); + const startDependencies = core.getStartServices().then(([coreStart, pluginStart]) => { + return { + core: coreStart, + ...pluginStart, + }; + }); - const service = new RuleDataPluginService({ + const ruleDataService = new RuleDataPluginService({ logger, isWriteEnabled: config.write.enabled, index: config.index, getClusterClient: async () => { - const [coreStart] = await core.getStartServices(); - - return coreStart.elasticsearch.client.asInternalUser; + const deps = await startDependencies; + return deps.core.elasticsearch.client.asInternalUser; }, }); - service.init().catch((originalError) => { + ruleDataService.init().catch((originalError) => { const error = new Error('Failed installing assets'); // @ts-ignore error.stack = originalError.stack; logger.error(error); }); - return service; + const eventLogService = new EventLogService({ + config: { + indexPrefix: this.config.index, + isWriteEnabled: this.config.write.enabled, + }, + dependencies: { + clusterClient: startDependencies.then((deps) => deps.core.elasticsearch.client), + spacesService: startDependencies.then((deps) => deps.spaces.spacesService), + logger: logger.get('eventLog'), + }, + }); + + this.eventLogService = eventLogService; + return { ruleDataService, eventLogService }; } public start(): RuleRegistryPluginStartContract {} - public stop() {} + public stop() { + const { eventLogService, logger } = this; + + if (eventLogService) { + eventLogService.stop().catch((e) => { + logger.error(e); + }); + } + } } diff --git a/x-pack/plugins/rule_registry/tsconfig.json b/x-pack/plugins/rule_registry/tsconfig.json index 707e1ccb98dad..5aefe9769da22 100644 --- a/x-pack/plugins/rule_registry/tsconfig.json +++ b/x-pack/plugins/rule_registry/tsconfig.json @@ -10,7 +10,9 @@ "include": ["common/**/*", "server/**/*", "public/**/*", "../../../typings/**/*"], "references": [ { "path": "../../../src/core/tsconfig.json" }, + { "path": "../../../src/plugins/data/tsconfig.json" }, { "path": "../alerting/tsconfig.json" }, + { "path": "../spaces/tsconfig.json" }, { "path": "../triggers_actions_ui/tsconfig.json" } ] } From 57f59bd15dbb2075c4d8c7b93ab9bb4920248d6a Mon Sep 17 00:00:00 2001 From: Paul Tavares <56442535+paul-tavares@users.noreply.github.com> Date: Thu, 27 May 2021 11:55:50 -0400 Subject: [PATCH 31/77] [Security solution][Endpoint] Add Host Isolation related data to the endpoint generator and test data loader (#100727) * Generate random isolation values for endpoint metadata * Generator for Fleet Actions * Added creation of actions to the index test data loader --- .../data_generators/base_data_generator.ts | 19 ++++++ .../data_generators/fleet_action_generator.ts | 62 +++++++++++++++++++ .../common/endpoint/generate_data.ts | 6 +- .../common/endpoint/index_data.ts | 45 ++++++++++++++ .../common/endpoint/types/actions.ts | 15 +++++ 5 files changed, 145 insertions(+), 2 deletions(-) create mode 100644 x-pack/plugins/security_solution/common/endpoint/data_generators/fleet_action_generator.ts diff --git a/x-pack/plugins/security_solution/common/endpoint/data_generators/base_data_generator.ts b/x-pack/plugins/security_solution/common/endpoint/data_generators/base_data_generator.ts index c0888a6c2a4bd..d1b107b5396dd 100644 --- a/x-pack/plugins/security_solution/common/endpoint/data_generators/base_data_generator.ts +++ b/x-pack/plugins/security_solution/common/endpoint/data_generators/base_data_generator.ts @@ -9,6 +9,8 @@ import seedrandom from 'seedrandom'; import uuid from 'uuid'; const OS_FAMILY = ['windows', 'macos', 'linux']; +/** Array of 14 day offsets */ +const DAY_OFFSETS = Array.from({ length: 14 }, (_, i) => 8.64e7 * (i + 1)); /** * A generic base class to assist in creating domain specific data generators. It includes @@ -33,6 +35,23 @@ export class BaseDataGenerator { throw new Error('method not implemented!'); } + /** Returns a future ISO date string */ + protected randomFutureDate(from?: Date): string { + const now = from ? from.getTime() : Date.now(); + return new Date(now + this.randomChoice(DAY_OFFSETS)).toISOString(); + } + + /** Returns a past ISO date string */ + protected randomPastDate(from?: Date): string { + const now = from ? from.getTime() : Date.now(); + return new Date(now - this.randomChoice(DAY_OFFSETS)).toISOString(); + } + + /** Generate either `true` or `false` */ + protected randomBoolean(): boolean { + return Math.random() < 0.5; + } + /** generate random OS family value */ protected randomOSFamily(): string { return this.randomChoice(OS_FAMILY); diff --git a/x-pack/plugins/security_solution/common/endpoint/data_generators/fleet_action_generator.ts b/x-pack/plugins/security_solution/common/endpoint/data_generators/fleet_action_generator.ts new file mode 100644 index 0000000000000..af799de782f48 --- /dev/null +++ b/x-pack/plugins/security_solution/common/endpoint/data_generators/fleet_action_generator.ts @@ -0,0 +1,62 @@ +/* + * 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 { DeepPartial } from 'utility-types'; +import { merge } from 'lodash'; +import { BaseDataGenerator } from './base_data_generator'; +import { EndpointAction, EndpointActionResponse, ISOLATION_ACTIONS } from '../types'; + +const ISOLATION_COMMANDS: ISOLATION_ACTIONS[] = ['isolate', 'unisolate']; + +export class FleetActionGenerator extends BaseDataGenerator { + /** Generate an Action */ + generate(overrides: DeepPartial = {}): EndpointAction { + const timeStamp = new Date(this.randomPastDate()); + + return merge( + { + action_id: this.randomUUID(), + '@timestamp': timeStamp.toISOString(), + expiration: this.randomFutureDate(timeStamp), + type: 'INPUT_ACTION', + input_type: 'endpoint', + agents: [this.randomUUID()], + user_id: 'elastic', + data: { + command: this.randomIsolateCommand(), + comment: this.randomString(15), + }, + }, + overrides + ); + } + + /** Generates an action response */ + generateResponse(overrides: DeepPartial = {}): EndpointActionResponse { + const timeStamp = new Date(); + + return merge( + { + action_data: { + command: this.randomIsolateCommand(), + comment: '', + }, + action_id: this.randomUUID(), + agent_id: this.randomUUID(), + started_at: this.randomPastDate(), + completed_at: timeStamp.toISOString(), + error: 'some error happen', + '@timestamp': timeStamp.toISOString(), + }, + overrides + ); + } + + protected randomIsolateCommand() { + return this.randomChoice(ISOLATION_COMMANDS); + } +} 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 fa7ee84441a9b..436f1573639c8 100644 --- a/x-pack/plugins/security_solution/common/endpoint/generate_data.ts +++ b/x-pack/plugins/security_solution/common/endpoint/generate_data.ts @@ -439,6 +439,8 @@ export class EndpointDocGenerator extends BaseDataGenerator { private createHostData(): HostInfo { const hostName = this.randomHostname(); + const isIsolated = this.randomBoolean(); + return { agent: { version: this.randomVersion(), @@ -465,10 +467,10 @@ export class EndpointDocGenerator extends BaseDataGenerator { applied: this.randomChoice(APPLIED_POLICIES), }, configuration: { - isolation: false, + isolation: isIsolated, }, state: { - isolation: false, + isolation: isIsolated, }, }, }; diff --git a/x-pack/plugins/security_solution/common/endpoint/index_data.ts b/x-pack/plugins/security_solution/common/endpoint/index_data.ts index 0dc7891560c2d..021b9bcb1eccc 100644 --- a/x-pack/plugins/security_solution/common/endpoint/index_data.ts +++ b/x-pack/plugins/security_solution/common/endpoint/index_data.ts @@ -28,8 +28,10 @@ import { policyFactory as policyConfigFactory } from './models/policy_config'; import { HostMetadata } from './types'; import { KbnClientWithApiKeySupport } from '../../scripts/endpoint/kbn_client_with_api_key_support'; import { FleetAgentGenerator } from './data_generators/fleet_agent_generator'; +import { FleetActionGenerator } from './data_generators/fleet_action_generator'; const fleetAgentGenerator = new FleetAgentGenerator(); +const fleetActionGenerator = new FleetActionGenerator(); export async function indexHostsAndAlerts( client: Client, @@ -175,6 +177,9 @@ async function indexHostDocs({ }, }, }; + + // Create some actions for this Host + await indexFleetActionsForHost(client, hostMetadata); } await client.index({ @@ -397,3 +402,43 @@ const indexFleetAgentForHost = async ( return agentDoc; }; + +const indexFleetActionsForHost = async ( + esClient: Client, + endpointHost: HostMetadata +): Promise => { + const ES_INDEX_OPTIONS = { headers: { 'X-elastic-product-origin': 'fleet' } }; + const agentId = endpointHost.elastic.agent.id; + + for (let i = 0; i < 5; i++) { + // create an action + const isolateAction = fleetActionGenerator.generate({ + data: { comment: 'data generator: this host is bad' }, + }); + + isolateAction.agents = [agentId]; + + await esClient.index( + { + index: '.fleet-actions', + body: isolateAction, + }, + ES_INDEX_OPTIONS + ); + + // Create an action response for the above + const unIsolateAction = fleetActionGenerator.generateResponse({ + action_id: isolateAction.action_id, + agent_id: agentId, + action_data: isolateAction.data, + }); + + await esClient.index( + { + index: '.fleet-actions-results', + body: unIsolateAction, + }, + ES_INDEX_OPTIONS + ); + } +}; diff --git a/x-pack/plugins/security_solution/common/endpoint/types/actions.ts b/x-pack/plugins/security_solution/common/endpoint/types/actions.ts index 99dac5ea5cda6..fcfda9c9a30d9 100644 --- a/x-pack/plugins/security_solution/common/endpoint/types/actions.ts +++ b/x-pack/plugins/security_solution/common/endpoint/types/actions.ts @@ -24,6 +24,21 @@ export interface EndpointAction { }; } +export interface EndpointActionResponse { + '@timestamp': string; + /** The id of the action for which this response is associated with */ + action_id: string; + /** The agent id that sent this action response */ + agent_id: string; + started_at: string; + completed_at: string; + error: string; + action_data: { + command: ISOLATION_ACTIONS; + comment?: string; + }; +} + export type HostIsolationRequestBody = TypeOf; export interface HostIsolationResponse { From 1ceecd395801fc5ab1c99e7677209cc420ea5fa4 Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Thu, 27 May 2021 18:02:25 +0200 Subject: [PATCH 32/77] [Index patterns] Default index pattern REST API (#100691) --- docs/api/index-patterns.asciidoc | 9 +- docs/api/index-patterns/default-get.asciidoc | 55 ++++++++++++ docs/api/index-patterns/default-set.asciidoc | 84 +++++++++++++++++++ ...ublic.indexpatternsservice.getdefaultid.md | 13 +++ ...lugins-data-public.indexpatternsservice.md | 3 +- ...-public.indexpatternsservice.setdefault.md | 2 +- ...erver.indexpatternsservice.getdefaultid.md | 13 +++ ...lugins-data-server.indexpatternsservice.md | 3 +- ...-server.indexpatternsservice.setdefault.md | 2 +- ...rver.searchstrategydependencies.request.md | 11 +++ .../index_patterns/index_patterns.ts | 12 ++- src/plugins/data/public/public.api.md | 3 +- .../data/server/index_patterns/routes.ts | 2 + .../routes/default_index_pattern.ts | 78 +++++++++++++++++ src/plugins/data/server/server.api.md | 3 +- .../default_index_pattern.ts | 49 +++++++++++ .../default_index_pattern/index.ts | 15 ++++ .../apis/index_patterns/index.js | 1 + 18 files changed, 347 insertions(+), 11 deletions(-) create mode 100644 docs/api/index-patterns/default-get.asciidoc create mode 100644 docs/api/index-patterns/default-set.asciidoc create mode 100644 docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternsservice.getdefaultid.md create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.indexpatternsservice.getdefaultid.md create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.searchstrategydependencies.request.md create mode 100644 src/plugins/data/server/index_patterns/routes/default_index_pattern.ts create mode 100644 test/api_integration/apis/index_patterns/default_index_pattern/default_index_pattern.ts create mode 100644 test/api_integration/apis/index_patterns/default_index_pattern/index.ts diff --git a/docs/api/index-patterns.asciidoc b/docs/api/index-patterns.asciidoc index 47906e1761138..79d2f164fb8c3 100644 --- a/docs/api/index-patterns.asciidoc +++ b/docs/api/index-patterns.asciidoc @@ -15,13 +15,16 @@ The following index patterns APIs are available: ** <> to create {kib} index pattern ** <> to partially updated {kib} index pattern ** <> to delete {kib} index pattern +* Default index pattern + ** <> to retrieve a default index pattern + ** <> to set a default index pattern * Fields - ** <> to change field metadata, such as `count`, `customLabel` and `format`. - - + ** <> to change field metadata, such as `count`, `customLabel` and `format` include::index-patterns/get.asciidoc[] include::index-patterns/create.asciidoc[] include::index-patterns/update.asciidoc[] include::index-patterns/delete.asciidoc[] +include::index-patterns/default-get.asciidoc[] +include::index-patterns/default-set.asciidoc[] include::index-patterns/update-fields.asciidoc[] diff --git a/docs/api/index-patterns/default-get.asciidoc b/docs/api/index-patterns/default-get.asciidoc new file mode 100644 index 0000000000000..5c7e8e01ce399 --- /dev/null +++ b/docs/api/index-patterns/default-get.asciidoc @@ -0,0 +1,55 @@ +[[index-patterns-api-default-get]] +=== Get default index pattern API +++++ +Get default index pattern +++++ + +experimental[] Retrieve a default index pattern ID. Kibana UI uses default index pattern unless user picks a different one. + +[[index-patterns-api-default-get-request]] +==== Request + +`GET :/api/index_patterns/default` + +`GET :/s//api/index_patterns/default` + +[[index-patterns-api-default-get-params]] +==== Path parameters + +`space_id`:: +(Optional, string) An identifier for the space. If `space_id` is not provided in the URL, the default space is used. + +[[index-patterns-api-default-get-codes]] +==== Response code + +`200`:: +Indicates a successful call. + +[[index-patterns-api-default-get-example]] +==== Example + +Retrieve the default index pattern id: + +[source,sh] +-------------------------------------------------- +$ curl -X GET api/index_patterns/default +-------------------------------------------------- +// KIBANA + +The API returns an ID of a default index pattern: + +[source,sh] +-------------------------------------------------- +{ + "index_pattern_id": "..." +} +-------------------------------------------------- + +In case there is no default index pattern, the API returns: + +[source,sh] +-------------------------------------------------- +{ + "index_pattern_id": null +} +-------------------------------------------------- diff --git a/docs/api/index-patterns/default-set.asciidoc b/docs/api/index-patterns/default-set.asciidoc new file mode 100644 index 0000000000000..3b3cec6be6324 --- /dev/null +++ b/docs/api/index-patterns/default-set.asciidoc @@ -0,0 +1,84 @@ +[[index-patterns-api-default-set]] +=== Set default index pattern API +++++ +Set default index pattern +++++ + +experimental[] Set a default index pattern ID. Kibana UI will use default index pattern unless user picks a different one. +The API doesn't validate if given `index_pattern_id` is a valid id. + +[[index-patterns-api-default-set-request]] +==== Request + +`POST :/api/index_patterns/default` + +`POST :/s//api/index_patterns/default` + +[[index-patterns-api-default-set-params]] +==== Path parameters + +`space_id`:: +(Optional, string) An identifier for the space. If `space_id` is not provided in the URL, the default space is used. + +[[index-patterns-api-default-set-body]] +==== Request body + +`index_pattern_id`:: (Required, `string` or `null`) Sets a default index pattern id. Use `null` to unset a default index pattern. + +`force`:: (Optional, boolean) Updates existing default index pattern id. The default is `false`. + + +[[index-patterns-api-default-set-codes]] +==== Response code + +`200`:: +Indicates a successful call. + +[[index-patterns-api-default-set-example]] +==== Example + +Set the default index pattern id if none is set: + +[source,sh] +-------------------------------------------------- +$ curl -X POST api/index_patterns/default +{ + "index_pattern_id": "..." +} +-------------------------------------------------- +// KIBANA + + +Upsert the default index pattern: + +[source,sh] +-------------------------------------------------- +$ curl -X POST api/index_patterns/default +{ + "index_pattern_id": "...", + "force": true +} +-------------------------------------------------- +// KIBANA + +Unset the default index pattern: + +[source,sh] +-------------------------------------------------- +$ curl -X POST api/index_patterns/default +{ + "index_pattern_id": null, + "force": true +} +-------------------------------------------------- +// KIBANA + +The API returns: + +[source,sh] +-------------------------------------------------- +{ + "acknowledged": true +} +-------------------------------------------------- + diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternsservice.getdefaultid.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternsservice.getdefaultid.md new file mode 100644 index 0000000000000..3b64ce079b522 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternsservice.getdefaultid.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IndexPatternsService](./kibana-plugin-plugins-data-public.indexpatternsservice.md) > [getDefaultId](./kibana-plugin-plugins-data-public.indexpatternsservice.getdefaultid.md) + +## IndexPatternsService.getDefaultId property + +Get default index pattern id + +Signature: + +```typescript +getDefaultId: () => Promise; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternsservice.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternsservice.md index 1511de18cab51..26b393a5fb5b6 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternsservice.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternsservice.md @@ -27,6 +27,7 @@ export declare class IndexPatternsService | [get](./kibana-plugin-plugins-data-public.indexpatternsservice.get.md) | | (id: string) => Promise<IndexPattern> | Get an index pattern by id. Cache optimized | | [getCache](./kibana-plugin-plugins-data-public.indexpatternsservice.getcache.md) | | () => Promise<SavedObject<IndexPatternSavedObjectAttrs>[] | null | undefined> | | | [getDefault](./kibana-plugin-plugins-data-public.indexpatternsservice.getdefault.md) | | () => Promise<IndexPattern | null> | Get default index pattern | +| [getDefaultId](./kibana-plugin-plugins-data-public.indexpatternsservice.getdefaultid.md) | | () => Promise<string | null> | Get default index pattern id | | [getFieldsForIndexPattern](./kibana-plugin-plugins-data-public.indexpatternsservice.getfieldsforindexpattern.md) | | (indexPattern: IndexPattern | IndexPatternSpec, options?: GetFieldsOptions | undefined) => Promise<any> | Get field list by providing an index patttern (or spec) | | [getFieldsForWildcard](./kibana-plugin-plugins-data-public.indexpatternsservice.getfieldsforwildcard.md) | | (options: GetFieldsOptions) => Promise<any> | Get field list by providing { pattern } | | [getIds](./kibana-plugin-plugins-data-public.indexpatternsservice.getids.md) | | (refresh?: boolean) => Promise<string[]> | Get list of index pattern ids | @@ -34,7 +35,7 @@ export declare class IndexPatternsService | [getTitles](./kibana-plugin-plugins-data-public.indexpatternsservice.gettitles.md) | | (refresh?: boolean) => Promise<string[]> | Get list of index pattern titles | | [refreshFields](./kibana-plugin-plugins-data-public.indexpatternsservice.refreshfields.md) | | (indexPattern: IndexPattern) => Promise<void> | Refresh field list for a given index pattern | | [savedObjectToSpec](./kibana-plugin-plugins-data-public.indexpatternsservice.savedobjecttospec.md) | | (savedObject: SavedObject<IndexPatternAttributes>) => IndexPatternSpec | Converts index pattern saved object to index pattern spec | -| [setDefault](./kibana-plugin-plugins-data-public.indexpatternsservice.setdefault.md) | | (id: string, force?: boolean) => Promise<void> | Optionally set default index pattern, unless force = true | +| [setDefault](./kibana-plugin-plugins-data-public.indexpatternsservice.setdefault.md) | | (id: string | null, force?: boolean) => Promise<void> | Optionally set default index pattern, unless force = true | ## Methods diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternsservice.setdefault.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternsservice.setdefault.md index 2bf8eaa03d1ae..1d216e781c7bb 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternsservice.setdefault.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternsservice.setdefault.md @@ -9,5 +9,5 @@ Optionally set default index pattern, unless force = true Signature: ```typescript -setDefault: (id: string, force?: boolean) => Promise; +setDefault: (id: string | null, force?: boolean) => Promise; ``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.indexpatternsservice.getdefaultid.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.indexpatternsservice.getdefaultid.md new file mode 100644 index 0000000000000..107d1e4e94a0d --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.indexpatternsservice.getdefaultid.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [IndexPatternsService](./kibana-plugin-plugins-data-server.indexpatternsservice.md) > [getDefaultId](./kibana-plugin-plugins-data-server.indexpatternsservice.getdefaultid.md) + +## IndexPatternsService.getDefaultId property + +Get default index pattern id + +Signature: + +```typescript +getDefaultId: () => Promise; +``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.indexpatternsservice.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.indexpatternsservice.md index d55a6e9b325a2..f5e845ced3cd1 100644 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.indexpatternsservice.md +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.indexpatternsservice.md @@ -27,6 +27,7 @@ export declare class IndexPatternsService | [get](./kibana-plugin-plugins-data-server.indexpatternsservice.get.md) | | (id: string) => Promise<IndexPattern> | Get an index pattern by id. Cache optimized | | [getCache](./kibana-plugin-plugins-data-server.indexpatternsservice.getcache.md) | | () => Promise<SavedObject<IndexPatternSavedObjectAttrs>[] | null | undefined> | | | [getDefault](./kibana-plugin-plugins-data-server.indexpatternsservice.getdefault.md) | | () => Promise<IndexPattern | null> | Get default index pattern | +| [getDefaultId](./kibana-plugin-plugins-data-server.indexpatternsservice.getdefaultid.md) | | () => Promise<string | null> | Get default index pattern id | | [getFieldsForIndexPattern](./kibana-plugin-plugins-data-server.indexpatternsservice.getfieldsforindexpattern.md) | | (indexPattern: IndexPattern | IndexPatternSpec, options?: GetFieldsOptions | undefined) => Promise<any> | Get field list by providing an index patttern (or spec) | | [getFieldsForWildcard](./kibana-plugin-plugins-data-server.indexpatternsservice.getfieldsforwildcard.md) | | (options: GetFieldsOptions) => Promise<any> | Get field list by providing { pattern } | | [getIds](./kibana-plugin-plugins-data-server.indexpatternsservice.getids.md) | | (refresh?: boolean) => Promise<string[]> | Get list of index pattern ids | @@ -34,7 +35,7 @@ export declare class IndexPatternsService | [getTitles](./kibana-plugin-plugins-data-server.indexpatternsservice.gettitles.md) | | (refresh?: boolean) => Promise<string[]> | Get list of index pattern titles | | [refreshFields](./kibana-plugin-plugins-data-server.indexpatternsservice.refreshfields.md) | | (indexPattern: IndexPattern) => Promise<void> | Refresh field list for a given index pattern | | [savedObjectToSpec](./kibana-plugin-plugins-data-server.indexpatternsservice.savedobjecttospec.md) | | (savedObject: SavedObject<IndexPatternAttributes>) => IndexPatternSpec | Converts index pattern saved object to index pattern spec | -| [setDefault](./kibana-plugin-plugins-data-server.indexpatternsservice.setdefault.md) | | (id: string, force?: boolean) => Promise<void> | Optionally set default index pattern, unless force = true | +| [setDefault](./kibana-plugin-plugins-data-server.indexpatternsservice.setdefault.md) | | (id: string | null, force?: boolean) => Promise<void> | Optionally set default index pattern, unless force = true | ## Methods diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.indexpatternsservice.setdefault.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.indexpatternsservice.setdefault.md index 708d645a79f1a..6dc584341eef3 100644 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.indexpatternsservice.setdefault.md +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.indexpatternsservice.setdefault.md @@ -9,5 +9,5 @@ Optionally set default index pattern, unless force = true Signature: ```typescript -setDefault: (id: string, force?: boolean) => Promise; +setDefault: (id: string | null, force?: boolean) => Promise; ``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.searchstrategydependencies.request.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.searchstrategydependencies.request.md new file mode 100644 index 0000000000000..18163bfebde7e --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.searchstrategydependencies.request.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [SearchStrategyDependencies](./kibana-plugin-plugins-data-server.searchstrategydependencies.md) > [request](./kibana-plugin-plugins-data-server.searchstrategydependencies.request.md) + +## SearchStrategyDependencies.request property + +Signature: + +```typescript +request: KibanaRequest; +``` diff --git a/src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts b/src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts index 04d2785137719..66e66051a6370 100644 --- a/src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts +++ b/src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts @@ -192,7 +192,7 @@ export class IndexPatternsService { * Get default index pattern */ getDefault = async () => { - const defaultIndexPatternId = await this.config.get('defaultIndex'); + const defaultIndexPatternId = await this.getDefaultId(); if (defaultIndexPatternId) { return await this.get(defaultIndexPatternId); } @@ -200,12 +200,20 @@ export class IndexPatternsService { return null; }; + /** + * Get default index pattern id + */ + getDefaultId = async (): Promise => { + const defaultIndexPatternId = await this.config.get('defaultIndex'); + return defaultIndexPatternId ?? null; + }; + /** * Optionally set default index pattern, unless force = true * @param id * @param force */ - setDefault = async (id: string, force = false) => { + setDefault = async (id: string | null, force = false) => { if (force || !this.config.get('defaultIndex')) { await this.config.set('defaultIndex', id); } diff --git a/src/plugins/data/public/public.api.md b/src/plugins/data/public/public.api.md index 57aa2298039da..fde7075d9e760 100644 --- a/src/plugins/data/public/public.api.md +++ b/src/plugins/data/public/public.api.md @@ -1624,6 +1624,7 @@ export class IndexPatternsService { // (undocumented) getCache: () => Promise[] | null | undefined>; getDefault: () => Promise; + getDefaultId: () => Promise; getFieldsForIndexPattern: (indexPattern: IndexPattern | IndexPatternSpec, options?: GetFieldsOptions | undefined) => Promise; // Warning: (ae-forgotten-export) The symbol "GetFieldsOptions" needs to be exported by the entry point index.d.ts getFieldsForWildcard: (options: GetFieldsOptions) => Promise; @@ -1635,7 +1636,7 @@ export class IndexPatternsService { getTitles: (refresh?: boolean) => Promise; refreshFields: (indexPattern: IndexPattern) => Promise; savedObjectToSpec: (savedObject: SavedObject) => IndexPatternSpec; - setDefault: (id: string, force?: boolean) => Promise; + setDefault: (id: string | null, force?: boolean) => Promise; updateSavedObject(indexPattern: IndexPattern, saveAttempts?: number, ignoreErrors?: boolean): Promise; } diff --git a/src/plugins/data/server/index_patterns/routes.ts b/src/plugins/data/server/index_patterns/routes.ts index 84199fe60b997..9bff590b54f1c 100644 --- a/src/plugins/data/server/index_patterns/routes.ts +++ b/src/plugins/data/server/index_patterns/routes.ts @@ -20,6 +20,7 @@ import { registerGetScriptedFieldRoute } from './routes/scripted_fields/get_scri import { registerDeleteScriptedFieldRoute } from './routes/scripted_fields/delete_scripted_field'; import { registerUpdateScriptedFieldRoute } from './routes/scripted_fields/update_scripted_field'; import type { DataPluginStart, DataPluginStartDependencies } from '../plugin'; +import { registerManageDefaultIndexPatternRoutes } from './routes/default_index_pattern'; export function registerRoutes( http: HttpServiceSetup, @@ -42,6 +43,7 @@ export function registerRoutes( registerGetIndexPatternRoute(router, getStartServices); registerDeleteIndexPatternRoute(router, getStartServices); registerUpdateIndexPatternRoute(router, getStartServices); + registerManageDefaultIndexPatternRoutes(router, getStartServices); // Fields API registerUpdateFieldsRoute(router, getStartServices); diff --git a/src/plugins/data/server/index_patterns/routes/default_index_pattern.ts b/src/plugins/data/server/index_patterns/routes/default_index_pattern.ts new file mode 100644 index 0000000000000..cf5986943eb37 --- /dev/null +++ b/src/plugins/data/server/index_patterns/routes/default_index_pattern.ts @@ -0,0 +1,78 @@ +/* + * 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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { schema } from '@kbn/config-schema'; +import { IRouter, StartServicesAccessor } from '../../../../../core/server'; +import type { DataPluginStart, DataPluginStartDependencies } from '../../plugin'; +import { handleErrors } from './util/handle_errors'; + +export const registerManageDefaultIndexPatternRoutes = ( + router: IRouter, + getStartServices: StartServicesAccessor +) => { + router.get( + { + path: '/api/index_patterns/default', + validate: {}, + }, + handleErrors(async (ctx, req, res) => { + const savedObjectsClient = ctx.core.savedObjects.client; + const elasticsearchClient = ctx.core.elasticsearch.client.asCurrentUser; + const [, , { indexPatterns }] = await getStartServices(); + const indexPatternsService = await indexPatterns.indexPatternsServiceFactory( + savedObjectsClient, + elasticsearchClient + ); + + const defaultIndexPatternId = await indexPatternsService.getDefaultId(); + + return res.ok({ + body: { + index_pattern_id: defaultIndexPatternId, + }, + }); + }) + ); + + router.post( + { + path: '/api/index_patterns/default', + validate: { + body: schema.object({ + index_pattern_id: schema.nullable( + schema.string({ + minLength: 1, + maxLength: 1_000, + }) + ), + force: schema.boolean({ defaultValue: false }), + }), + }, + }, + handleErrors(async (ctx, req, res) => { + const savedObjectsClient = ctx.core.savedObjects.client; + const elasticsearchClient = ctx.core.elasticsearch.client.asCurrentUser; + const [, , { indexPatterns }] = await getStartServices(); + const indexPatternsService = await indexPatterns.indexPatternsServiceFactory( + savedObjectsClient, + elasticsearchClient + ); + + const newDefaultId = req.body.index_pattern_id; + const force = req.body.force; + + await indexPatternsService.setDefault(newDefaultId, force); + + return res.ok({ + body: { + acknowledged: true, + }, + }); + }) + ); +}; diff --git a/src/plugins/data/server/server.api.md b/src/plugins/data/server/server.api.md index b1c90667c2d71..4abf430252164 100644 --- a/src/plugins/data/server/server.api.md +++ b/src/plugins/data/server/server.api.md @@ -962,6 +962,7 @@ class IndexPatternsService { // (undocumented) getCache: () => Promise[] | null | undefined>; getDefault: () => Promise; + getDefaultId: () => Promise; getFieldsForIndexPattern: (indexPattern: IndexPattern | IndexPatternSpec, options?: GetFieldsOptions | undefined) => Promise; // Warning: (ae-forgotten-export) The symbol "GetFieldsOptions" needs to be exported by the entry point index.d.ts getFieldsForWildcard: (options: GetFieldsOptions) => Promise; @@ -973,7 +974,7 @@ class IndexPatternsService { getTitles: (refresh?: boolean) => Promise; refreshFields: (indexPattern: IndexPattern) => Promise; savedObjectToSpec: (savedObject: SavedObject_2) => IndexPatternSpec; - setDefault: (id: string, force?: boolean) => Promise; + setDefault: (id: string | null, force?: boolean) => Promise; updateSavedObject(indexPattern: IndexPattern, saveAttempts?: number, ignoreErrors?: boolean): Promise; } diff --git a/test/api_integration/apis/index_patterns/default_index_pattern/default_index_pattern.ts b/test/api_integration/apis/index_patterns/default_index_pattern/default_index_pattern.ts new file mode 100644 index 0000000000000..b12600f5ce4f3 --- /dev/null +++ b/test/api_integration/apis/index_patterns/default_index_pattern/default_index_pattern.ts @@ -0,0 +1,49 @@ +/* + * 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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../../ftr_provider_context'; + +export default function ({ getService }: FtrProviderContext) { + const supertest = getService('supertest'); + + describe('default index pattern api', () => { + const newId = () => `default-id-${Date.now()}-${Math.random()}`; + it('can set default index pattern', async () => { + const defaultId = newId(); + const response1 = await supertest.post('/api/index_patterns/default').send({ + index_pattern_id: defaultId, + force: true, + }); + expect(response1.status).to.be(200); + expect(response1.body.acknowledged).to.be(true); + + const response2 = await supertest.get('/api/index_patterns/default'); + expect(response2.status).to.be(200); + expect(response2.body.index_pattern_id).to.be(defaultId); + + const response3 = await supertest.post('/api/index_patterns/default').send({ + index_pattern_id: newId(), + // no force this time, so this new default shouldn't be set + }); + + expect(response3.status).to.be(200); + const response4 = await supertest.get('/api/index_patterns/default'); + expect(response4.body.index_pattern_id).to.be(defaultId); // original default id is used + + const response5 = await supertest.post('/api/index_patterns/default').send({ + index_pattern_id: null, + force: true, + }); + expect(response5.status).to.be(200); + + const response6 = await supertest.get('/api/index_patterns/default'); + expect(response6.body.index_pattern_id).to.be(null); + }); + }); +} diff --git a/test/api_integration/apis/index_patterns/default_index_pattern/index.ts b/test/api_integration/apis/index_patterns/default_index_pattern/index.ts new file mode 100644 index 0000000000000..7517c87ade25b --- /dev/null +++ b/test/api_integration/apis/index_patterns/default_index_pattern/index.ts @@ -0,0 +1,15 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { FtrProviderContext } from '../../../ftr_provider_context'; + +export default function ({ loadTestFile }: FtrProviderContext) { + describe('default index pattern', () => { + loadTestFile(require.resolve('./default_index_pattern')); + }); +} diff --git a/test/api_integration/apis/index_patterns/index.js b/test/api_integration/apis/index_patterns/index.js index 8d279a5783703..9c1e1bba0ab9a 100644 --- a/test/api_integration/apis/index_patterns/index.js +++ b/test/api_integration/apis/index_patterns/index.js @@ -14,5 +14,6 @@ export default function ({ loadTestFile }) { loadTestFile(require.resolve('./index_pattern_crud')); loadTestFile(require.resolve('./scripted_fields_crud')); loadTestFile(require.resolve('./fields_api')); + loadTestFile(require.resolve('./default_index_pattern')); }); } From b1e664ca409b556acfe0524a07e172ffa4164b21 Mon Sep 17 00:00:00 2001 From: Devon Thomson Date: Thu, 27 May 2021 13:06:57 -0400 Subject: [PATCH 33/77] [TSVB] By Value Migrations for 7.13 (#100746) * Created common TSVB migrations. Registered them in serverside embeddable factory so that by value panels receive them Co-authored-by: Stratoula Kalafateli --- .../saved_objects/dashboard_migrations.ts | 15 ++-- .../visualize_embeddable_factory.ts | 52 ++++++++++++ .../visualization_common_migrations.ts | 44 ++++++++++ ...alization_saved_object_migrations.test.ts} | 42 +++++++++- .../visualization_saved_object_migrations.ts} | 83 +++++++++---------- src/plugins/visualizations/server/plugin.ts | 9 +- .../server/saved_objects/visualization.ts | 2 +- 7 files changed, 193 insertions(+), 54 deletions(-) create mode 100644 src/plugins/visualizations/server/embeddable/visualize_embeddable_factory.ts create mode 100644 src/plugins/visualizations/server/migrations/visualization_common_migrations.ts rename src/plugins/visualizations/server/{saved_objects/visualization_migrations.test.ts => migrations/visualization_saved_object_migrations.test.ts} (97%) rename src/plugins/visualizations/server/{saved_objects/visualization_migrations.ts => migrations/visualization_saved_object_migrations.ts} (96%) diff --git a/src/plugins/dashboard/server/saved_objects/dashboard_migrations.ts b/src/plugins/dashboard/server/saved_objects/dashboard_migrations.ts index bb95e9e4c38b8..4ebca5ba8965e 100644 --- a/src/plugins/dashboard/server/saved_objects/dashboard_migrations.ts +++ b/src/plugins/dashboard/server/saved_objects/dashboard_migrations.ts @@ -147,7 +147,10 @@ function createExtractPanelReferencesMigration( }; } -type ValueOrReferenceInput = SavedObjectEmbeddableInput & { attributes?: SerializableValue }; +type ValueOrReferenceInput = SavedObjectEmbeddableInput & { + attributes?: SerializableValue; + savedVis?: SerializableValue; +}; // Runs the embeddable migrations on each panel const migrateByValuePanels = ( @@ -158,19 +161,21 @@ const migrateByValuePanels = ( // Skip if panelsJSON is missing otherwise this will cause saved object import to fail when // importing objects without panelsJSON. At development time of this, there is no guarantee each saved // object has panelsJSON in all previous versions of kibana. - if (typeof attributes.panelsJSON !== 'string') { - return attributes; + if (typeof attributes?.panelsJSON !== 'string') { + return doc; } const panels = JSON.parse(attributes.panelsJSON) as SavedDashboardPanel[]; // Same here, prevent failing saved object import if ever panels aren't an array. if (!Array.isArray(panels)) { - return attributes; + return doc; } const newPanels: SavedDashboardPanel[] = []; panels.forEach((panel) => { // Convert each panel into a state that can be passed to EmbeddablesSetup.migrate const originalPanelState = convertSavedDashboardPanelToPanelState(panel); - if (originalPanelState.explicitInput.attributes) { + + // saved vis is used to store by value input for Visualize. This should eventually be renamed to `attributes` to align with Lens and Maps + if (originalPanelState.explicitInput.attributes || originalPanelState.explicitInput.savedVis) { // If this panel is by value, migrate the state using embeddable migrations const migratedInput = deps.embeddable.migrate( { diff --git a/src/plugins/visualizations/server/embeddable/visualize_embeddable_factory.ts b/src/plugins/visualizations/server/embeddable/visualize_embeddable_factory.ts new file mode 100644 index 0000000000000..6f214745e1291 --- /dev/null +++ b/src/plugins/visualizations/server/embeddable/visualize_embeddable_factory.ts @@ -0,0 +1,52 @@ +/* + * 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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { flow } from 'lodash'; +import { EmbeddableRegistryDefinition } from 'src/plugins/embeddable/server'; +import { SerializableState } from '../../../kibana_utils/common'; +import { + commonAddSupportOfDualIndexSelectionModeInTSVB, + commonHideTSVBLastValueIndicator, + commonRemoveDefaultIndexPatternAndTimeFieldFromTSVBModel, +} from '../migrations/visualization_common_migrations'; + +const byValueAddSupportOfDualIndexSelectionModeInTSVB = (state: SerializableState) => { + return { + ...state, + savedVis: commonAddSupportOfDualIndexSelectionModeInTSVB(state.savedVis), + }; +}; + +const byValueHideTSVBLastValueIndicator = (state: SerializableState) => { + return { + ...state, + savedVis: commonHideTSVBLastValueIndicator(state.savedVis), + }; +}; + +const byValueRemoveDefaultIndexPatternAndTimeFieldFromTSVBModel = (state: SerializableState) => { + return { + ...state, + savedVis: commonRemoveDefaultIndexPatternAndTimeFieldFromTSVBModel(state.savedVis), + }; +}; + +export const visualizeEmbeddableFactory = (): EmbeddableRegistryDefinition => { + return { + id: 'visualization', + migrations: { + // These migrations are run in 7.13.1 for `by value` panels because the 7.13 release window was missed. + '7.13.1': (state) => + flow( + byValueAddSupportOfDualIndexSelectionModeInTSVB, + byValueHideTSVBLastValueIndicator, + byValueRemoveDefaultIndexPatternAndTimeFieldFromTSVBModel + )(state), + }, + }; +}; diff --git a/src/plugins/visualizations/server/migrations/visualization_common_migrations.ts b/src/plugins/visualizations/server/migrations/visualization_common_migrations.ts new file mode 100644 index 0000000000000..3f09f19d9ac63 --- /dev/null +++ b/src/plugins/visualizations/server/migrations/visualization_common_migrations.ts @@ -0,0 +1,44 @@ +/* + * 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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export const commonAddSupportOfDualIndexSelectionModeInTSVB = (visState: any) => { + if (visState && visState.type === 'metrics') { + const { params } = visState; + + if (typeof params?.index_pattern === 'string') { + params.use_kibana_indexes = false; + } + } + return visState; +}; + +export const commonHideTSVBLastValueIndicator = (visState: any) => { + if (visState && visState.type === 'metrics' && visState.params.type !== 'timeseries') { + return { + ...visState, + params: { + ...visState.params, + hide_last_value_indicator: true, + }, + }; + } + return visState; +}; + +export const commonRemoveDefaultIndexPatternAndTimeFieldFromTSVBModel = (visState: any) => { + if (visState && visState.type === 'metrics') { + const { params } = visState; + + delete params.default_index_pattern; + delete params.default_timefield; + + return visState; + } + + return visState; +}; diff --git a/src/plugins/visualizations/server/saved_objects/visualization_migrations.test.ts b/src/plugins/visualizations/server/migrations/visualization_saved_object_migrations.test.ts similarity index 97% rename from src/plugins/visualizations/server/saved_objects/visualization_migrations.test.ts rename to src/plugins/visualizations/server/migrations/visualization_saved_object_migrations.test.ts index b082737cce288..dbe5482c442b7 100644 --- a/src/plugins/visualizations/server/saved_objects/visualization_migrations.test.ts +++ b/src/plugins/visualizations/server/migrations/visualization_saved_object_migrations.test.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { visualizationSavedObjectTypeMigrations } from './visualization_migrations'; +import { visualizationSavedObjectTypeMigrations } from './visualization_saved_object_migrations'; import { SavedObjectMigrationContext, SavedObjectMigrationFn } from 'kibana/server'; const savedObjectMigrationContext = (null as unknown) as SavedObjectMigrationContext; @@ -1977,4 +1977,44 @@ describe('migration visualization', () => { expect(params).not.toHaveProperty('default_timefield'); }); }); + + describe('7.13.0 and 7.13.1 tsvb migrations can run twice', () => { + const migrate = (doc: any) => + visualizationSavedObjectTypeMigrations['7.13.0']( + doc as Parameters[0], + savedObjectMigrationContext + ); + + const migrateAgain = (doc: any) => + visualizationSavedObjectTypeMigrations['7.13.1']( + doc as Parameters[0], + savedObjectMigrationContext + ); + + const createTestDocWithType = (type: string) => ({ + attributes: { + title: 'My Vis', + description: 'This is my super cool vis.', + visState: `{"type":"metrics","params":{"type":"${type}","default_index_pattern":"test", "default_timefield":"test", "index_pattern":"testme"}}`, + }, + }); + + it('the migrations can be applied twice without breaking anything', () => { + const migratedTestDoc = migrate(createTestDocWithType('markdown')); + const { params } = JSON.parse(migratedTestDoc.attributes.visState); + + expect(params.hide_last_value_indicator).toBeTruthy(); + expect(params).not.toHaveProperty('default_index_pattern'); + expect(params).not.toHaveProperty('default_timefield'); + expect(params.use_kibana_indexes).toBeFalsy(); + + const migratedTestDocNew = migrateAgain(migratedTestDoc); + const visState = JSON.parse(migratedTestDocNew.attributes.visState); + + expect(visState.params.hide_last_value_indicator).toBeTruthy(); + expect(visState.params).not.toHaveProperty('default_index_pattern'); + expect(visState.params).not.toHaveProperty('default_timefield'); + expect(params.use_kibana_indexes).toBeFalsy(); + }); + }); }); diff --git a/src/plugins/visualizations/server/saved_objects/visualization_migrations.ts b/src/plugins/visualizations/server/migrations/visualization_saved_object_migrations.ts similarity index 96% rename from src/plugins/visualizations/server/saved_objects/visualization_migrations.ts rename to src/plugins/visualizations/server/migrations/visualization_saved_object_migrations.ts index 093255d65a7a8..b9885588b6f76 100644 --- a/src/plugins/visualizations/server/saved_objects/visualization_migrations.ts +++ b/src/plugins/visualizations/server/migrations/visualization_saved_object_migrations.ts @@ -11,6 +11,11 @@ import { cloneDeep, get, omit, has, flow, forOwn } from 'lodash'; import { SavedObjectMigrationFn } from 'kibana/server'; import { DEFAULT_QUERY_LANGUAGE } from '../../../data/common'; +import { + commonAddSupportOfDualIndexSelectionModeInTSVB, + commonHideTSVBLastValueIndicator, + commonRemoveDefaultIndexPatternAndTimeFieldFromTSVBModel, +} from './visualization_common_migrations'; const migrateIndexPattern: SavedObjectMigrationFn = (doc) => { const searchSourceJSON = get(doc, 'attributes.kibanaSavedObjectMeta.searchSourceJSON'); @@ -799,22 +804,16 @@ const addSupportOfDualIndexSelectionModeInTSVB: SavedObjectMigrationFn visState = JSON.parse(visStateJSON); } catch (e) { // Let it go, the data is invalid and we'll leave it as is + return doc; } - if (visState && visState.type === 'metrics') { - const { params } = visState; - - if (typeof params?.index_pattern === 'string') { - params.use_kibana_indexes = false; - } - - return { - ...doc, - attributes: { - ...doc.attributes, - visState: JSON.stringify(visState), - }, - }; - } + const newVisState = commonAddSupportOfDualIndexSelectionModeInTSVB(visState); + return { + ...doc, + attributes: { + ...doc.attributes, + visState: JSON.stringify(newVisState), + }, + }; } return doc; }; @@ -929,25 +928,17 @@ const migrateVislibAreaLineBarTypes: SavedObjectMigrationFn = (doc) => const hideTSVBLastValueIndicator: SavedObjectMigrationFn = (doc) => { try { const visState = JSON.parse(doc.attributes.visState); - - if (visState && visState.type === 'metrics' && visState.params.type !== 'timeseries') - return { - ...doc, - attributes: { - ...doc.attributes, - visState: JSON.stringify({ - ...visState, - params: { - ...visState.params, - hide_last_value_indicator: true, - }, - }), - }, - }; + const newVisState = commonHideTSVBLastValueIndicator(visState); + return { + ...doc, + attributes: { + ...doc.attributes, + visState: JSON.stringify(newVisState), + }, + }; } catch (e) { // Let it go, the data is invalid and we'll leave it as is } - return doc; }; @@ -962,23 +953,17 @@ const removeDefaultIndexPatternAndTimeFieldFromTSVBModel: SavedObjectMigrationFn visState = JSON.parse(visStateJSON); } catch (e) { // Let it go, the data is invalid and we'll leave it as is - } - if (visState && visState.type === 'metrics') { - const { params } = visState; - - delete params.default_index_pattern; - delete params.default_timefield; - - return { - ...doc, - attributes: { - ...doc.attributes, - visState: JSON.stringify(visState), - }, - }; + return doc; } } - return doc; + const newVisState = commonRemoveDefaultIndexPatternAndTimeFieldFromTSVBModel(visState); + return { + ...doc, + attributes: { + ...doc.attributes, + visState: JSON.stringify(newVisState), + }, + }; }; export const visualizationSavedObjectTypeMigrations = { @@ -1021,4 +1006,10 @@ export const visualizationSavedObjectTypeMigrations = { hideTSVBLastValueIndicator, removeDefaultIndexPatternAndTimeFieldFromTSVBModel ), + '7.13.1': flow( + // duplicate these migrations in case a broken by value panel is added to the library + addSupportOfDualIndexSelectionModeInTSVB, + hideTSVBLastValueIndicator, + removeDefaultIndexPatternAndTimeFieldFromTSVBModel + ), }; diff --git a/src/plugins/visualizations/server/plugin.ts b/src/plugins/visualizations/server/plugin.ts index fa64e28a39dc7..5a5a80b2689d6 100644 --- a/src/plugins/visualizations/server/plugin.ts +++ b/src/plugins/visualizations/server/plugin.ts @@ -24,6 +24,8 @@ import { visualizationSavedObjectType } from './saved_objects'; import { VisualizationsPluginSetup, VisualizationsPluginStart } from './types'; import { registerVisualizationsCollector } from './usage_collector'; +import { EmbeddableSetup } from '../../embeddable/server'; +import { visualizeEmbeddableFactory } from './embeddable/visualize_embeddable_factory'; export class VisualizationsPlugin implements Plugin { @@ -35,7 +37,10 @@ export class VisualizationsPlugin this.config = initializerContext.config.legacy.globalConfig$; } - public setup(core: CoreSetup, plugins: { usageCollection?: UsageCollectionSetup }) { + public setup( + core: CoreSetup, + plugins: { usageCollection?: UsageCollectionSetup; embeddable: EmbeddableSetup } + ) { this.logger.debug('visualizations: Setup'); core.savedObjects.registerType(visualizationSavedObjectType); @@ -59,6 +64,8 @@ export class VisualizationsPlugin registerVisualizationsCollector(plugins.usageCollection, this.config); } + plugins.embeddable.registerEmbeddableFactory(visualizeEmbeddableFactory()); + return {}; } diff --git a/src/plugins/visualizations/server/saved_objects/visualization.ts b/src/plugins/visualizations/server/saved_objects/visualization.ts index fb7ab3d1531cc..880e277294fc3 100644 --- a/src/plugins/visualizations/server/saved_objects/visualization.ts +++ b/src/plugins/visualizations/server/saved_objects/visualization.ts @@ -7,7 +7,7 @@ */ import { SavedObjectsType } from 'kibana/server'; -import { visualizationSavedObjectTypeMigrations } from './visualization_migrations'; +import { visualizationSavedObjectTypeMigrations } from '../migrations/visualization_saved_object_migrations'; export const visualizationSavedObjectType: SavedObjectsType = { name: 'visualization', From 5dde07ff6f01783811c1ebe859eca7da9554040d Mon Sep 17 00:00:00 2001 From: Jonathan Budzenski Date: Thu, 27 May 2021 12:21:48 -0500 Subject: [PATCH 34/77] Revert "[Security solution][Endpoint] Add Host Isolation related data to the endpoint generator and test data loader (#100727)" This reverts commit 57f59bd15dbb2075c4d8c7b93ab9bb4920248d6a. --- .../data_generators/base_data_generator.ts | 19 ------ .../data_generators/fleet_action_generator.ts | 62 ------------------- .../common/endpoint/generate_data.ts | 6 +- .../common/endpoint/index_data.ts | 45 -------------- .../common/endpoint/types/actions.ts | 15 ----- 5 files changed, 2 insertions(+), 145 deletions(-) delete mode 100644 x-pack/plugins/security_solution/common/endpoint/data_generators/fleet_action_generator.ts diff --git a/x-pack/plugins/security_solution/common/endpoint/data_generators/base_data_generator.ts b/x-pack/plugins/security_solution/common/endpoint/data_generators/base_data_generator.ts index d1b107b5396dd..c0888a6c2a4bd 100644 --- a/x-pack/plugins/security_solution/common/endpoint/data_generators/base_data_generator.ts +++ b/x-pack/plugins/security_solution/common/endpoint/data_generators/base_data_generator.ts @@ -9,8 +9,6 @@ import seedrandom from 'seedrandom'; import uuid from 'uuid'; const OS_FAMILY = ['windows', 'macos', 'linux']; -/** Array of 14 day offsets */ -const DAY_OFFSETS = Array.from({ length: 14 }, (_, i) => 8.64e7 * (i + 1)); /** * A generic base class to assist in creating domain specific data generators. It includes @@ -35,23 +33,6 @@ export class BaseDataGenerator { throw new Error('method not implemented!'); } - /** Returns a future ISO date string */ - protected randomFutureDate(from?: Date): string { - const now = from ? from.getTime() : Date.now(); - return new Date(now + this.randomChoice(DAY_OFFSETS)).toISOString(); - } - - /** Returns a past ISO date string */ - protected randomPastDate(from?: Date): string { - const now = from ? from.getTime() : Date.now(); - return new Date(now - this.randomChoice(DAY_OFFSETS)).toISOString(); - } - - /** Generate either `true` or `false` */ - protected randomBoolean(): boolean { - return Math.random() < 0.5; - } - /** generate random OS family value */ protected randomOSFamily(): string { return this.randomChoice(OS_FAMILY); diff --git a/x-pack/plugins/security_solution/common/endpoint/data_generators/fleet_action_generator.ts b/x-pack/plugins/security_solution/common/endpoint/data_generators/fleet_action_generator.ts deleted file mode 100644 index af799de782f48..0000000000000 --- a/x-pack/plugins/security_solution/common/endpoint/data_generators/fleet_action_generator.ts +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { DeepPartial } from 'utility-types'; -import { merge } from 'lodash'; -import { BaseDataGenerator } from './base_data_generator'; -import { EndpointAction, EndpointActionResponse, ISOLATION_ACTIONS } from '../types'; - -const ISOLATION_COMMANDS: ISOLATION_ACTIONS[] = ['isolate', 'unisolate']; - -export class FleetActionGenerator extends BaseDataGenerator { - /** Generate an Action */ - generate(overrides: DeepPartial = {}): EndpointAction { - const timeStamp = new Date(this.randomPastDate()); - - return merge( - { - action_id: this.randomUUID(), - '@timestamp': timeStamp.toISOString(), - expiration: this.randomFutureDate(timeStamp), - type: 'INPUT_ACTION', - input_type: 'endpoint', - agents: [this.randomUUID()], - user_id: 'elastic', - data: { - command: this.randomIsolateCommand(), - comment: this.randomString(15), - }, - }, - overrides - ); - } - - /** Generates an action response */ - generateResponse(overrides: DeepPartial = {}): EndpointActionResponse { - const timeStamp = new Date(); - - return merge( - { - action_data: { - command: this.randomIsolateCommand(), - comment: '', - }, - action_id: this.randomUUID(), - agent_id: this.randomUUID(), - started_at: this.randomPastDate(), - completed_at: timeStamp.toISOString(), - error: 'some error happen', - '@timestamp': timeStamp.toISOString(), - }, - overrides - ); - } - - protected randomIsolateCommand() { - return this.randomChoice(ISOLATION_COMMANDS); - } -} 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 436f1573639c8..fa7ee84441a9b 100644 --- a/x-pack/plugins/security_solution/common/endpoint/generate_data.ts +++ b/x-pack/plugins/security_solution/common/endpoint/generate_data.ts @@ -439,8 +439,6 @@ export class EndpointDocGenerator extends BaseDataGenerator { private createHostData(): HostInfo { const hostName = this.randomHostname(); - const isIsolated = this.randomBoolean(); - return { agent: { version: this.randomVersion(), @@ -467,10 +465,10 @@ export class EndpointDocGenerator extends BaseDataGenerator { applied: this.randomChoice(APPLIED_POLICIES), }, configuration: { - isolation: isIsolated, + isolation: false, }, state: { - isolation: isIsolated, + isolation: false, }, }, }; diff --git a/x-pack/plugins/security_solution/common/endpoint/index_data.ts b/x-pack/plugins/security_solution/common/endpoint/index_data.ts index 021b9bcb1eccc..0dc7891560c2d 100644 --- a/x-pack/plugins/security_solution/common/endpoint/index_data.ts +++ b/x-pack/plugins/security_solution/common/endpoint/index_data.ts @@ -28,10 +28,8 @@ import { policyFactory as policyConfigFactory } from './models/policy_config'; import { HostMetadata } from './types'; import { KbnClientWithApiKeySupport } from '../../scripts/endpoint/kbn_client_with_api_key_support'; import { FleetAgentGenerator } from './data_generators/fleet_agent_generator'; -import { FleetActionGenerator } from './data_generators/fleet_action_generator'; const fleetAgentGenerator = new FleetAgentGenerator(); -const fleetActionGenerator = new FleetActionGenerator(); export async function indexHostsAndAlerts( client: Client, @@ -177,9 +175,6 @@ async function indexHostDocs({ }, }, }; - - // Create some actions for this Host - await indexFleetActionsForHost(client, hostMetadata); } await client.index({ @@ -402,43 +397,3 @@ const indexFleetAgentForHost = async ( return agentDoc; }; - -const indexFleetActionsForHost = async ( - esClient: Client, - endpointHost: HostMetadata -): Promise => { - const ES_INDEX_OPTIONS = { headers: { 'X-elastic-product-origin': 'fleet' } }; - const agentId = endpointHost.elastic.agent.id; - - for (let i = 0; i < 5; i++) { - // create an action - const isolateAction = fleetActionGenerator.generate({ - data: { comment: 'data generator: this host is bad' }, - }); - - isolateAction.agents = [agentId]; - - await esClient.index( - { - index: '.fleet-actions', - body: isolateAction, - }, - ES_INDEX_OPTIONS - ); - - // Create an action response for the above - const unIsolateAction = fleetActionGenerator.generateResponse({ - action_id: isolateAction.action_id, - agent_id: agentId, - action_data: isolateAction.data, - }); - - await esClient.index( - { - index: '.fleet-actions-results', - body: unIsolateAction, - }, - ES_INDEX_OPTIONS - ); - } -}; diff --git a/x-pack/plugins/security_solution/common/endpoint/types/actions.ts b/x-pack/plugins/security_solution/common/endpoint/types/actions.ts index fcfda9c9a30d9..99dac5ea5cda6 100644 --- a/x-pack/plugins/security_solution/common/endpoint/types/actions.ts +++ b/x-pack/plugins/security_solution/common/endpoint/types/actions.ts @@ -24,21 +24,6 @@ export interface EndpointAction { }; } -export interface EndpointActionResponse { - '@timestamp': string; - /** The id of the action for which this response is associated with */ - action_id: string; - /** The agent id that sent this action response */ - agent_id: string; - started_at: string; - completed_at: string; - error: string; - action_data: { - command: ISOLATION_ACTIONS; - comment?: string; - }; -} - export type HostIsolationRequestBody = TypeOf; export interface HostIsolationResponse { From 9129887bb76516f4d2f4cf407ee6131e01d92fd0 Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Thu, 27 May 2021 18:55:28 +0100 Subject: [PATCH 35/77] chore(NA): moving @kbn/monaco into bazel (#100709) * chore(NA): moving @kbn/monaco into bazel * chore(NA): update register globals definitions * chore(NA): remove build script Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../monorepo-packages.asciidoc | 8 +- package.json | 2 +- packages/BUILD.bazel | 1 + packages/kbn-babel-preset/BUILD.bazel | 1 + packages/kbn-monaco/BUILD.bazel | 108 ++++++++++++++++++ packages/kbn-monaco/package.json | 6 +- packages/kbn-monaco/scripts/build.js | 53 --------- packages/kbn-monaco/src/register_globals.ts | 6 +- packages/kbn-monaco/tsconfig.json | 8 +- packages/kbn-monaco/webpack.config.js | 2 +- packages/kbn-ui-shared-deps/package.json | 3 - yarn.lock | 2 +- 12 files changed, 128 insertions(+), 72 deletions(-) create mode 100644 packages/kbn-monaco/BUILD.bazel delete mode 100644 packages/kbn-monaco/scripts/build.js diff --git a/docs/developer/getting-started/monorepo-packages.asciidoc b/docs/developer/getting-started/monorepo-packages.asciidoc index 8f033029cfac4..4e8bbf76eaacb 100644 --- a/docs/developer/getting-started/monorepo-packages.asciidoc +++ b/docs/developer/getting-started/monorepo-packages.asciidoc @@ -82,10 +82,12 @@ yarn kbn watch-bazel - @kbn/i18n - @kbn/legacy-logging - @kbn/logging +- @kbn/mapbox-gl +- @kbn/monaco - @kbn/securitysolution-es-utils -- kbn/securitysolution-io-ts-alerting-types -- kbn/securitysolution-io-ts-list-types -- kbn/securitysolution-io-ts-types +- @kbn/securitysolution-io-ts-alerting-types +- @kbn/securitysolution-io-ts-list-types +- @kbn/securitysolution-io-ts-types - @kbn/securitysolution-io-ts-utils - @kbn/securitysolution-list-api - @kbn/securitysolution-list-constants diff --git a/package.json b/package.json index 936f985498ab1..1369b1d105aa4 100644 --- a/package.json +++ b/package.json @@ -136,7 +136,7 @@ "@kbn/io-ts-utils": "link:packages/kbn-io-ts-utils", "@kbn/legacy-logging": "link:bazel-bin/packages/kbn-legacy-logging/npm_module", "@kbn/logging": "link:bazel-bin/packages/kbn-logging/npm_module", - "@kbn/monaco": "link:packages/kbn-monaco", + "@kbn/monaco": "link:bazel-bin/packages/kbn-monaco/npm_module", "@kbn/securitysolution-list-constants": "link:bazel-bin/packages/kbn-securitysolution-list-constants/npm_module", "@kbn/securitysolution-es-utils": "link:bazel-bin/packages/kbn-securitysolution-es-utils/npm_module", "@kbn/securitysolution-io-ts-types": "link:bazel-bin/packages/kbn-securitysolution-io-ts-types/npm_module", diff --git a/packages/BUILD.bazel b/packages/BUILD.bazel index 43528e0ae4162..c885666f7a916 100644 --- a/packages/BUILD.bazel +++ b/packages/BUILD.bazel @@ -25,6 +25,7 @@ filegroup( "//packages/kbn-legacy-logging:build", "//packages/kbn-logging:build", "//packages/kbn-mapbox-gl:build", + "//packages/kbn-monaco:build", "//packages/kbn-plugin-generator:build", "//packages/kbn-securitysolution-list-constants:build", "//packages/kbn-securitysolution-io-ts-types:build", diff --git a/packages/kbn-babel-preset/BUILD.bazel b/packages/kbn-babel-preset/BUILD.bazel index 06b788010bdf5..f5ebc153b9e1a 100644 --- a/packages/kbn-babel-preset/BUILD.bazel +++ b/packages/kbn-babel-preset/BUILD.bazel @@ -34,6 +34,7 @@ DEPS = [ "@npm//@babel/preset-typescript", "@npm//babel-plugin-add-module-exports", "@npm//babel-plugin-styled-components", + "@npm//babel-plugin-transform-react-remove-prop-types", ] js_library( diff --git a/packages/kbn-monaco/BUILD.bazel b/packages/kbn-monaco/BUILD.bazel new file mode 100644 index 0000000000000..3a25568dfd811 --- /dev/null +++ b/packages/kbn-monaco/BUILD.bazel @@ -0,0 +1,108 @@ +load("@npm//@bazel/typescript:index.bzl", "ts_config", "ts_project") +load("@build_bazel_rules_nodejs//:index.bzl", "js_library", "pkg_npm") +load("@npm//webpack-cli:index.bzl", webpack = "webpack_cli") + +PKG_BASE_NAME = "kbn-monaco" +PKG_REQUIRE_NAME = "@kbn/monaco" + +SOURCE_FILES = glob( + [ + "src/**/*", + ], + exclude = [ + "**/*.test.*", + "**/README.md", + ], +) + +SRCS = SOURCE_FILES + +filegroup( + name = "srcs", + srcs = SRCS, +) + +NPM_MODULE_EXTRA_FILES = [ + "package.json", + "README.md" +] + +SRC_DEPS = [ + "//packages/kbn-babel-preset", + "//packages/kbn-i18n", + "@npm//antlr4ts", + "@npm//babel-loader", + "@npm//monaco-editor", + "@npm//raw-loader", + "@npm//regenerator-runtime", +] + +TYPES_DEPS = [ + "@npm//@types/jest", + "@npm//@types/node", +] + +DEPS = SRC_DEPS + TYPES_DEPS + +webpack( + name = "target_web", + data = DEPS + [ + ":src", + ":webpack.config.js", + ], + output_dir = True, + args = [ + "--config", + "$(location webpack.config.js)", + "--output-path", + "$(@D)", + "--env.prod", + "--display=minimal" + ], +) + +ts_config( + name = "tsconfig", + src = "tsconfig.json", + deps = [ + "//:tsconfig.base.json", + ], +) + +ts_project( + name = "tsc", + args = ['--pretty'], + srcs = SRCS, + deps = DEPS, + declaration = True, + declaration_dir = "target_types", + declaration_map = True, + incremental = True, + out_dir = "target_node", + source_map = True, + root_dir = ".", + tsconfig = ":tsconfig", +) + +js_library( + name = PKG_BASE_NAME, + srcs = NPM_MODULE_EXTRA_FILES, + deps = DEPS + [":target_web", ":tsc"], + package_name = PKG_REQUIRE_NAME, + visibility = ["//visibility:public"], +) + +pkg_npm( + name = "npm_module", + deps = [ + ":%s" % PKG_BASE_NAME, + ] +) + +filegroup( + name = "build", + srcs = [ + ":npm_module", + ], + visibility = ["//visibility:public"], +) diff --git a/packages/kbn-monaco/package.json b/packages/kbn-monaco/package.json index e818351e7e470..4f372d8ae62dd 100644 --- a/packages/kbn-monaco/package.json +++ b/packages/kbn-monaco/package.json @@ -2,12 +2,10 @@ "name": "@kbn/monaco", "version": "1.0.0", "private": true, - "main": "./target/index.js", - "types": "./target/index.d.ts", + "main": "target_node/src/index.js", + "types": "target_types/src/index.d.ts", "license": "SSPL-1.0 OR Elastic License 2.0", "scripts": { - "build": "node ./scripts/build.js", - "kbn:bootstrap": "yarn build --dev", "build:antlr4ts": "../../node_modules/antlr4ts-cli/antlr4ts ./src/painless/antlr/painless_lexer.g4 ./src/painless/antlr/painless_parser.g4 && node ./scripts/fix_generated_antlr.js" } } diff --git a/packages/kbn-monaco/scripts/build.js b/packages/kbn-monaco/scripts/build.js deleted file mode 100644 index 96159b4ad0dca..0000000000000 --- a/packages/kbn-monaco/scripts/build.js +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -const path = require('path'); -const del = require('del'); -const supportsColor = require('supports-color'); -const { run } = require('@kbn/dev-utils'); - -const TARGET_BUILD_DIR = path.resolve(__dirname, '../target'); -const ROOT_DIR = path.resolve(__dirname, '../'); -const WEBPACK_CONFIG_PATH = path.resolve(ROOT_DIR, 'webpack.config.js'); - -run( - async ({ procRunner, log, flags }) => { - log.info('Deleting old output'); - - await del(TARGET_BUILD_DIR); - - const cwd = ROOT_DIR; - const env = { ...process.env }; - if (supportsColor.stdout) { - env.FORCE_COLOR = 'true'; - } - - await procRunner.run('worker', { - cmd: 'webpack', - args: ['--config', WEBPACK_CONFIG_PATH, flags.dev ? '--env.dev' : '--env.prod'], - wait: true, - env, - cwd, - }); - - await procRunner.run('tsc ', { - cmd: 'tsc', - args: [], - wait: true, - env, - cwd, - }); - - log.success('Complete'); - }, - { - flags: { - boolean: ['dev'], - }, - } -); diff --git a/packages/kbn-monaco/src/register_globals.ts b/packages/kbn-monaco/src/register_globals.ts index a07d979e2022b..4047ddedeca42 100644 --- a/packages/kbn-monaco/src/register_globals.ts +++ b/packages/kbn-monaco/src/register_globals.ts @@ -11,11 +11,11 @@ import { PainlessLang } from './painless'; import { EsqlLang } from './esql'; import { monaco } from './monaco_imports'; // @ts-ignore -import xJsonWorkerSrc from '!!raw-loader!../target/public/xjson.editor.worker.js'; +import xJsonWorkerSrc from '!!raw-loader!../../target_web/xjson.editor.worker.js'; // @ts-ignore -import defaultWorkerSrc from '!!raw-loader!../target/public/default.editor.worker.js'; +import defaultWorkerSrc from '!!raw-loader!../../target_web/default.editor.worker.js'; // @ts-ignore -import painlessWorkerSrc from '!!raw-loader!../target/public/painless.editor.worker.js'; +import painlessWorkerSrc from '!!raw-loader!../../target_web/painless.editor.worker.js'; /** * Register languages and lexer rules diff --git a/packages/kbn-monaco/tsconfig.json b/packages/kbn-monaco/tsconfig.json index e6ec96b12c6cf..3c17118337899 100644 --- a/packages/kbn-monaco/tsconfig.json +++ b/packages/kbn-monaco/tsconfig.json @@ -1,10 +1,12 @@ { "extends": "../../tsconfig.base.json", "compilerOptions": { - "incremental": false, - "outDir": "./target", + "incremental": true, + "declarationDir": "./target_types", + "outDir": "./target_node", "declaration": true, "declarationMap": true, + "rootDir": ".", "sourceMap": true, "sourceRoot": "../../../../packages/kbn-monaco/src", "types": [ @@ -13,6 +15,6 @@ ] }, "include": [ - "src/**/*" + "src/**/*", ] } diff --git a/packages/kbn-monaco/webpack.config.js b/packages/kbn-monaco/webpack.config.js index 5ee00565e6494..d035134565463 100644 --- a/packages/kbn-monaco/webpack.config.js +++ b/packages/kbn-monaco/webpack.config.js @@ -18,7 +18,7 @@ const createLangWorkerConfig = (lang) => { mode: 'production', entry, output: { - path: path.resolve(__dirname, 'target/public'), + path: path.resolve(__dirname, 'target_web'), filename: `${lang}.editor.worker.js`, }, resolve: { diff --git a/packages/kbn-ui-shared-deps/package.json b/packages/kbn-ui-shared-deps/package.json index c284be4487a5f..162606585c43e 100644 --- a/packages/kbn-ui-shared-deps/package.json +++ b/packages/kbn-ui-shared-deps/package.json @@ -7,8 +7,5 @@ "build": "node scripts/build", "kbn:bootstrap": "node scripts/build --dev", "kbn:watch": "node scripts/build --dev --watch" - }, - "dependencies": { - "@kbn/monaco": "link:../kbn-monaco" } } \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 24f80c7dcb7b5..3add4843d0966 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2682,7 +2682,7 @@ version "0.0.0" uid "" -"@kbn/monaco@link:packages/kbn-monaco": +"@kbn/monaco@link:bazel-bin/packages/kbn-monaco/npm_module": version "0.0.0" uid "" From 84206053526e81aa260bf3372f4d06f7911f4ee6 Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Thu, 27 May 2021 12:32:13 -0600 Subject: [PATCH 36/77] [Maps] timeslider (#99661) * [Maps timeslider] * just arrowLeft and arrowRight icons * tslint * color icon when timeslider is open, auto select first section on open * increase width to prevent timeslider from changing sizes during interaction * fix filters disappearing when timeslice advances * use shorter date format for ticks * review feedback * do not show timeslider button when map is embedded Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../data_request_descriptor_types.ts | 6 + .../maps/public/actions/map_actions.test.js | 3 + .../maps/public/actions/map_actions.ts | 31 +- .../plugins/maps/public/actions/ui_actions.ts | 20 +- .../classes/layers/vector_layer/utils.tsx | 1 + .../classes/sources/es_source/es_source.ts | 9 +- .../sources/vector_source/vector_source.tsx | 2 + .../classes/util/can_skip_fetch.test.js | 318 ++++++++++++++++++ .../public/classes/util/can_skip_fetch.ts | 3 + .../public/connected_components/_index.scss | 1 + .../map_container/index.ts | 2 + .../map_container/map_container.tsx | 48 ++- .../timeslider/_index.scss | 89 +++++ .../connected_components/timeslider/index.ts | 42 +++ .../timeslider/time_utils.test.ts | 30 ++ .../timeslider/time_utils.ts | 84 +++++ .../timeslider/timeslider.tsx | 176 ++++++++++ .../toolbar_overlay.test.tsx.snap | 10 +- .../fit_to_data/fit_to_data.tsx | 77 +---- .../toolbar_overlay/fit_to_data/index.ts | 5 +- .../clock_play_icon.tsx | 36 ++ .../timeslider_toggle_button/index.ts | 34 ++ .../timeslider_toggle_button.tsx | 49 +++ .../toolbar_overlay/toolbar_overlay.test.tsx | 10 +- .../toolbar_overlay/toolbar_overlay.tsx | 41 ++- .../maps/public/embeddable/map_embeddable.tsx | 5 + .../reducers/map/default_map_settings.ts | 1 + .../plugins/maps/public/reducers/map/map.ts | 11 +- .../plugins/maps/public/reducers/map/types.ts | 3 + x-pack/plugins/maps/public/reducers/ui.ts | 5 + .../public/selectors/map_selectors.test.ts | 3 + .../maps/public/selectors/map_selectors.ts | 5 + .../maps/public/selectors/ui_selectors.ts | 1 + 33 files changed, 1064 insertions(+), 97 deletions(-) create mode 100644 x-pack/plugins/maps/public/connected_components/timeslider/_index.scss create mode 100644 x-pack/plugins/maps/public/connected_components/timeslider/index.ts create mode 100644 x-pack/plugins/maps/public/connected_components/timeslider/time_utils.test.ts create mode 100644 x-pack/plugins/maps/public/connected_components/timeslider/time_utils.ts create mode 100644 x-pack/plugins/maps/public/connected_components/timeslider/timeslider.tsx create mode 100644 x-pack/plugins/maps/public/connected_components/toolbar_overlay/timeslider_toggle_button/clock_play_icon.tsx create mode 100644 x-pack/plugins/maps/public/connected_components/toolbar_overlay/timeslider_toggle_button/index.ts create mode 100644 x-pack/plugins/maps/public/connected_components/toolbar_overlay/timeslider_toggle_button/timeslider_toggle_button.tsx diff --git a/x-pack/plugins/maps/common/descriptor_types/data_request_descriptor_types.ts b/x-pack/plugins/maps/common/descriptor_types/data_request_descriptor_types.ts index e1f682678df4b..e65e19d7def48 100644 --- a/x-pack/plugins/maps/common/descriptor_types/data_request_descriptor_types.ts +++ b/x-pack/plugins/maps/common/descriptor_types/data_request_descriptor_types.ts @@ -13,6 +13,11 @@ import { RENDER_AS, SCALING_TYPES } from '../constants'; import { MapExtent, MapQuery } from './map_descriptor'; import { Filter, TimeRange } from '../../../../../src/plugins/data/common'; +export type Timeslice = { + from: number; + to: number; +}; + // Global map state passed to every layer. export type MapFilters = { buffer?: MapExtent; // extent with additional buffer @@ -22,6 +27,7 @@ export type MapFilters = { refreshTimerLastTriggeredAt?: string; searchSessionId?: string; timeFilters: TimeRange; + timeslice?: Timeslice; zoom: number; }; diff --git a/x-pack/plugins/maps/public/actions/map_actions.test.js b/x-pack/plugins/maps/public/actions/map_actions.test.js index fafafa6b6a071..77ce23594447f 100644 --- a/x-pack/plugins/maps/public/actions/map_actions.test.js +++ b/x-pack/plugins/maps/public/actions/map_actions.test.js @@ -271,6 +271,9 @@ describe('map_actions', () => { require('../selectors/map_selectors').getTimeFilters = () => { return timeFilters; }; + require('../selectors/map_selectors').getTimeslice = () => { + return undefined; + }; require('../selectors/map_selectors').getFilters = () => { return filters; }; diff --git a/x-pack/plugins/maps/public/actions/map_actions.ts b/x-pack/plugins/maps/public/actions/map_actions.ts index 4b2d5da31a242..32e17376acaa7 100644 --- a/x-pack/plugins/maps/public/actions/map_actions.ts +++ b/x-pack/plugins/maps/public/actions/map_actions.ts @@ -19,6 +19,7 @@ import { getWaitingForMapReadyLayerListRaw, getQuery, getTimeFilters, + getTimeslice, getLayerList, getSearchSessionId, getSearchSessionMapBuffer, @@ -53,6 +54,7 @@ import { MapCenterAndZoom, MapExtent, MapRefreshConfig, + Timeslice, } from '../../common/descriptor_types'; import { INITIAL_LOCATION } from '../../common/constants'; import { scaleBounds } from '../../common/elasticsearch_util'; @@ -226,17 +228,21 @@ function generateQueryTimestamp() { export function setQuery({ query, timeFilters, - filters = [], + timeslice, + filters, forceRefresh = false, searchSessionId, searchSessionMapBuffer, + clearTimeslice, }: { filters?: Filter[]; query?: Query; timeFilters?: TimeRange; + timeslice?: Timeslice; forceRefresh?: boolean; searchSessionId?: string; searchSessionMapBuffer?: MapExtent; + clearTimeslice?: boolean; }) { return async ( dispatch: ThunkDispatch, @@ -248,10 +254,24 @@ export function setQuery({ ? prevQuery.queryLastTriggeredAt : generateQueryTimestamp(); + const prevTimeFilters = getTimeFilters(getState()); + + function getNextTimeslice() { + if ( + clearTimeslice || + (timeFilters !== undefined && !_.isEqual(timeFilters, prevTimeFilters)) + ) { + return undefined; + } + + return timeslice ? timeslice : getTimeslice(getState()); + } + const nextQueryContext = { - timeFilters: timeFilters ? timeFilters : getTimeFilters(getState()), + timeFilters: timeFilters ? timeFilters : prevTimeFilters, + timeslice: getNextTimeslice(), query: { - ...(query ? query : getQuery(getState())), + ...(query ? query : prevQuery), // ensure query changes to trigger re-fetch when "Refresh" clicked queryLastTriggeredAt: forceRefresh ? generateQueryTimestamp() : prevTriggeredAt, }, @@ -261,8 +281,9 @@ export function setQuery({ }; const prevQueryContext = { - timeFilters: getTimeFilters(getState()), - query: getQuery(getState()), + timeFilters: prevTimeFilters, + timeslice: getTimeslice(getState()), + query: prevQuery, filters: getFilters(getState()), searchSessionId: getSearchSessionId(getState()), searchSessionMapBuffer: getSearchSessionMapBuffer(getState()), diff --git a/x-pack/plugins/maps/public/actions/ui_actions.ts b/x-pack/plugins/maps/public/actions/ui_actions.ts index f9c0e324aa5d8..7809c71d7f696 100644 --- a/x-pack/plugins/maps/public/actions/ui_actions.ts +++ b/x-pack/plugins/maps/public/actions/ui_actions.ts @@ -10,11 +10,12 @@ import { ThunkDispatch } from 'redux-thunk'; import { MapStoreState } from '../reducers/store'; import { getFlyoutDisplay } from '../selectors/ui_selectors'; import { FLYOUT_STATE } from '../reducers/ui'; -import { trackMapSettings } from './map_actions'; +import { setQuery, trackMapSettings } from './map_actions'; import { setSelectedLayer } from './layer_actions'; export const UPDATE_FLYOUT = 'UPDATE_FLYOUT'; export const SET_IS_LAYER_TOC_OPEN = 'SET_IS_LAYER_TOC_OPEN'; +export const SET_IS_TIME_SLIDER_OPEN = 'SET_IS_TIME_SLIDER_OPEN'; export const SET_FULL_SCREEN = 'SET_FULL_SCREEN'; export const SET_READ_ONLY = 'SET_READ_ONLY'; export const SET_OPEN_TOC_DETAILS = 'SET_OPEN_TOC_DETAILS'; @@ -87,3 +88,20 @@ export function hideTOCDetails(layerId: string) { layerId, }; } + +export function openTimeslider() { + return { + type: SET_IS_TIME_SLIDER_OPEN, + isTimesliderOpen: true, + }; +} + +export function closeTimeslider() { + return (dispatch: ThunkDispatch) => { + dispatch({ + type: SET_IS_TIME_SLIDER_OPEN, + isTimesliderOpen: false, + }); + dispatch(setQuery({ clearTimeslice: true })); + }; +} diff --git a/x-pack/plugins/maps/public/classes/layers/vector_layer/utils.tsx b/x-pack/plugins/maps/public/classes/layers/vector_layer/utils.tsx index a7ac9dd9cfb6a..5f42d80de9bbb 100644 --- a/x-pack/plugins/maps/public/classes/layers/vector_layer/utils.tsx +++ b/x-pack/plugins/maps/public/classes/layers/vector_layer/utils.tsx @@ -136,6 +136,7 @@ export async function getVectorSourceBounds({ sourceQuery: sourceQuery ? sourceQuery : undefined, query: dataFilters.query, timeFilters: dataFilters.timeFilters, + timeslice: dataFilters.timeslice, filters: dataFilters.filters, applyGlobalQuery: source.getApplyGlobalQuery(), applyGlobalTime: source.getApplyGlobalTime(), diff --git a/x-pack/plugins/maps/public/classes/sources/es_source/es_source.ts b/x-pack/plugins/maps/public/classes/sources/es_source/es_source.ts index 749e3d6058266..23bcd9baed8c0 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_source/es_source.ts +++ b/x-pack/plugins/maps/public/classes/sources/es_source/es_source.ts @@ -218,7 +218,14 @@ export class AbstractESSource extends AbstractVectorSource implements IESSource allFilters.push(extentFilter); } if (searchFilters.applyGlobalTime && (await this.isTimeAware())) { - const filter = getTimeFilter().createFilter(indexPattern, searchFilters.timeFilters); + const timeRange = searchFilters.timeslice + ? { + from: new Date(searchFilters.timeslice.from).toISOString(), + to: new Date(searchFilters.timeslice.to).toISOString(), + mode: 'absolute' as 'absolute', + } + : searchFilters.timeFilters; + const filter = getTimeFilter().createFilter(indexPattern, timeRange); if (filter) { allFilters.push(filter); } diff --git a/x-pack/plugins/maps/public/classes/sources/vector_source/vector_source.tsx b/x-pack/plugins/maps/public/classes/sources/vector_source/vector_source.tsx index da5a236a20936..eabc5c4314d62 100644 --- a/x-pack/plugins/maps/public/classes/sources/vector_source/vector_source.tsx +++ b/x-pack/plugins/maps/public/classes/sources/vector_source/vector_source.tsx @@ -15,6 +15,7 @@ import { ESSearchSourceResponseMeta, MapExtent, MapQuery, + Timeslice, VectorSourceRequestMeta, VectorSourceSyncMeta, } from '../../../../common/descriptor_types'; @@ -39,6 +40,7 @@ export interface BoundsFilters { query?: MapQuery; sourceQuery?: MapQuery; timeFilters: TimeRange; + timeslice?: Timeslice; } export interface IVectorSource extends ISource { diff --git a/x-pack/plugins/maps/public/classes/util/can_skip_fetch.test.js b/x-pack/plugins/maps/public/classes/util/can_skip_fetch.test.js index 1901b15e8f350..c13b2fd441cad 100644 --- a/x-pack/plugins/maps/public/classes/util/can_skip_fetch.test.js +++ b/x-pack/plugins/maps/public/classes/util/can_skip_fetch.test.js @@ -287,4 +287,322 @@ describe('canSkipSourceUpdate', () => { }); }); }); + + describe('isTimeAware', () => { + function createSourceMock() { + return { + isTimeAware: () => { + return true; + }, + isRefreshTimerAware: () => { + return false; + }, + isFilterByMapBounds: () => { + return false; + }, + isFieldAware: () => { + return false; + }, + isQueryAware: () => { + return false; + }, + isGeoGridPrecisionAware: () => { + return false; + }, + }; + } + + describe('applyGlobalTime', () => { + it('can not skip update when applyGlobalTime changes', async () => { + const canSkipUpdate = await canSkipSourceUpdate({ + source: createSourceMock(), + prevDataRequest: new DataRequest({ + dataId: SOURCE_DATA_REQUEST_ID, + dataMeta: { + applyGlobalTime: true, + }, + data: {}, + }), + nextMeta: { + applyGlobalTime: false, + }, + extentAware: false, + }); + + expect(canSkipUpdate).toBe(false); + }); + + it('can skip update when applyGlobalTime does not change', async () => { + const canSkipUpdate = await canSkipSourceUpdate({ + source: createSourceMock(), + prevDataRequest: new DataRequest({ + dataId: SOURCE_DATA_REQUEST_ID, + dataMeta: { + applyGlobalTime: true, + }, + data: {}, + }), + nextMeta: { + applyGlobalTime: true, + }, + extentAware: false, + }); + + expect(canSkipUpdate).toBe(true); + }); + }); + + describe('timeFilters', () => { + it('can not skip update when time range changes', async () => { + const canSkipUpdate = await canSkipSourceUpdate({ + source: createSourceMock(), + prevDataRequest: new DataRequest({ + dataId: SOURCE_DATA_REQUEST_ID, + dataMeta: { + applyGlobalTime: true, + timeFilters: { + from: 'now-15m', + to: 'now', + }, + }, + data: {}, + }), + nextMeta: { + applyGlobalTime: true, + timeFilters: { + from: 'now-7d', + to: 'now', + }, + }, + extentAware: false, + }); + + expect(canSkipUpdate).toBe(false); + }); + + it('can skip update when time range does not change', async () => { + const canSkipUpdate = await canSkipSourceUpdate({ + source: createSourceMock(), + prevDataRequest: new DataRequest({ + dataId: SOURCE_DATA_REQUEST_ID, + dataMeta: { + applyGlobalTime: true, + timeFilters: { + from: 'now-15m', + to: 'now', + }, + }, + data: {}, + }), + nextMeta: { + applyGlobalTime: true, + timeFilters: { + from: 'now-15m', + to: 'now', + }, + }, + extentAware: false, + }); + + expect(canSkipUpdate).toBe(true); + }); + + it('can skip update when time range changes but applyGlobalTime is false', async () => { + const canSkipUpdate = await canSkipSourceUpdate({ + source: createSourceMock(), + prevDataRequest: new DataRequest({ + dataId: SOURCE_DATA_REQUEST_ID, + dataMeta: { + applyGlobalTime: false, + timeFilters: { + from: 'now-15m', + to: 'now', + }, + }, + data: {}, + }), + nextMeta: { + applyGlobalTime: false, + timeFilters: { + from: 'now-7d', + to: 'now', + }, + }, + extentAware: false, + }); + + expect(canSkipUpdate).toBe(true); + }); + }); + + describe('timeslice', () => { + const mockSource = createSourceMock(); + it('can not skip update when timeslice changes (undefined => provided)', async () => { + const canSkipUpdate = await canSkipSourceUpdate({ + source: mockSource, + prevDataRequest: new DataRequest({ + dataId: SOURCE_DATA_REQUEST_ID, + dataMeta: { + applyGlobalTime: true, + timeFilters: { + from: 'now-7d', + to: 'now', + }, + }, + data: {}, + }), + nextMeta: { + applyGlobalTime: true, + timeFilters: { + from: 'now-7d', + to: 'now', + }, + timeslice: { + from: 0, + to: 1000, + }, + }, + extentAware: false, + }); + + expect(canSkipUpdate).toBe(false); + }); + + it('can not skip update when timeslice changes', async () => { + const canSkipUpdate = await canSkipSourceUpdate({ + source: mockSource, + prevDataRequest: new DataRequest({ + dataId: SOURCE_DATA_REQUEST_ID, + dataMeta: { + applyGlobalTime: true, + timeFilters: { + from: 'now-7d', + to: 'now', + }, + timeslice: { + from: 0, + to: 1000, + }, + }, + data: {}, + }), + nextMeta: { + applyGlobalTime: true, + timeFilters: { + from: 'now-7d', + to: 'now', + }, + timeslice: { + from: 1000, + to: 2000, + }, + }, + extentAware: false, + }); + + expect(canSkipUpdate).toBe(false); + }); + + it('can not skip update when timeslice changes (provided => undefined)', async () => { + const canSkipUpdate = await canSkipSourceUpdate({ + source: mockSource, + prevDataRequest: new DataRequest({ + dataId: SOURCE_DATA_REQUEST_ID, + dataMeta: { + applyGlobalTime: true, + timeFilters: { + from: 'now-7d', + to: 'now', + }, + timeslice: { + from: 0, + to: 1000, + }, + }, + data: {}, + }), + nextMeta: { + applyGlobalTime: true, + timeFilters: { + from: 'now-7d', + to: 'now', + }, + }, + extentAware: false, + }); + + expect(canSkipUpdate).toBe(false); + }); + + it('can skip update when timeslice does not change', async () => { + const canSkipUpdate = await canSkipSourceUpdate({ + source: mockSource, + prevDataRequest: new DataRequest({ + dataId: SOURCE_DATA_REQUEST_ID, + dataMeta: { + applyGlobalTime: true, + timeFilters: { + from: 'now-7d', + to: 'now', + }, + timeslice: { + from: 0, + to: 1000, + }, + }, + data: {}, + }), + nextMeta: { + applyGlobalTime: true, + timeFilters: { + from: 'now-7d', + to: 'now', + }, + timeslice: { + from: 0, + to: 1000, + }, + }, + extentAware: false, + }); + + expect(canSkipUpdate).toBe(true); + }); + + it('can skip update when timeslice changes but applyGlobalTime is false', async () => { + const canSkipUpdate = await canSkipSourceUpdate({ + source: mockSource, + prevDataRequest: new DataRequest({ + dataId: SOURCE_DATA_REQUEST_ID, + dataMeta: { + applyGlobalTime: false, + timeFilters: { + from: 'now-7d', + to: 'now', + }, + timeslice: { + from: 0, + to: 1000, + }, + }, + data: {}, + }), + nextMeta: { + applyGlobalTime: false, + timeFilters: { + from: 'now-7d', + to: 'now', + }, + timeslice: { + from: 1000, + to: 2000, + }, + }, + extentAware: false, + }); + + expect(canSkipUpdate).toBe(true); + }); + }); + }); }); diff --git a/x-pack/plugins/maps/public/classes/util/can_skip_fetch.ts b/x-pack/plugins/maps/public/classes/util/can_skip_fetch.ts index 575c99432f508..1f2678f40eecd 100644 --- a/x-pack/plugins/maps/public/classes/util/can_skip_fetch.ts +++ b/x-pack/plugins/maps/public/classes/util/can_skip_fetch.ts @@ -89,10 +89,12 @@ export async function canSkipSourceUpdate({ let updateDueToApplyGlobalTime = false; let updateDueToTime = false; + let updateDueToTimeslice = false; if (timeAware) { updateDueToApplyGlobalTime = prevMeta.applyGlobalTime !== nextMeta.applyGlobalTime; if (nextMeta.applyGlobalTime) { updateDueToTime = !_.isEqual(prevMeta.timeFilters, nextMeta.timeFilters); + updateDueToTimeslice = !_.isEqual(prevMeta.timeslice, nextMeta.timeslice); } } @@ -148,6 +150,7 @@ export async function canSkipSourceUpdate({ return ( !updateDueToApplyGlobalTime && !updateDueToTime && + !updateDueToTimeslice && !updateDueToRefreshTimer && !updateDueToExtentChange && !updateDueToFields && diff --git a/x-pack/plugins/maps/public/connected_components/_index.scss b/x-pack/plugins/maps/public/connected_components/_index.scss index 9a49dbe550efb..56fcdc9165974 100644 --- a/x-pack/plugins/maps/public/connected_components/_index.scss +++ b/x-pack/plugins/maps/public/connected_components/_index.scss @@ -1,4 +1,5 @@ @import 'map_container/map_container'; +@import 'timeslider/index'; @import 'edit_layer_panel/index'; @import 'right_side_controls/index'; @import 'toolbar_overlay/index'; diff --git a/x-pack/plugins/maps/public/connected_components/map_container/index.ts b/x-pack/plugins/maps/public/connected_components/map_container/index.ts index cda96792fc6d6..408137b6f23b3 100644 --- a/x-pack/plugins/maps/public/connected_components/map_container/index.ts +++ b/x-pack/plugins/maps/public/connected_components/map_container/index.ts @@ -13,6 +13,7 @@ import { getFlyoutDisplay, getIsFullScreen } from '../../selectors/ui_selectors' import { triggerRefreshTimer, cancelAllInFlightRequests, exitFullScreen } from '../../actions'; import { areLayersLoaded, + getLayerList, getRefreshConfig, getMapInitError, getMapSettings, @@ -30,6 +31,7 @@ function mapStateToProps(state: MapStoreState) { mapInitError: getMapInitError(state), indexPatternIds: getQueryableUniqueIndexPatternIds(state), settings: getMapSettings(state), + layerList: getLayerList(state), }; } diff --git a/x-pack/plugins/maps/public/connected_components/map_container/map_container.tsx b/x-pack/plugins/maps/public/connected_components/map_container/map_container.tsx index 9128cebf480ed..02374932a4c70 100644 --- a/x-pack/plugins/maps/public/connected_components/map_container/map_container.tsx +++ b/x-pack/plugins/maps/public/connected_components/map_container/map_container.tsx @@ -15,6 +15,7 @@ import { Filter } from 'src/plugins/data/public'; import { ActionExecutionContext, Action } from 'src/plugins/ui_actions/public'; import { MBMap } from '../mb_map'; import { RightSideControls } from '../right_side_controls'; +import { Timeslider } from '../timeslider'; import { ToolbarOverlay } from '../toolbar_overlay'; import { EditLayerPanel } from '../edit_layer_panel'; import { AddLayerPanel } from '../add_layer_panel'; @@ -29,6 +30,7 @@ import { registerLayerWizards } from '../../classes/layers/load_layer_wizards'; import { RenderToolTipContent } from '../../classes/tooltips/tooltip_property'; import { GeoFieldWithIndex } from '../../components/geo_field_with_index'; import { MapRefreshConfig } from '../../../common/descriptor_types'; +import { ILayer } from '../../classes/layers/layer'; const RENDER_COMPLETE_EVENT = 'renderComplete'; @@ -50,12 +52,15 @@ export interface Props { title?: string; description?: string; settings: MapSettings; + layerList: ILayer[]; } interface State { isInitialLoadRenderTimeoutComplete: boolean; domId: string; geoFields: GeoFieldWithIndex[]; + showFitToBoundsButton: boolean; + showTimesliderButton: boolean; } export class MapContainer extends Component { @@ -70,16 +75,22 @@ export class MapContainer extends Component { isInitialLoadRenderTimeoutComplete: false, domId: uuid(), geoFields: [], + showFitToBoundsButton: false, + showTimesliderButton: false, }; componentDidMount() { this._isMounted = true; this._setRefreshTimer(); + this._loadShowFitToBoundsButton(); + this._loadShowTimesliderButton(); registerLayerWizards(); } componentDidUpdate() { this._setRefreshTimer(); + this._loadShowFitToBoundsButton(); + this._loadShowTimesliderButton(); if (this.props.areLayersLoaded && !this._isInitalLoadRenderTimerStarted) { this._isInitalLoadRenderTimerStarted = true; this._startInitialLoadRenderTimer(); @@ -111,7 +122,36 @@ export class MapContainer extends Component { } }; - _loadGeoFields = async (nextIndexPatternIds: string[]) => { + async _loadShowFitToBoundsButton() { + const promises = this.props.layerList.map(async (layer) => { + return await layer.isFittable(); + }); + const showFitToBoundsButton = (await Promise.all(promises)).some((isFittable) => isFittable); + if (this._isMounted && this.state.showFitToBoundsButton !== showFitToBoundsButton) { + this.setState({ showFitToBoundsButton }); + } + } + + async _loadShowTimesliderButton() { + if (!this.props.settings.showTimesliderToggleButton) { + if (this.state.showTimesliderButton) { + this.setState({ showTimesliderButton: false }); + } + return; + } + + const promises = this.props.layerList.map(async (layer) => { + return await layer.isFilteredByGlobalTime(); + }); + const showTimesliderButton = (await Promise.all(promises)).some( + (isFilteredByGlobalTime) => isFilteredByGlobalTime + ); + if (this._isMounted && this.state.showTimesliderButton !== showTimesliderButton) { + this.setState({ showTimesliderButton }); + } + } + + async _loadGeoFields(nextIndexPatternIds: string[]) { if (_.isEqual(nextIndexPatternIds, this._prevIndexPatternIds)) { // all ready loaded index pattern ids return; @@ -143,7 +183,7 @@ export class MapContainer extends Component { } this.setState({ geoFields }); - }; + } _setRefreshTimer = () => { const { isPaused, interval } = this.props.refreshConfig; @@ -258,11 +298,15 @@ export class MapContainer extends Component { geoFields={this.state.geoFields} getFilterActions={getFilterActions} getActionContext={getActionContext} + showFitToBoundsButton={this.state.showFitToBoundsButton} + showTimesliderButton={this.state.showTimesliderButton} /> )} + + * { + align-items: center; + } +} + +.mapTimeslider__close { + position: absolute; + top: $euiSizeXS; + right: $euiSizeXS; +} + +.mapTimeslider__timeWindow { + display: flex; + flex: 1; + margin-right: $euiSizeS; + font-size: $euiFontSizeS; +} + +.mapTimeslider__controls { + margin-left: $euiSizeS; +} + +.mapTimeslider__innerPanel { + display: inline-flex; + // background: $euiColorLightestShade; + border-radius: $euiBorderRadiusSmall; + padding: $euiSizeXS; + display: inline-flex; + align-items: center; +} diff --git a/x-pack/plugins/maps/public/connected_components/timeslider/index.ts b/x-pack/plugins/maps/public/connected_components/timeslider/index.ts new file mode 100644 index 0000000000000..90d29f9ae0635 --- /dev/null +++ b/x-pack/plugins/maps/public/connected_components/timeslider/index.ts @@ -0,0 +1,42 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { AnyAction } from 'redux'; +import { ThunkDispatch } from 'redux-thunk'; +import { connect } from 'react-redux'; +import { Timeslider } from './timeslider'; +import { closeTimeslider, setQuery } from '../../actions'; +import { getTimeFilters } from '../../selectors/map_selectors'; +import { getIsTimesliderOpen } from '../../selectors/ui_selectors'; +import { MapStoreState } from '../../reducers/store'; +import { Timeslice } from '../../../common/descriptor_types'; + +function mapStateToProps(state: MapStoreState) { + return { + isTimesliderOpen: getIsTimesliderOpen(state), + timeRange: getTimeFilters(state), + }; +} + +function mapDispatchToProps(dispatch: ThunkDispatch) { + return { + closeTimeslider: () => { + dispatch(closeTimeslider()); + }, + setTimeslice: (timeslice: Timeslice) => { + dispatch( + setQuery({ + forceRefresh: false, + timeslice, + }) + ); + }, + }; +} + +const connected = connect(mapStateToProps, mapDispatchToProps)(Timeslider); +export { connected as Timeslider }; diff --git a/x-pack/plugins/maps/public/connected_components/timeslider/time_utils.test.ts b/x-pack/plugins/maps/public/connected_components/timeslider/time_utils.test.ts new file mode 100644 index 0000000000000..16973b5a84478 --- /dev/null +++ b/x-pack/plugins/maps/public/connected_components/timeslider/time_utils.test.ts @@ -0,0 +1,30 @@ +/* + * 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 { getInterval } from './time_utils'; + +describe('getInterval', () => { + test('should provide interval of 1 day for 7 day range', () => { + expect(getInterval(1617630946622, 1618235746622)).toBe(86400000); + }); + + test('should provide interval of 3 hours for 24 hour range', () => { + expect(getInterval(1618150382531, 1618236782531)).toBe(10800000); + }); + + test('should provide interval of 90 minues for 12 hour range', () => { + expect(getInterval(1618193892632, 1618237092632)).toBe(5400000); + }); + + test('should provide interval of 30 minues for 4 hour range', () => { + expect(getInterval(1618222509189, 1618236909189)).toBe(1800000); + }); + + test('should provide interval of 10 minues for 1 hour range', () => { + expect(getInterval(1618233266459, 1618236866459)).toBe(600000); + }); +}); diff --git a/x-pack/plugins/maps/public/connected_components/timeslider/time_utils.ts b/x-pack/plugins/maps/public/connected_components/timeslider/time_utils.ts new file mode 100644 index 0000000000000..7195851aafe2c --- /dev/null +++ b/x-pack/plugins/maps/public/connected_components/timeslider/time_utils.ts @@ -0,0 +1,84 @@ +/* + * 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 moment from 'moment-timezone'; +import { EuiRangeTick } from '@elastic/eui/src/components/form/range/range_ticks'; +import { calcAutoIntervalNear } from '../../../../../../src/plugins/data/common'; +import { getUiSettings } from '../../kibana_services'; + +function getTimezone() { + const detectedTimezone = moment.tz.guess(); + const dateFormatTZ = getUiSettings().get('dateFormat:tz', 'Browser'); + + return dateFormatTZ === 'Browser' ? detectedTimezone : dateFormatTZ; +} + +function getScaledDateFormat(interval: number): string { + if (interval >= moment.duration(1, 'y').asMilliseconds()) { + return 'YYYY'; + } + + if (interval >= moment.duration(1, 'd').asMilliseconds()) { + return 'MMM D'; + } + + if (interval >= moment.duration(6, 'h').asMilliseconds()) { + return 'Do HH'; + } + + if (interval >= moment.duration(1, 'h').asMilliseconds()) { + return 'HH:mm'; + } + + if (interval >= moment.duration(1, 'm').asMilliseconds()) { + return 'HH:mm'; + } + + if (interval >= moment.duration(1, 's').asMilliseconds()) { + return 'mm:ss'; + } + + return 'ss.SSS'; +} + +export function epochToKbnDateFormat(epoch: number): string { + const dateFormat = getUiSettings().get('dateFormat', 'MMM D, YYYY @ HH:mm:ss.SSS'); + const timezone = getTimezone(); + return moment.tz(epoch, timezone).format(dateFormat); +} + +export function getInterval(min: number, max: number, steps = 6): number { + const duration = max - min; + let interval = calcAutoIntervalNear(steps, duration).asMilliseconds(); + // Sometimes auto interval is not quite right and returns 2X or 3X requested ticks + // Adjust the interval to get closer to the requested number of ticks + const actualSteps = duration / interval; + if (actualSteps > steps * 1.5) { + const factor = Math.round(actualSteps / steps); + interval *= factor; + } else if (actualSteps < 5) { + interval *= 0.5; + } + return interval; +} + +export function getTicks(min: number, max: number, interval: number): EuiRangeTick[] { + const format = getScaledDateFormat(interval); + const timezone = getTimezone(); + + let tick = Math.ceil(min / interval) * interval; + const ticks: EuiRangeTick[] = []; + while (tick < max) { + ticks.push({ + value: tick, + label: moment.tz(tick, timezone).format(format), + }); + tick += interval; + } + + return ticks; +} diff --git a/x-pack/plugins/maps/public/connected_components/timeslider/timeslider.tsx b/x-pack/plugins/maps/public/connected_components/timeslider/timeslider.tsx new file mode 100644 index 0000000000000..0b7bcb115eb95 --- /dev/null +++ b/x-pack/plugins/maps/public/connected_components/timeslider/timeslider.tsx @@ -0,0 +1,176 @@ +/* + * 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 _ from 'lodash'; +import React, { Component } from 'react'; +import { EuiButtonIcon, EuiDualRange, EuiText } from '@elastic/eui'; +import { EuiRangeTick } from '@elastic/eui/src/components/form/range/range_ticks'; +import { i18n } from '@kbn/i18n'; +import { epochToKbnDateFormat, getInterval, getTicks } from './time_utils'; +import { TimeRange } from '../../../../../../src/plugins/data/common'; +import { getTimeFilter } from '../../kibana_services'; +import { Timeslice } from '../../../common/descriptor_types'; + +export interface Props { + closeTimeslider: () => void; + setTimeslice: (timeslice: Timeslice) => void; + isTimesliderOpen: boolean; + timeRange: TimeRange; +} + +interface State { + max: number; + min: number; + range: number; + timeslice: [number, number]; + ticks: EuiRangeTick[]; +} + +function prettyPrintTimeslice(timeslice: [number, number]) { + return `${epochToKbnDateFormat(timeslice[0])} - ${epochToKbnDateFormat(timeslice[1])}`; +} + +// Why Timeslider and KeyedTimeslider? +// Using react 'key' property to ensure new KeyedTimeslider instance whenever props.timeRange changes +export function Timeslider(props: Props) { + return props.isTimesliderOpen ? ( + + ) : null; +} + +class KeyedTimeslider extends Component { + private _isMounted: boolean = false; + + constructor(props: Props) { + super(props); + const timeRangeBounds = getTimeFilter().calculateBounds(props.timeRange); + if (timeRangeBounds.min === undefined || timeRangeBounds.max === undefined) { + throw new Error( + 'Unable to create Timeslider component, timeRangeBounds min or max are undefined' + ); + } + const min = timeRangeBounds.min.valueOf(); + const max = timeRangeBounds.max.valueOf(); + const interval = getInterval(min, max); + const timeslice: [number, number] = [min, max]; + + this.state = { + max, + min, + range: interval, + ticks: getTicks(min, max, interval), + timeslice, + }; + } + + componentWillUnmount() { + this._isMounted = false; + } + + componentDidMount() { + this._isMounted = true; + // auto-select range between first tick and second tick + this._onChange([this.state.ticks[0].value, this.state.ticks[1].value]); + } + + _doesTimesliceCoverTimerange() { + return this.state.timeslice[0] === this.state.min && this.state.timeslice[1] === this.state.max; + } + + _onDualControlChange = (value: [number | string, number | string]) => { + this.setState({ range: (value[1] as number) - (value[0] as number) }, () => { + this._onChange(value as [number, number]); + }); + }; + + _onChange = (value: [number, number]) => { + this.setState({ + timeslice: value, + }); + this._propagateChange(value); + }; + + _onNext = () => { + const from = + this._doesTimesliceCoverTimerange() || this.state.timeslice[1] === this.state.max + ? this.state.ticks[0].value + : this.state.timeslice[1]; + const to = from + this.state.range; + this._onChange([from, to <= this.state.max ? to : this.state.max]); + }; + + _onPrevious = () => { + const to = + this._doesTimesliceCoverTimerange() || this.state.timeslice[0] === this.state.min + ? this.state.ticks[this.state.ticks.length - 1].value + : this.state.timeslice[0]; + const from = to - this.state.range; + this._onChange([from < this.state.min ? this.state.min : from, to]); + }; + + _propagateChange = _.debounce((value: [number, number]) => { + if (this._isMounted) { + this.props.setTimeslice({ from: value[0], to: value[1] }); + } + }, 300); + + render() { + return ( +
    +
    + + +
    + {prettyPrintTimeslice(this.state.timeslice)} +
    + +
    +
    + + +
    +
    +
    + +
    + +
    +
    + ); + } +} diff --git a/x-pack/plugins/maps/public/connected_components/toolbar_overlay/__snapshots__/toolbar_overlay.test.tsx.snap b/x-pack/plugins/maps/public/connected_components/toolbar_overlay/__snapshots__/toolbar_overlay.test.tsx.snap index 506767fcd4706..168a070b07744 100644 --- a/x-pack/plugins/maps/public/connected_components/toolbar_overlay/__snapshots__/toolbar_overlay.test.tsx.snap +++ b/x-pack/plugins/maps/public/connected_components/toolbar_overlay/__snapshots__/toolbar_overlay.test.tsx.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Must render zoom tools 1`] = ` +exports[`Should only show set view control 1`] = `
    - - -
    `; -exports[`Must zoom tools and draw filter tools 1`] = ` +exports[`Should show all controls 1`] = ` + + + `; diff --git a/x-pack/plugins/maps/public/connected_components/toolbar_overlay/fit_to_data/fit_to_data.tsx b/x-pack/plugins/maps/public/connected_components/toolbar_overlay/fit_to_data/fit_to_data.tsx index 64e163cd96a92..f975bc293d823 100644 --- a/x-pack/plugins/maps/public/connected_components/toolbar_overlay/fit_to_data/fit_to_data.tsx +++ b/x-pack/plugins/maps/public/connected_components/toolbar_overlay/fit_to_data/fit_to_data.tsx @@ -9,68 +9,27 @@ import React from 'react'; import { EuiButtonIcon, EuiPanel } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { ILayer } from '../../../classes/layers/layer'; export interface Props { - layerList: ILayer[]; fitToBounds: () => void; } -interface State { - canFit: boolean; -} - -export class FitToData extends React.Component { - _isMounted: boolean = false; - - state = { canFit: false }; - - componentDidMount(): void { - this._isMounted = true; - this._loadCanFit(); - } - - componentWillUnmount(): void { - this._isMounted = false; - } - - componentDidUpdate(): void { - this._loadCanFit(); - } - - async _loadCanFit() { - const promises = this.props.layerList.map(async (layer) => { - return await layer.isFittable(); - }); - const canFit = (await Promise.all(promises)).some((isFittable) => isFittable); - if (this._isMounted && this.state.canFit !== canFit) { - this.setState({ - canFit, - }); - } - } - - render() { - if (!this.state.canFit) { - return null; - } - - return ( - - - - ); - } +export function FitToData(props: Props) { + return ( + + + + ); } diff --git a/x-pack/plugins/maps/public/connected_components/toolbar_overlay/fit_to_data/index.ts b/x-pack/plugins/maps/public/connected_components/toolbar_overlay/fit_to_data/index.ts index 99fddff5153b4..b4322c93097f0 100644 --- a/x-pack/plugins/maps/public/connected_components/toolbar_overlay/fit_to_data/index.ts +++ b/x-pack/plugins/maps/public/connected_components/toolbar_overlay/fit_to_data/index.ts @@ -10,13 +10,10 @@ import { ThunkDispatch } from 'redux-thunk'; import { connect } from 'react-redux'; import { MapStoreState } from '../../../reducers/store'; import { fitToDataBounds } from '../../../actions'; -import { getLayerList } from '../../../selectors/map_selectors'; import { FitToData } from './fit_to_data'; function mapStateToProps(state: MapStoreState) { - return { - layerList: getLayerList(state), - }; + return {}; } function mapDispatchToProps(dispatch: ThunkDispatch) { diff --git a/x-pack/plugins/maps/public/connected_components/toolbar_overlay/timeslider_toggle_button/clock_play_icon.tsx b/x-pack/plugins/maps/public/connected_components/toolbar_overlay/timeslider_toggle_button/clock_play_icon.tsx new file mode 100644 index 0000000000000..bc24889d2ec2c --- /dev/null +++ b/x-pack/plugins/maps/public/connected_components/toolbar_overlay/timeslider_toggle_button/clock_play_icon.tsx @@ -0,0 +1,36 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { FunctionComponent } from 'react'; + +interface Props { + title?: string; + titleId?: string; +} + +export const ClockPlayIcon: FunctionComponent = ({ title, titleId, ...props }) => ( + + {title ? {title} : null} + + + + +); diff --git a/x-pack/plugins/maps/public/connected_components/toolbar_overlay/timeslider_toggle_button/index.ts b/x-pack/plugins/maps/public/connected_components/toolbar_overlay/timeslider_toggle_button/index.ts new file mode 100644 index 0000000000000..b31747f7e6a9f --- /dev/null +++ b/x-pack/plugins/maps/public/connected_components/toolbar_overlay/timeslider_toggle_button/index.ts @@ -0,0 +1,34 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { AnyAction } from 'redux'; +import { ThunkDispatch } from 'redux-thunk'; +import { connect } from 'react-redux'; +import { TimesliderToggleButton } from './timeslider_toggle_button'; +import { closeTimeslider, openTimeslider } from '../../../actions'; +import { getIsTimesliderOpen } from '../../../selectors/ui_selectors'; +import { MapStoreState } from '../../../reducers/store'; + +function mapStateToProps(state: MapStoreState) { + return { + isTimesliderOpen: getIsTimesliderOpen(state), + }; +} + +function mapDispatchToProps(dispatch: ThunkDispatch) { + return { + closeTimeslider: () => { + dispatch(closeTimeslider()); + }, + openTimeslider: () => { + dispatch(openTimeslider()); + }, + }; +} + +const connected = connect(mapStateToProps, mapDispatchToProps)(TimesliderToggleButton); +export { connected as TimesliderToggleButton }; diff --git a/x-pack/plugins/maps/public/connected_components/toolbar_overlay/timeslider_toggle_button/timeslider_toggle_button.tsx b/x-pack/plugins/maps/public/connected_components/toolbar_overlay/timeslider_toggle_button/timeslider_toggle_button.tsx new file mode 100644 index 0000000000000..9332c2baaa502 --- /dev/null +++ b/x-pack/plugins/maps/public/connected_components/toolbar_overlay/timeslider_toggle_button/timeslider_toggle_button.tsx @@ -0,0 +1,49 @@ +/* + * 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 { i18n } from '@kbn/i18n'; +import { EuiButtonIcon, EuiPanel } from '@elastic/eui'; +import { ClockPlayIcon } from './clock_play_icon'; + +export interface Props { + isTimesliderOpen: boolean; + openTimeslider: () => void; + closeTimeslider: () => void; +} + +export function TimesliderToggleButton(props: Props) { + function onClick() { + if (props.isTimesliderOpen) { + props.closeTimeslider(); + } else { + props.openTimeslider(); + } + } + + const label = props.isTimesliderOpen + ? i18n.translate('xpack.maps.timesliderToggleButton.closeLabel', { + defaultMessage: 'Close timeslider', + }) + : i18n.translate('xpack.maps.timesliderToggleButton.openLabel', { + defaultMessage: 'Open timeslider', + }); + + return ( + + + + ); +} diff --git a/x-pack/plugins/maps/public/connected_components/toolbar_overlay/toolbar_overlay.test.tsx b/x-pack/plugins/maps/public/connected_components/toolbar_overlay/toolbar_overlay.test.tsx index d8ac971ae3983..28b5ab9c78f40 100644 --- a/x-pack/plugins/maps/public/connected_components/toolbar_overlay/toolbar_overlay.test.tsx +++ b/x-pack/plugins/maps/public/connected_components/toolbar_overlay/toolbar_overlay.test.tsx @@ -19,12 +19,14 @@ jest.mock('../../kibana_services', () => { import { ToolbarOverlay } from './toolbar_overlay'; -test('Must render zoom tools', async () => { - const component = shallow(); +test('Should only show set view control', async () => { + const component = shallow( + + ); expect(component).toMatchSnapshot(); }); -test('Must zoom tools and draw filter tools', async () => { +test('Should show all controls', async () => { const geoFieldWithIndex = { geoFieldName: 'myGeoFieldName', geoFieldType: 'geo_point', @@ -35,6 +37,8 @@ test('Must zoom tools and draw filter tools', async () => { {}} geoFields={[geoFieldWithIndex]} + showFitToBoundsButton={true} + showTimesliderButton={true} /> ); expect(component).toMatchSnapshot(); diff --git a/x-pack/plugins/maps/public/connected_components/toolbar_overlay/toolbar_overlay.tsx b/x-pack/plugins/maps/public/connected_components/toolbar_overlay/toolbar_overlay.tsx index c5208bc254fc8..41c6c1f7c4a7c 100644 --- a/x-pack/plugins/maps/public/connected_components/toolbar_overlay/toolbar_overlay.tsx +++ b/x-pack/plugins/maps/public/connected_components/toolbar_overlay/toolbar_overlay.tsx @@ -12,6 +12,7 @@ import { ActionExecutionContext, Action } from 'src/plugins/ui_actions/public'; import { SetViewControl } from './set_view_control'; import { ToolsControl } from './tools_control'; import { FitToData } from './fit_to_data'; +import { TimesliderToggleButton } from './timeslider_toggle_button'; import { GeoFieldWithIndex } from '../../components/geo_field_with_index'; export interface Props { @@ -19,25 +20,33 @@ export interface Props { geoFields: GeoFieldWithIndex[]; getFilterActions?: () => Promise; getActionContext?: () => ActionExecutionContext; + showFitToBoundsButton: boolean; + showTimesliderButton: boolean; } export function ToolbarOverlay(props: Props) { - function renderToolsControl() { - const { addFilters, geoFields, getFilterActions, getActionContext } = props; - if (!addFilters || !geoFields.length) { - return null; - } - - return ( + const toolsButton = + props.addFilters && props.geoFields.length ? ( - ); - } + ) : null; + + const fitToBoundsButton = props.showFitToBoundsButton ? ( + + + + ) : null; + + const timesliderToogleButon = props.showTimesliderButton ? ( + + + + ) : null; return ( - - - + {fitToBoundsButton} + + {toolsButton} - {renderToolsControl()} + {timesliderToogleButon} ); } diff --git a/x-pack/plugins/maps/public/embeddable/map_embeddable.tsx b/x-pack/plugins/maps/public/embeddable/map_embeddable.tsx index 65fdbca328542..f9eae1c90a164 100644 --- a/x-pack/plugins/maps/public/embeddable/map_embeddable.tsx +++ b/x-pack/plugins/maps/public/embeddable/map_embeddable.tsx @@ -162,6 +162,11 @@ export class MapEmbeddable const store = this._savedMap.getStore(); store.dispatch(setReadOnly(true)); store.dispatch(disableScrollZoom()); + store.dispatch( + setMapSettings({ + showTimesliderToggleButton: false, + }) + ); this._dispatchSetQuery({ forceRefresh: false, diff --git a/x-pack/plugins/maps/public/reducers/map/default_map_settings.ts b/x-pack/plugins/maps/public/reducers/map/default_map_settings.ts index 8ecaa8dfc2bf5..c73bf46d4bc0c 100644 --- a/x-pack/plugins/maps/public/reducers/map/default_map_settings.ts +++ b/x-pack/plugins/maps/public/reducers/map/default_map_settings.ts @@ -25,6 +25,7 @@ export function getDefaultMapSettings(): MapSettings { minZoom: MIN_ZOOM, showScaleControl: false, showSpatialFilters: true, + showTimesliderToggleButton: true, spatialFiltersAlpa: 0.3, spatialFiltersFillColor: '#DA8B45', spatialFiltersLineColor: '#DA8B45', diff --git a/x-pack/plugins/maps/public/reducers/map/map.ts b/x-pack/plugins/maps/public/reducers/map/map.ts index daeba8e9982b0..591215efcddae 100644 --- a/x-pack/plugins/maps/public/reducers/map/map.ts +++ b/x-pack/plugins/maps/public/reducers/map/map.ts @@ -73,6 +73,7 @@ export const DEFAULT_MAP_STATE: MapState = { extent: undefined, mouseCoordinates: undefined, timeFilters: undefined, + timeslice: undefined, query: undefined, filters: [], refreshConfig: undefined, @@ -218,13 +219,21 @@ export function map(state: MapState = DEFAULT_MAP_STATE, action: any) { }; return { ...state, mapState: { ...state.mapState, ...newMapState } }; case SET_QUERY: - const { query, timeFilters, filters, searchSessionId, searchSessionMapBuffer } = action; + const { + query, + timeFilters, + timeslice, + filters, + searchSessionId, + searchSessionMapBuffer, + } = action; return { ...state, mapState: { ...state.mapState, query, timeFilters, + timeslice, filters, searchSessionId, searchSessionMapBuffer, diff --git a/x-pack/plugins/maps/public/reducers/map/types.ts b/x-pack/plugins/maps/public/reducers/map/types.ts index 6b10b4a66fb61..e8dd7261e3dd3 100644 --- a/x-pack/plugins/maps/public/reducers/map/types.ts +++ b/x-pack/plugins/maps/public/reducers/map/types.ts @@ -15,6 +15,7 @@ import { MapExtent, MapQuery, MapRefreshConfig, + Timeslice, TooltipState, } from '../../../common/descriptor_types'; import { INITIAL_LOCATION } from '../../../common/constants'; @@ -31,6 +32,7 @@ export type MapContext = { lon: number; }; timeFilters?: TimeRange; + timeslice?: Timeslice; query?: MapQuery; filters: Filter[]; refreshConfig?: MapRefreshConfig; @@ -61,6 +63,7 @@ export type MapSettings = { minZoom: number; showScaleControl: boolean; showSpatialFilters: boolean; + showTimesliderToggleButton: boolean; spatialFiltersAlpa: number; spatialFiltersFillColor: string; spatialFiltersLineColor: string; diff --git a/x-pack/plugins/maps/public/reducers/ui.ts b/x-pack/plugins/maps/public/reducers/ui.ts index 676ac6ce12efe..9f948ce3d6473 100644 --- a/x-pack/plugins/maps/public/reducers/ui.ts +++ b/x-pack/plugins/maps/public/reducers/ui.ts @@ -12,6 +12,7 @@ import { getMapsCapabilities } from '../kibana_services'; import { UPDATE_FLYOUT, SET_IS_LAYER_TOC_OPEN, + SET_IS_TIME_SLIDER_OPEN, SET_FULL_SCREEN, SET_READ_ONLY, SET_OPEN_TOC_DETAILS, @@ -31,6 +32,7 @@ export type MapUiState = { isFullScreen: boolean; isReadOnly: boolean; isLayerTOCOpen: boolean; + isTimesliderOpen: boolean; openTOCDetails: string[]; }; @@ -41,6 +43,7 @@ export const DEFAULT_MAP_UI_STATE = { isFullScreen: false, isReadOnly: !getMapsCapabilities().save, isLayerTOCOpen: DEFAULT_IS_LAYER_TOC_OPEN, + isTimesliderOpen: false, // storing TOC detail visibility outside of map.layerList because its UI state and not map rendering state. // This also makes for easy read/write access for embeddables. openTOCDetails: [], @@ -53,6 +56,8 @@ export function ui(state: MapUiState = DEFAULT_MAP_UI_STATE, action: any) { return { ...state, flyoutDisplay: action.display }; case SET_IS_LAYER_TOC_OPEN: return { ...state, isLayerTOCOpen: action.isLayerTOCOpen }; + case SET_IS_TIME_SLIDER_OPEN: + return { ...state, isTimesliderOpen: action.isTimesliderOpen }; case SET_FULL_SCREEN: return { ...state, isFullScreen: action.isFullScreen }; case SET_READ_ONLY: 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 a7374650d0451..cf739957a3993 100644 --- a/x-pack/plugins/maps/public/selectors/map_selectors.test.ts +++ b/x-pack/plugins/maps/public/selectors/map_selectors.test.ts @@ -57,6 +57,7 @@ describe('getDataFilters', () => { }; const mapZoom = 4; const timeFilters = { to: '2001-01-01', from: '2001-12-31' }; + const timeslice = undefined; const refreshTimerLastTriggeredAt = '2001-01-01T00:00:00'; const query = undefined; const filters: Filter[] = []; @@ -74,6 +75,7 @@ describe('getDataFilters', () => { mapBuffer, mapZoom, timeFilters, + timeslice, refreshTimerLastTriggeredAt, query, filters, @@ -89,6 +91,7 @@ describe('getDataFilters', () => { mapBuffer, mapZoom, timeFilters, + timeslice, refreshTimerLastTriggeredAt, query, filters, diff --git a/x-pack/plugins/maps/public/selectors/map_selectors.ts b/x-pack/plugins/maps/public/selectors/map_selectors.ts index 4f3bfbe303cb9..5be14737cff15 100644 --- a/x-pack/plugins/maps/public/selectors/map_selectors.ts +++ b/x-pack/plugins/maps/public/selectors/map_selectors.ts @@ -176,6 +176,8 @@ export const getMouseCoordinates = ({ map }: MapStoreState) => map.mapState.mous export const getTimeFilters = ({ map }: MapStoreState): TimeRange => map.mapState.timeFilters ? map.mapState.timeFilters : getTimeFilter().getTime(); +export const getTimeslice = ({ map }: MapStoreState) => map.mapState.timeslice; + export const getQuery = ({ map }: MapStoreState): MapQuery | undefined => map.mapState.query; export const getFilters = ({ map }: MapStoreState): Filter[] => map.mapState.filters; @@ -234,6 +236,7 @@ export const getDataFilters = createSelector( getMapBuffer, getMapZoom, getTimeFilters, + getTimeslice, getRefreshTimerLastTriggeredAt, getQuery, getFilters, @@ -244,6 +247,7 @@ export const getDataFilters = createSelector( mapBuffer, mapZoom, timeFilters, + timeslice, refreshTimerLastTriggeredAt, query, filters, @@ -255,6 +259,7 @@ export const getDataFilters = createSelector( buffer: searchSessionId && searchSessionMapBuffer ? searchSessionMapBuffer : mapBuffer, zoom: mapZoom, timeFilters, + timeslice, refreshTimerLastTriggeredAt, query, filters, diff --git a/x-pack/plugins/maps/public/selectors/ui_selectors.ts b/x-pack/plugins/maps/public/selectors/ui_selectors.ts index e5c83bd0f8f4a..c9ec8bac6d83a 100644 --- a/x-pack/plugins/maps/public/selectors/ui_selectors.ts +++ b/x-pack/plugins/maps/public/selectors/ui_selectors.ts @@ -11,6 +11,7 @@ import { FLYOUT_STATE } from '../reducers/ui'; export const getFlyoutDisplay = ({ ui }: MapStoreState): FLYOUT_STATE => ui.flyoutDisplay; export const getIsLayerTOCOpen = ({ ui }: MapStoreState): boolean => ui.isLayerTOCOpen; +export const getIsTimesliderOpen = ({ ui }: MapStoreState): boolean => ui.isTimesliderOpen; export const getOpenTOCDetails = ({ ui }: MapStoreState): string[] => ui.openTOCDetails; export const getIsFullScreen = ({ ui }: MapStoreState): boolean => ui.isFullScreen; export const getIsReadOnly = ({ ui }: MapStoreState): boolean => ui.isReadOnly; From f0e11bcd1be8b327896908f5614e2b0dae66808d Mon Sep 17 00:00:00 2001 From: Jonathan Budzenski Date: Thu, 27 May 2021 13:37:43 -0500 Subject: [PATCH 37/77] Automated package testing (#88900) Co-authored-by: Tyler Smalley Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .ci/package-testing/Jenkinsfile | 29 + .gitignore | 1 + .../development-package-tests.asciidoc | 64 + .../contributing/development-tests.asciidoc | 3 + src/dev/precommit_hook/casing_check_config.js | 1 + test/package/Vagrantfile | 27 + test/package/deb.yml | 11 + test/package/docker.yml | 7 + test/package/group_vars/all.yml | 2 + .../assert_keystore_available/tasks/main.yml | 13 + .../roles/assert_keystore_cli/tasks/main.yml | 22 + .../assert_kibana_available/tasks/main.yml | 8 + .../roles/assert_kibana_data/tasks/main.yml | 13 + .../assert_kibana_listening/tasks/main.yml | 2 + .../roles/assert_kibana_log/tasks/main.yml | 27 + .../roles/assert_kibana_pid/tasks/main.yml | 27 + .../roles/assert_kibana_yml/tasks/main.yml | 27 + .../roles/install_docker/tasks/main.yml | 39 + .../roles/install_docker/vars/main.yml | 7 + .../roles/install_kibana_deb/tasks/main.yml | 34 + .../install_kibana_docker/tasks/main.yml | 26 + .../roles/install_kibana_rpm/tasks/main.yml | 45 + .../roles/upgrade_apt_packages/tasks/main.yml | 6 + .../roles/upgrade_yum_packages/tasks/main.yml | 6 + test/package/rpm.yml | 11 + test/package/templates/kibana.yml | 5 + test/scripts/jenkins_xpack_package_build.sh | 12 + test/scripts/jenkins_xpack_package_deb.sh | 25 + test/scripts/jenkins_xpack_package_docker.sh | 25 + test/scripts/jenkins_xpack_package_rpm.sh | 25 + vars/workers.groovy | 1 + .../test/functional/apps/reporting/index.ts | 14 + .../functional/apps/reporting/reporting.ts | 46 + x-pack/test/functional/config.js | 1 + .../es_archives/packaging/data.json.gz | Bin 0 -> 1644631 bytes .../es_archives/packaging/mappings.json | 2561 +++++++++++++++++ 36 files changed, 3173 insertions(+) create mode 100644 .ci/package-testing/Jenkinsfile create mode 100644 docs/developer/contributing/development-package-tests.asciidoc create mode 100644 test/package/Vagrantfile create mode 100644 test/package/deb.yml create mode 100644 test/package/docker.yml create mode 100644 test/package/group_vars/all.yml create mode 100644 test/package/roles/assert_keystore_available/tasks/main.yml create mode 100644 test/package/roles/assert_keystore_cli/tasks/main.yml create mode 100644 test/package/roles/assert_kibana_available/tasks/main.yml create mode 100644 test/package/roles/assert_kibana_data/tasks/main.yml create mode 100644 test/package/roles/assert_kibana_listening/tasks/main.yml create mode 100644 test/package/roles/assert_kibana_log/tasks/main.yml create mode 100644 test/package/roles/assert_kibana_pid/tasks/main.yml create mode 100644 test/package/roles/assert_kibana_yml/tasks/main.yml create mode 100644 test/package/roles/install_docker/tasks/main.yml create mode 100644 test/package/roles/install_docker/vars/main.yml create mode 100644 test/package/roles/install_kibana_deb/tasks/main.yml create mode 100644 test/package/roles/install_kibana_docker/tasks/main.yml create mode 100644 test/package/roles/install_kibana_rpm/tasks/main.yml create mode 100644 test/package/roles/upgrade_apt_packages/tasks/main.yml create mode 100644 test/package/roles/upgrade_yum_packages/tasks/main.yml create mode 100644 test/package/rpm.yml create mode 100644 test/package/templates/kibana.yml create mode 100755 test/scripts/jenkins_xpack_package_build.sh create mode 100755 test/scripts/jenkins_xpack_package_deb.sh create mode 100755 test/scripts/jenkins_xpack_package_docker.sh create mode 100755 test/scripts/jenkins_xpack_package_rpm.sh create mode 100644 x-pack/test/functional/apps/reporting/index.ts create mode 100644 x-pack/test/functional/apps/reporting/reporting.ts create mode 100644 x-pack/test/functional/es_archives/packaging/data.json.gz create mode 100644 x-pack/test/functional/es_archives/packaging/mappings.json diff --git a/.ci/package-testing/Jenkinsfile b/.ci/package-testing/Jenkinsfile new file mode 100644 index 0000000000000..b749c1fe2e9af --- /dev/null +++ b/.ci/package-testing/Jenkinsfile @@ -0,0 +1,29 @@ +#!/bin/groovy +library 'kibana-pipeline-library' +kibanaLibrary.load() +kibanaPipeline(timeoutMinutes: 300) { + slackNotifications.onFailure { + ciStats.trackBuild { + workers.ci(ramDisk: false, name: "package-build", size: 'l', runErrorReporter: false) { + withGcpServiceAccount.fromVaultSecret('secret/kibana-issues/dev/ci-artifacts-key', 'value') { + kibanaPipeline.bash("test/scripts/jenkins_xpack_package_build.sh", "Package builds") + } + } + def packageTypes = ['deb', 'docker', 'rpm'] + def workers = [:] + packageTypes.each { type -> + workers["package-${type}"] = { + testPackage(type) + } + } + parallel(workers) + } + } +} +def testPackage(packageType) { + workers.ci(ramDisk: false, name: "package-${packageType}", size: 's', runErrorReporter: false) { + withGcpServiceAccount.fromVaultSecret('secret/kibana-issues/dev/ci-artifacts-key', 'value') { + kibanaPipeline.bash("test/scripts/jenkins_xpack_package_${packageType}.sh", "Execute package testing for ${packageType}") + } + } +} diff --git a/.gitignore b/.gitignore index ce8fd38b18a92..f9855520cb110 100644 --- a/.gitignore +++ b/.gitignore @@ -60,6 +60,7 @@ npm-debug.log* .ci/runbld .ci/bash_standard_lib.sh .gradle +.vagrant ## @cypress/snapshot from apm plugin snapshots.js diff --git a/docs/developer/contributing/development-package-tests.asciidoc b/docs/developer/contributing/development-package-tests.asciidoc new file mode 100644 index 0000000000000..10c09d6cae8c0 --- /dev/null +++ b/docs/developer/contributing/development-package-tests.asciidoc @@ -0,0 +1,64 @@ +[[development-package-tests]] +== Package Testing + +Packaging tests use Vagrant virtual machines as hosts and Ansible for +provisioning and assertions. Kibana distributions are copied from the +target folder into each VM and installed, along with required +dependencies. + +=== Setup + +* https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html[Ansible] ++ +``` +# Ubuntu +sudo apt-get install python3-pip libarchive-tools +pip3 install --user ansible + +# Darwin +brew install python3 +pip3 install --user ansible +``` +* https://www.vagrantup.com/downloads[Vagrant] +* https://www.virtualbox.org/wiki/Downloads[Virtualbox] + +=== Machines + +[cols=",,",options="header",] +|=== +|Hostname |IP |Description +|deb |192.168.50.5 |Installation of Kibana’s deb package +|rpm |192.168.50.6 |Installation of Kibana’s rpm package +|docker |192.168.50.7 |Installation of Kibana’s docker image +|=== + +=== Running + +``` +# Build distributions +node scripts/build --all-platforms --debug --no-oss + +cd test/package + +# Setup virtual machine and networking +vagrant up --no-provision + +# Install Kibana and run OS level tests +# This step can be repeated when adding new tests, it ensures machine state - installations won't run twice +vagrant provision + +# Running functional tests +node scripts/es snapshot \ + -E network.bind_host=127.0.0.1,192.168.50.1 \ + -E discovery.type=single-node \ + --license=trial +TEST_KIBANA_URL=http://elastic:changeme@:5601 \ +TEST_ES_URL=http://elastic:changeme@192.168.50.1:9200 \ + node scripts/functional_test_runner.js --include-tag=smoke +``` + +=== Cleanup + +.... +vagrant destroy +.... diff --git a/docs/developer/contributing/development-tests.asciidoc b/docs/developer/contributing/development-tests.asciidoc index 715b1a15ab5ed..e7a36d2866728 100644 --- a/docs/developer/contributing/development-tests.asciidoc +++ b/docs/developer/contributing/development-tests.asciidoc @@ -74,6 +74,7 @@ to learn more about using the node scripts we provide for building * <> * <> * <> +* <> include::development-functional-tests.asciidoc[leveloffset=+1] @@ -81,6 +82,8 @@ include::development-unit-tests.asciidoc[leveloffset=+1] include::development-accessibility-tests.asciidoc[leveloffset=+1] +include::development-package-tests.asciidoc[leveloffset=+1] + [discrete] === Cross-browser compatibility diff --git a/src/dev/precommit_hook/casing_check_config.js b/src/dev/precommit_hook/casing_check_config.js index 0d5ecab40fbc4..d523f78a9f589 100644 --- a/src/dev/precommit_hook/casing_check_config.js +++ b/src/dev/precommit_hook/casing_check_config.js @@ -40,6 +40,7 @@ export const IGNORE_FILE_GLOBS = [ 'vars/*', '.ci/pipeline-library/**/*', 'packages/kbn-test/jest-preset.js', + 'test/package/Vagrantfile', // filename must match language code which requires capital letters '**/translations/*.json', diff --git a/test/package/Vagrantfile b/test/package/Vagrantfile new file mode 100644 index 0000000000000..34c29eb2cefe7 --- /dev/null +++ b/test/package/Vagrantfile @@ -0,0 +1,27 @@ +Vagrant.configure("2") do |config| + config.vm.synced_folder '../../target/', '/packages' + + config.vm.define "deb" do |deb| + deb.vm.box = 'elastic/debian-9-x86_64' + deb.vm.provision "ansible" do |ansible| + ansible.playbook = "deb.yml" + end + deb.vm.network "private_network", ip: "192.168.50.5" + end + + config.vm.define "rpm" do |rpm| + rpm.vm.box = 'elastic/centos-7-x86_64' + rpm.vm.provision "ansible" do |ansible| + ansible.playbook = "rpm.yml" + end + rpm.vm.network "private_network", ip: "192.168.50.6" + end + + config.vm.define "docker" do |docker| + docker.vm.box = 'elastic/ubuntu-18.04-x86_64' + docker.vm.provision "ansible" do |ansible| + ansible.playbook = "docker.yml" + end + docker.vm.network "private_network", ip: "192.168.50.7" + end +end diff --git a/test/package/deb.yml b/test/package/deb.yml new file mode 100644 index 0000000000000..294657e99473f --- /dev/null +++ b/test/package/deb.yml @@ -0,0 +1,11 @@ +- name: test kibana deb package + hosts: deb + roles: + - install_kibana_deb + - assert_keystore_available + - assert_keystore_cli + - assert_kibana_yml + - assert_kibana_listening + - assert_kibana_available + - assert_kibana_log + - assert_kibana_data diff --git a/test/package/docker.yml b/test/package/docker.yml new file mode 100644 index 0000000000000..6da20360c174a --- /dev/null +++ b/test/package/docker.yml @@ -0,0 +1,7 @@ +- name: test kibana docker package + hosts: docker + roles: + - install_docker + - install_kibana_docker + - assert_kibana_listening + - assert_kibana_available diff --git a/test/package/group_vars/all.yml b/test/package/group_vars/all.yml new file mode 100644 index 0000000000000..cedf02162271a --- /dev/null +++ b/test/package/group_vars/all.yml @@ -0,0 +1,2 @@ +elasticsearch_username: kibana_system +elasticsearch_password: changeme diff --git a/test/package/roles/assert_keystore_available/tasks/main.yml b/test/package/roles/assert_keystore_available/tasks/main.yml new file mode 100644 index 0000000000000..cc0b3c187aa27 --- /dev/null +++ b/test/package/roles/assert_keystore_available/tasks/main.yml @@ -0,0 +1,13 @@ +- name: stat + become: yes + register: keystore + stat: + path: /etc/kibana/kibana.keystore + +- name: 0660 root:kibana + assert: + that: + - keystore.stat.exists + - keystore.stat.mode == "0660" + - keystore.stat.pw_name == "root" + - keystore.stat.gr_name == "kibana" diff --git a/test/package/roles/assert_keystore_cli/tasks/main.yml b/test/package/roles/assert_keystore_cli/tasks/main.yml new file mode 100644 index 0000000000000..4ca2622aa5c01 --- /dev/null +++ b/test/package/roles/assert_keystore_cli/tasks/main.yml @@ -0,0 +1,22 @@ +- name: "add server.name: package-testing" + become: yes + command: + cmd: /usr/share/kibana/bin/kibana-keystore add server.name --stdin + stdin: package-testing + register: kibana_keystore_add + +- debug: + msg: "{{ kibana_keystore_add.stdout }}" + +- name: register kibana-keystore list + become: yes + command: /usr/share/kibana/bin/kibana-keystore list + register: kibana_keystore_list + +- debug: + msg: "{{ kibana_keystore_list.stdout }}" + +- name: assert kibana-keystore list contains server.name + assert: + that: + - kibana_keystore_list.stdout == "server.name" diff --git a/test/package/roles/assert_kibana_available/tasks/main.yml b/test/package/roles/assert_kibana_available/tasks/main.yml new file mode 100644 index 0000000000000..b096f9b87350d --- /dev/null +++ b/test/package/roles/assert_kibana_available/tasks/main.yml @@ -0,0 +1,8 @@ +- name: "localhost:5601/api/status" + uri: + url: "http://localhost:5601/api/status" + status_code: [200, 401] + register: result + until: result.status != 503 + retries: 3 + delay: 30 diff --git a/test/package/roles/assert_kibana_data/tasks/main.yml b/test/package/roles/assert_kibana_data/tasks/main.yml new file mode 100644 index 0000000000000..76fba22e3697a --- /dev/null +++ b/test/package/roles/assert_kibana_data/tasks/main.yml @@ -0,0 +1,13 @@ +- name: stat /var/lib/kibana + become: yes + register: kibana_data_directory + stat: + path: /var/lib/kibana + +- name: /var/lib/kibana 2750 kibana:kibana + assert: + that: + - kibana_log_directory.stat.exists + - kibana_log_directory.stat.mode == "2750" + - kibana_log_directory.stat.pw_name == "kibana" + - kibana_log_directory.stat.gr_name == "kibana" diff --git a/test/package/roles/assert_kibana_listening/tasks/main.yml b/test/package/roles/assert_kibana_listening/tasks/main.yml new file mode 100644 index 0000000000000..3c072ce426404 --- /dev/null +++ b/test/package/roles/assert_kibana_listening/tasks/main.yml @@ -0,0 +1,2 @@ +- name: localhost:5601 + wait_for: host=localhost port=5601 timeout=60 diff --git a/test/package/roles/assert_kibana_log/tasks/main.yml b/test/package/roles/assert_kibana_log/tasks/main.yml new file mode 100644 index 0000000000000..d0c2d36caa0ef --- /dev/null +++ b/test/package/roles/assert_kibana_log/tasks/main.yml @@ -0,0 +1,27 @@ +- name: stat /var/log/kibana + become: yes + register: kibana_log_directory + stat: + path: /var/log/kibana + +- name: /var/log/kibana 2750 kibana:kibana + assert: + that: + - kibana_log_directory.stat.exists + - kibana_log_directory.stat.mode == "2750" + - kibana_log_directory.stat.pw_name == "kibana" + - kibana_log_directory.stat.gr_name == "kibana" + +- name: stat /var/log/kibana/kibana.log + become: yes + register: kibana_log + stat: + path: /var/log/kibana/kibana.log + +- name: /var/log/kibana/kibana.log 0644 kibana:kibana + assert: + that: + - kibana_log.stat.exists + - kibana_log.stat.mode == "0644" + - kibana_log.stat.pw_name == "kibana" + - kibana_log.stat.gr_name == "kibana" diff --git a/test/package/roles/assert_kibana_pid/tasks/main.yml b/test/package/roles/assert_kibana_pid/tasks/main.yml new file mode 100644 index 0000000000000..a77ab2a743d1f --- /dev/null +++ b/test/package/roles/assert_kibana_pid/tasks/main.yml @@ -0,0 +1,27 @@ +- name: stat /run/kibana + become: yes + register: kibana_pid_directory + stat: + path: /run/kibana + +- name: /run/kibana 0775 kibana:kibana + assert: + that: + - kibana_pid_directory.stat.exists + - kibana_pid_directory.stat.mode == "0775" + - kibana_pid_directory.stat.pw_name == "kibana" + - kibana_pid_directory.stat.gr_name == "kibana" + +- name: stat /run/kibana/kibana.pid + become: yes + register: kibana_pid + stat: + path: /run/kibana/kibana.pid + +- name: /run/kibana/kibana.pid 0644 kibana:kibana + assert: + that: + - kibana_pid.stat.exists + - kibana_pid.stat.mode == "0644" + - kibana_pid.stat.pw_name == "kibana" + - kibana_pid.stat.gr_name == "kibana" diff --git a/test/package/roles/assert_kibana_yml/tasks/main.yml b/test/package/roles/assert_kibana_yml/tasks/main.yml new file mode 100644 index 0000000000000..02f6c1b7dd1e4 --- /dev/null +++ b/test/package/roles/assert_kibana_yml/tasks/main.yml @@ -0,0 +1,27 @@ +- name: stat /etc/kibana + become: yes + register: kibana_yml_directory + stat: + path: /etc/kibana + +- name: /etc/kibana 2750 root:kibana + assert: + that: + - kibana_yml_directory.stat.exists + - kibana_yml_directory.stat.mode == "2750" + - kibana_yml_directory.stat.pw_name == "root" + - kibana_yml_directory.stat.gr_name == "kibana" + +- name: stat /etc/kibana/kibana.yml + become: yes + register: kibana_yml + stat: + path: /etc/kibana/kibana.yml + +- name: /etc/kibana/kibana.yml 0660 root:kibana + assert: + that: + - kibana_yml.stat.exists + - kibana_yml.stat.mode == "0660" + - kibana_yml.stat.pw_name == "root" + - kibana_yml.stat.gr_name == "kibana" diff --git a/test/package/roles/install_docker/tasks/main.yml b/test/package/roles/install_docker/tasks/main.yml new file mode 100644 index 0000000000000..c985fdcb350ea --- /dev/null +++ b/test/package/roles/install_docker/tasks/main.yml @@ -0,0 +1,39 @@ +- name: install dependencies + become: yes + apt: + name: '{{ docker_dependencies }}' + state: present + update_cache: yes + +- name: add docker gpg key + become: yes + apt_key: + url: https://download.docker.com/linux/ubuntu/gpg + state: present + +- name: fetch ubuntu version + shell: lsb_release -cs + register: ubuntu_version + changed_when: false + +- name: add docker repository + become: yes + apt_repository: + repo: 'deb [arch=amd64] https://download.docker.com/linux/ubuntu {{ ubuntu_version.stdout }} stable' + state: present + +- name: update apt packages + become: yes + apt: + update_cache: yes + +- name: install docker + become: yes + apt: + name: 'docker-ce' + state: present + +- name: install docker sdk + become: yes + pip: + name: docker diff --git a/test/package/roles/install_docker/vars/main.yml b/test/package/roles/install_docker/vars/main.yml new file mode 100644 index 0000000000000..ba561ba2e2d91 --- /dev/null +++ b/test/package/roles/install_docker/vars/main.yml @@ -0,0 +1,7 @@ +docker_dependencies: + - apt-transport-https + - ca-certificates + - curl + - gnupg-agent + - software-properties-common + - python3-pip diff --git a/test/package/roles/install_kibana_deb/tasks/main.yml b/test/package/roles/install_kibana_deb/tasks/main.yml new file mode 100644 index 0000000000000..570fd2d06f173 --- /dev/null +++ b/test/package/roles/install_kibana_deb/tasks/main.yml @@ -0,0 +1,34 @@ +- name: install dependencies + become: yes + apt: + name: + - libnss3 + - fonts-liberation + - libfontconfig + state: latest + +- name: find deb package + find: + paths: /packages/ + patterns: kibana-*-amd64.deb + register: kibana_deb + +- name: install + become: yes + apt: + deb: "{{ kibana_deb.files[0].path }}" + state: present + +- name: copy configuration + become: yes + template: + src: templates/kibana.yml + dest: /etc/kibana/kibana.yml + register: config + +- name: start kibana + become: yes + systemd: + state: started + name: kibana + daemon_reload: yes diff --git a/test/package/roles/install_kibana_docker/tasks/main.yml b/test/package/roles/install_kibana_docker/tasks/main.yml new file mode 100644 index 0000000000000..6d2f0a2caed1c --- /dev/null +++ b/test/package/roles/install_kibana_docker/tasks/main.yml @@ -0,0 +1,26 @@ +- name: find docker image + find: + paths: /packages/ + patterns: kibana-*-docker-image.tar.gz + register: kibana_docker + +- name: load image + become: yes + docker_image: + name: kibana + load_path: "{{ kibana_docker.files[0].path }}" + timeout: 300 + source: load + state: present + +- name: start kibana + become: yes + docker_container: + name: kibana + image: "{{ kibana_docker.files[0].path | basename| regex_replace('kibana-(.*)-docker-image.tar.gz', 'docker.elastic.co/kibana/kibana:\\1') }}" + network_mode: host + env: + SERVER_HOST: 0.0.0.0 + ELASTICSEARCH_HOSTS: http://192.168.50.1:9200 + ELASTICSEARCH_USERNAME: "{{ elasticsearch_username }}" + ELASTICSEARCH_PASSWORD: "{{ elasticsearch_password }}" diff --git a/test/package/roles/install_kibana_rpm/tasks/main.yml b/test/package/roles/install_kibana_rpm/tasks/main.yml new file mode 100644 index 0000000000000..d29dba33f19b8 --- /dev/null +++ b/test/package/roles/install_kibana_rpm/tasks/main.yml @@ -0,0 +1,45 @@ +- name: install dependencies + become: yes + yum: + name: + - nss + - fontconfig + - freetype + state: latest + +- name: find rpm package + find: + paths: /packages/ + patterns: kibana-*-x86_64.rpm + register: kibana_rpm + +- name: install + become: yes + yum: + name: "{{ kibana_rpm.files[0].path }}" + state: present + disable_gpg_check: yes + +- name: copy configuration + become: yes + template: + src: templates/kibana.yml + dest: /etc/kibana/kibana.yml + register: config + +- name: open port 5601/tcp + become: yes + command: + cmd: firewall-cmd --zone=public --permanent --add-port=5601/tcp + +- name: reload firewall + become: yes + command: + cmd: firewall-cmd --reload + +- name: start kibana + become: yes + systemd: + state: started + name: kibana + daemon_reload: yes diff --git a/test/package/roles/upgrade_apt_packages/tasks/main.yml b/test/package/roles/upgrade_apt_packages/tasks/main.yml new file mode 100644 index 0000000000000..7dd4000d88ad2 --- /dev/null +++ b/test/package/roles/upgrade_apt_packages/tasks/main.yml @@ -0,0 +1,6 @@ +- name: upgrade apt packages + become: yes + apt: + name: '*' + state: latest + update_cache: yes diff --git a/test/package/roles/upgrade_yum_packages/tasks/main.yml b/test/package/roles/upgrade_yum_packages/tasks/main.yml new file mode 100644 index 0000000000000..fa874772cedcc --- /dev/null +++ b/test/package/roles/upgrade_yum_packages/tasks/main.yml @@ -0,0 +1,6 @@ +- name: upgrade yum packages + become: yes + yum: + name: '*' + state: latest + update_cache: yes diff --git a/test/package/rpm.yml b/test/package/rpm.yml new file mode 100644 index 0000000000000..456c2bdf18b72 --- /dev/null +++ b/test/package/rpm.yml @@ -0,0 +1,11 @@ +- name: test kibana rpm package + hosts: rpm + roles: + - install_kibana_rpm + - assert_keystore_available + - assert_keystore_cli + - assert_kibana_yml + - assert_kibana_listening + - assert_kibana_available + - assert_kibana_log + - assert_kibana_data diff --git a/test/package/templates/kibana.yml b/test/package/templates/kibana.yml new file mode 100644 index 0000000000000..a5e44b7acb018 --- /dev/null +++ b/test/package/templates/kibana.yml @@ -0,0 +1,5 @@ +server.host: 0.0.0.0 + +elasticsearch.hosts: http://192.168.50.1:9200 +elasticsearch.username: "{{ elasticsearch_username }}" +elasticsearch.password: "{{ elasticsearch_password }}" diff --git a/test/scripts/jenkins_xpack_package_build.sh b/test/scripts/jenkins_xpack_package_build.sh new file mode 100755 index 0000000000000..698129a2d253b --- /dev/null +++ b/test/scripts/jenkins_xpack_package_build.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash + +set -e + +source src/dev/ci_setup/setup_env.sh + +export TMP=/tmp +export TMPDIR=/tmp + +node scripts/build --all-platforms --debug --no-oss + +gsutil -q -m cp 'target/*' "gs://ci-artifacts.kibana.dev/package-testing/$GIT_COMMIT/" diff --git a/test/scripts/jenkins_xpack_package_deb.sh b/test/scripts/jenkins_xpack_package_deb.sh new file mode 100755 index 0000000000000..42098a6464f53 --- /dev/null +++ b/test/scripts/jenkins_xpack_package_deb.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash + +set -e + +source src/dev/ci_setup/setup_env.sh + +gsutil -q -m cp "gs://ci-artifacts.kibana.dev/package-testing/$GIT_COMMIT/kibana-*.deb" ./target + +export VAGRANT_CWD=test/package +vagrant up deb --no-provision + +node scripts/es snapshot \ + -E network.bind_host=127.0.0.1,192.168.50.1 \ + -E discovery.type=single-node \ + --license=trial & +while ! timeout 1 bash -c "echo > /dev/tcp/localhost/9200"; do sleep 30; done + +vagrant provision deb + +export TEST_BROWSER_HEADLESS=1 +export TEST_KIBANA_URL=http://elastic:changeme@192.168.50.5:5601 +export TEST_ES_URL=http://elastic:changeme@192.168.50.1:9200 + +cd x-pack +node scripts/functional_test_runner.js --include-tag=smoke diff --git a/test/scripts/jenkins_xpack_package_docker.sh b/test/scripts/jenkins_xpack_package_docker.sh new file mode 100755 index 0000000000000..6cae225830380 --- /dev/null +++ b/test/scripts/jenkins_xpack_package_docker.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash + +set -e + +source src/dev/ci_setup/setup_env.sh + +gsutil -q -m cp "gs://ci-artifacts.kibana.dev/package-testing/$GIT_COMMIT/kibana-[0-9]*-docker-image.tar.gz" ./target + +export VAGRANT_CWD=test/package +vagrant up docker --no-provision + +node scripts/es snapshot \ + -E network.bind_host=127.0.0.1,192.168.50.1 \ + -E discovery.type=single-node \ + --license=trial & +while ! timeout 1 bash -c "echo > /dev/tcp/localhost/9200"; do sleep 30; done + +vagrant provision docker + +export TEST_BROWSER_HEADLESS=1 +export TEST_KIBANA_URL=http://elastic:changeme@192.168.50.7:5601 +export TEST_ES_URL=http://elastic:changeme@192.168.50.1:9200 + +cd x-pack +node scripts/functional_test_runner.js --include-tag=smoke diff --git a/test/scripts/jenkins_xpack_package_rpm.sh b/test/scripts/jenkins_xpack_package_rpm.sh new file mode 100755 index 0000000000000..6aa7754ee4b21 --- /dev/null +++ b/test/scripts/jenkins_xpack_package_rpm.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash + +set -e + +source src/dev/ci_setup/setup_env.sh + +gsutil -q -m cp "gs://ci-artifacts.kibana.dev/package-testing/$GIT_COMMIT/kibana-*.rpm" ./target + +export VAGRANT_CWD=test/package +vagrant up rpm --no-provision + +node scripts/es snapshot \ + -E network.bind_host=127.0.0.1,192.168.50.1 \ + -E discovery.type=single-node \ + --license=trial & +while ! timeout 1 bash -c "echo > /dev/tcp/localhost/9200"; do sleep 30; done + +vagrant provision rpm + +export TEST_BROWSER_HEADLESS=1 +export TEST_KIBANA_URL=http://elastic:changeme@192.168.50.6:5601 +export TEST_ES_URL=http://elastic:changeme@192.168.50.1:9200 + +cd x-pack +node scripts/functional_test_runner.js --include-tag=smoke diff --git a/vars/workers.groovy b/vars/workers.groovy index e0c5ddb358d09..4f9fc789a04b3 100644 --- a/vars/workers.groovy +++ b/vars/workers.groovy @@ -103,6 +103,7 @@ def base(Map params, Closure closure) { "PR_TARGET_BRANCH=${env.ghprbTargetBranch ?: ''}", "PR_AUTHOR=${env.ghprbPullAuthorLogin ?: ''}", "TEST_BROWSER_HEADLESS=1", + "GIT_COMMIT=${checkoutInfo.commit}", "GIT_BRANCH=${checkoutInfo.branch}", "TMPDIR=${env.WORKSPACE}/tmp", // For Chrome and anything else that respects it "BUILD_TS_REFS_DISABLE=true", // no need to build ts refs in bootstrap diff --git a/x-pack/test/functional/apps/reporting/index.ts b/x-pack/test/functional/apps/reporting/index.ts new file mode 100644 index 0000000000000..286693f01ac52 --- /dev/null +++ b/x-pack/test/functional/apps/reporting/index.ts @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../../ftr_provider_context'; + +export default function ({ loadTestFile }: FtrProviderContext) { + describe('Reporting', function () { + loadTestFile(require.resolve('./reporting')); + }); +} diff --git a/x-pack/test/functional/apps/reporting/reporting.ts b/x-pack/test/functional/apps/reporting/reporting.ts new file mode 100644 index 0000000000000..a9d089e9fd397 --- /dev/null +++ b/x-pack/test/functional/apps/reporting/reporting.ts @@ -0,0 +1,46 @@ +/* + * 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 expect from '@kbn/expect'; +import { FtrProviderContext } from '../../ftr_provider_context'; + +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const pageObjects = getPageObjects(['dashboard', 'common', 'reporting']); + const es = getService('es'); + const esArchiver = getService('esArchiver'); + + describe('Reporting', function () { + this.tags(['smoke', 'ciGroup2']); + before(async () => { + await esArchiver.loadIfNeeded('packaging'); + }); + + after(async () => { + await esArchiver.unload('packaging'); + await es.deleteByQuery({ + index: '.reporting-*', + refresh: true, + body: { query: { match_all: {} } }, + }); + }); + + it('downloaded PDF has OK status', async function () { + this.timeout(180000); + + await pageObjects.common.navigateToApp('dashboards'); + await pageObjects.dashboard.loadSavedDashboard('dashboard'); + await pageObjects.reporting.openPdfReportingPanel(); + await pageObjects.reporting.clickGenerateReportButton(); + + const url = await pageObjects.reporting.getReportURL(60000); + const res = await pageObjects.reporting.getResponse(url); + + expect(res.status).to.equal(200); + expect(res.get('content-type')).to.equal('application/pdf'); + }); + }); +} diff --git a/x-pack/test/functional/config.js b/x-pack/test/functional/config.js index 573350dad24d0..ee5be48a07663 100644 --- a/x-pack/test/functional/config.js +++ b/x-pack/test/functional/config.js @@ -59,6 +59,7 @@ export default async function ({ readConfigFile }) { resolve(__dirname, './apps/transform'), resolve(__dirname, './apps/reporting_management'), resolve(__dirname, './apps/management'), + resolve(__dirname, './apps/reporting'), // This license_management file must be last because it is destructive. resolve(__dirname, './apps/license_management'), diff --git a/x-pack/test/functional/es_archives/packaging/data.json.gz b/x-pack/test/functional/es_archives/packaging/data.json.gz new file mode 100644 index 0000000000000000000000000000000000000000..69c9e4cb4d8a22d2b75084ee20ebb637e9fefc17 GIT binary patch literal 1644631 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 z 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%0A>h<40Hn1<%LW5 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⩔V79s`U=0V6liET zN9D*AN@pRAiP~I(I%Q{YU&CG-hIw!X^6Zt%tvag-ghb$H_%ji|3(cXgv(xD5b6SbK z9ZVeMAMGkr;m+{6j2~2Yy33~8i%K}Jf9vA1tiR^PT`39M3rUacEj6wD)xIC#k3)so)y2AXz5iQ7B-g7N zR4vV0w8D?KyKMuisS|DDR4=OQM%(mt_$1YEk}SuynNoUe=!%F>xu2W#&nBPYzGHA@4v|NFf5p_vp>Y(e*YE83zzsWAGu7 zKiS)fC!r`*nj|NNeQ=){YL7%Ij5ZLxx;j_K$%8gugIICU(>dNB0AAA4nGZRD&mVcq zHIh!gw;Ay4lzDWq0$?+O3rrzgg0 z#fhnyW_un;49^v`u>0C3LdVHm=eLIB$a)N8aF);7JjH7{8^WkzenN99SS2mI(Q#Egy=nKLnI?wKW`_dy4^*S6n?b5=s4eciZlRIV0x z=S+kpmgD?*?iWrHEOG+2#W=1cbMCQw(e9XLQ&@4Fi8Z>Dkrb&phoVPRQ7reb1ixHH z=DtucIUc&jTRE@03o~Idqty?_y(4YywyHOMpL_ zV1*B45F^R{HS7;lB1O={5a^}T4)@9y=yhTE1r;va+KXqINvv1Cm=}R^oc=O71&yV` z$ZoOgq6%T(bca)HtK;TmTcZ`9YJjq`NSlO7KF1&rBp_Mz(pk=5tWbHOtgYA;B2A6X zy+pm1#-MVVdcZ^!^#3|laqOh>t$HBKp;PJdM$Jcs>W-YuE4)yd@v=}051Z)O;tpob zaA6M+DW7u(0GA^;QP7al?#41blID0g>MpsbKJN7Z6Jw6TR@f_7{^*WbC}I=%DHo05gMF`u=wKTR(hL)=Pgd3)=gD8t4kCdrH>aO51xo< zKJ5d~v&ql`Jp}cmKuXl&34XRC0b96K<;ec(-;z8;sJXYxKBh+fsaG@&!NXJQUQrIa zu)Xi2Oq5psRGQA&IZw1!ni!nPmWh{~oE~P=)Kfk^W2#8w5^zO(eA?Q5h-ODRi|h>p zP!Y7KkgSPv5AmpK3%3`NCx~HcH7o@=rYac!g((=BkX|sEs4e|stkpmE*9Yc2nW_k^ zvPq4KQi^p+xd${c+-Tu}qJ<~!G+V9qiiO-N49GmY>z!9GOU)G-1+VZ?Az+8!Yp)ys z;wn+g2~6%^6humW?cW2)te{Ia<(+UJAq$2OWw2&-nS@oun)>>XU$CMbjWMFRTMf;R zYP z%VMx}ZOLdxa-xiRT^sIc!FOJm*2^(6SxWK=;)o_tifgZ7jyW}SCf`@A*Z9n{K(6$8zxr{< z_0ipW?!zNmVzQehAZ4a})_;8VDn-SX>l^_=&+x$|up&o%lOp6*`71v%xj4jVm|m@9TX}vwxD4Qy-TlYh0{OryBXH;^Ct8dpb&}7xEA8$5%2Mu2b7YzFC? zeKle;x43Mo zgZ_N7+jE|)uB|9=j*FdKl7wcHkJM4swuBam?|y_!1)W@^S{dAvd}ZTo3V%aA2hv5iBrQpC1fxYi0A zWWr<+92XpU8=nT6B_%Y%CJWa~!KKNSG|2>V8g9Yn86Gosot&si7lv>+dn!O*4|Pb) z3D2tqYzxAt=Z`CaSx&4e)MmpZLX=53*W9c`sX=TTOh?;$rZb+E=@!8wq;TA=gyQiE zn;o9rOvio(Qo-a$D)%k{h%YzzL1(vHSW>cV0FL(>F!)gRJ|;aa`-n@A&OSCb(H^D+ zR?05fm-mIQg>)T@3;%q*^p;jHnpfCdx~J^mM4{v3d~LM_Klbr_z#q4+*7u#Mf|PS? z)sD3av{a9IwQaY@CLqC7w54?>%RkTJnKJdR0C=459@TvE*;8y3i}4@}tp}!mP$|idE>aD4fZtc2Dhhtx$&u3T__YJ zb=YRJlTKxc$JpxF9ay2n)PyJS9i!ewfmT^BHKt zju-l*b&-tn4nNqzIyhzREb)wlB+|?rhf;-i4f2QIq)3tU<8i*q8tgx?`o--1Ee^qV zGbLd1SQl>4363js##0$|wSDC`FR~Ycg!AV(w)Z$bu|f`rRpeq^!ouu8!-I@(`)o`` zZNjZTrijLS*EA-?e&riiUyYn=GX22Yh+S&~O}H#9b3jW3w0dKL4?TJ2V>;^Bb2mEe9yVeB_VUiWp?hSMpKXAng!2*ryc|M| ztA@d~R>N#a2q>MCCvNH@pa%_5xyK$`DcX~-B=biqOs?3`hX=~P%&+n4=73#dmcD2G zwTek0JY8FE;xvA~oR%IhDi@DU(YPkun1Nth$6=D%#B5F8!AS$6vuO5ody(cf9PW$f z95{{`ofIqY7}Bkeo3vmj7oOnQA7iyctej`%@W>+mtuPwts;v7cfb%n4%m(~ijswv2 zqpvin#DGr;7Cs53jCzY5<)&P=5P3*NeYeBW0Nzd6L@+U z$7#_R5Hk|Rg}kL%IC%|A1imuFrLh39w^SG9V*w%ZhaszlHwQ9vV|d3N3gcqE=C&J? zS8(9a6<!%x-%z~7($jIAih3?k`)fox#`mt zdS*Vs>NytM&*zFd$Yb$FlUI|;?=lW1A-`(F*|<~pTsad%BiQnyr6R`}*Vm$PrtE0_ zd{ADehYE|z88RYisPY%5_mRpL?Uli-#`Dx^-ro1_KgI=qkhhYAP6Femx^Z&ZF!$q& zWrWu$^y_07yb^ku3p}Zz+l%g`M~sIkHrzcD01?|fs`i{e6%2v(JPxV-Aq-9+H{wy# z`SsN!`6=$66JwHAnGSi>8v#V?`-Deqz-&^^eYAXF_|8DG(XQ^xNg>1AW)YRGd?g#1 zTgl48LKBnN!XydB@SR&TiCynOBkFnUzPl^l{^S(q(LD-bg=Zw(H0iM-&;+(?Ifq^V zW4urVlh36#pP{CNswPK;5N9uj@8kMnAE5Fs=!X&~E$DVQEG`7!k601+^4b}nR+JVGTY zIPqb5zyhf=l=I}~PVV#u)>@M}LRZ>}OzrF;bqtTJIcOob#<>I0QNj+EcQ4=`Htsf# z;R3+d@_j{QfXQw5?uV#wAh<*^bb$Aj(^`3bc8ME?)*ISHMIkK4mk-dIWe?n0?4E!m z#z!}46vm81noI-QQaOHf8Eo&@sIB|TsV-`VlwTw@T!4$E2TU=UrNmXw&7+(tvVuxy z!V2^~Y3czZm@Ec6*l@0|A=))p!l&HTbQ5FtFqn^Kpp({PZV!@nS%XUDN8?Rwy246U zSL?%M(Ckv11p}>Qr$2JYJQ{#H#LVTgvQK=-8_@TAUJIN^?{QnenT`=hBu%WIPF2Fx zb+7BsEq9J}u5@_avkxfC7+7~TT0j)a>-Dhgg&wm!HR3XLpGlQRNnV&9Oe6`qmu^M% z{lOo*9-YYW%7FNHf5uthCNb30tmSxSk%iqY(=HbYm2lsUoBYhv8DEev{TePacJHD4 z!DL3#VDOo}$29M|qKcCw3*mu|AoIR_sZ?Jo3bUtrJo5QekR`~J;)-M}WG)oIpN!^~ zSb{4&4ykE5O=z3;50az=!4l#XYmj;hpZwI!O$LmepP;%)N!XDPoO|8fZIACMK?(*D7=F&ZBzoZo z=Hw0#)m$1SH|kaK7~R=Fs3lA-X1FxhYX20ZLA^ont6QYUd%)S!3oF;`z!e>+e)M(>$F_dE9c9KI4)tJ zA!|z>GT7|N48{zC9!v&gJVLJV~xtGJpI(*poOQH(JjbyM>I#P z1HsZr%N8uNFIDb1Ys%?$6fn#WR=L+Y3p2+EY9B^*x*`QYh7X?R$x&`C;x%$zFmdhS zl^~EKo}cQ(muNp?>N?cSy4>fLrA9!k&b4e)qzZw|8eA+i?w@vvM3Yew_K*bB`t;W< zF`-v^P(eCiM+WQFG`rn%MzIBiAE6*e_gtsw42`OqkjU@~sZ4(fva6X$fiEby0Ie}3 z2@QY^hnBXp$f7X+LOOx_IA%{f$5_|8qB!qUO_3s8js-K4`a}CP z$#T#04@Z$}dR)l+-5>n^m=WD+%xgn(>LQ=J@hXLvkvkcx)*Lle!fL_53%7pE;~YCNXjKQn$Z zk!vNJYj5+Zp^zEU0TY7xb%=!5By!f~x9i=}`56F`c?#G`&0v4zrzqHM#!4kGl2I981(~E>7Aq=B*N4e>gWycW1i}d_`Wr6EF zxidxjvVXe1bv|%6V(?pWb@ct^{2JT@540~$hvIStQ3NYdFgE?+%K%~;FH}4n_cv<2 z`P}q<#e*aX8zC{7I~@P`m725H4l^W z5OZYjRT7Yg1Qk0|8hZnN70x@I z?14^Zou}plH)(!$%z9HlBQ7)@J}ZJdIyqSylvuiO6Q;s6c#v4uQKTH66|gDpt&_=Y zPKrOUNvl_67la)8ngoyYBu-jim%YU7iPt$bxZ`?wa$)Mf4&vUPK0EQhGR{+Q}qBoilA%CvMIux<&r{MbRAl(%slwZalz# z(fZ=e!eKt$mgJiT9m!k;VU#iL+`XDd+M&GB1 zeF5zqkJpK*@axOu(T03}si>!>3%V2D&MIf{$7_m^_pH--XAHPEJ9I@%0nT1Efi3Az zNzXZ#OZGY7*Po9Q=YN!+lcYr!oWQwoB(>F0UEgdE3_#x6xmL5STr-sur^Lpz*&Wl!o1Anyy$Xa5I9O?or$$ovEx(x) zH@+e_j^-2Xo~w=fv(}VE&O3b>0{u8TN}%7c2rDQR=WCkjFyMTJ2pQ zpY!qN<#;tT-ie!d_!QV}t8z>4rFLIa`RlFjBz5X3=c}d2D&RwNPCOCeKHLw|n~icw znzm1NX#!x-oX;~eaT~5^<`GYOR{H8q&pOD(x7*Te{S#)FOL>^ju(I~4o;X0;3o*+6 zT|ZeM%fg;<@61&WmGjFo&Iky`0BFg>ez6PRcz4K=s z@~L{bI*aE^Z80=D$Dae~LAKVFczn60z$vqIJ2tBy)mQ;d!0h{VZ%F&cwyI;$d6e>J zO|@&LM5k8xoR7A+1oBae-5wNK0ej`2Xn1jhed0P%H#qL&r0@{|`-{VW)+xwgdnqW+ zei`lk=)^I?A-~kOG2i<>7%IUtUytvcsOLUH>*tw!N?E<_i?j`pm5=u&{hSj(Fy+#g zp<*FnwiN^+!|gro#usvYM!uNIB!jpJ8>HP14CNErBxN5%1`u3h-;QqVzup|=upB$_ zl$=(FIG!eLGEzjdDMn+2wv67z0zDnwn+^5LjNHRm;%S$2`Q8w6{7(CIPm@;#Y3}%p zp2o_*H($>C82@X4XUYjHFL%D+yK9R2R8woJ4|Me!UFA#O=P!E)08t#f&&OWK*T^}X zdAaT{WeM!QZIt_XH|RHga;|if^09ThNJ7Wrk(&8A=JwYD?cn3p2S(Cs9ExAlH+&^) z&sJOSd3qaZdnN(K5|5pCEK&j(1L;5fXDUCdn&s;Sev3^Q>HBCUwX9nl-n^MhwDrPp?cyDGv5GNobA4`jg=;v zx<{FB`hqufpq~MYJ=Y0d573RD1Q8YC@|o6A*>V6#fneVdZT-%#p1`l53mxTWDK(L{ zZ^LaVEIQjIrmbfhB{WT>eI1RZs+t&82u#~IS6!>`VUy-!ECe;;qBg>Jy zd%8&{?8pRS8ZlPDDirHvZ+T;WJ=`LUZCt|1yRu#939vwzxBIo;UUFA~P^x;i^0|Jh z?yt_^&cI`wCt0}`c|N3qbX;k#Zfq)7qj<9vrv)9ELBwC_>Q z9sC02*txB*@(aXGt3M*Qk-O$p^(6@bJaYs(dLHl5-ORO^(<qee0SB?BCqqkDNPN$Id_QQ|UawXU14^H1G%P?pJ5t1C;Vf z-^DLBEj&T2)$9cXS{5Sr>3-r)H#xsS_9Iu(LjqgC?1=u>1|V8}8JDXq`#dQgPBa!J zPQmIuJ9bMTpFy2UIpvQnjJm#%C-ent?CTdCB=XqQRg4qnd`4)MDsp8EucuqKF-)0+W`u5caK<7vQF zi{TS=oc0wI$fvO3Z9#`pYUT-hpwUJ;nO7fiZ12m(geq;ddChr>D1_IAJK9a}_Y0lQ zbiGctFVVdGcy}#M6qe^|R-=fHF-Fsz#07SxpP-?!lzl__HG{#-BD~=UZS!G^brrP$ zI)r@k3iMRniU&2HuzGK;Lhlp6VZK~}+VTmys8b)}K6YRn@Y|^|R_!_SM}WJ1{893s z#dQ#(Ej|wy5Vs*FeR{8ja|9L6j35ON@<`2^e$L+pbo#0fAn(u?d-8?ap{h6h!7~S7LsxXVjV<*Aw&!VJOxZRj_UIIm zs*NA#em@;&1>5KM0^9O3QeF~BRLfK908zJntIoFkYA*@#z;2y%#o-vfaBqIgf;boZ zxkSXHihIBXLADj@v+wktS6ol8h;Bt)LW#@tS$+a%q%R=91Iq6MBR?11YqTHhNf&ZD zx*g8dY(YkvmiM^rYpij;I0k?N4&XK93k`x+mk?*{*3GYKAB?S&PV{Mr$`N2eTEby< zjMif~u(tSyS0StncvcahbFX!u-CMsKdcK zM*6mI%yq*gXnylXdmKYkLlh@oaBW0_asd$iiycl8qn<|H&(i1p<2cV?+|wE&TI{t1 z8K3fDX7_J?51j!%M5*>s(>dx)e(IbY?0Io+UeDYlA4ew&}hiCbZe4tMrQc35%^bwalqtgVi z!~upt|H=jR`ypSx#59p(C!jm50fvEU2!=>k_Ku2`aJ9HP$|)fGy=@Vg?5kNHu=)Cy zdkuaDm}bKuTTuY-@^bCwNAtbYDAL~S zSO-aGxpk{Xpjt?%W9CCM#bRHsrE!)Z08N4z3ld)BsyTAO5tmOz?D)jg>wq zSc?Jr<#$*K;PMzcs%fXspg3^>ue?CM=pEOOnmZiJ>t!TIhul|6_~y5S0q~4opqIs} zVQ^Y_;zKT84}Bzo*wAUl-S_6ZAyXjke#yDqo+&|$lvxKa+N}2Imnw03W_`Ne8C*|3 zY5}B_j!#4q_Qrt?!Q008C|^0X&b?btV2lEdDhXyT4pt2dr~0Z~j$oT;_&(4y_s$ zP0`zaP}e4ZkO3Gffbq6j;@3KYOTxo1?_|V*xY!q}(^vi3!jn7(7^w0qz7tIA<2(i5 zV8;M$Nl%0>;Z4!>h2;ez$LNOAN>=elILT( zARBg0*e&KSomPm~YXysBBqO8qC6^t9`yTa*W@+2DT@L+(1}bzm=EBSKZFp|{{Zl-0YKwPE%^ zLUY`6)0$Yi#pjYTRKvTX{r!T`iZFUHp86->!ds!6;Gkn1X z8&2M2%SbH?vF6CFnGLO%;*`G4Cl#=4K4%8TQU|N5d{)9r_wPvmK+i=oRzb=k5KnhwWihQk47ZI(ia<&Yc!;buQVp<>!U9HXdb@iGX zw7qxi5ZeiwKkN3b3!PMMq0Jvv6;(@BIm@=_a>hQt6dJ1#2pvKZG3_I?SV4}Dn>X$( z1V_M~tp@j_N7+yf$-FdAAkU(kN=LE04LM;IzHDsr&|zzCP7#ca@1_aB5d3ZxY3-Dc zV*zkr5gd3%Ize%Tk%~J-y)m3OMPC+HXKd^~Bq;h;H<~H(vO7 zLVHXskGjJ_9Er5%6MIz#yLiS*jEVOYxAv&jibZ2R)4fL6*qg6oAY6Efn@1Exw^+tP zx5SW`N}d$+Wwlqw6yYU=XdD-B_N$;*^>7_mJNY={pH z@-}xeB_Jly63B_m46XtIsoo)0b;UX5`GPF>h@V5UKZh){>SJD$3vv%%B`Q^>%$yk+IV#w=Y7k`rPN%|`^I1Ltocg?% z6am9RcQ8*ZR)oU!9nUq0!wEG6W@_)S8jM1UaCaybODYr%YQlYgwK@-L89_9$z&uB1 z752{SSZ?{%@!oQ#o<#}1GLXI>IwbSg9eS zJ~pxHloVtkip`rdemo>hSq2fLoZs##M6cN`t}0?K7;Ftj+JTJn5U7bhC40_VRlme; zV{~z-y{h``ZDjIQuObXTtZm0ad06@{=u2b98k-oxALFMuKJQR(&NHPQAWq@D`Jvlu zdBE|JZQXoDlzUa*IijxDy?OT^khNFx6Y_3OK~Iy?v+L`_d}_T#+RzzpqZ+H+16ScF zv_>YfFd0tV5kDlcTeePcxFk7)6XDYUU(WCFoUwSFc$ECxfw@K|e9G}{u}B|N*oiyo zbo2sI?+{1OVLXS=vLx$=xYR}ZZXVMJRO-?{a^(X^6uT7^czIhr#o>@m6 zRvCw^GgH}SoOsxM@HwVf_ax-8FiK(3>n#LK3ULIs5sqn}icdFkf+y3U_rS{Siz`}Y zgW3L!gTh<%l&cX*q}9zDEP27N$U6oyMoQ!5Of=SX&%fl+6X;J@*^OJy>K=#NyG7C; z$4Q;IgAO|xCfLSfB_$?ZlmSBw04|{DA$EAlQXbiuy4WI!<#2B}aZ1zHrlw-08yk{~;DL~1(V%=LX+9Kh)|wLmt+Q7B(> zd(Y)%gI;~FDNJbH&oy<2V&kPq3)J%nY?_fVH8Iy^^a*d@rui!lK-~t$_Ct1G)e58{qY~| z?*#0xY?8X)Vr7IiLC8A$M)XOR%d8vRUqoq%#h2n76E=}>wVkt9h!uWa>kuh2$tjLi z$h6<#ifrGBsw3}tWg*#H5cKD(D>mg5LX(wSrDw^F92uob89ixiUzq){ScPU9rE*>$ zo~FE3{%C)JRh6I$OMZQdFx4SzRzac&jkh+qvi80)0^lX1MdN-JKg%$FgwO-zHV22H zD_$Ea4bO0?EYE~3;C2+@4ziNr0-J3R-C+Ci^xpfUXm6aZ`6!QjJOQrs*a z2V!HW>;twWG0tsglSa7}d!xHtloX}vb4B7LnF!8355#GVClRm>yJ=Zdg%H5nG&t?v zaFi`X5ARkXSIEGK@m@~mDTC3Rx9MrkO4H-roC%|7NeLSZ%%@InfwD zuGDl_%_ktYu9T
    (g%Yem9E?)ly7~(LoaEv&L!0*g3EAP>Lq8z|GLXrwqO6S5bFr9jW0-VTuOPx>IM%q+2MEgf=t;0@O!uEmHG3LKgMTO%AwdS6eH$L-l&IKdn& z%Y1V~KzPbQ92NNZ9u@u}Z5-hzqZd@-{Q#@>&UzpnOP{~#WZcR$ZSaqKj zd1s#6+Rx;EULS#%t3J(9w+*TI{8e1=9y}wx{xwoO)SSe;J>$NfHoRf+wzYM#4XtPv z(iuMzHZ)0EorOPox)W%_c&4A|hAdo0aWHT;I)>V{;NTvRLZZsfenUe0LPaFvO{L%6 zn3CG)owhU#Y3%WR3M3zX@@4aIr=5AlJ5d?hMn`{XQutRjh@>vr)W~&7`l!ClJ>NWxkrrNN8u8~|O}+7UxwX+f-`$9e z33W^ms*A$3?ZC}%J>|1u0!pGis^8BZ2CtpyG*PRLuW z5__N!qRHMB>XYr7*xLD1(lBVq%JcDhUP@pResJ%!Mdq}`ZZXtq*P3~V6OJ46uOVho%_#EG-81b`BpV{&d&98(iK|L|sV zFX55DkHmtk`k|S^^)M(#Kx#0S${ZTQ+Lwv&vCsBl5n|=w&hun?2Z8aqe9!J)(s9v; zLKdt$XLoMRXg7`@ddKik2Px>3`6MW%(o#%N9B6eM?3-1lY*r0o!=OvruGjQfc={Qw zTX}s#wPUVxgH>X($x8P-KKL!M+n`}gb|cy~qoeJYb7G5!~ zYDAUt^VUf387|d12XO{hvvLs?ZlhD|1sx?gcJos$6Edf*`;R#~lowAV5uKE}Q7yFHEhDZ{Cvp?!NV1OcL5iB3k(Nm<#dYDM1C|B5Ok0c1Q-50IK4REvXd z1~?H#z`1H_^R<`EDQf9-CPPkoThK49Dl!fLtF3L5tozogWFKtl9k)@#N4$wD;07{4oq$wLy$hX}2t>yFh%>+zw7b@Pm0N7UM zW8ErcLn@f&SSbn+(M#gIXLY%M#%~r#+z3l{dBpryZf`9#!Fgu-Ef=sO!6s&QpNCBb zRg@p!RA1d_mJ(fj0cwocBgXFUV8r}XDJGcLT(#8G|8db~xPg`pXiO$JG)7?@%o^1{ z#bp_u3>=FOQ!2aobzfK zTs8^P21c#Uur`JCgndTlhvS0#^4^u}KkSQsE_oYX%};2=S> z#!X`RzzB%C+-Cf@kB!$fg*jj-nCE0hp*u~c;byGFn-0fDRPR30)C)Du-b0`93tds( zC@||6xt^HX}b;?E9l4SDX;wM9O4zMg~Z-Zy#sv)|2p0s*}Am%)3!YG+Me)rRlE4gM-s)s3IJ zus(p2ldk2QWdz%4E8>|qv*(27B#)c(2_}A~N6QV#vDRLG2GBEH7)yNtv!?gN!-w^FHUIvQcBQP+-l8igli*JF^SKDrENk zxr+HO;pEpp%s_d-x%u^g{o`WcFL}||f($eDL^KDJGeP}f+oFxiSE9!&1CHVSa*?{mtA% z*y^XjB2I!=bBxK^n{BWCd!*-eOL{*fU$7g&VB3-Hl?lLXTQq*L45t9*#?5tGVXw%q zT0@zNsRRTHn}9F%>O%jzEgWi`cng2`2QJd<)|`8xUKb$h$+bYz1$GBE7@gt{S(2$@ zt6wBf$=hNT8`qw#geq;4LLDxX8YK(wV#+OqyX8UpQpLsR#E-Qm*~{d}5B5s@z2FSj zaiLjy@}bqKK|~R&mkH85 -PR?=BF9;`S`;qMV3>bA|daS}upJhP{ZXR!x>`&2iw zf&I3~)G0m+!Ac8AxC;%pj8>^vGkT)EbEK;zTcl=cAHP10`+DVX`TkXn;mOT*bR}4E zaDN5Cobop3Go!MZ#YVQs6IojsO^m{CQ`8TA))%VULe*E?mj9JP#8ciAa5zPpS$ZU1 zNU*-FZe_ZNy52dT{nbLZs7$nkp;k?N4iXY4G`yxBR6(O^0|hqEnXWzAPmyH;XPfKbh73A?Y>m5f+hPqJ-0CK;{E|jA@$Pt1Voy zwpNKk+M~=~LA^g++dWv*t(gW9d4R^tn^@)!f(?_0=4{}9>thZ(c0T;;C`6|ptvQ3G zhCkdnzkb4qeU6Y)W)og;MmAH@+Lmy;kjgPomLaI?wJ>O3(YJZ=QR8-g6v%Mzq%UBE z6z%OE9rf$ai%hRQ~{A_LK@uQz{c@K$R~eod$4W#eDn08go@UoI7p+yX^AjT_ZHyk@)6= zE`d(J)q4-227S;8iz5UpelvvM@D~GPo@5f)RPq9O3n6kMV~^`-uUNeVNtk&X zdkixDm6YgJzWHNEn$IZM(7Zst+(qPnEjH3YM!0ZY|5xRORush*dHVZ$*)pqHH{)rp z9qz4JoDB>n_iraq$)=!7guw_TdMF$ zVCH!dc1nxPgy!+V2=~t@va;W)SFUm~5z#5Xh{0#%daW^Aq`3Oc@6u zguzpg)}+gJ|0>s<-;RFl37O)Mu`IX#Lucl%ZblN?%B3ZR-&>OXesaHkd9O*N*=GU+ zUH!CesXO+pH_&WjaQbPaq|m?CAyMjgjh-^zU8uh| zu1!8GM)9Oth;^4t9R(&5zQj*!u{U4$bBK3rHaPaV+0)uQrjz)#@A58^qT(J?G-%u) z;cT*gLL~^#`$1G+fOkHzM6DhUr60EWnT$t-_kBA-|G^F=m!hNr2m<)%zhe}}__KId z&RSzqJVkGL^|@B`Nf!x3cvu!_BUJndCFigZF~4IbK|!#PJ~WB4<`>N{=TugqF(Bgg z?+S>kjzzOikZ-MJWc#@nxH!EOF$M%(c@S~@U3IzV`)ppQ{0bB%K0mLCr_ne7nX>oI z+s8Nf>#mo5or7oFW=;mdQ>aok*)G(z@eRQZij*WEOXolsw2f;=+KznG#AO(ox)s#% zRU>dSE04ye+Uqifh+}?pq3%q3ePr<_v#-4K78a>{F)|=9Eh%WQXEt`nL*Zc zg~alHA#wXVcof<16#3@%CQ^|rDe$?w%eK2mUklwqpi>s+^E?Ov$l8iP$J=(tU0>wAhFM*LyPQ$>6v6FO6j6?Na@e%2=@bXF0%g`>JV4CQNxEoNA6xS!UY+{t$ ztrfqEpoM&DhLZ$FjU}Flmp>j9RE_Q9&*cwST+FmDIPzC_B8h+R`bhY3iCl+?%{0}DH_?}?_nj2TP**{jj4y=^ za)5NI+Vi4kYlZIp8q<-@kWTvn;lQ??WZfcaEi{Z2!f()Pp6b)yN$}qrN5y;GJu`#~0mj&yN$C0O z!@0)ipxioa@-niC z49F^3lJWAn5ddJ~rtMlQ?;YAfVEWP|Pqth0k?^?b>N^C0VnN<=@!)i70z1EWn{{g85jjJsOHH4H!Z1-4)`vj0dRQN8E5%tE+U7~2&E6yOP>WxX03;kO z-looIy;%ZZ{B8I@i*r5_lTTJw8`=Dm_pdwyR%u9NNYisA!>ayd7g7F|d%aT%U(8e@ zlRTzJ`e|JN*-)&Dwo_o*7W(ZXd#71dm%plIa4%gWZ1GW!WILG$@DneAaUQQEDhr$4U*y>fis?EAVirg=!f{j~md$UdaKZ8bL>PcFbPvNG$^8k(e& zF)lnz$tMPRXnz&|$^AUdH_=AHWq;?`_v)|ab{UUeJ*n^8Y_jO?NtFnf4?8?&0x!c) zgLtDb1!`eCvCEdq`muHQS3PME(eEPj%;R)_wU9bxCRVZxshHMTcjFJrs5WfbC8ayd zT$|5C0S?igcj6O?C`cuJ7JgK2Nzw*O$<)Q+{+p1O0uXOX`yPpV*g#bTE_SFs-!*uM z2wF5lMO;PwS+9$LxO^)3UWbM6IQzzYNQ*Y>71IuUy!y4Hi_sB3SMb7mkN$p9gaT=p zAd69`nc?W+-9;0(5BN4`Q}PAZ<@UeopiGkY0#05XOFpa{6q~tx{MNO7slQp=qax5e zSGM2qdu_nX=^(xJB1%FyGY{vyQ#7e>v%lw(q}s%WZV&7es&W8NGv{5(7kro*&|it| z-v}KwWTYVL9ilJ?_<7;TY=A4Hq{BBdm=?lC6e1m%u9|n*ZQC19N_`<}pcr8GXkQvZ zQEX|JuXCw69`U32QdH)`2umQHW;mMhBs)^nhy7vv`eAJ!6n!c_CY5487l8;g#|X}v z%uapK&v*K=Sl=aUgJ|ELxSZ?`&LmmnnObJIAOG4J>l+AS@Vh`=)WIxrqG%_W%@TeN zZcTd8hA!cG*$pl}!%~ur`C|_P>T`ZHnWI9^H>($P6!H1*u~(+Lb7Rsa_2XsVzq&~J zZ)4GH=c6UmFve>jR-7G#&kJj@27N17On{R94Z?QG_s5`Cf`+#?+C0rBn63{DeBt)V zuVUk=t5?;T#uUw?KJ=)l>Fr6JIwq@^tD4CT%=KpH9!8f=5|@1odt)>Jag z%sSby`W@zzu7ZnU#y@`Zx_{Ky>G|t7k*4SF|+62*~)Q+*U(1Y%}Ce6Df2Dv=S!vPW>03KrGK3bCTR*` z9~Qj>m*`M)b3eT`yO~{HZDtg~5rlX!`@=G7{4oDjXg-99i(r~gKs^CvYYrwVc{R)% zpJ{SFk`2|RkCC_iY5C`74km2#Nyr&Ty)e~AhMlN=9_0l4OVb_|qr?The>U=QWUrpS zaPJTNtF#_z&Z5s6g5~oRP&(4bm*k3zna5|C;+zT$=G z<4f^zl;>XVw+<0bDB7r4OswlnQb1SyT%o0g7+%7_ zWmjYg|M)$fVf$^e%pT>FKN}Dz)+b0iZp3tLe;!p=Z;&6XknakRoArb4fVh3a+lrY9 zUgUiKNy}^}U&Z(c@mVzN>^CnDYcI#$fj9k%zJvMS`8jpQ!dGlB*sHyMe&PLAJ@xCHrMqZ$;Ed+`&QYD-63#s zw9_Y!GN`na(}W~uqW=W9S)O2DSZmKSlhdyijDbDg(s-Dm=kNY2Nj>Sksj~8jsV^^5 z->Q1s4tPHfDYYxrU!`eInv~m!c1+%>IZJ*4{}?U52|?C0^t=+3p`_HAN)kjKUsU#* zc7SHMQXWJmP#a#sZBllqGoWiQrFma|MbwLOVhG50gylCSYQAjP4kXV)rJPez|260P zxvqOVBPFz?w4fT4{_U<~0ZGW1iLf;0`^P*!0me1eQ&U( z_h-at{FG)QU5rylE{L(`)>^l6u$PTdDxMUSjWzBC>3Ztjd$kz{`@KH=Ri?w&-%*nA zO%=cVZ`<31mMO(X$jwB+yDW>8!8!1!iuw_IkFb9=714iC#yTs}WuDfjp#^c~wk5EZhQU)vx1*f+YUkFlGgrWx`Ey$}x1NE(P|7=I z*sWY$6{kn-J-MOGKY$-bdp^7phg$~g5EIVfQwZhJ8cV48PQ`We6Z`Z81OBg|+&I0|2eXUdBC*oW&S>$Hxj z>GU)cz)VSWwu2;^vofuK0da2Am^uxFU^~FuFnPeabCxZOzS_ule2oL0$mr!jt+uq{ zob%%0Zhtq57$QXp)HF{-d);A55mg=X07$iKSDK;NEgt>4HjZlwVs(g zUDDdh$gt6Abgs(jvf^2wRZfzsm%?B_GE;%C;5367LZV`DLwv3Huw)>$O6NRlm|;-v zv_(5HSRlA(Np1@=g&Sch(|N9+*hP5Vp#@2LV$&~m)0&0X9R=hTX&#M8QG<2ZW=%m3 zBU~?HvvV9r&wdh*kZjRzUE`?osKf8F-PmBI^Q2>OzNKk!6Z^ItEslU!$y!JZbRmFsfm_zvA68~E>E zhxph3y#LY4DV>7AHilxC?eKR9FvP}@ExU_-5a^kuF|_WhCIce z(8GRLqaKO4-hMCb*ISter=cERg2;7YLV{l`SOHOuDK?jroZ7>3B3HOAEfgm7ca-xk z{M3Oby;{S6(~;HLwpMIgcUuKBzA*C6)#C?Z-eTepUGy-^L24@84eHT!_^rOs#!GQu zr=JgjOM;`^*oM@uv_|He7omTh$Lrp<4a=$8FjNLmT9Vb|fDN``{6t!^fK#lF^;J7S zGoFLm01B6K+XIW1KKDanisYvolKmy`*)))7`BgB^`|?NY9^(qL+i4-=u`TUYiQE}X z-K8~8#mM0&HoJ0kY%f>2)7AI>D_(E2ZT8UY-VlY;cY3N;U_A@QQ+I9M`dk#eb3@eI zFI|*5BO3NkiCjmNtL9f5D$z~Eq(EUjP5UcjzBgMp{UI5k^ihN z=C%M7)1-hm!lVOh*Xm{DsKSq>3WtoTukQW4xq%GB)9(zAK_mWG(GA)IxO`w}qedSs zyWm}#CJwc^?YytRCCHNl>$yvGe-ubGLv*I%*Vt-eW1Tm8o(~{R4D-n^BAoZodj;My zD21t)pdDVJLn6uOL`|xjA{rVawwiw7Qgw%oE&=wOOBQ?M>tm_V4^mepjT*ngUMEjF zV<*QJft%z_4YA=diD^y)CAT@UP0Exg)!hMc8L(uJF2geZ1`NDnEZ1%JKS0NM`lGcgE*M6F8r zSj(4NO^WCwItIKAi&8KJ5}Y^{qrtJ}tL~>6SB*6nC>I=De|?cbs5@u5zgj*@uLD+d z2wtsS`PfspV{pQ>>Bn245w{5-Uu>DXquXl(Nsp0EFps$1wa7#q*@hb0|6C0DNAqRZ`g%a_<-&8_#BHNG*C>OtkzFaIts_DlA9g)WWSB{?83-tg|UbMU%< z{C4%hdy>UHP>4>t&1-Jf?sIU3y>P%1H*&Z{Hj+LtUZht4Y(O95{`AHJ2U52ZMuG9S z;e6yH2a*CDgqmTqy|GIlG5O_9^!fHQHtEP_)96HwTs;VJ+oZ!AH6@Zm0i~~1Y8OXT zDD_hwcv0E$EBW=ZU(3r}BBTZpCT-?6spYloskGZXm1a2ML!|i*KS%Z$RQMglvhde2KCu>@4yq{o@#b&ueAX_;S~Cwwk_4iuSCb);qlOru<(aM_ zNCN%70F)92LsyhQ&4!g9P>|#SaUtKFH&{zgF@hhsy?|>#sSH>}K%h|;;!Li|)(hS5 z_gi;xVH6AnD!nje`Ax!Hn+^CPo&foqvQ z%+XYtHoPx7*zCtwU8J>iF$ArvUt40@OUk1+CE%={LJ93o)3l_xl52xF7oPWC@M0Lc z3;OUndT^9Q{>>204*$iD>~ z!kRnoN7w>YF~|rJ#ztrxH;9WU#v#KOW<_h(a_}3XpYZ%3aNW{Vg(xG* zrBbiMhsbYdQ<6fgyQ&rmjhOs^CR+OW9()&3f)42dEU&r02!<_155YuTzD}jCn_t6n zt@@$a#W;Ki?6`iYqL-kaVYBopicf~s<;l6QBr)%$fhF`+?nS(~SA?$Ljk_2_%XyHr zITRwb>Y41m#J%Kg`VS#eJMi{YIneC;zWGkjGWI6FL1f^{B`LvV?UqWxJ_0FZCvXCl z@9bca=(yc|!h7BT=1~VDJi_YV!S-|um#V5TAv6V)sui+@oKt6Jpm*YB((bEd)37-i zKUn%D7Z&6fUI`2#AwCJTtiNeNE{dUxYf=Vunc_E0&4?}{lpkmRhNYxZ;Yf3F2FLUz zvLGaHL7E)u9yhj303?U^piay7@2vY=Nj)JNnujwBn|~>byoflbHrYJV<*zvg2D47a z_Yfb-dc<*TQ%9q3fB?F{u~+mBac9pxZ_KNrd%9b7zoy=XZxgh{&h3-_=u;?f-nYed zf;el?Fva$5t@x{`&&j@v<`ti1JO?KY!Wk<73g`?V`xLwm6aZSB^AlY+zgFKAcvldg z+`$|r-i0i$bMqR5vVR6TEAE;5Y51Ytmgsy9h#??QR;O9|UJ;vTmlM;`?Z;`=k`>~~ zG_W@A?O^=3>3bHiR#|Cf22zT(BcfQGWT)5m+2P!x;>P!$;opN9{m&UlUoS$$@bBFH z(hlSPs`GMCb9_BNCd{#-DOubF47XdkXdbK|vtGBfMv0M9^J0>8E>rQeDBe@If2Cf2 zj6t;Fb-BXJ6N~2K{k!Ih=rXY+cYTFf)8ud{>!(`@{3CJ;M5n5K4Pj*cr0gi55pm(V zWb72|c%Eh~%lgs(fP?3QO~#mFZ}YCTU^|cldVqavXLZ8iL`FvV7d{> z_}J#;R;+h4p^$>4qi>r*r@sN+AWhBg-kLNLLkb@WvzH!lRBCgaTmwoy zaR?qBCXPRspkpcJ)K1@;h_ep9ZWu9aaEvm~6O^A+QIYOYpRBI=GM+rVc8>XY=5 z1=JA-JeB-x+v;5n_8FQ;y~j&EXHtj=a#P(%*1AG-QnYhf_kH%2@6&oXMx!(c9s!{h zs-LRPpxXqo1Gx7@-VrdO3rL(M>TekXo(O*_A(TcOF%4tx(W0YgW(ZSLihpaLYOwa) zg2SEi*e+q5IL-zDDy`1P0=5LHP%|lU#3qy0AiK0&n?fLvN z1xKvo3)DCh`P4^KYgFHVe%O4v3IAYJy!n0eAl?qYL_^${J?%mK;~K+yQve_60SF`D zjckM)mk}eFd&@G|9h1A~`xs;)YbX%5dR!;G#E0Q$Xa=T?!~|)|3i&`UDHJXFXO~`< zeKLI?!7pbU?})n8P3J}zLD+PZ`1k3LWm}3&tY11T;(!*Dp+C$*M6PUAjZ>e{z-$$( zY-racQ2aCatCHfM-LeM5Rr2lGbbrryQpHt0!qZ)?vx_9lZ*>=iX`;}XFS)k(2GFis z07d8}ej|?W3+)CBUTI1XYZl~^j^%JB)%KMyF}zj>;chIJQtaDo!|OB)B%gy@$i3)Q z$cAn6E}trLoK63Ah>ma_#6IEK5?nr{x&^yolj}-B{yAy#>I_mcQ45c-aNY|CUI6T4^PEV@=U| z&GoX{YuH{bU?8; zi4(Nw%R^=SnBdQL?kyCe1C`yLfu>lW_mJSFh{tZhNpUifS?=c`_@<5^P(h z*_^HFUw)YWp%9}6PGPHMyHgKvHf4xo3t+7c?bTbPIF1AqgFXOULE2q%WIYm?SnIO1 zwD#3L{)+1&%o)C#P>%0H!LW=`J^Ro9Z(V4ss(lH2Y*n+Nzm067o}SuPHE|mt1;%f} z%e-3PfEsMlzy6TCHYyl`g@&A|W6TH`D7t$x-%Q*N^-wGLcw+rhk7x!3_ec(qYEcf@ z5K2u$6VuI3&1sYcqhr`XnqJ=RQ#pT@^uGZ!zgAe(yLF z$4}KiU0c>kN)blMflX1tOPzf-%bJZz?Bfk@=F2kzWk|bXvqXVx64zaeUl!MYor8Y& zEy1`B|6YUbULp)~)TO@&JjK6qpv91tXB*y-?Bg((n;pZW%@;S!2KCp&>(}c7gJd=f zjzX8JSXL9Zz|f}!&4La#jd{<1<@eyExc&~}RqVT-Id6%~Bp}yxU5T@NW*29IcXFYy zO`Uy8wnj4FZ<6*%#@ibhNf6X?mqjZR{`wUG>7wjx5(ZD*Ss4uUV=rrlN@$@5lgCYg zBqxSXOW^q>pqm-w>kahmWva~E7aZNA1=8F2Pyn*mJ-AGPlAc?9!dT~i3^_%=W%Nn` z(IhKx$d{cI`LKytnp5w^{5(q*?ako@jRf)cjh4n7y@2MO<{U1xF=o2nr=?4-yTiua z%rP?sMgzU(K-EW$%cc=*^SM-H`PdjOXU>=ZKKY(RkjhnG4H$HP3_1JEU%oyGjrUDc z78n0{4Q>^Cau^5=9?9~|?`UqvRA@`s`SZwQYH+9$DVUITL~lDeNVf1CM@+5$Izz43 zIeyi)h0GjosV;j5zvWu(7Fh{BEpJa;NFVE;e{M@@8^qs67(=+qB!`XSnKxb4)1BNd zja(ZPF)&%ah<CE)iAo%TR~Sh@_WVJ_t2-#O zd9wqr!0VS&D(}V&rlDn={Rn&fL46i&f&e`@31VF6tNY~EJE^9hxl#gRQGdG22rgePL5}55gatEOUJdMaH$&?zPiFhmRR`UIgi+n`k530qrIeTghjr9J>5lXAryNjG z^{}5L&|GpuU8d^m;-=cc6=^iVU-@I*M(rI6Y9Y;YQg_%JC_uvx=Yya@)a!>gdh^?j zrtT!kN3)uj`Tow9G=O0=FNNrvDzc(T4aqBFEe!-h8c{JB3Ec;VIF$q>|Il4cQqRC4 zgm0PA&iR^OVTAR+GO5S!7rj7fe_7%Mv*YW|3+597xBBRP#IGZuSU~cI%trPxcfyL5 zp4%>>E=hJX!TY^5F9SrJ51S3)3FC-^a0!qld(TVqE%VY}^^W>DC(yjqSvV~A#3HkJ z;DbQVR&fQe{OCJ6vloMoNRWcYJgse+fxvTKRaPNf%QXn`-SeC-r*zHSK;%DR&Cq`P!>+XqV0iGrI`OyZs3DL?=Wlqo2Z^rpo9FF=OM9iz+WYMoxlR0g8A_CaL zg@u%tTE*zQ2@{Wxz?g;G=PT5)LBbLf**kduE-@985vDZ^_ilg2ud$!--}=R~{0FC) z>k~o1MPfSkDJGghJssk9!UJBQk>e2lS?Upm9zm}ZSRq*($DIJrL>9}B}Hn;0zo6D8Y z&~h33uCE%odeTRX1<+L3K=vxAbNw=LNA3dSJwz^TZyfe3abhKSaLVJXS zB4Wg|{;v^tHlg=Br1~+HHF!;OW`{%{%LigFcnY1sH!q(6G{iXvn;be^(%9Ixi&3N? z-1_fkdT%4CIxwd5$5jw& zpEpNLFZ0{h_)-o-#c2zML8Yw*5QpHDERMa?6tgD@V%i()NSWSmL`U32SM|SQcWv{H zA%tT5U+}>5`~3;m;Gq~(h6q`G!GM6$c-f_&8k_HBT|P)Up6&I$^!8t6+U!tMy0Z}4 z^k*vAO#4cnV_P1%mU?O2e*r-Q^{5{;Sxw4vi~%i9ph`MvDcQ8*m3adfK1X@dSTaGc;B0xmoTrqpd;M_ z;7InLct#0D`?mdlXu)?LKi~NjIHZ_t!`e^n@0>p^k5eN`%WQat^@qwESzib!Xa9t*{3Mvade09Iho+}L$i``ps@2@js9w)Jk?She&Q*F zw6-31twk~2@Xbg1+FB-^ja=S!wLeMiYAnT&tWvOI5jv4%rsybA3kbW3iCeoHR% zq|Gs*Ox^MqB~irP?3#OjsdX-mF4|Xob}26ji6Klf|l=6)a}{4;PxhM%7`L{`7oem$VGXZmw~xAkA` zBNY&kP!e=3P}RD>|7=pW`2rStR+I_Uuu&v3#%*K7#X^#S)D(ET1% z9M*j6wzg|(uygG^tYoEcE=$EMM`*!R|1+`?e zn@P1LY5q{K`21FF1b-f!~|^{T#;YY=%ezx|(ALG4(&&=qECX z8=(HE3LzPW-!Hi@D3PKS&L(T|O$JF_RR!$IiDIhm1tDcpoUzR5pRH7#IlDSVN8Isn zx}|o^dn=r>;ca-j;@fZ$Ue6P zv?z<=QydKWAxjmg;f7{;&zJBNGKEHDx0!Z`y+6VI^Y~is+qz{^=s*?4!K3xZ98Q!q zGo(OWIXwgPqquO%(DM5$HGsWK>AKr*4rrf?BGV|-icTo*@r7yM9J^T9!h&lJX=~Fa zsG|^M!?8%B{QT{uNXzl14HNj zlK=|%uCpU49^#p;x$PbAl;NgJgOyp1&IqeslztQU+wESAtSDW~OWvp3uI8aWCgPig zRk~*Bd*YDFD9N|K#+&axH)63|U`| z)Vm&$DIfYH9xR>*yy$0HB6MS^C{GnK0Z1V_BL=W_O)8Yt7*5=i&Op=K-FeFB0`B#W zKN$0<#rgg1u^|mG9qO=k<<~KSxd4!547Zy&rUkX1STd-?wv*IH5H@Ddb0MnkwTGz> z+2VzfFLp7zkXGVtIaF8T#qB!necN?Rw34V>XSnP5VLK0&2*~e`2NIhz-3TTAC=={kFay> zRg+&{(_r*B+5lD_Qw33Js-hKn7?L0{(h~@T3Qt`$+x+LQmV=N*r%o{ssZbt5UXEjW zJdv+hk;=dvCI%u~!ee>Dli35@CNoKhW{=}FQt+tRl;GJ-3O-r@=7%~@$_a}}*m(g+ z;=GR;Pl`67XX(vuHernzF6EZ;VUTjI|cQB||=aH2d z=iIkzK;tPi4I0r4uiCaA^3!}rQhEhJY+a9Z`Zkx9=hBSK!sfqTXWblm!SP2r34w=j zfpQd`kJK_@Y)^4+H;-SjY*&JKeXoIiOOMPw%bIXPZ;0yO0Jy8VW3kM`rqO z-*3d0_*yx~aZm?1P|STx&piRHW)M89eCb)vv-O27>79}SKW!sgtQn4quEpy-f&qN@ zx?v8~R_$&4B9c~d z=Ci6^p9E>>=>t_LaH3&r{b+I)A56euJnmtkCDT zK7(wX0QG^kM|SnrAfpyv9!73RhH{V5G`Bm9J}6?^*qVJ{WZ!m6n&oLQ`HvoTYKmaj zSu_p;rz?{Wys|vy#}^Fs?$U2cC152@+vG+BYAdK5Dw)GtN{%PsT9>xDt*L625$}@) z>=S$&gj1AHqSXEAnjVoqpol=IpH)Y^X6vf)EPZ;~b@gjrrh+VA+?_;lcFnYD#ZO1k5`gZfo52&G9kDUpPLkpMC%;VHg&+NS1ez5zxbo=JT;8 zvkg}u%W zZ2>xhjrvn1+HdqqwHz6HkF>|sGC3BW7qY@vLs-eTUs&sEZHVh26AmP3tV#V9d0X90}^|u_f=s4h_p^5lx;}SQBmQJzUY2Z zCr2>SW3thKQz@RZiI!gWWZZS_wYZ_><72a4?K2s`6}R|D7mddcJ;g1?hoo92ohNI- z`RFXquUF*j-p^QQe0}?yCMnehdhA0 zpfoeFI2Bs&x;;-wcAvv>ok0TE+lNEdQ_-()3di1)+hR8UgNd=nlS`dFWsM~`{B5%jhTY)x)1(ak8jWtHU{Rm-NY4TC%f@7 zCvz&H-;iJo10Q6%`d=%S-^#scs@-bW?#F!>B*Zv=P;43tKhhTo|D3caCi)Rs-34mJs&>yf1wgNs1Lc9@tY zpYZkBWYPZ=4iO}97DXGGU5je!F@ev$u#Ex{2#Wq7&2sfwb6JwR>sD0+W9I)XcewdQ zUbNLd!{KK*Q+-}DPd`@&j8)?JOFRQyavYcW^O13(-_+4x|3kxspo{3%_gdMm#fZp) zMY0coft-(h1~*m#Zb;UbBJe6!o18Tx(>{hPN`J@TjzjvQ^4G221Am;-{OtFzp7vUb zvZvQBfGcc##y=S)VJ}dvB|Esbpl~C#&1nAJ4%7;l_^t6$IqEN(?FQJ?VMTmK)ixZ` zah53p@d_C%K%dUOHk}XTJk-S&^9?Wp9PSX343p31)Xb$qbBg65`RyC65RQ^1;okIu zSvXf%e_m1D0x9(QU=up(u2l|-q@Eu$59iXI5W*lJ!tMNXYxFIeHsg_g>)uvx8R&o?FQW52`9T#F*AQ zW#czyS&{j+1B(9jIeH`j2(5O|OkI;+6VC=L@!Qp{VA!^XFoX^(uZRO13L&Uc7KY7t z)VAJ~y~74ib@~Zg{zw~?=BD52^=vohEi-vmA!Vn-xbl9#2uSNfY@0iL3mOwpbq;** zizcug`=kW2y9kM_rzHU?daLNg7j^RqE+8H=1pZXctk6UJG@62qqOU&JyM9bqdpusG zb_&=7=1&$sT32XlF_0hrIa%bITa$lz_jU;fk0?ao)2%vM)+BuM&Ep_pX_wwr|4t>>ip@Sl<^hjT{ROSpN_S3) z$Nl8FdJOwb)%KfF;RsKe>Wz=w4XUjCo4TjI#{dxXi?kiXOb)^o0s)H~jUdA}e!vV5 z*Ptkp%+u}FM7owVW=ZVyM$IAL%I23w%g6zIxI8-D@nIDqeX0%gvKj^dzUo+eT#s>z zfT{v~&R7whBv&KPmSS4H1+d!ax;Iuqi)nr}Altqs&IeUWRNwEnO0tjZntIEOB1)CC zEn~>SpG`cXy(MF5#FGIBG@Rhn_~Q^QJFvf)-@1py5D@OOK@}dh{)q`V-OdqPHH(y$ z-O`f>L?SGpzIFBx3U(^a5tO4;8`s@ZBtAjr-@F+kbvlAC@vj-A+g|PQ!OhF`X19Z8 zA6xkferL}?Cq>;IFcbbFaRF3PKi@uDJw4il$WU5oZ9{gg2pEd0xeYOkfi}}SoJzEOi4L=3!0;@-L%XDwe>3O zEvy!dUeH$lupO#%=>7KKS?Knt^=;?0Dyke4uJ3bjJ&}B7n}Ux|+0v z(}YLnkK0J9My|(;L)~U?fNYH;9v**Id(e|(tMI@R} zJeO+TG&wc?JPHZt3a>JU&bk}ApJQ3+-+=iE;iV=rt|gY4R)F;}Bq$t6P1)A$1Y8{a z))NF1!U4*)Pf)k(Qp6q?0t$3B$e4hPhn}27zq|0ByxP*Z>Z~PT;Wu|b3jPWS)^`QG zOkym^&^Z@gS2F7{MogFJwUcY?b7VkIDfDa?d$&a1Pg%0^dE^9@^I>bAU202^ zOEE6Lr`G}X9mJC@ir(1^%JQ0DIj*fu*U4kBG(OfF+HbO|(@Q1S`IS9#3PQr@4)5Mj zXk@LAI!%+w+!3RlV5G1XJo^Uy7DS4}!=_1l>d)awKJq>hb*CD4xsV-A6OW+&SsncsQ} zm7TPPLWnqTQ1Yigd#Er2g>e&k&AtNhSyFw@_fNhWW)w*3iQcr6p1g=(sBbMoi4`$| z?Ve>MU)cwNu*>{T{BKu_0|j-T!J7**>`WNMD!(S}sCl4m^fY`RL#@_iwZGM_AfHdN zm_)5GB)mLSjrX+7kDiM$SDBjwnRU%y6x2;{&B^PVR4xlK*aT%$GCNtkx4wc<_!;_x z)%nexbu@Bt2}X~0^D2(C`n9oWfXE1|pyJ*juxiP0$lnC;cfkd|_$WUD2sg^zE01yP z4*GCt$Ah?qz+yoDZhu7?=o{N_L|h*k!QZ>7zLV{(bJ&9>;<0UrM_OH0rAwA)q+(69 z>?kS&U3~c8Qx&y){Y!5vTy0LII4yup`zhQZDaq5jpHUAxjiz&Nun4oWy)QZT-6n^lB zI@*4ayr{b&m&MWVyK?=Ff4&OThe?)_EzUPr;`x&4U{zkFP{~QiYT76J-hl7o^GV<> zHMXfu!iDLoE%c5I2cp~X-l8uPH<<@r`U^0a{uC5AHuWfm23YXgVt5Re_^wDSEhTs_ zG-z@$X!paFo}#ib9z;<;xd+E1vP=_?f=-q*7el&g-5?P)27pHL*p0XxqS@5|)|$Af z>*<;XZ|9so&(bnQWIm}uNc>zT^bFksa~5;DO2wm316f?xQDz=a4nxoH9?%Y@fZ9LA zzxlS7OfoMA#3&(x>A}Cny!*PlQKnH!3{CY2shl9a8s_;%oOQdR0@Qfs^VFVWfzt$B zHR3~_^6w`i01E<%W&z=e^b+cgqmT5Z23z(Tu0{M%tfL164l>>6GCv)Q7B-B$Vs*h~ zmaR|nRlFl9-Ib@%f6;I?U9Kb+I%qFevXs2ec?0E|!ue}PyILUU>HRI&NddI_b8SH? zFMY>u-nH>Z3NHD{ur&s_`jKic$|pQe!4o-Cf9;Lm*f-++Qz!CX?M2F)Mo7Mcj`nU2 zeTW16J^)L6GIFvOWl8CX)1BDMK0Au5bW=7Tc(!O;T#~WdfPnZNDdi@B^ z)18&fjl$Jh(e+$X{?3=*DdVV>&c{RDzama)7r|o%H9fZEUfWJjIAF zj-B8JR<~dX5OV=mtWQI%E7vqC1C!VjoyG?l`iv25q}7?IsP~Uoz-Po;%hA*x>{s?| zhq5hc(e(@Oo~n&(-IRW}047*bf2_W{e2Lm9lENn5V=x=38v>KzYo8KADY?@s}$5#kKR{%2JwBDf=Qoc*3soOr+?*_F17`lr@w zAByQIb(Ejccl&c-lB~XUdD`rPigu2rOA4H1On`CA41yu$(adLirh;)t=I zo5@e2#ph|en&W{#+R@+M@()W3&XPkd^IA>qsRs1lK0;%7!Fm5%C~+j3l;)okt6=63 zhr8!%eCMB&Mol;6jGiUvlL%M<`=AQfSeNlj1 z$Y|%Qwm@L`*q%#h0g()c59s1$R`z?7Nn;40yk{FG{xeN1Btx!WUm(>=6AmVoZT{l} zTaVDY{IJ-AV#B_)Lp?ag1y7Wrt3{W{T#=-L0AxH3W!J6Bea0T8ZAF4dOz>dXt$W5+ zHh<*fzDdkbVWc9%>e^-OHKrQ(DfEEfl?Q#j!?sZ+@%Xigw)fW6i!@<}a7qJZymuq_ zPBgYIHn?hT0c?$K-nHZSV<@6|BB4|9Th@o4nu%T*-2us%%&FMQeC%=AkOAD`RmaNh~_#$iiEZv;8HA3gefO*>gqbP+x%>^ zAet>e&aUMfeWbOACr63J0Bv~Dd1Ax;GzS{qM8(xVFIvP;A96n2blbi4xXhIisE35M z(EWh40;^vY+2N1meax&T;SHyvn-fJ3G0t3&Q!n&IoNoWKY3LMo+f_g0(L z`Q9j6ELjRMI{K36kUgZrF(er+F~`t3-dLkx8Bw#H`2)9?Bww+~j%hVdT>lQWm zT3;k5yxd6y+dDqezr{yqdT81xJq0N>cK8k zq+7L)T0G74`S@+G=7SSd-xaI85PI8 zhcs^HUcS#>5saWJM+t-TGStIQXfWf?Y0`ha^reJ_Ea#i#Q0s}5cs2);w^cWk*W^-v zf)ehzqzNr6M9t0}UuMdfZ{~J_$r(W17^xwC>#R52EHA%R3#oI{R2el6kO%S2erKkT z4k6c_C4#b{9>#$?vV)wS948v#(FhPpN8Wuni9QAC8r}pP_+%Hu`IhA&ssGMa>Emz9 z_V|2(D`r%$8wWCVV3f%V!pm727Fas>AF6X9I-N4|&0&5I4Nf&-Eb~~SfLddeI&H-H zBvZ#kF~fb>7|%`PoC3FYKLf}2CXY@=79d&5Uu7?NA;mhMSz-k?chM5$$%fuBuD#W# zcGkHSE|YK0aom6bdQiealmHXro-{$9Qtej)!Iz{e0J21 zJWAyIZGCo_L+yewvWJZ_3DR$>ua%9_DqscXQ^$yQ8kI~>6q>Z=fJ(_(qWjwGV3SI3 z9}oGvLwHJu{Vi@BPo9~_AOvsYiM-))Q%hXU!gF-e{>{N9{D8gEJ};=GNcSBHDLu|& zbpt;4^DeNzo1fv@L$oKHCC%O0V>-oSS6WZc&4btECs}(=n?g9nA3g|!$lR#iZ@ ztdy=(ev>zoCy&-Ay346rhGCZO~u!b2URle*!}&=HiJ zR^5Bg*Z#Sl?I%saU>46di6gz@S5U;!HQ0|6Ah`AFYQYkMuh@1(OTMFw<8#@279IE2 zcUYbYopQtH=RRRxRPM}M2*9bGcAqSFD>m!9reS{Fj~5-bkmo}Yqps9)(4tQnQFooS ziwoN}nWIk<7i2a231h6{ zOFK&`FeoS(lBT7>N0dzww3?MOF|B_+?Y@10jh#K@Q($s@IOb_kR!~TWXw$8T7&M{$ zdHv2mEzQi_RN~`DF78e>xSqS@*|s7jLg1J{#SaY(Oh()t4DT0~AD3cmT>uI{i$A%Y z*AQsa6r|qbs46^g*??UL_1rB)!azbjtuQMn^usih&;0foY$C^SJwXW>XGn{RC1LST z#y%p;)ahR{96S}&^$TJkFDu0CX0r|55~}+`ZayLPeIP=&(%7qGn{Nqd+p|)6Z;t%% z=TxlHYb4TQXtXLtb0Q&b0ED71di>5B>}AQ%4}34IO}^g@_akOJ~G*+%pn1GP$qn5dC`hxc3lJk(sVI;`r1-C%8-jlR)zP z1sVHR9YPyg>4QZSDV!A1qy>MNXvA=v2HFM&8w+%Gf8+7x2{k=$gn6_er+ynUFFnX) zBSpUH*UF;h-RjE+Wkk~{u7yWr60Tq^MZv&N*SW4q$TJUYQcizZ_34EQzaGqaSoX;5 zpg{wuTgTHlS0{}1i}Mg@n#cg4xJFIgHR~XcaFpIB&t#}PE3?K!xcyB-d=4k4H8%6i zTzf)r*M7$^Bz~_tAUhP=9v#wlfR*+*_v#szW+U~5Pp0t785_JsjXfJr! zyia;q75Q+QS3OyNxhDDIoyMBKBy@&iuQsBJ>?QRzn71RIr(d}Gmey0POo#6W;(6P0 zGa27{x5u;l*4>9y-@p0Q?(dNG|9j|K=DS|c>5nyf+)rEbAKlOPv|&&8Sq@C*xJ^9% zXBCvSb!bD;asBn7XN!He*{Tig8Tz&6u-Uk7)P&lct=tXEO+(d*T#sdM04F|KqCoR3 zXgF8ohuWg{qYEE%O}yJ$Pr#kV$tp3TML=JmF=s zS7O>tGd?vhJbt^=7#9@C7c_ZISKeRUR(KR#1t$82kF;*`U3Sq32J)&S-1=DarnRRA z69V+yWcIGsST&F)*}M{Ke{Il)7@yiAii0pHH~k&1^=t8>SGs;Mk*z=e+R?Kn2W^jN zwV9q`yqw9>^bklOY`eE;wKo}8xJGT98M*^yvUPi8e#_OFQx;|uV#*ft3c-EkGw+j^ zV#2n$rW@c>)=23V62zw=X!y`jgYd~?$r?%jK|B{kMA~J@^4lGCW4#VpiLyGYM;O0@ z(uDd?sFrGKtW?r4!PzjcU$+utb;EJIuFq39+z$Trq$f9=I??XUHfqmi&|_cyazJQw zq%WjLbMNqM43)1o6rH{|LUJpq5MAdy8oO^qKPHD_B`dNX@agxJioop)0DG8$5HxJ5 zccRyv)tYFvcTef>uRkG8umsn*(dV0cH2o<|De=}OHS7?jt5f^+?U+jtO?+0m0E={1 zegs>doOJXPQ0-D+3!RpR@^iU9w2Ua&UC;1*0j5m`?`@v2 zE(ms@^PSZUebOousX} zfA^cVKQ3$Ek&5|Cj!Q!6*|!o`tNN0+i=cTZMYvJ~xmfNoRu%Tls0j8-?s_MFHY*EH zr*7!wNHK`zLHz1bHxbnOA2?AeFTZ;9WZoLY;=+sCJM!HGIlrQ_X_&h84JzDgEv(PCQ0N+Z zEWD1Ws+6^lDkGuK{Q>t3kB`ZFyvKHaU@P{Pz3Y0NTVuX=z(5SNgq=$`wgUB#apJQL z@oqzzH)9M;9cupqW%cy(cU&-@Xi3SG*m}t)j!;E2xMwmyUZT}!A`OUS)vu5#W@m(NK+HC^DkEjxX-I!SY-AeXDGC>>!JWFGXS%HN$C zsOEdyn<6jU2wBW%?u2jD~ACDQl=4n>|WLa&aJJRKyf+DjvE-I9xO*>B;bS#Eh&?;a`V4rS}@naavZHzbnJAK6Ifz zSOUHS;-%PW0{be2d7guK577wWC=jv(&DWVKj#IVR=d5E_LG(>w?&VfP5~h{<8m(lB z_g@#OnvT=&i)q<@veogyTEhO74riK)uLz%0Q#qyEd~1xr>eYo$|BtjyR`(Q#@Hl!;vjmssDYFfUFP7}-XCBb;j1 zul}_2;M%)A*8`^jRi)W-hFb}fncRg~*1Bse`Fw*%;?LBDdiu1yX^N~LMN*t9cl;Vv zKdziis;U+5&xhg(xZm^*T>(V8?o!|Lx{*>t?k$l_IH&1*ChG2HZ;GE&IPLi2h&anA z!}@e_uI@6E2?h{?K0t-ObiS9TR&WF8OwXdrn&M}?on)2b-mN=ktj{D@`fHYUE5&Jg zwV(iP`AFn!xH8dx>YXW)$%K|C@m5A(fEn+FV9uqI3Hsuj8W~luR&Q8aMwQUND3SX& z5G6p!OnNztZ6>MzOMVT0>)JXts_mwI@d1>INqt4ETDN-+3;)v-3%sA3&S*$IinAtF zeJh$GPv9##o}&uZW`P2<$GaP66>9c*GvP}8q8S79=F=R|suTmPKR3JeKDY?Jw$*wX znPR|n9{41-aZEyt2{gC*Tf=C_-_jwY`Hc)fd>{g^`glckc|Calj}zZNTNeB&4(oGu zXQj3z0^;!66GjQ&TUu0cWm@7db;PyWi@eX>ZHTJ6M9@=IJSa3CR3ZHJ6#L~fUaZ-L zK%9eA_A-$XAUi)LxFt+JnJ(X~sG+|`?xX52qc_ub!XR1`pI8Xsc*MS4yB5+~=jiLD zMX$z@Z#;dL@>K%J^@ZR}?~nEw5XL;FIYpa=pAFumvT|xZ&kkIJWoS8?EhjZPubNjR zzo*hypF8qGp3W?6+|--)9wFnxzf(ngo1%QzA{$6|ueNT<J*3E*EqJ6Ky$cK8@c64=G zp;?UEajXRCz0c57UEo?+B;Ct<#KZl`xncG8k-W$CWaOXc{wh`?R8(a8kw2!_Gb3p92GR)E5p+jO6;)qnuHm$?q(ZjrlfAI%ezI^Hv;FIQJHCtd2!=Be# zv?B%)un#JA?-C5M80gj2Cp-BZG9T@L@ESEM=WQDsen0xdK{*n`iW9WEl^q%vkWa%72T9O<4U_6kUh`wCBA%TT9&eB-k)|3e~_;68>eNl*VA- zvxZjSOQfh{EjnJpi;MCq;YDJx0SFqUuEu28wI+(OhK)=cNHiB&H~LoaJSDrc;pRu1 z$wKSm_1(nG*?bLZR~mXf``H5t0F99|FQ;Y{I)!K*g0% zKrlhn_GNKVcW#B(5*yO+pm9SJ<=~~ zI}uBC3;U@I0zHV+mA>DPFtnL3mauZImS2{gjmBlBtWX=#;#zZQXnKb$%DY&bz63$jQC&XPZm-mwXk|Csb7wF{PkFhcdACK)<$J#*<^b{qj!~dyzRF+B)=T_)PuX9 zZ!b{>49NjSd|=auel$xQ*n#vrFJ1YMeEl?uWTq^2rrS6wFssEj&3bY?D&Z*x(%fLv zjANmfhQVHb$vtyj&F2pvA8rh&9VgOs}O2B zW;KdWrq6px(DY@Qy)~K4y0}-ADHWkLZmG)~!-O}9x&A?fmtW?{8j|YWLPx<2>w&1K1BLb5cppq=DL7i25%eh&}05xh-X8lmmwD*=^@?|(nOeO=Q3tmySlK34| zVrVM4%fz%7B+=PdL-^-Ek*uKz=l!MxX29Gebp6DB2i1D7NWTT*VMSM0&Hcw`?_R%& z0>5$F?qKaI>&|YhsJtYl^ph4>$>}3Z`X0(u!RN<__#jM)M#UsCoqy+h2Gv^tq}j5JSxo*#A4Ay zkv=9ynPo7&E8@A*zGI&WgsLG!f~$Kg$duwa3c0o$>F3ABUrtQgKtP%Oqp(DBhAPpE zdhY@W3~1v}q-WD=sCX08L+wxR+e0c0_eWjqnmGV;*}9|6%V)U1$odShlyVP4z*;B; zOiH}hoebWZVogN-f$ys{NCct`mv}X37ee2ADV31xVOGYT+~&3$b0^BA8!h3sw~B0a z6eBZ6m_WLr4sl}voO!e4&b2$PA?%t*QZITgceMw`_48=+1fwAnUce6+xzMRTM>LMTRocsQCb*%>utE$MnZ z=D7~f1+?Uj!~63c&sV~XWWta^LHViLRjr~$;R-4}+?YbQ zDz0lKt;~iEOdhy0PIE4duc}e7CSqAyy_Af@UQw_1okOEu1GEGJ5!GaP{>rz#=of%o zX{0B!hr2(BJjfs*oQbn3<}&-j2mnzr0O?&VM75%<5hh&+kpsbL0X9P;U#3~IZ z4AJU{p_o$h7@P0BXvy;x2te~J2cprn)}>qdeZM@chzxo%&I$e2r1nN$NFq0DY^kyK z+=}OCiV+j3l-P&$mQn}RjAT3R*PW~Hz=PRGTeMU_nwnpj z6zb1JyH8qC>)-hotUL#b0fnvig|)tx)h zCD!Lu8Pe5n8S3BpJyA4i#Z!deqRq3U7atkP7>Jpr4C2k?P`mr2!MPftl_LgG6TQGY zWFmUyoB>q@C|2lyT_>L~2_B>+5dG;4zMra@g5eg&KPOVa_s27AleCvNSdosYmuD@; z#_fsx&b+lrT^nZsl?y7J7OVvp2bFc&W<*hrBC`~?!m#E?vcc1Ts>}Q2=kiPRu`?^! zd(BG1XN)|&^$p`;p9&7E*UiuAQ+ktESktKq5evDmv(9KzLQDoVQ3w4LW|etnDGW3* zQx18d_7!EJ5M3(;@~yTQQc%t~H->gcd{$(Df5+ORQ)m`g!o`Vc`2dar5}uV_MmlnR zNzG1M^XYrMRj!v5U}tJ%Xt5}tgJ@zIKr1ZxNtOakcOA|)H;BT~t;oE-xdY>|M6w^KVX>vyVrN z7+6F=G?_eoi3lb{MRH2f;@8L2Uv!GnuMY&rR}y2mU2<;PVbI+3J8L#2J=`@incGNt z3NMlz5|_TyGjlr*RFWBniII#M0Ldf|QPXfLmp?uuakc}ECGUIGlAE>msQEQ|cEjKl zHyrydc?T0j);@1Ey2}#cay4i?DMspwV(hX(CIulN_E7~v{$on+Aa(`3vo1W-C! z=(>+bIB2wnL${!Q^et8~kXeyF6sdW|de59IDm5C( zO+eN;{vxWNW|;gY8R440UIMA$1)}W=YRH1jDv#9;gF27aHTMqISeL$Yv!25u7$;!2 z^9@n4F|$N-ADTbjsk?X#D8E1JA|V+*_MpSLIK@-BA41ARfKgrWb=*XdxIVi`wUN}Q zk_~0+aL#d3W$HDWCwg6Z#u|E&1_f1Y2kOtm}4aGieW1 zzhN!sE49m(512(XY9X=CZVD~&?5d{jY?mJDbAf>CwDB;tVK4Jiv3xbqOh#VH7KEAd z!u`)9WXxGwgU5qPQ`joqh(q1uavdXMoIyZN1Gc3_JzCWR)przBJ)^zs^P%*IvcKBf zC{S}81_&~xl`LF0M{Z|`5H ziM1eltPqLvUX`#bTwN1ZIi{$B!1rMFx_$0%Dew=S;U9&={`CZ>A*91hwL#0sr!$y8 zU@UuLHtOx9SoQFPyN@bN1No_a<4b!o>SuAeI}vs8%=4Y{3%6M+i^CRWwMrxt(9Ff+ zW1C;!AnR+sU?T%TtB_iXS9q@EKzgcD>F+#_4~L|JidcVYvz(&fSzNo3N3UI>6mn<`XH zcm`$&b&Lw9vaUMY)U>*?Mdf%@2i@NR&ei^sav!zuubHDad z*rjtphP?}Y9#;s%3cmQ%x4c3(}D?RR1}9uva8`VjjU#Xt~( zA`Y)74BEGKqtzlRc@&^!BK&$y_h~7*%Zql-1K~pi(eG4z>$r%B8)WsufH*L~lj4mi zx0`o48vX9yk(sF`{L*92jQ9`8{95GRZpW@rd5d~MXdfq-A1?$-wUbS*62L8>aHGB)Cvzm_6&G`_H*osu#(2!QLY4k3E}wO!0YF<5WsOdkI0v8gR( zJ|rWjY^~^BL*KL`3^w@AJ0-7FrJM~iXpf1SGvDc~MTeI(dK2j2c_F>#pdNJedJDRc z47c_|1CN-}a0(jQ);|gf7i+s>Z?x_K3&{NZg?(CCoe-yPe#%!-^3D+sz1)2`I3!Oi zycw?no>*JGu)bPn=;XR&-vn`mUZ42%H8qH*LzYQtcERv(hMbC=c`a@;Aw%6Y&AZr| zyIEL-407*evCj&Ma@W9Il9h_vPQ&|~7bVC`^^}0Xz`uz4^n;cZtspX<*+$blco{vV zX+^W0%_HcniqAdorYJw3QRsnyj3n)C7itVdDLitoc!GlXZcQI8J+7aaJ@{ULmtNJ% zu~=y2>7 zxEn!nQQOdqXVUA_TfWGruMKZzO;UZUaTzngrL$k6hUe8V zAEH&8F4FDEn-?dML%9Xlm1u?tAg8CeYQ6P#*W3d4vDDvYMN@tAKK$&q0`mDTI6c8d z20h4CIaXwH%rNmdo`Mqgun$t4wjpf6V69RTNl2^nefGi6rlwS=HrxP8#?Txo?#=hn zTQIH*nT}Ch8yJz2!wy87Jt0LtLuuZcee7lzS;?22#0xXjfVtKX8LknuL7P^dy9UG^ z7G(;a2{tIb>K(OB8?Q2+KSt9F)7r-ogyvoMdm+{8%*=AizfA(Jz94Yv1s8Hlkox@+ zfsqo)J2F-)KM-=|83w8`%zt4*Y68X1eb6Onsz%EK#qS}q+MVb3i*YsOSm}MIcNSJz zXB^+!d#OpQ`nmWIC>$!TcWYbc&%qE^H^T6MsPkq@Z2*XNo zd#N3_+pOx#De#G~vb`#>2c#W0)`hO3XbyAh zh2Sc*bxord2W`=re)ZiDqM&q^UZ!3)Iu{XR#cNI~Hje(Jd3FUPm$^ju zfmddob1mQejhQ+|MVx-)AA*+(lizhWNU2YIpcxqXYRlc^@$Ry*p1nGEztz#?QucXC z-Bc)U(3v_apw38qCjkMH*uOOazq5{-$8KuO(X3yaqnw{?%L6-ZJ4LxY+z;ZQk=|?I zjNtyX{+(}EL^X5!Vfw{v<-%$7^77aNak_)3a`u%Ygp z=XtY^_)s^h%Hqve;&38)hRb9+&lbmQK-7{c(Kgq*h0uXqJ1&BZiA&m3HG;i`$;3eb zKS0309ewz@^FUJ>f%>VY8xk4Sb~PC$?^KjvpwT+ zR9mIpP4Km%peYx(co&92*F?C}_tga5Wr*m>NVU7Et%F!4ik%Cg$c;1~v~&0@P2^kf zYs>0N#?{ihr_|LvRS$@F1AV|6{-xHKYNj2vJ!m9({#AZYHyDx;Q4%oft^qZOv7fyP z1XB99L&&e3W^O2-%Q94@g|PXu8SgSY{5!zSZ?a^nTu8nQ!4+}{af~`fnWy_{Hw>w& zCdLL$m>l+-1BD>@OMW;JTL;x~aOLo5nOE?;uAkvh%W%s-=OAu4o%L!yHDvtOFZG{# z{mD%Y>BC_cHZJS9*Kv}^QUeLI?0b-0!ui1`!>iZdw%9t@NH+W(GVRSY2DG9X2Boon zXDWY8LFHKL4T|oq9H6X>K|0DJH-Ea1TePtgQ#k%~=aQ<>!2LYN zNf?Jy&7E&c^S-uk=UIK6ZO%VLUae-)kq|EUBRP`a^%H-zgEMJg=00zVDYJEd3syWN zBDIryI#tGo=bzLReX)e46N zPG2CuGdC4ohJF#x)%?RN0s|rR9Z}{| zU2|~>VPJA!(|wQOdm8nXG~}vLHjJGXh1+NW69M^5m{7#pQh$9Q1PE>9JSBQ4;D?WK z^p!$dN;A-vUC61vTk{Fc3a=JaO5S(FR0GnVuNWq2!m)IBRYm`^`n+W5|AKIkh2Ik0 zZz}xX?qmC3@Gx&c`Wke6a%v*H5*?F8E1ZAfSO#G$k;^OFW1n#lsA=*cRj!)Bd43Mz z%t75WSGu}p68bE@=m-kb2=BS9*$k~OeDi{Pv>Vaa^a%R&BkJ4-au=7Vb4Am|8r;-@ zpr62YW6@q^QKnf>Nq8A?8Ef=ZHa}*`O56G!BgJ5eW}3Nr4pMb9W3p3D_qWra&4Zs6 zj^_+v#$u!9GgrO{k2T6B&JQ0r$L*QGf^d3OWW@r6cUAPwhdt6w6TOzioDy$k(H!?~ zzT82+=zU6$jH9GD1E0trQp?LI+_%D-&`A8cCn zF<58jQ^S*zaC6pT@{rognN*=dHWX}s@wl^MuSZ8pWVw7{%EKy$zpiq2-?O&^Eljqf z9VwW$fOCiBHp!wpRewdyTNEVbJZ%PT7C-?NPzD#M@s$sIoPq)27Ok)-|4HyMNi1_i zf(r-_cFDyLyM7HIkp&$GD$z_;nnoHUCVCJ}hmb`?LH_ ztN1uYC4NmnjCVeDgg;DtXdcdzun$lW6K;2#U-x98>YQ=UM2sh(>_+i%WnMkGnjC(W zy(E~Llm>tXrQhFyRYv-CT6U}7($4RU`7g-L-=S7!6$Eu^_pMfFwQ_PtRg1-H$@(Py zU)MD^xL6?AzvW&I=zBcC?!{znJa#PGiowT|4 zTz!?b4T0*W3lXSZTc-gkWzsiE6hMWls?zj|q*T*Yk1SMOynFe6X2~ZL1fuIj0byAh z7T0Zwe>ZvTLE&jC8MolMKY2G&`ziAW<3R!0K60LncwM91E~=G9eqAv_c3KRc3=9wj z|EA{~>KIfU9EaiC6E@l2DBFigM`mXvNLh>Sk;Y8)O0Tz!ZtSBd--N+s@25AmvaL}w zzxo1QTxdT39M*2;t&Yn5;Wlpn!qGH&2tbctPb3uYy;8RXaY4=YB!D_xtBC)09-Bb~ zd>QLI3PxrB^aba9C<6OD&>o=YkgcJ9vm2cunh_kTgCn&C7cx_*ae*+Ai!+UEBF|1Mb=QEChPsNOG zk0=k1YNEt-{#~j)w!X&vs8Jf`$EXS)l?x|EC1$4n_*&^MLV1p3*zH4FX9i(3M^=^p zHbAsx-xUJ45#CnA7Ir>)0)a~GxoY;fuV&}g)}`}!Li5i$V$x&~=b(DYLiB1zz#_sncIfZKHIWv*~TUtH^1f5D!hw&pclq1ys?py@_d#2XfJf z+|sDi>mkoDsYbU}hCyFv7v0%jKO&Ddr>;J?omzO?K2XV?*KVaz#b@oO^`igsRTN8F z_pv)XKbHSHcH71?WH{=7bBzh@g7}aNEK-q&@6aT8)o7X7rbCRg{8D`sn;QXY^Ov+X zGyP5HyZ;W>{GF=-+$a0x>W2+~O%D~1S4BRS-j-brlT%lpw5Y=cBh8Ww=A#05$0nu< z89#3lNSM>PB%H|?CnPK0>Ww$x^<6EU$OsCk4>HmvKOT~k&c@a-D?xMLd;PnsHN3b} z!If0(a=aF3pk96qlekfz$a%ij57qp_<}vYr0jKq&mty#OOsN4VNe37u@jMs}pdzOh z>MmvrEqZ1HH5f5=k>g(>xg6ero4VM!=PJoQP

    #mZzjXhU-%>sa+ea`HR&Txt|)q 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

    7&eJ#Z7?=Vzq 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

    UL`D_fWNsd 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 z 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�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
    &P3Q_k#-nxKE|K@$tk!Tkpm6I9}NDies`0*a{N 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 z%0A&X$kc!lcojBf#ga2E5QaYB*VYg0t$2jTh09m$)gBvT`gtjzsTj?dIOnpAzCySD zxknw5=E-JHj$24QchnrqMtxP5CFXn*g{ zB3PbiJ)Lya&)M<~`ti<=G{kz$BC!}_2A8Tx+_UpFGf%Uk3{$K_zZ?6NejZ8559EYE z5(x}LR~y^zA=%8R-JAEd#c5&6Nf(HN6hpOAx$wXZdSfxp%IlPIY&8S@;DooVTzZ{i zTD{Oqf!01=phNvcC%H%^CPON|ipx#5!9cXh21i1i9WyW?<|2ZVhU>?2IP1}5qbx3> z=n7yq_@TFE4zc0K00XE?x0hm{RjV)M6H<)rhq=fqc5C}0%WTi&@W&}x{;18FOTRKK#{493pdf0= zGgiRVkp;G&NtRuVb)S$$e>kKt=x<;9s>DS7#`%p}KqHu^7oI5%9Q4HK#m!Kg#oz?R z2kw+AR#CfJ^Ga0GL+gf;8jrWsuQX_+Ss0kSz*Hm)`_=fSm8LtN>0=_i*?UGZQqj?p zoMMnf_0e!P1V@-muE%e7+;2G_z?6`vPOuBlRgzHG^b#m$?69V6%Y|ubc65@&5AVZ$ z!>V+$-xjes>B0>x3nX65g4u|U7}E}V+Aq7od&G91eN$}Uu5!wJmiKX~wvM4&Fekyd z_I}Mvyg!wVyp-)@Um@O_GP)U#K%5JKlnv;Q4+4zkLndCnp@meq5!%j@PxV*m*r)bs z=%7!2l-qnJF1@_<<-8BPCsF=2VSSA>c|S;=HkQylF)iWTG8bVYY6;^Ww|o=fQbC@@4r(BCv#<7i;NR`iX7E8U>lk)I`r zf-9E4zy}0#^!Y~5jZwTwVNg5E8FHwtu1|ICOsE8ZhMJc4MM5}$$vLHA?2~g*DV3qL zCV-O?5XK$30MHFngcQXmbP3RYITKMW&^%6M6AtS+3pPpUqoPw(lyg3mNv>xpH6#sn zdX;OVZ|~8Doq@I&f8uW<9#aNj)0Vt!YiUhF({lx}xktE76CU*N^|X841c(ya+~k#m zrxWmgH9yi6;n$Zhhz7)xzZ3BJ28YHSIZJj$EKqEo4v|Owa*UI0(q!3k({cT!9nr7i z$3Tg;`^ZYX2}VpXFeiWkhL!?2y=eWbL`>7E-1(}UI|_l^G0hWBpPWN$Tnmy*Q?RB? zTNKbRqwEC4nY0B*`~MmNgWCk;|iuzH@;r) zen4-H=+S62Xpy4<_1bxGe%{Ns@4+fXVif#E=$b4 zN`}a}mkkKr&+iG}j;HQlj#7VDu*o1IT27-)dXpJtRr>d(->LPny|wBpAV?@yTniDv zwk+Y{&FLZ*Fh|*h8oDQaHQI@sn$m z`W}HoxIX$ED{TU41ehwhn;|@i9zd?Zn)lhM1akv-=zNdH+txI2oEp^nkhQO!x{uv>1Znf=a9R*FpS7O_^&*dU&B+-!KwlF^RJLkK*6 z^sdveT_fc63N3Kcn^5@Lg3)fO8-}6p^Fmd(Io~y}%F%SHFa39O2Yi)PXGsZ2;pXqN z5l!urL>;5_M-6E*^PR9rx_#Dv7Votz&^iQ>exw9;qb#`^R!TiFADc}OJ}JhjLNzgp z}>bZnhXmKWd$)IiL)05wcxALJ2fLoYKqb8=YP8L^TD%w2MT8F@5ug zZ0(#^j2Awpd;$h*PqJTYsjSB=8Jd`P&qJMm6!vjoEg8;15kE@NW3QpZoMF3-dqNy| z4_d)G%PdB9;xSVrxihL|P=+|4m<`RzvnA6F3M}8GH=A$YLl-X@kl<2>dy%q zUMZO(y5c!e!a-akn`iXwLn}HXhNsuf-cQ{haq8=10ExrTEYjLAoLq}p=ZI!`uX`ia zIsLlSs1>zOs=+=JvJF>VKkF-xn*6)=xQ$ZD0PcIJ)<=>dkS;Qn5t_hsu_wxYo^T|o zEVzl=*qCc2+MDgwZ+IUXEMpXNIw?VZIZM--U`Oo3J*t9JOs+qoJ=z+MU+Z_H8Ct zfxn?)1y#pubG8eGXkdZwFY%$yshfWyRs^NkMkv%3T-JK)fLr*s_Oe&8FC`-2EmkJE z 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

    aDwy05zNxQ$0a=YcT$ZnC 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%0AlL7k&(DHCt&$0v)PUI*Q5SzD5aA@!y*f! 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 rK`n|ysCr9dnXI)pLc$dA{E=F4p}N$k65 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 z

    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 >dp5xdU%wH4-jvUKLf&yb4k*cr8F3cy&zNX z$@`4mvwJVBKCjW0DqJle@)SN?#&oYulUrF(=*SA4Y`}!u;CuwA5?~_Xcv6iHA+KW& zA05E@D7j;+B0WFCAH%nZ`nMJ0WW91<4eor0{u@y^q9mu6Bu8NFO0M`BB@0WgzXDam ztgJ!e^g5__=YeYgAwA!Q@P)+6(qqaYaKo0sFpxlE^*GEcRQA&qljSP*SmQul+8leL zT?HXMSZv!1{P(0%*~d`R;T_^oQHEVsW980z202~bZV5W(%{CrdX3xXEZL6+V8;ptp zk#yeFBjQQ+OclLMRqb1iz%oDHc6E+)R=JeEN>OWe40AJRMB($vnLZ2rq(5<{16G8> zTDc^qts*XjJVUvRfd{S-P-C=p@L6Z;MybAojW;=B)Iv1rAntt1zL3TNXA{(HKK^s2 zZ*GS{A$pYx&1qCjd6iwMMQ@{V6Z^-Ow_m-###RYrOn2_`QqTyo^kuKXO9M5;uck8D zAoyVeEvg%orDbbxqf{NJE2cR`bU}*`K9a!>p44$)6rqrBWDf4OUU-+NRSI=_ zAoMNP1I={@V))fHYy=A!aQgVR&gJywHcNbNK`z|JJ~fbpymV%m9pz9JJHmE|MXyJ2 znY;h)3akQ!Np2=_Vw!Rq_gU=CNimJ=`Dv1fMEC0uXrIM!_(KM$GD zpSsqfC3n+>4u$K^+$=O|`ODTlGLcgkw&;4#k+)&RS6sDEuzp6oepB%K{i7+5% zc3gr&zn${PGjnWHT_r;eKIBJcptU`ct%WQ0?gOE2Ay2>{eE48CIZ7ULfX!AIWTsZ< zpqGL>H$PMRrbai|L2=XMJ<^l3Pz65q>Awnw1pZ58F<*?o*zQ4a=Dy?1VNH7?h`uMk zmMIu}H>Wxm?9(uifhT=RPai+PTu}O8JPbhoYCr! zGf6(Td~_Y(~|JMYC11G5h91w z?>vjuw4r%x(eNr2;nS)hHAiS()>stje)lKn?4U|GLc61(3! zre(NETq|!+pQ;6M&NH960YZo|@byFov=%0iNh-#tLUAYm@t1>~Syi3W;Q01aBG;O~ zXu)J=nlI{a)Agh<<89b-{Q^g#ZhsB1i7_RlA1`}~c_@O}`Jk9&won<4t50Q;T&*0a zbb6J+E{nHp#7TG`=bm=8c0Zy-=H16AB}p;)NrMl7K3y*8rXCM>y72xPhVcD5Mz)yu(m3ToIU3hGyEtX|@{w+rt@)ao8FW>2MxPq==w@0~|qRQ(#a*8h-thww*B96|7&bR#ZRVC)*V zT?Rk>j$X%yfp%l*d2zluP+t#zbr5|czYB0ssl|c!g%6|LG5WR>Ul{w*&Z>wgJRZXm zd!X0Trb96_2GjcAMVz5xw>*C&d86K8G(W}{) z;~a@EHP!y;)ik?Ag0lhsK%mqc>kUx2M`C$^|9x(2h;h*FKVOUt$LqQ=6(IxZ1!DgWym6vpMEzg*Ld=5iK+xPXRBVezPse!7In~u;Ne4FlnhUnwKbRC5 z{T&s9mwdSN*^^$C;I_T^tn#OVSC^=JW7SH7FpdsCqj5TOrx1Q==-V4zMAx7oeGET{2V3YZtT$%jZ*NV7*$DS; z*~>H!i$$!-RJ;?(Qcjzcg!eC3%Ys^EQRIweXt$EoCXYA@^LTu1kB2P?NXKCW{Z1ALWXN z0UcjO;%X$g+2KZ3jw9W}pFh}U8FoBCX=t%^} zKUKZ>+N>dW3xc~g;ojhS>02TJLmJND+Og4K(-nlUt-JGf3_0J^E0c4)u+Ru`rfUt@ z&#fg1ED@h@MQ-1+o{4;8dB@=;SahV+UxjVjhhOI#L&)HBx8!_)<-mS6z5l`Oik81q z3}6DR)QR4*75=+Q#kiMXS>sQkuhy@ERg|MXfv{VZP9H@e&U%eQR(SH) zC0Ha@&jVHqTl^mCr6w~MqWegkH52l$(%qjVzG5Vs3%9LNhUt>_Uf{(25#alUaIhv-o=X>V@k0R0d>#{^jENZs=7BSKTkpxv(mB9`s0)AUK2j(YUqJ;XGO zTx3n$eL)i1WsL@%16~)Pm6^@6RKo3H z&Y|`DEm{m|YcZ7!o_R{QL8JyEUff1Zk2GUY>VhUw7^?4^QxRf}R<{-DAAWNJX zuVoH(I$#e#o7npgpxIuj8~R!Q<-mbL`<8qhE4EkkaK=w^upUb-!>Bz^%Ylbpc^XZ7 zx%VS!H;#XuHAsN?4h_)U3xd=6{7{IccHR;D^Y?gkU=ycTm(UUUph-lPN|1B(R?uBm z=X~9~ZO`9`{*_^65FmSl-PRt76;|dMQr#L_gk_+V6K9c|zPlWIaV7t3a3>?i+6%v) z514X2$*Fn6^D9s5=&f1!2y2FS`)?6L2*cuQo^t&~x-X~pJ9VuNT*9(>iC3w>o#J}Q zK+6=H`0i<)$hv*n`|V>zXH~g*M68yAzTkwv-NXgHUAZ7J?_)>C41L_Yh z(G*o_X8*MCAp%?=u1;FeGfP;YfcbNf=ZZ}yo%I9*u89le{rs%`(j(3q69pd>%yy1I z{B*$YO$?#I`RAW1?RqPtzDVtKsu)@B+b;n=xhx^@u>O4iFJQY@KO*ca?C0#4A=t#j zp7crc_bh+zcX*%)0taB~TQGs54cJk{at6vnKWdcj;KLw<9^*YE+%0Lpys2zsgZVBjbmc-{Q-wnBuow%mlalCW8+OteKtWw>6+U!w+ydK&(LMUVnTd&l!XoRd zIP(#NkkS-T?JB|Hu^Z5ahU>| zSMxKt>0rN(?SB~5M@HXxdx9kc!8n{({(GxCkA^FqRPcZ@xQtxJ^~1m{EBW(5@V^zJ zj;g`x33iyBxI249QLiFp6BP-&C0erkLc*uCLd%~;?1d_-6rMOg!XKX(>6lzX4yYxl zX=kLbvg`Ef+@lgYMVbnA0z^c08?gJ7)ku-1n{1Y+`@PuL;e3kIXV*kYX?hg*JPvff z8XuvPkYV`QKP$FTKW~vSCSy}7dww`r(!lDt;m;L72=50pEsJqRjf8rviX*5cHp(NN zkuU!Hx*_`^dj+)72_>VZFYV7r;Kts;e1A{J43kP3=jphp{Rx9~8fkeWYP{tFWTS<- zY+Nya>+Ww|la^a!q8@QRQ*~rBSsM3)?qW|d{DZG_#I0DZo_`F;v|t$OgRly z^l*ay+jd*q`eR30PfmP0NL@5F8WH7b;{WYiMX+xqb>ifQcMvea-Y5PTeux3;$_X%Y zakM!N;n9wlzf{}rPZpN^Gv-M9TkZV&J~EpWUX`MkLZP!d z!so+L!ek>D`}b?5Wfte(cN&Oe1`Vf&gngZS;G6~|dlUQxBV}GaerkwLm7kJcH5g-2 z{Q33s*Ib1|or$o4qV!T|-$_&O9aAL?<|?kym8pgK+vc8&x6+XPPX2o^MbrUD`YIB) z%Qw|zK)BPMwz)aC+p%&s&EnX=go@ONj3owdb-K7Ge-{Nvd^8*BLv7yabC=yNF71AD zxrVewht4$bZSf`_HYc&yDje{^yeW7*)9?Y6E2w-vAUQ|hJMe$hU6!Ld`FIp8`w}9M z{r8!l>A2iJZfXh^qAh4$ZL{3Wqd7FEW)1t=#G_9wI01vU;5h;e{i)6+35Xhue|*FY zq8u`YyVfGjq7fyhP`*Y`OgFCqxl{J@pBKwF(U#a!W%x;FX<l|oqcB)i@}9C z^4-RH?%)^}CYKJ0RBJiY5e22BlKT7gHeBPEihbq`ybkPBb?y`?36c`8{U`RsxK}}h z;wNWAzrulFgC^hucf^2SJkDP*4DqcU?DFM(@BqH16Qv%aU{LUSl45ERU{JUibk6HGxWb)Sh--;N>9zQZ8Ch zE%JA-XE@lST+&3+^|VZg{Bar@65{vZ*r6k^vt{Q*K6iGsdT~UVVeG|Dxx!fXOZ=~W zV97G=r{vpOkYPZNTZumT zgJuv%p-TRuz4xnMYc|C-O|!NSOlbQDIO0L5)J}nz9Nt9}+4xB{VEv7$Qwuj! z@O671yCcc(^#k-ewA;*AAEx)EJ9S&W4tC-F+jqHxq+honnuvD{&=L3%!VS9!=*@8r zw33mxo;4Jr@7@SHR#@&it(7som=8rG$#Spe7{tIApI(2w$Qdlp2;$X+3gH9iRwY2U zqfd?stPsn;@GYPWflCI95{O>2$AvV@J^Q`V=T5Sw3W@~bJ)_2(=Lx84@X^dSxCBv& zjsARhrXeZYy*)_;fTCH$o1}Zzpc$FqFgVI3<|`x0xzRkky}Uj3>)d}VsW3ZORE~9N zp)b7ze}cGhQyUjBc)YG3_Gu%;Sg?i`soGJO4Rr4h;Y4Wp3YkCs{_=v|-x~WK=WK#Y z0D7JqFn^Dlx$@!mRs6xoH!lhS3$jrlX`IQ?nwf?3`RT?b7Q+{mV0lBT%D=}Yl8@X# z7*aO4N>YK^6l&7AJpUG8whs`HyJ=bsm{67tA`;Nxb@-?A#9+aH&l;bJ>jUE9A!X51 zXAz26`VG6$&%@#2+Ta`H-@r`L$$=(NpvE7uT#E{vtZ=cOD+DHPSCDMQ4M6kAl~Hq~ zf|s~{`m;)IcRep2GDO2DT_ z?4AF{_{$D2%z9k<)8c@KY150piY*kg3a>@v?_L_EJs0kFpzHxfGcRET>Vjo@IF;P8 znIf9A^8$;!r|8_9BxYX0;xL?fy~=i&tjAkl1nR{{%O%0#eqrl?BsaQDZC=*2MUzZY5y14>{feuR zcicxB<;|Vlg9R9AKk4JMRlaOze&}YwP#;JZe)Na0-|J`h0|+%a=)v(zR-f%leJJKK>hYZHaq= zf8Ehj4c$Lyh!%x?Jk-bwzEdy*O%794bG4@kEbpXu3d;w0P%PP+JSoP3J3{h<>xZj>!#Ex0{aXqO?r>0;Npf;#9$=D;^B|i* zp>J6=e{G|t#&8V6aafbDYR}8>D+jX=`_1TN?>xJ%=QDGs&QZuHFD6DS+ZuKyLpZgLnR+x8 z@EA8B61fd$mLaeCrpy)O1hMSHDI&X}lo4dU;^tGw?K`HA0r6v#V-WH6{V_G~JMSIQ zjDN@@HHn5?-yGBDvaQ>fB#Ck_#!elAf>^$Pj<+(2%g|r@&hMUI1F(MMw~D^3Sbf`- z3fzra=GgEyaOFT6w*&Uirrs$bp#41ENO#mget{$E6B{y2ke)T_9lfqv78A}|;XF8w z)($&i^D4hEBccl@nqNbzq1d@lVn^&%HCg>SvL@jUmwZJe`yWOmYCxit96jdDi|ctA3rYUwGTE zE}Sgsp^HHo6dLQXZ}{a8+#So83rhDRr_~;3j|p8&Wa+iX;7X=qQAM ziA}#wrA-OcHIFsDGNsM&G$QKy`{+9%^qn})`mCZ#k;FC?tH*hdicuz)ifmtkXQNH) zquR>o8hxSpY$M^R!N7@YIR4eSX%)~^bb;Ee`8lg3OaxmVq#-N);eAE&Z)ve@j?_a->CIdvxGPwLui} zvG3;hWrKn55ui?^Bl%pgwTVgX*kdVOr=P9Frbp@TvQKDO zYLEMNAFiY%6*oc&2l@+MZ5bU(k>ki*G0 z`*zwrWb4nqmIk+yPLIy0sX0nCZ(Lo^|tSWEPt;}$B7eW**DjhK>cCnf>no~srLuY_`CQNX*#RGuARK^Hqu;eOgf7k zdj*xDfs_+r60^JJRhjL0TB{vzVGs9nPs%c#bB|`3u8$i~gix{uQ-7ZgWPz$$#LThk z*FrU-Yu{tQzabA5!mL^;uTKmi0j|J7$;T5RN)8xczvJH`zF8HjTPGhW42JzK_%^@9 zTW?-iq=!K7XY`E^2(KZJ#BmB^(a`td#ishKFQ=vjl6Jc$*P^{(jdAc_&Z^gtmec3k7Da?|1^(!hb7tW zdy(F@d5%Q?HZbW8h41+3SepZ%S4)l-ihiFU?*n*RCNKQ5R3-RYzNPHThu7;}Xvw`C zrcCKu>RWl_16`tKkH)WZb7R_?>nA(Z^hY!_VKwc=0DigYBwhw?7gpZv0 z(EfyQ;I#L09lYc@KKlMXRklZPDySVJdIqN`b*AfYv;nre0?A8kMm6IsR}t7r{q6lI z)R2m9WKxY2mIMCYKeA4V@-w zU9)Y?js~Xv0GbX*=7sm+@9}*p;+Qwkcjk1se~^C5p~(eL$^%yceNqLa<0B zyd=fbe#lZ|1x4|DZqJOybP!Tqi>Onaduw3ZSHW#xS)aW}4e~hgz;`wnUmi;=z!%&e zp3LK$cNp_8Vnu33kxJ#ao z{sXJ(B1C?sVcBYUwF5c^DPO5i#mF*I{YI)AM0&u=pX&OkBS$gM-(%CX!+5{2u_lg_ zcR3_>a3*C~{e}d1*i_Jc+N3IZ#HSjox2%z#xWosX=K5lANLtj+&{tfmOVF?o6M>kBX3u zhe875eam1stE~s2==d#y-4s85o{cY{c`_{7y-w)v)j9jQ5$%O5WaqAQx)8XJupFds zp4e)uIdx7`4tJfh8dGN0cpsA76cZo0=X;eYW$o-?wg^sF0rfq2ke=g0)W^eD*7R*M%-QN~D#>E%5Dv55 zv|tv@3DDQQ-s}`X^5vb0n>os!k2=Kn)b2;Miwgj~Q>Ad*QpiT>TW&f~TZs$p#pKp` zCamOnkUb-q$VdDY12V1g(aY*C9ypE2m`*J)KZ5r_&?bFaVeq)#9fa!)-%A$p zA>JCEH8A+!&9j{)INWSgJ5YJx!-#Z$FfeiIxQUOcQhh8;vuxKyQrhaMCRO2iubyl8!Ap=IqDp96P+db@S|3ro%QJdb2jBR$7_h7QqW2oe-nMS@_t zc@*PH=~qv%xf2jub_F6Hk>5(K2(%=>_h`lU_0U=*X}>cz8vS9gB$S>TddWZVkVsb? zX_EHpU`Vds`=^d4b^_$rEqp0@wW;c4D+X}R|30e0XCUrspEeMRD~At5os(~+xAeo& zFWefxHLU<3m&y9eDc$NVee^?S~( zFp9e0n8c?vPcL8lOSViuWayNdoq|>4TV0QaHkZIdSRf|({$1WK*GK#?=}(a3k24n| z$8uhZ4m>pE>+DmmzKEAnM7$lp%H5t@wgbZdwDtsE%OV~KvAT{9)c z#mCUjPgcWaBL6l;w?!7L;sBBkrg2j@fdc>pMbddyN=EUG4)Px%3HneLaq6 zmp#GU7z%KP zPqxN|G$SAOS}P0jU`t-WcO2%T-OZ4cO%i0*w@+7!=Hm)h`(zA6D{z_qdp3K>t(*EZO>Qs90PzeBr<$ zSSjN1ZFeRfskHXOsq{T-huB8!l5Qhr;G|h9zgkpjBK1JMllpkMNHfdobKI%@%fNzR z&k8_b^w*71KlEm=R7bpLyAxfvzm1@#KHW&PGdwWF${aBKc#q?_ABlk>JX#ZZ#+qZ+ z*2Ry!L2H&se>Go8unFk&S#Xfa7_`;-80Dd?jk^63<&^O?=aUkMGUp1F9D~Kz3)+j515Q=Gf)}@*@jrK(B*8j<=?CI?g;t} zq4XLp(TWkMqhdy^Z(Sl50iA#Ad8HUR$~+0tsZ6VV*MMpE&{(c7CI4e{xCRSVz<+No z;Ui*Sg@B@n51`*@bPQKSb;u{BO*Foc&+V~oi@W@{RbgAAZ>j?JJDluP_Jx=3yryS# zf;Xvl-ivqat{_04^=4TI8m@Wc>-J>)KAN^>&7Vi1Pu(4#knPb@30B!j!U64G3NrwdVmL?S} z5R8{|Psx&2DsEy4ot3>W5J5z8Wk{ZDc7K3FUnXi)XKO};PPp|99?n@^H<`VN4e!4f z<9RHny;BbTRiW6z+5qG|@s+3#r6aW(@W zPr_qCp0cM!CQNd&_k-%adZ2^e%22{D*bX`L8{5!}Q7xexr?FBT=R3B|X3SNjFCV8i zy$?t%(Q2~A4t!JQvG6SsZ!`lNmrN2h$ zw04Di=4%N#=g=x-?T=nkokA0Ppa=%pH*0SM^HLGTZ+Hf8SgA@cH62f3V!|%V^1;tqkZft6 zO4dKON@c%>VnGV|4PIPhu4H$8aB6pgrr95N%`84w#NWCz83DcQ@Ad~ioL?+WkS?4k zxrpnAc*Q`97SyV$kymZ!bEgP59+8f#h?)N_Aa@-OlldrQMi9@ zJVG4BS=!lol_y$laS8Zh=$1D}TpxmxEf@{Vk-gGXrR#>SX9)Hd zgh%~G{zmT`7H#c$#gOCNOtsedrivEacNl~YA9QiZkj;lvB>)nIq7Nt2^&qjhn%uML z#ZTwX-bnBg8RiwErOuX^sYZjFF+Lq2KBE?OuO+Qz2A z&z9|(*2{Te1sR*K25TlQ@{3@I|=+?_vNGlg9l(L|l~;}KvjESKO%*njuLt1}zh z2iq?=0$$PDnXg)Rr)RYawLY>;exoLO&GHqFv=-^mpMPjj<;3nH^+UNS~jv22NXS2%n91_D17P;=O_7d`*OyuSpG+_ayujn-VyK!xNRSOb!2ZQ%45Y@ zy%FJF(R$tB7dF+fr_Hb0!NQ|;OR>&~!j8QxMohqkhs95Z0qT@^goV-GF~q8n{)H8!M~6;6*e%GVS!Sz?nY+)M z^W04(m@V5h2hsKVZ8Z9wq&)2co5?LS-LbTz&2UxiZy|#MGJRq@2+S<($u0B(*z%pn zo_~TjR$aJwP_Ey@!&F6&fO;|`EFR#{-)_H9r~^y@EzIvtR)n8@Q;lrEmIT0eaF3v` zl%~U>AYONopzOyt!p&0KSZI&ncbpB?+e9N1lvR$38a&2zLoN=6Pu6gM1 z<2B{A*g5Fe?4E8~Ul~fNhie#Y_eDYU=nJt_tOsAU$yl0h{J)DXbe^kr0PRL-Yt-V^ zyWk9&?ZxuAHAo!<>jL(-=acVzahpppws5~8ONAC7Ow~=V)N`L?TK>BV;z37^tcFG} zG$6EAAYUH8dD1yYQ)!R)P^U+TT~>X#?+@o7s9rg6!~NTfcA_iLuGXYCM!9@i6bf^R zX#d6T-Ds_9ErOqMQZ30`oBUq>BNGgXi)4MR#xc1LNdI>J$l`B>mW(M)95J&bh?G(_ z#UBc7{?u5$uDXoG;`vnl450HM1FC5dq&{tW)2idzmzN6Xzs`Xk2 zLEdi0h98w9lAfk^Y8t4J?$b{H5m2vg*2^L*ZwwI}oG~o|)=Nb!gP-g4X&-I8HhPJv znC5a(?9bhmA>(wi33q$+cSjEkY1Y?UK_wEi)Y}y-DL>gELhPqs7(dDu0n)uR)?>y^ zy&-suSj{4)30T%XGNm);QRZ0mDC^Y5RvjiDbgv*|tF+^Mz!Y&OZ?A^)@qt6okdNed zjX#g)=dD*DfBTE(n>f}jomHq0&#Pl#8zsY@F^hM3bFgffA?56QQ>ys8;l9H4^qBFa znV0epkLdNFQ7@Y}(T zU!dDU9X^^ofBoga-_x?O@daI?^obr zsRpXsC0P<)-AB0s(FX58 zoydq+6Hsczc!f#0YekugP?U`~??TJt@_=6dWb5NTvi~Eh`|PFFLy_rNzYhBe?>4$yqcykxwX)5VVPO;n}UEWob^q4>TF7fGc@IS z`m+WzGdJ`{Cd40-RX@@r9%=%LLV58A{=H6G*^D4krMY@K|0;%M4_CDCaTc%=x4yeVg9} z;n)WseW!u>oDwdyrSy+T9x!kR&$=g<5N|kZ#VuAFVS4-5`^FeBeYtbLV4r{Lk76yK zq%)YEDBZ!O&$+bW+j-o^A(z7gGX7f>82I zd3VIWnE5QbCq81f|9IjJS$iy{k2`OW$?dxAPJO$GX@?C=bqY!m#@t*vgFs@J}KYbSOjaXuf@n5mW} zDUQ4Z>^x~3evUP)h%b;9 zzK{g*5)b61e_mvC7LlilL#{)FIZrG!5zYC@#zilCNQ>a#TFIb0a>ZDJ8{zzd!joD@ zWBHBNxT%ob0~15}Af9+mD&WBqUyMMQTHPg}=XvJl*HeXJJmsL z>zMq6bqkkmO%&~?0Jc60rR@D>KJrLsdymxG^3P|&GWVi8Fs{RdeoMn%ik~o6?l1iD zF%pgDSsKfpxN>S76kK1}~NUEde^YSD$k!zV3-=2)qX{n4V zkb*xKS`1mju%qcU7rrl2Uj(1&&Gq2~IE~oYV-mMRRT4XRJ4vBd4ucq&H+|KV_Rva9 zCsO#9nSO!|{+OiVGieGKe#X{<$%)fv`&I)Go2{n1?)OfHm>d>K;>o1?ITmtVfp-L$ zTGNOB!+0rzD50MGMM4`aUrMGxHg!y@#1?#RT!VpOhxqFWnku-j9-m!z;WxpzpY;|7 zLLDg2kn^rt=Q^D!XQ70nh}c0|I56c~ZKm-WLN6PZ%@>yLH^lmW-Ycqs_3O@y3;P`E z+az~c6fZ<7)LX=R>hM5}_cES)D=kZlz>S#ipUvDh1)h9m|$Zv`H`$B!JS{m%xW=1 z%YpWrj)ct-;)ldDu>~fhQQ6)1@{g7Qb(_ymzZp}TurPdb9NxtNQ zUl{xYiAYDSvZF)Ioj6$x@u79&pFx@(g7=}@G&6xIC4^CCyN)!Cv)}2UVt4#ZJ*KlW z9TJ=}3<&nB%^O8)puZl$ZP2iAx9;C0$1>IGNHimdEG7Wn3mt>!i*`}*U&B^>*qA&e z=GV#EVz>(XTD_N9%c71Cx36VD0`VB}GTO!%5vLA;#D**D+cw8TWpWZ%z73e~+PbXJ1l~@poIKVE?Kg1DN3gBGUi~mo}ntQFT5QUc8LANcDF?#z57sY3q}M zu{eJoc`497%``$R!r7u=nZ3l8?orFmdi|>ePGzMLPyj3#3Xq0mFb}dPTSgMaFjp62 zK{GXS38cZw?To7J>=vAxn>G}~dWJ`Qg>skuw`O1RExrV|DlyAz8`9@DVNgneO<+bD z&l`}mC2X(#2QQpm#El6T!XI>e=);%W&8xd#pHQkqT#Kt4{94BQ%RgTy_1a6^GM7E@ zd&IsrKXN`>R1L6((DywkE3{=P+v(g^)6xHS!t_I{?!*penl)|~jI*eQ0d=e?{ad#c zd$wMx>Rm0>mJ=0sQkEEm{`QCt)D*TN=n!JR3=UB40vs|Y_d7pFn;~6OO}W$+Ag}ZW zoSws3mLbUL*+ik=BUEc$B4GRjqF*(j1+_uGzM{z+7C0)J*s#b;UCxIbU&sBlf6>A% z$+;3Sa{R1*o4j-XutWRjo&KD*k)9OeK*3W@EdpFFe!30Jo=5zor_M*TH40U05npv@ zMIJG4vWvF!D=+*)vN;AZJ*qiTd^McU$~KEus4Z>n<E{ zCF@g*0{wo2nZ*<2kmEyrRFot}s~Sx#O>fpGs5?I8&7GztIX+{dE%LAQ_0oIKFE(3u z6TdC{rat64uBO8R3S<=_PsM2$fA0JIT<40jKYhJH&Hvqhive9R2gbkUUgMD}?4V>1 z-v(H-q?*=Q1h?oKArotG&h>sW0y|O!V*Xz2*TBf_SXmF&%}RJPn9LZCkMwI@w?MeB zoi6@k?@ybaN0KW+^!xo4uT|Sv&lvTH*cXlI12$p@v4g5eD(_vA+Dpsekvkq_M(+cEjosJ-QkU}U@zl#_6P;rwbSQ9U7yTy)50_iExu1$ zlB2d0b1NHNqpLdG`SR*fQ@2*1WdvA9DoyB-)|o90mK15>2I9%oH!D>cW%S>}o!C1b zeq%Kx>HMxkbBdhB9A|nm?}E+FK&Ww-n^fEO8VC$Nqev($borJd%T?*DSyB*LrGkvj z9-0P)xdPwEegC|>vm3G?UpDcynnRKcu-XY;+?j(+mI7+D0#C(GKzRPWpqMm&Ivpd7 z%w5_F%lo=Q&c!yQDRw8&O$H;<+88GHG%FWJ_M< zDOQYe0`L`gB5H&W9g4+E7uv4QLl69mEK}2Gc>y|e^Yg+sAxH}&+kUz)?jXV2b{O7< z>4}MnsM~PNw_|ZIMJNcE_0YeQ<)l;{kVgzhv*sh^WbGSc=|Ri+q+`{QSn!a{9>(gz z`D@XeHgY4oyv+Bi>GL3?j+YUZ0^Y`h``pBr5M^V}ex3x059-}G%1##Lbl-5CV!Y4# z-O#vrOgtUt`Qm!ELzuqJ5?2(`{e zg1j~A)u(R=M?}1&jWH$r_;J4?2(>HS&97u#1__7B11h{cO|#e;!4=TX6)j0CnS924 z6^@Z-9x{)T)9Eb^2--FK=GG}bn+t7K(5w{T1wwR!;s%{#_`S@|;SrB116a9J2qS@5 z%tMg^$tk7nHh6s)pG;!=P+YUrJJPMPcb8<~Iq99exT(07E?yt?e5`;0Kx?=y1%)Yo zm=Fn%>Ryje)n`txjEz_D%dlR!Ru2JiO*btXWb+x-&U$8DbI zgi?db%TkWX)zMQ)jKu*XM9NA=%|;)fx9wa z_DiocbUpUD*tH%MU(tN(OdG2SczU?k*<~EanaEevgiLbSl#DWG@{VjeIhP@QOl+oK zS6HdGR+)Ol5;}+*tQEpa~(bj!L_Zz z*^a;s-Md#z2aZp;kG%z4=@LgfB^|-7xk!o*vhx~HD#!z(L8eu)s0O2@Yv@9DSl;p5 zo9qu?C2(FHrFCYo_zBC;OVmiybUn<2e~FLnW@VoTnBOoik=$Xn-Xk`=J1LP0F^OpI#U)Ayx`glIsyuff(#jac?XK0OFb~hOhR!G@JAvwNI~SCEeF??e z4%yztzj+)}i{*8lN1_ZgBUBCiaA$LS2K~+34oJGXrVPhT-P$6#05vQHT(ieF57BxY zZOuwB`$9{PB8>ECL$_qE!`C6D`M@|~2f)aF*DJDbeto zK;M1LvV|;z4Q%mit5q1w4E!ay%xKS-YOumJ3y8|*K3+_J7Ad&bx9`O`0_2!ftKC`q z>WFM%dKTMf9*i1Z^%RPgQ-5SzSZtwtdHW(VHKH)}gwvS;zw^|aLoF@>Z1LLiqez8S zy03$JH%O}qii+k|$QB|Hf=A!4p{haU;m<;NkGxTF!&#iIqyJ2_5Wt_jEqB%v>#1k(6%n{kiC*mPZ@<}WH znLy}l6VlTb0lrJLOs z(N}Y?P+yM{sAnkdDN8G~2OUoB%rAQHGltQmLC;r3JE8U!hm|?h>Z3K$j>^_^haDXb zT4#i;n5C;+NK1B&`h)lQQRf+yrCj+zW0GB-YRQ;W!4^B@O;`0Dln`_Z`BD-#N`Q2zK?iLDME~IYLm6?8-8m~pt=WvT~0~R60DV(`yC^xXQW^G zn69K(Y855a&ATE78zT7kn~V9nAoN*Bzg2qa63>k0qsWzgG1&w_`YYw}?#>Lf%TfZj zJs#px<=sXN#J>6Id=NcNstfs$1R!HGQ!<5Xhx5O$nyMa3aUbD8t zz#IZ(;351}>;*&HbwpW_XFTyquMptAbR%SE!Y^tgNSd&h=wZZk;VyzEDPoigkM>41 zf*+S~d_QS(3d__0YQQzR6hYo0R|ppOCQ(AvUPilh`#T17vmoym4&h^8a=L!sRvA|o z5@}{QZBj&_4g>dwp4?Yiqb>d}^Uu<7h@$Qs?VaC~3lIs^!*3Bnups!>uF39Mju7C> zX)dBCspKxr%9sq%q4AnHcn^pvN6Id+mX^2b1}NhLj<4fw5X~kxyM{v*w39RBxrr)>-yUgNJCWmY2h>piq?2lmYEebV0%w(Wm+XPOUPLHCrGTMrIjXv`Uce zM@mE-TN98~Nl4JLTw^-7;8yct9i0vL=2u>H(`3pqon=ox_s|#2k+=JUU02#EH~du> zx8eqGBhGu;8;rCrA7d(Tm_W^%E|ERK>X#dtO^E#bFT0UK6XSIsfCbMns;@UhPQa}YmTqz-FH{#r; zTRA?2>E`VfO61ANcceh{x`nQTKK3hd9l||q-k#+aME3~sP%YxU9w&4*b90D^>SY)E zsQPkIq|606&NtR@2mT;IiXc)l?M$>ifp`dWI|98T<&3y!diJ3+&o z=LT}gKC~;#UKIGXQ0N89l;^W;o`Bg>Q@vjciMh0%C~nT$Fi#+$rz_9*qfVBA{ug+D20ZRdE=-uQx!h za5O|3X>`Wx1RZoW;uDMDNDGU1mqJHcR3vrBz4A`^_8S2rS;SkhyVv|KoC9f0VeJuh zd8^%YKc11MbCI8k@_DrP;nfC9XYTlBI6Ur=7(yl>}P)@F1r~wOW^3z zrK^E}#ZvOI&)D+pM7iIavw|;U#B$@EiUQ%r0x_og#BM|3!>fZvur74y5J?%`Biy5 zlPq#-`SFguUJJz6)3&W8rpdhAq&Zl*WYUFartGkHxWfrN~S`#!?LsCpQRk)G#3Nk{8Hp~k?#QeCuO95R@ zR^0WASgIYglDCHMsDZ=YUivI7yS1w1(n0BJIqoV?P?IGX?cU-6H!e>QOxM-b%B4vk z2*9KV^jL&(E@X!Z80L*s0WJqITjS>)(+8k0@n%bmU~p-L$fC^EF-mEqZqw5xE<9^y zn9G~*9hsQt`JMr@7CV2WdOOD?poK%b>7$tEm<0FTq{XH?u1S&gf)|)i5b0<1yrjG^ z5kz$B-h_B#G~Na5TK7|-#!6Us?s3`EPki1lyG+nL?@XagW%sA?tf6COIhMu<+u*L5 znENkRSOM|T`4prs?48|OB|oX^hLy>yyr8mfhSc=9sihnSvTkVJz9K+3JEQH7c%XLN zn|bMjHS8w(K5Wyike-E(3v0raOj!5LVKDwxo{M`Yd2a(GTen}%Ojl)WGY)(fRH+ca ze9yj(vayTwdFc3>qfCpMlCroz?QlYO~V6v?Xp?6mn8+4+^u9*DE~6HMz(X>)zRDsK2;pY`iPzIZ9>ih z%9P?<&~IYzZdSo2ZOo*{W8}}rDN7dB&Z%~VG2!x_V0W&a`NZI@0aB;Y*J#b-$t}yK zQ_Bb4`$k9e8fmMOMm`<192#uk2{x7bWPd%}u^N^uP_~*B`AQqFg?F5x+W1uBJ14-;acAB7T@3^@v+MNE^&G zN9pNatdtC4vQ#)dP)oBbZnG1L47CNC?~YFgz9N|`)4ZfgMkC5gG@spZIna*9QtJ_i zT^DQ`_Xtl?41!yy8w2aRxLkTZW<6!YnBIY#TapA%f>FdIL=3^4a z{nb19b0$S`-f0%QUEWbuO)uLsHuW>saE&SsrqcR(yOoaH$}k<|m2Sl40^KpmiGUtr zCe?8nEfT23er1j36Aw6e1e4Zrqj%>L4)TeFnes&5cbltF@9A0y>h1=b0xmg0Ay7Px z9;mmOZ#$9A`yjU0P;ti*25fUt>jgsa(P9rL2<}9Os#N68mMuQ!+=|-urfXu>Fw^vz z!nUIl>HRo#wc2HoOu_kKT*O$E?#$C zh#i_LR8*oeQIBijy^>oYWsNCU9Q`gGQu5Gd6F>C_IO3uCtp{MU0Z#66f`{GSG5^2? zd7E_3c&z&kX|6mR-nAW#LO5|8eq*#p-`&O+SDtfGv8BU@BE+Z&)IMce8Lb>Ac9dNV zJHXgewy&9AO1oyD!nnEja?DY_Gz}b(RdwFH-2~vC5b=->JM~=) z>$XsYX%b=WsY0WAJE!s?DZs0NX(g$44*p`U=FhKMkDrS3s%_?C|9b_uzpyDDlW-eQVXOH^2^jSwYl zVHlbooL48S_LB3DXiMEUQx`Kap`CW9=D}HYyNijCIVn58m{UTf>b)A5Oe~GI_H4-G zjAXezAPOLGC(U;|B-MlqS`Tp7C%Md1+t7+XE$dr2r%iELb-&i7mvr2-+KsDsz7v`k zr}=~kwFAt#a!X$(;oy>9FN2%opYi!zo)hCxhwD7RK`Sn<0U1W4XByS%nrs@Zoi$nd zscCjNgk9yPDWcJN#3%nO7*~aZ@hMxk$KG_V!S$?IFsBT+0xU9XYQ1d7yOQU{acjTz z)Xx)y7;JJ{f^V@fjM?=NCEmrOco-tb81|q6(Lb-YntdiP*rR>W;WE&KIdQoiNJmY0 zkd}dp6p)iCvhK4Sj&x|^x#Lar!*&gF$q`86;uoc>XMGU07cbgP9kly4$xFMHR)gi7 zd5Ah^agqV@6H!_A{u1}FbV_Cwlu1X2S!NGDsrBg`b2#6w6eIHZ zjed)8aC@f#5Vq-j-4t+d-6N&hTT%zg20cR2J6ncP8Htb9aJi2=VfMVvmRTiUXG&hw z)&ut;2{+9HdXqk2Sm^Y^ecpqm&^+>lGalhHrBQoUkm?+b{ipYcmcjOzOJBl8doIjV zmn#GF#?YOh)$K>-IFCC7)LQZ|Tfr9~ltUD9UxBc3Zao7?6o;L5$O$A8mUcr4&p36i zdl=+h3i+e@N-vzoR+i1qW1a5MfCGrd7paQvSirV^JnZ+fm$j~$U zEU54TNhL(Q@J11XaRAu0;nm707oVcbEDGYC3i|vVpAp`&TWtn1!QMJMi=ASE)F<;Y z%u+C_n34qrmv-hEnMl(>motCSmkF+J7LpgFUj!7|Ot(#~CfF}C zh}G*oN&ztht~W>76I##!xStH6?ZUec$J=!x1_-9@{TkWHyyO1eZa>4X6&D2)&6YW{ zFayX0fDA?!>*~|#c@0I^)}`?nWtKFAzM(YTMM=Hs=}g2rEwiJ%;C*-F>cq0oB{L#3Dv)g-Z#$4aqM+T2a?;;!2(g}jDL92TgWx8!EZCv0(_lXU!9~Z;F>XzDzKA$42im;yv zS>N9DE(D+RS0=5w>QFqCRi7L*egX!^3wIC) z%@CqUY3gV7%fhEv7bZIK>D^vo19d2GA86gocc(1s{|gN2Ki? z;Nyu}9RGop7u+eIB{y`O0NIC6cjl_6J$bXSxZfxy^uz+UKvs#b7a1k^1CIMJr~uxtqoqTnXWCEazgt-0@b)DbPu^dtmT}Ct7j43exJh{NQyj)(%l&3 z5!&>F><49JR~N39jmtn71+18g>LF_Z;hs~-+3^E7a~MRMrpm6SeP%UakoHb8!3j;Q z8;SR!2$*#p&aRdL?T7lK-npQGa~zPE<#aE}^B$JCba9NEK)-le4$X95VtV{M7B`qR zx8tHw#KB|KL1t5~;-^P=LFS?Lw-xdaa^d-+FN3y}IolWn5vSyr&-UbSIUg7KB3{!X zybWdaLT(iXe=5p&%=DZCEn@__*$k^gjXv4N=<-iCtkzE_&MMsSHj!2(6IaIUpQ_>Bef{d~bk+0@ zeTnMVXVtEn=Ok_;8(q%Mkr3g7^JeU$fXn(Jyi59uHcO7}G7$MBUF^H}_7``AIRRZ{~3~e&m(Isrrhs zwQ-G%+msoc;qn|c8EJA~pBJp2@NJ-~%Ij4TiXyyB4o$qsO}@#tt4h=?sC`%${FNiE z`k}PY#Jj{^xhenRZnwAgJRZ)NzdVBTV&#$@*_I8Jmd6LulDkmT6_;PA`6kSRq`#F; z83bUXxVkz5T3Lz6ds(G-g0Ooh4yh>*m~CJ{v@W zL8NM2=&~+t8=;(L(EEdcFGD*H3cUuvqb}lxJBP(1{qs{U$AS!Vw>1tRhkDO+X&4&r za>J|pOH}i*y;$2U--y1On&`ICu9|Uk<3Sho5j}|xuFTpaun8jKhxT~i@7UJ(o2A~W z&gVv>TkT>nSyy^t>Wh!B<;q!6w7;5*?1CV^>h3Ar@5FTzI}ON|x7w=RwVh(ij3LY? ze92KYU;td|Muh8$s}7Y&r4-(phJ_r$xP>$6X3A`Y<9S?0q_v9RjuJ98&DXB6j+?DWoMDgl)rq zEfaLZ@iZh( zvS@yuk$sTP-i424jzSJ1I}tnOA{V4*?(6xr5)@O}@W?YMtD+C-vMB{VZtQ7pC+EFF zRKFCoO#7NRWVJoJs^KH@(i0X)FAqm&XxnflLDJ;1#F?Cp;qbGXLEa;oMKgw6Dy3Pn zq;%A`1_H*@=5J z+}aCW8641sUZ_WoezYFGh5a*+Y6g&5s&QrNZmV6f9@epBRacM|2hT(UAU+P1Q|5RE zl@Y-EPi}(YBRwlCO2uxFmN>rMS`S&%uvX>))py=7|~Oy$MPZ6Jzkqbk#Vs?{y&RJA`xz)!Ym+s8{N+(&wN zeFl(WV$Ppf-6SNv=fu|C+jV@C`{()7Q(i0y#rxnjbLP>rO>AN7z_3Z!ya1<27JW^a zfTNY%>j`8Iw`f!IU}*G|u(X~L`1Uj}4Y!1-_4fFj8&<4U!Et-CR(C|M8tc;E4*@Fz zdxRYlxrcDnl-*uQiCh|2e$y9IaW&_J%2{i7-lX!t$kl0^yjPme=PM)+7eznvFngs9 z#-0k#se=4`9VL&E^CZS0K!6yiP*s1!eiW6bFlMG zRN;L!bRc<9E-+~~HzF4ARP?djtZRk<>Uuu_U9Bg5j$R?I&palKwDBfw-wT*qY0hsc z>>gdV7Ys($Laul!UN;BRj9Np=i*r>oYe(5WylC$izBb&wBE%TLUKV^ei8V}##tHDJ zZSufWKRMkO!OvP>A*WDGl7$&}UUhf_6}WluH%F!AvYSLtG?GETKDryTx{PD$86KuJ zQy@)ZJ+Ir;;m8(Vpb>UGkC^bWe7r~5?5ea$&I>i6_sjvTA`xjiQIl(@EN^J)h9v z!`Yr3mB7ON^*TWehqqQ8L&-@#r4GmXnIQ|tooT{u_ipPSXo&}pwte-pQWl)Mh8!sZ zlE+(vVBpo*HhLG`jr;x4mfm>{!-^eA@o^-bCBKnfp(>CXasIiJwJ)u9_&5+9;%dj< z)VK*bz?1aDcISiWF03vqsS>){b!4;m&E#j}{(P({+IRd3Q#-OyMa@Q`xZs^Xdhn7x zMXs>kr|&4%q%%i6$NuKk6gR-MGW&W=*U7_J%U02_CD)TcSF_MX#1JIfSzpQ`)=jrN z`yIB4i&PPX>!+8!Ki2i-m|+pB<6XohQhcktHozEzDdh~IIIbI3?Bw5KoW z?fC$rea@@aiZtE{4#ELa2d8CC$_m&Kr18AffGXr{2ep8Ptz28?E5*kpNJdHP6k~qi zF;}Qpy5KWA8e%{0?1U)m_=TZ%_?hlH11cZOhn5(idL9_S1kTjKME2CghhU*4>~D2h zGF+^)w)%oz^)q3f=P)XVaHF~eua-<877c+-ID8k+>!492QnG?Q_Af)OW?4pb@!`Gk zH;=!~UNUffM zZx4C8A6uF+GC`C?8LTU1Pub(Gn$K-5g5nl8V}7|%H-pD(y<=|gf!&KkIKD%XZ9YSR zj7(j;7#sIOP&~RvTj=0Mbyu)KTX3PY5?L-pUMQe9Jw6@c`7)IN4`tz+`0oU&Y&*Qx z75{36+^Y1b5mTDagF7m((a7$1rM?a8aivp<_M)OmKP(qfLwBE zaq9)z(#qt4xNpRch@8^*u~-fF!I;=)hLPCwC5#o)@+kzLKB*X=2O;V`(}Ug`k4R=7 ztggs*8J@%sod&{eGa93b8C#^>Tm){@@E0*4;;@v7r@P*t>o!M(8z(Niex}|QX19Dp zAVJZbYXCgfVl=h4yKjbdnmC5-Qb7}0KqrNsdNVjeZ*=YXG}Ib8E|6cJDDkYh6;u5z zuu&nH&gcC=0{JXNwTmyZy>s)(_0+%~^z_c&>}g%LioXK9(iyy`3GAGFB_IZ+N>sbD zA*SbLJ3b2`zF$-7b8(#gvXQ*geWW0Vycc(**f>=LZICHDnmZ=pt*dOlsVph*5}La&+H64>{c=& z+O^kBi-kGqUu45JDtrqRz^z6hQXTokS2m_jR(o0x@mLi~W|NGJy5;p)pxfw;bd#o? zwS>}$0iVK8yN3cc;oxO(ZjeCxO}V_h$OC!{lFq)}^g24!7P;U+-k4~g*{UP7^=)=V z+wN1#pWbXQ?gS?|aP1nk(l!Qm*6~3Tk7!py-PLytJw&GOI+-u@N$AJskPv_fu8b$t z>*a>KFpiSfG0U1&f}Fi(!>Q5^g-R8QUs;`6ufXE{lA|#;Cf-tcly3*4YolSwv!P6X zQiD{Y{L6DP;>*5>A=wF2q03!~$lKGs3NiZX9w0iDDh4TXtY7~6Vo;vbY<~wrumS$9 z6ijK{GUxE87X@g3Ze4a2J&y(RlGS7bcO5HHEEcndMXJ@&py2Fxbg77-=f{gOUjP`{ zZ3pycDBmHj4BAF}EpHSj_>JxhQmibI?C@4^7GbQpof>X0s>VU)?sy*2Z*~$8=OuML zzhg1y5k3f2_B}!%`K!gvJjjDH9(stU!wY#1DWmj+$Ug2?dQR7a%awS7p9mxD^Tl&R zcf9vn&V+Ip0H6}qYKGUygg`pawm#9)azHk2?DHNnlYR6G+-UAhVX^KSNUsy^u5#;d z=CePMzE3$3KEq*)-)_mn8Y(T>L!vo6n)JO8X`WpDDAa{B9#i`T~y z0bzg`q;(6JsL(a~5T{%D78o&58E}YpcpkMU0};<2I?xL47E?S6VmeS-+l?`!0p#^Q zQqXpL_>((_9=NP|C+bkYUF^!#JDn-ijSk&nzZHAG3pT_dCuqv&9?i6SmViN;o;uRX zVT!j@UMsm~x|4$rCeK#CHW`iw8Hp58M3&P1Dc$s-D;=6#VtQZ^v=l!58)J*^z!;$y zl(w7P^BmRQ_kjlakG4sT18lXdB1BQH5I+W<%EXL-fCs~b-`=` zz#Jm!-*#QcKEW5=`&tG3^EKrw6b#j#2P5A>+-zzth0{lw3$IY5(x+e%pZ;p7dmeNp z#PeF}iIzX^ku6%cG})!WHpVJibfn{ywhptKygvfS>mJMdlt)r}y3+wzNlN4Y2U|9Pi>d5CfhLMhp?O!3JKWWf%qNuMF~%h!Y|=T!3%x2l_eHo zJ+^CVT?|XMi<5Lu`W>4`W?NGFXq_RrFa3F^I9SbIeCnP)<8owoPFi;d;uC(%p@6kP zpn2meTBKk-6DyxNKBXEF&}G8z?)bgnysd0@O20gVoGY7-7)OQ<-#LUiJuDkO_I{vx zbh1dh_A)iovcuw~Y}pu-S7<5UufVhjzd?TVcrB|Fc?sbR7!eB5I_j_#+Ofl}-X@!|7)%Uo3X!X<~a%}+klt`qvh#ZGK^=k$yrq_58+~{; zmAvLmLs$=a)-Di}_hFY<_xNe^fw}Ka^4Pfum%8B@^l!H|8@O`TL_KI(Vt9z&iAZ3# z6Iu(zO?E*LfYp+xJ@xN5K6XL-*1D8;Xffve?j?(ln6*-^PWToP6jlK_0Wt6n+F8zt znvKaUZf_kRwdUv<33p&38Mqf4GmTOz-RtoAgzGe3xOVuX+SGD;4uIjP(Y2~dDG@Z0 zg>I*DoZEb#2bdWk*mA`3Mn37tjYM&+_Xs9RUA`Ww*(GlY(a*&$;I4H(>sDz?yl;8z z?ZEvzwplb3a1BGRSRl0RJ2RHK!#pqj9Q7f_0+uR^SDK0TmcO2U0yH;5a0cnVGwniS z;^=dpNYFg%bGN*)HUz0sToIV|QdSRgy6|xj&1ZEm>`l-Uz(!1_jY?C=!>IOAeUwwV z@6vZIvEnlrUyNL~uM4xFriM)oN|}3SF4&uHL+O2ohnjZel-71>0(=gTsyyv-g*F{X1#)GQux2T!F&MkHZB?R9 zo{usw1BlE+bPdnCeU0eq%d6tslm85{#~@o8a<^40OwgEhif8)by`f}}XPJe5!s1-z zn@>Vo-aysh5D=@G*|jfp(YnH6&D|^Se%_NJD-ufq+UaHXu|$u#I@P4`bVzhFhV*G$ zFEk`~g+NMb7fwVeL!h!>0^sR59u~Tr=bmLXdpp>(h6$2l7F`j`MF4TvN|BU6gf5)AdBHiq@{7xu%y(*c>Rme+(-{p+7mEz8$df5# zoJ42`){qJ3Fm=Xa0Nwh~w1N=@f9&^8=t&M5puFC_V;*Yx{wfCfCOQ19BrRa#Ty(#e zEp~h!QT5|cH=G)-kUW^Y(|n9?YEc?m0ZD_#pOb=5uU+S9Nql8%-%ayiu+z8p8Q9Y9Hs?4_ zczIqTN8aPv4y_rEKnkzff@y30>^-8~1rpeLW&uAdMO>FDmif&8zU~VXQ9~sQk_v@c zqYmWLxP-Wnp3#xa>A+s*=uDqzwXE)4Hqn&HuL1DZ$?rc8PM7(v=^8>SI9uz0u~iPE zXm?hX80a0w=}~6%i#{XtZu1GARr&n_CyiF!v9acFokCYJci~)GbD=$YCC0roYu${E zpr{LrLvD-i`{m@V3O57hNkz%yq9+#6LFKhJ^(WPZ!OGS$rUc`pXb&JLM+&2inQ)o% z9_V7q1R#M|`fcq^m|{|1rewdtU2T6*Y~7&`lEV?vRq2$})YpL$vSyt)P&LyUR8f;s z8*tQRR*!F`wQ(L0A|-y20Wf0=g*vu>{7DPLq(`XZ=ZLZW{G185q{T-tojtX2A*&P z&TjKD6wEY$%l?E~a$&tmRZ-!3W$r2nvs`|yF-#0g5!v8u3m+4Ax@LCQ zIr2uKtQY4XZZfUtsq04dM#a18hQ~vh37l>3of^x6KrIj8=cjV5A8j{+e1dD9J=Zc3 za7#3}fHxeQ?Xo$CP*NvSSP#F9>!VF2c8{F=^5)bCX`jl*F!1PMQFqc^-NB^G2-3*1 zVVDNB&L{eQ84$qATA4WY8IrI%>^Jc-@VY~ad)tai7l;Q)@J6_tqr7=&U6RO~D@Lp# zYB{Ix=vAOv)9CKIz)3hU!rPTG(kF8}H70+F-bJ)9E271;_K9*%_Te;-pFqlU@sC?@t>UU~E-G15oCy7Lx|W>K%1on5laSKDORBzl7rjnGvzia;+;br}8uj%! z?a)SuHF4=^0t}Awq?lUW&>9_t+)?UwDK5&zLzVulL*`QULE4c1*Yn?Bb=v z70sI4a(N!M1S>i<$>wNwottaV^0=B4^T2~s2@HnoACG%8U^Ku{gI%n}>;p!v!ahc# z7w}6*qCEEH^S;iy)f6s-jZ9E0Gfly7ZmbiRtXTH^Xl1iir%P%H(de7{JiVNgBaKT` zqhy_mZOP)ul@PF`isOoRS9OB`X+Vxlr{kDX6MTDN=^R>b^SbR&8@NKssD_GVlmozLcU8$}x9 z@?n+5&+OAf8gxwYZb4pLC^HlFZP2NAnP24WZrSRnAdZBVR#B}XQ11(fOGCspC%{dw z8FfEUHuCHO6SXxN2yV{aINlY4xq04PAp?TcE*38C1%{K{XZF^RMb*m0U_jdA7yJy} z9N&z{)T2W~i~+cje2<*4S6EzdAWMqeD zlZEnOBNo2cbTYWUI7`EqVtl&wsxgcAD(2~NjapJb39D#xEsge@IVjFROEC)7l;jXf zTp*DnKBnrk2CjY!>JeG@&7{QF#p+@|xi)H~L;<_r0O~Jlq89g#*W8AQ^L031gXA3D z7&lNy07`#!JDR?p654F=5!w%9CuR#8W)EOq0FC$ibYYsd)$`|;Q`DLs49Gef-zU2+ zTLq9Ocb+NcS1kc$$G@Iu>yW(8@slm4?lwbaL}z ziCqX;67RH8kD1cFZ15(|6d;;mDPaUFe?DrJczXBx+LRzLeSazsLNiM*e(83LGDvFx zt`7O9W-xn#)pzaEG}mGG)o7KhqX}Nn(M*s<-5o+=jYeBS#>jDF^s|e8>(VD{3*&Wh zi>#ShwehOKZ$SF@EynrGTE-G8t0|mxceP`*hm~#@riL7R;cS;{2BjSi(&-vYBgz-Csn?iw-n|6`(|bC z?J;XMS>%fG|1WSTU;Moemn+f5)hazOgHu2>NA={cWV5l5QN;qd_wo*r9lXVULE008v7C)=g;LtYO`Vx!d`Tx-x|jo11v#%T zW3|<*=yyhYd-9PmX+AqkntX~!AXRNX?Ju6BF0&1xYJc6?w-@lt5+8(xE~y0*!Hodf zc6JHTNZwlO>xR&)Y4!GxRdx~K1vd@^bVQKE@zc*Sx!rBXg#*Uw9+VRDEF~)hAgS|x zQyR!S2h_42i1nx_OL8bJ*r2}K!@wfXx2enXp5)MZT;97v&F?shBc+3o>)U~1M?m!p zZ-MlXN9#)z>g4br+Rmg)tXqI~8ZN9hP^|}zS}Ia3u7f@^U^O38KHC;BNT1yN*hhNEcD{!xAO3(4p&mvmB!F zP>T;;QF)?LSX1g`@XOlUKwSCPdNQu?xxx4RF+}c*^2VDGaT17=YL#RjnGXrI&00bN zUky6^WeVezdXCnwNA2~mLS;BxWHJObmZ&GS3X)ziQz9*zcFEClD9;_H3i!ALGH3pz zo=Rk&VQ`0L1CC|ZSrG`DhX;h4H%SxLx5b7w$FE9T8F&O}I8#gAjXjNv)vj&>wJRpq z7gV<6SbCcp^U%~pTBGb`cvm~j$2;B*NzVw;1!2#?gGq&BH;RFE59moAYLoh+S;E?V zCg9p7#+h^`6C3yi$mG+AdMRnpm4teHyD^-?>R6#z<%zX!(c7TXVm3UQg zUz7gK6DUkh6rCcr8=`=2NMjEDJJFj9$1x!55_h){Yvia{S@GUAa%W@8yD(Eew3g0@ zmar6g>RTgRIer~CDqG`-kUe<*)`~=@I9LZO$Y;sAN)s=7P?~vw2ND2`y}Ymxfo^mc z`G7NUO7L3N5PeCLlp&O@AHqn?yh8D1Z_HNN$awEUlC1M79aXL|w&NNtMs;4iHy#12 zz3=noan(oHcbsEpWQX1wvmN~YrS-xDyU=Y+sh8`pxO90ydI*&a>bFlV`T*V;hAY@1rQ+~cB;;>$21p~gFj4N z5LNsF7;tXAA%V69>{UP65Ff`Y0?1NZzdZJh2(SU0_}M1KgFhArJ=8%S`B^q1Wt@=V zGPbU7Pe$@m`(3q;O>5iWk&l;UtdjHT-D)eUk1pmOwLvLtR7UQ^FlZo%SliwZQ+X$& z=)cq6#CIW6rX_uc_E4H}Xv$~>_)PguFY@zv5_FWbQ|Vvd<$|$h3K(NZvD$eZl&i^*x3kln16_7wgV~`zeN~M4{(^&gm5L_Anz)A}HZf zQ=@3nChZ{@#H%x1PcNDvxUr0^6fI?&-4Y&zB)mc$zSeGid&vzYdk^dp;6x`b`=bYn zwjAbaQpNK{%ce?Pp0Fz@+s0ysh1YDw?025-COU4M-VwPB^QA@j%*9mB>RPNscip*) z%WXVvyUmWNcj#&^t0T8dE_Bejw}7Q+x@uCF{GO#sCGU@%arHB`Scb6*1LMXfZYk{Q zfrOAL1Zey)kuR`-F%sZ-Y_#O*!-9g0@b4@Lk(HWhr!%vGc(ClrnL$i6dC%g4kQ>xMu=#XPfOG?AOvtUeO{wog z1B=JuB|L;dqMx-oal%89PmNFCnCzad+oW9@jX>wNGfQxSRd?FcNNZosP9D*zeYKRq z$|=8D#Mu|~y}fZrrk~nA>uJw6v(Xq>wA~~$vud=20C`_ShBZTQ50%nU3ZcqaqBd{Q z@RJ-jRZ5oIqm9a|6XCF#Q|2qY0uScMrL;hNF=?OnYeWE7Qc9(@_;iH~y`P!L$B0S) zZXP4pPG`rL$d5k06^u7M`~&z&Q9FiMU$HSPmlOWV}5~) zVtY+CTBZdA5b879ST)GHO)V(5V=ip_S*@jpAkCln*N6rztO_|q5pvv!m<mm#gw| zXBpwuI}M^~4dIMC9xlUJbvh5By!JMYS0X+0$EW+6Zo}+Ts^?RRmfb!xe+hHJHtG3p zh??=J!y%)#h~Lk&!xO$OMeYnb2T=5<@Wxr4DORW1X+6qDXYh{56T)d=>UU7IJak%vvYSkmXHyo(n$7m)xk4X$Lj zO_f-$iLBL|FO2mb_B*FNVDMug3`4S8pG%i(;in{EYBSgSuONhvJvL z(md_8T)!GVc>%Pfy))J<;Xsm%?1aD~=`>E14_QN4o`5)V4ZwK`v-kbx-*p2G4ncz- z8k0vrJ@ZbYL2g2bLdFB6*y7Q?`eA*8l_HK9rBqiob!HJ@fv7!NeHsArU+*U8jB`Gg z!Ltfq>UQ``j>u}w2CvAG%VkTLJF561AAktY^34NS zA52;S3#(o~m_-xnD167ESFBr|tMbVR0fQb32io|mCf3k)uL7#3`=LoM-kOXI>L`6X zH7(SY5K9wL7cJ}pjmkyY<cREALEPpi^)A1HcKdxrq zj?J@{tFSGZJKl4tSgoY_D&UwKJ$k=CviB?pAsUk1V+$qf%|cSl)>`*)hVvPV}7u69zgR)_sO=F0SZ#4wJQz&6fB|wWl-#u<1Q|If(WzmW?te!?hl*{ z%+z+Ll{b_-FPJZWyq)|4zPUAUjfAKK<>$;4_-srR)%bRp(At?t+Jx`yb?yZ@wv%{Y2`63aCp4^sLXJOnFprsD}eqI76*x(yi;Dx8)>bDycT2`&MtdoW} z?k1}CP+Vj1W0ole*4%lz&2MdoM>(#B!#Mbw6r-3pX#!;g%0)l0z+{QpBjSjdO{4C) zi=DY6dRcBqa%FDvV#aV2aqitlv=9dx!_GL1#DH)c6=6Y!D?z2_^~IxcbA26JrR1pr z)oL6l$?2T0tp#FRs3Y6i>QdO+`Xv5D1JvY%$qB>@Y&->Mxjgz7e_n*je|PREU7dQpy)SQ> z0P%At^EX!g3i7f87wydZBVC%kmXYSXuMiU{u<)z(Jt z7tV`b*FMB>`(|fF_5`IwJYPW8wN@>;86~iYJK`pmDE?FnSQs_W?D=+SR-|vf3tiu3kftu$~49S8=fL zxu97m71$XTz?ete@s7N7qZCQl9WnQ8!iK^ruPh-Xi&2*_8eCkcrJAy9pi!%kyX0M1 zWNIGt^F_(zgVM7jfC8l*>L-ovP3t_>>vMUXr`Ddh?sXjz5zp(BcBev>X(z#_W{aPA zw$uc*VH|ONGjwcHkIPP}2X`C8vs$a^@JOHH5Min36O-PZbXU?gk;Z_W19TmSWS$o( zZPq(Br=6B*1oylPfdA`5;XV@N6-guMM}&z+#N#@fBeJ?sq@8yG#%>U92t7jH$PhQS z7g|wQnACt{Qj+B#>DIY|o7p!FR~&0J1oYz9WsjTg1xNI8tmDYs0gC&Rg{Yt%AN?^@ z2kk*!HeI-ux@nmDfJr>4V#G62xs}33S{x@z6lc-+Lo3szbw%VVBM`j4*Q|G_W`xJr zhl0Ana_=wn0uU>|rV(n~Pi-|Iqoy#b$&V00Z+#`(euN3{blsOjo{2DhWDHdtMaZ!->3VL`fAXeKX5UcYQu z-gcrWz>y4-D37}{ug?W&_#-lzs}hj^M{-iDx( z6Doc*yLJ;O+t&m9f{F8ZWLqgcU5I77XmZ`rAZo5A2Yh zVHG~fh%+`mlb>XscT0CZ?jaS13rcFYcmKW|0O1=uF;29?@Ex}1@p{*c9=pR*cxQ$U zyy@e^cA(6dv^CB^<13UA_Qs0sSGcCeGzUa>o2$998^G|N?J-7}U4SVCUGi@$+TWb%S{f{Xs?FHLUHJRaSjK{*%dGi;xxJI z3n8@=>h1!0@v?c7I{^52d*1OT2~Qx->q{%9cVdCEn@a!)LI~=%jNEx;9eG_|@X*l& zWFx>`dnFE!Ii5Xl%fr>K5gQX_>{bE0IF~s;LtqK|9fla$rksE4<7U1be$Kv98&*?A zp*%YST*t9}MGk}>JA{I$oG5!)O(khkXEIA4DC?8v4jv()`N4DG!s#_6~g82-pm&wLdGh>f=cYK9oMQrj$>FWDk^7c(>@7rM~8Z; zr+lxSvpb=?Rm+#ur0=qpA1g>k?%+yR#UYp3ma^vRdCBb|`PS^|K@55R`moTKb=)>i z!o>5K9c8xKJUC_Q#B-4KqTsYv8%rNe70V5NX#7>Y^RMAC8OrZ!P z5Eqba9kumzGEE54(ZUnFzkoA@^+IX9)z{Cvsv;YQxI0j_uSh`-t}~CSzR~gOn5=OV z@wGF15gBWN&@^~62!F6G#P94|@UHw8!z^^`Viev*O|v?U4@4^0Q(N5^WM1kAe03uw zG0jVJ_HEjTT90%|yZP6k30t~0{pa=27u1#UXU%~t6Hw=n8UbFq;B;>7y{aKY#G??R zwh~;R)|=iF>K|%!yS59f|_19$dnTD06$^6R?Uf%?WwJ0akU07%{q zZgE$DAVUVZ!#WiMp)4Q(IK6mQUWZ~ENFq-K+<~39;IyE%lb!Nr#porHg)XU+lY3vK z4Fq||KoQ2d@IhN2a#g+f`@xr$<=57=;pWY}HMwjSdUt^ycvz!nyR>(B$j30ppr>)u zJzLQb5!xnCF+R@$z=2Ruy?eouR^BWd$lsmsvUWvcOUu_K|z(z-~L9pQ7*L?p$?X1(m4Ez}R~jpcbdM1=_WuheeZ zjS6#G<1e}yVw7|dphG?EQLwQ>j1jA?@cJ6s_?_MKmA@W&hi7j$k$3O&5TFN$uv{EB zD122itw^JNVO7=7#`wW~o@N?X=-~({DGbozIcH^zP~{Y@&~MGvoN5bugat&DX;xAI@k`5Gyql-ZrV|-P=>BUA{@1`g|6ab@|?e2#hHhV z^BY7!y5Qmw^L(X(e2JJo|U_NUcWIPz-w5oSGKv z-MEdIMIAY^9b+D=;B~3P865k8SaKvnXBFSsltf856zcqOp*jwqfeS>)?CzRB0 zljQ_ltRzEt1~fAz>>COEawQURa>y(yVhCsX`B_lJI z&N42=TmfmWF)eHjA%2Dv^5#O&Ji0@^jlsnXhx3IC51XP)n-hC1W|cienAiR4(spW- zjS+n&Tdk%pz_*(y?$;oE-&%8}goiqhi1@m4J2qZu0NWFI51Z4P1gzK<}7ML)ZzPUl3d^#R@!mA!fp1*yyIG~nob46Tk7yb z@XHjijzrj-(1=;{ZYpv_W@C%I-*j#Wy}3iT{Csg z)?IzyL|$>t3NlN__p*CWKQA|^e@2wpi^f@0gn3K&A-WcIQK2SL_4|FGjJraC-%~bG z_}3Rd!Z<3o`GMTIaJo)Mnh0;5Uha>!3zPXZF{+Jqq4>~_+ldTpcHy(uZG*(Ry(tDMl4>@oQ{TO6#Kfd>eIJFTOjN<(P~II9(5rV zaUo1^6I`H*@qr*xFzKcVhzk&SlCYMQPqw6}QKXhq!h7lv3 zZ0NjxUwhKUOo#6L%pAL;*QBw&DgI*auu0<=k)H62RFKjei;@%$n+SSpY$rmK7*;xY zG;Fm$UfALurcP41OumJKNcb3`&`u1anw5H-@hVt-*CY71-qs8$Zs=p_5A-sc&2{Hr z{DkESl~?%q`+K3Ck~+IyhVy`3cloVRR~Jt_(!2V!P;mnBzJz8dQ^JThTd6ISdbUZ+PNg|L*flKn<$1d^hE@tp!yAv<8PcNjty|3iMBDP!A<$(up&(?pW z({s1*@NDr$bv3TfPM68$&_iI_J{9JZLXjGb9 zgl#ba=|3^#r^}l9J@W8`y{%Ha=9zY+uyOIq5bdOkKT_8O?s)F`s99&d6Je(bF|bK@ z)4Is+86@!C_g%yHN5M+S(j+=i#mDp>kG7Koib#tCKYXB#ZJL?)*6b3#Y^};rzEI^`;*>p>Mnz=9C&?gjDi*&hP<4aQ` z+Uu@ZPqD;gIKo@+;7-bo6RExdei!-g8VL=`HQwRnHEQM^wBcTv=#{zKxVARORW23? zTWlX9@;C)RF-(~50`=iQV}s-xU-SANzBT$=XRgIb)~F&bVUN(?F=jZ^xp!IM&6s*h?1eJ+|;iqkA}2@Q_fUR{d2x> zdFCFRu>+PVKVCSOYnuV~5awW7mW_$reS6cUB4tqG#-VmwHNLkSWZTI18ln5tXLR&z zJUhVEMydM-sTFL2)|#c<>5AEu5p5Tw_D85$C-fEh9=ry}N;rAAZ%**g;wN;cU6Fi; z&6_Z5KaC|uSGqe)0Znao0E80cm_*SKv%9hoQhK(dTE+IkPtfA}9(mzznZdyDJ??yX ziC-yvE1Ls+FhN4=#JacfXQ zEOZEN#l`-#`=b!G2mS*$pfJ6}6Dt|&NohF+uUs~)!sxPd4h#K3XEe?m9%rom^$l_fzgIZApRD+P%8&?9Gsz1Ds-_vsWGx{4t)& zkg>e$o(t7amtuCs0GKBVKWk#mMb5UIf4`vb=&h~~^3peU+h;C4giXTg!tTb1fuL6d z4!W0A^&WX26r}3kdKefbjU`cE_?^#s(a}JvYZ0n#7=B<3cV0m0a65^6a-GtggSGO3 zpM54%1P>dS+o8qfpUjwH89=i6MSt*A@iOKW{r+dHkRtA`ORsd4Na zA}>mO-1mSxUBk6)x=7!~+#&Y%ajy)#7D3pI_ysgcB5wBzWS&8N2&sMy98np4y<=H> zGm!-Qii~F7oIN8KLis~@AojJ)Y{#xmZ_+H92IWl_elESEy^VNm#3<_z! z*zF62QSU96V+Vl@yrQhbG>#*J`k}vf<8J9*0w9UJq4HGW< zJI8OEE-g}bM%6R9ZTIayb(-FuXUuldb-p6#y%Dt6WN0Ti+N!^SX?0G|!!)=j{srP$ zDXYb|nPcRUu0=2UN%HP$0WGf`i)BG-FWtMiH~L$T@ah%X9rxy~nLDx7hQ#JQCb*VI z9eKKYpow$vots(akE6t-t)M9NT}Nw<^42RNes`i%9ok}f7L^>R19Ap>+drlSix-d>F5E;)oA z90Q0Y_jnbys2hu<>BzCvK<(mG@0q%kuHmsJdlhLL%K_~mX0|cb7x=mj=h+hnktq-# z>j{5@y|(XQY@$r z4;M>GHl)=7bL56C6bS@m6Yu*%_ID+`WVAU5N;(fjot(Om2y&LnZxLuO4wU_)U4)hv%G=LNwrQJi+v5MXL z3wJ8Q*jzmMo@}cXok0+7ST!R_fv3$Y5fZGzm)V|xiIFzAn{0&au6`_i3{Y@BmoOmf zuB8#LZ<|3g$F*#(jDGc9IjWU2Ak}`~2|vO5UENfRFk}*T7eY?m$%90kf=EHSJBq$@ zq4|2($x}hzLij0=CB-%F_$HMsK{LsojZo_a34e-i%q4>V%s0 z`t_E9$l!c`N!rS9>f$!hIOX^G8*4ojV0W}oRoMwxNt_`WyruZ&JkztUN#VV&Ak*#d z+eU>#=pKXCkJ9Z#ldbF2G+K5xZo+8-ex@K7Qo#5Yq_dEGa>_QyI3V1#&cT!BaH+k8PC&<@jhI}?38S210t?Pe}< z(@yjNtEAH-U7F6*Bs4y)VUid<9-euJ)T%Q8o-cNyfB<~!+v##C`H*8`4ZQ0J3?|2- za7b|^Ra$~Ra-ab+O>FKZBpi1&QM#Jz-YQ?1%XSY*VY+ILcO`a4M<$^55IpQ47i4H? zNGDcW&XUTLe%#*nPN=I(=5^XOG|SVvrYARwBda?k=(Fk=tQ6l#K*Pd&bL*|VyeR&8 zfb6Bwa@lku>Mri)yC$5u{5^i+zxwdIbZCdy{JVen_W%8pAN=mWp(IUF+3)`Ddz(|3CJ^cen-dC6 ziQ)&F(SoK?`Ujg~lEM?{hsTcb0>yu@8N-w8-`KlAk`zUMusJ8Ogi3yRkRmCtA6_?{ z$3&L?@YoqiU_U%IiKKb@!_6S{Q~ZZbm8T>b|L~M#oE9YZ!wXE4H2>jdKvt-KqhVt> z%QNzadsA6P!~aH8#aQ~oh6T4?#K;deQ$&X3KfIkHOJe$mR|0+a`r++-_xj<@fA{*q zX7;<+4>sSvdwqZNt4!km6T$Jn`{Q5e|N7V7{{Q@`f6pK1{@vfFalgg08JGFD3jVuq zfASgm-e>fCpRww1s2@Gr z4}Xk)@5d5m<=a2~?z{iLVibyj_)fkM zge1N&EP=mb0?EE8oX8OvCSa6G|LJ%C{H+_Z{2%`b0Q8o>{^@uB)c^m!z4AWGU*8Ld zKU_eaeNOy`3;#mN7=r*M`HB++oTDg+uOva^FFH%}oFE`TYrY?Ze{7*)u9x56#=mu= zV2`*j+fUO%|JLvSwY6xN`jK7Qy!h@oXODhu+aK9y8OF~cU;_Pn1pkqJ z_Bvatj~5^m{%`E@&p+7q&p$lS&oK8~#bXZaJ5MXP@PGQEFPvfB8E2T={YPrN5QKw<>@AsU!ST|LsSdVf;~F_yJ4%*Btcsr11~g;~&2LJ^AyU2hPz1EsFdL z%QNZ=LjkRcV}K$gnL|KJ&}m%czq<1v^k2n!2n_m-o#)>rmk63?89~usNQPoxSdvhH zZvw6f;TQsC8AT=({wL(}JMQr3(n~zSArz0%uMAH}Kw&BLD@HKr3rPzKD)1Zv68Bd( zIQ0|k5~qKRPyBpq!{|@hnudR#slT`7|M~u5e^(J2Z6`U|H8i6js}uD?`y5gA6(bc}rA zF#(iUPA6X!jlf?SOkpsLqa^u*{+T}<=a&o(1pfD9x{;|z}!94gAN$|%G@bk@%lRudO zar*CnV;S{%ed8Ec5bt*Q4TAsNIL?!tq|ucAqM;8VP7&~~z|$`r19B;)36v~|-`tku zj|Jc_YD}1>e`8yIlj64c_TjXD_pSQ8{U6`q{NMkNKi8@>5u-Hp>DkDj_`_5YfX-?1 z1=uS}<#|fu#P_?&|Jb6xpx(uQY?oiotO)#5*ox48v4HVN~`76@VRM z83KJ#1eJavFiw+zDrJDR{`!_jeyXG67cf0a{FLc`Yjg(E^`CyH4X?cWR*&=Aeak+= z^c!gAZ*iA{7zeUs26oPu_4O^z>am{Fx-Y-wZN2>cH|`bBfZ>gGvd-VuS08`thyGiU zuVo!C-|BA6Us;`l9r>Zp({Eeeew&B3t%0sxv$_Y@vA*j0@4l_ew>bsw0X|G?{@s!O z{+p9$-~FP`Kij6Yp1*-B0w>zmc3hVjDDrkq!G^#8bD;-;DU?isQi5qL1N=Pxh~%R9 z^!;OGhEo~xSI|uGPiB0b(ZekIX_BWaEzaq)#BpYHC0#=nv@Nr0>ckU#E(|@mm!2ErHEkDzd1MB<~n6FLUWxQ+fTjQbci*JE-SVYQC`M(33ymWXO*a{y!tDLOKwd81c+ z4#?9me&-4QS={X39aH-^s(F6icv=P%B!Pdp1`a3&jbmR_j>KO?N?>`05qLs=zmDvW zF7cntFR33p#(xmM{L93~{~HbQpUC%rR*yD<5hR`#Acf~ZIpY{$%M=lR;TS|GNsgm& z`d8@D{)rClU&57f{I`YJf4^!hrr{Vx0E|E|@`aIP{uPrs_C=;>nvpSqqDb+V5A0VL0kVs9S~0c-52(=dj_8S$5!Iz?#s6WU)0k!4>Ppiy5moPH!% zoB`@i(s2G)7_`TKjDP@TOu|KZc=cimk>1>mKt zm+C(e2>mSDMrQ?##OYTKQSldsAoN#4BPrNUCUH&yw86gryxkuy{GSX{ez^{>?``>| zhLJEpF;WykzbG<+fF#36Ajwkd3#Nc3qp}1liXV!;Klnd76>rN6Hd3{DnavB;y>2S^|gA7(tV? zz<&KlS^hR=_-_>7!O)*wE0LjjT*So}No0Ub;RW)sWeNfr#V7<$QwoiLb6fszGjz!G z!%_i>^htW(zDr*}>*2KTKbB1V{(;}0shwyd$srQKz99Nj&Q3v}Nc^iH`sE5{VEV_NWcU|CO`^XEl>bJxdT4?rF0(j=xogB^K}|N7Ge{7q#4%e~lVWnEr`T zFc|+O&<&-2I#(nA)xoVuVHij7^b5)8kK!YfPvIN!mEl-UCMkiD^!Mk({bNJ_^}vm! z|0{#r--y{SL(JmrGa)mQe<5fJunU3cFDe0IBQIzK#>hM+iC@3x|EGuBm0xN8b|+Yp`Qe^R0m`>`a;G2g3YryxvE42~?Nr)mQzX+K6h#(v=MMNIOC5E{R<8Y|HQZ#LHrU* zi}*1?_b)X8zh+I+e*jx&FqP36MSi6O^{GPo%ovta#TN~vdqF1zk;cEito|um!!U{c zhqCtfw)|2h00a<)8IHqWfMH}`7*;@EF-9j}G>*arU>g{f{;k&jkMThkNQQrUfY9{g zxpWKxRZ*Z{Ih{awmIG~_{KfO!(o|d!pXtm{koLZSGzWo^LFrdU(n&_e8JfVqesmx| z^{6=U?-X$Uq62~i^uJZHeM&+(o)*Lx6ca$VLNxV7=Tr_nj3iJ9PvbcG^(V9YTOGhJ zGSh8>Q8WwzEQM$YL~@bgUkROJUs(aiG=|1VO8;%1uJ3L6)ol5V1!Cvhck6z9H{b2I za>(az|Kqd#!~giRi&&uoNoa(iz6vP$tnQMKUvZLBUpP*q2uTzOAW^@45$j)Pwp;So zR3`u7D(JBS`z+Cre-$uD%vk)fd<=*aUO#6Cwi~H2X?n z1pdM@D*K`fAf8|hLSrJ$DH{9rYsLPP&35}MB^53nKkfOi(#h`^6Z%zpo?oA)|Eo;R zF@Ap$&F?Q@ME(5A#sV!63dexDBtEMck$L<@(Eu~y6sJ%)N2r|q^`|)d84DOu)L;Hw zJqqxU`sto)g7{7KenI3|@u^?Qvd=Oq$!GFd1cE*smB`2xi_zqVMJ)fj>ixgQx;8~Z z6g2R^FCzZTpP#3n*?hq%<21&T7@Qo+eto@9B0mP$e_SH+$GWk8!9{J*U$w;KKb+J@ zK?X-+Jo}0ZD=skXQ!P(_(K!r%Ay|%}7?l=r{#QT%=*OtfFURGPADtcRUj{gTqeXLmBkcdI z7D*&H@&#p|dJY;%zG4zCzEB*ZVhTek>aQ?`|Ig?~_yuGfj{I~v$FH0K{sS!RnI|cN zB}DQ?5y0wLQP5vWo)uqsL8dvH0ld$C{eFGory~6?U)K}Ie`@w5;p9ln3t z>!tcV;D7e}(>2fj-G#w_Ho)gahQKgReWlPR%n1bkN|3zx%u@-REs1gDuTZx2lTXL| z0^0ZI4CGV=53F{ZCQT z__qN0D+UN)f;a(_Uqt>{4xEOm|9^W|*4)OCq~HB35O~@L6{GHhZ$82?-q^9c){GxK znqbr^_6P*94S-|qhX4C!b^{_rd1a6# z(e72sSFBhsJ<(KS-)HYW z4@h_=o~NkybCr(dyf_;v2~J>>1}TW6)M8)}=S&&J>1%(6dq-YO97zc&YRM$%5)EAM zL92KxEK#6;1>DRtc6>ne8b`7gM*?8l_pTEBa@D&-G{+AovB4#gc>vSO1b|}&c7+2= zD-`%li_jvSpgx)Es#kS@a1z#)R4eSWWDT|yJG}~^mPWypz>Y44$Xp_91};cW#t4y>D!^8Zu*7myJiibpAY^wI-S3BFSK*DP z?k~Ras+|RRJH(ed`EKPisO}}H@wNvVzNaJYPR1f(`}9QxGvr9zQ$t)ef5@!Cz`Htmn?OQ5~y$rVLOzq7{(=nce!jg3t8~Fw{+JXZ}=<5joi@h|fFp6>tXBPl( za20$4B=|owIPW$O^U&jOaEq0p^UWBBhUc2ipRBptZFQS#jEigzHOmBdna+KXi+Qx3 zzzO`^0|iF;FK|H%h7NaDl}gwQ(Ou>Rt;kwPe-6zDCepeNcKAPK4hPt+TX0vyHJFAS39j%W?pJCpV{UsteLzURS=9n}}T z`NmD{^W#p8z!&=@i{I&LNaeOZm()bRJXF)Yt<#3AlJN z0%*)Gw;@%W;az2&!$ci3kZhSPD;xHQ2PyJIs|+)Se>j>A@zOf!Kc2JkI>f{IOcQ{{=|z1I9&JFx*{mibRQFeTfO; z9M>c|ZZx$)0i-`cKxbFOS@uY3@;)6%w~e!u=ImMOLq1nR2aq>&M=jC#Kbevyjuu8l z^wK&D*p!{%6738mi{7Hh`B@Azko-p3j5l)u45+xC#1jeJt!5u#f zzf+JK^+*c+mm|n`vnsFgeNSUrHmr8lZmgWHdh<7jFJK2h&5-n7$s$c8CC7q2M+5QL zBP>{^lJqv2b1)>0IYd*wZc|cN`gNI-+GlEbHiR<~0e)mGQ_DFq1^b*R8H?g)U`jf1 zfZ8F?ZAzX&fl`yG(_9M@1LpEmQ3$?B0)r!1t*{8bIYEI^+Zh6=+(CM-3VyLY;bTE{ z^SrGYspEnPYltn_1Xl`29AF1RLr_9#o+8~u4KMgT!EQJml>7Vl@B0g=JIAjr#_kQP z$)Jr-n1_liVD1nD8>X{*jM2itLaAzlJ(^&UiT_YF;TZtM0nP);y%#JI1|F`!IEb4I z9Q=%-!@c0*opOv*$~MCm%mKTdNv;Tdr6fhCn5SBWaDpZ-s;gluKSWgtzO{J8i9({z zAcVkKmwYLf2xS;%esL@;5((E@nZT3t{`jh(D}+GPr@uhh+T`?%A_&?{(x1@$K4Yn} zt3h&%$OdN=wV)6Is(4I$2aIZS7Ni&*r4^Ybb$sKxE3$#BgY?T)+l`$iXxSCD9M(*E zu7-@UIKe`qB#WSl^gwvWuncI)E_f!bIYGdBx0#|DJ&bRqD}i`-OXWzYRSTB{mYCEU zqgyx)BskC>$uk?Xq9N(cax^a(wVvI31sN@v_8g#tOCT>p!PY~v5HRr=Rf!elPN3e; zA-aWe_dLyOpDC_MD_%rYiYPAt*hQC#Roau7nWn}EC)4v63wo^-wOggAecic9d+NMm z1fV=9N@X+&DFg54ES)!8`v=mA+LeE;6t(>Gtm)1B)NeVUsqk3Y>}P%Zwwe9BD=$PT zgiZ==2e6|#L+$4@aYcGvEK{@`KftrI;EbZ3QBo~NBTP_{XyAk@gU(y5@=Z%2(osNS z)N}hl)t33a<_=M_P2Vm%w3%ZX!)M_32v%?vgCMY4ARtT9#6|_$F?cQoP05SnC&72Q zJ(N31v!>^9d^C*&WQi;{R?2uyoUgYxw?vNE+8JB%mrL~{Ko?|2r&Gy1_2Au zwqJt)oMqGC;82s~k9lr3CwU-oJpcaJX1%Yj=JWs&4QlN}H6&p)osMp>PsKiRSOx8v zOcoGmR76^viR0dol9R|z7MV}rx?!TD_pzg$Ax;OA!+dKv)lv@A=dU3DrPgNIWSHgK z^>IA``LFgW+a9rnZ_~{PEj*cA`4f9XR&#QQazY&R|0h z{jzP_9d}}Y_zhnE%AGHOJGm%eZDA~W(Xg9k(IiO82rZyDVWV5lPT>3M;!dVd=lkM9 zbvi`8RIBS1aUKY9GFMm%V1yYjHIXp};&s57=%f?I=PG{ul3<;Plksiw0mnd`-G0QK zG3UJ_hYChW)JY^8VT=lFf0@zcUx*W6Q^z6=i<_Z~FE|)sr`(utvC6^}!N9b-&AkyY zKNgB^vt=fOD&^gKnXK@e-m7Spq&86R5-C`C4+v#Q(8UnrjCRIIW9bP%q}#s54_UUV zGyl;X^M&OZynB&CD61nQGD!)vkHDhn4UR=Iu%fxN<@lM-odp+9@^bnNVouMeYL$u^ z6s+JR;NxnU+Wp5#HBwbp7-L1o_NW}=OEN6)W zrUgJmZB~VImo^QD=hUSu-_{A7N^FHCS7y}5Oy>b0=&O(UQ?p9d zG+q;AH=w$2=J?IMtNL{=z)r)sHuiGd{`Aur7pvd$7Wwz6{y6rDEJj)`Z+|uh-p%RC zH;|4~P66V8ZTC0kE|t6li^ehadpkZZ#Gl{%`OP=DUdtiUsMVkSrdRoLHRlu`3meZdql;k}h9_^=2W>Q^8J{=h3QK32gG{nY|j^(UiQ9apzNbMrOw z^;4e2x*E^vx+)rA1L1?O6T6RstG(|#{CTpm8QS@b{SKUB6;ObK+0F1R2JSrw(wdWK&akeqrko+T@hO6y#SV^A zN$rv<4q)j6mu~Rq%8(B~%kIN%yL!Ibf17Wc;p`@C(do^()#STb{Fq^H!r6`Cw)ND; zMT7VJ_BPiDK}Mxlsyui&46V5YuxQur{7%j$a&39`mq_hQIh!K z!IL+o?Jg2{yIfima0~7Hs8j+ozW%hi-3Oq}X0V1h|BuZn>rcD9uHWA}{B1RvfxZ2| z{z38D_YtJlWQ5y#w;lE7{uF`Zeri^DCk9)c=fmkUN_WBLTaDNdNVyka17`vc5%Jy|wHkYo&dX}->0ti<1xL}=MhmP3>tFMSPawi2z zoYjam$eP$&yTd~6H)oK=DGx2|NhaLv2C~ye*y}O2s?>&hyXjAJsrZEz@(KDg`N?${ z`8r(+6Qqmk;7W8k!p@rXx@sH;D|olx4)f06=JYmTU=?tNzprd3+1K&59B*ee6ljib(Qij zewYVM9mok>+$xp#{n;e{wQ+>w!6qtW^<5T$-U8kXuqJHI@<_8?#y9}ph-b2-GXx%><)*9_7exS}|LJ)XOH z&aMadhPmRMB+5o$Sjq($WS|0+&yg#^6qV}12jA_&gFHBc3H-CarYLUmuX!>Z)p-+? z+^LZ}j#^bAOHHsy71>o?tTN~UbjBWFe16?R1kbm_!*a9{i#uuo8fjpLe)bf$i1Jpx z>>|TADfGA?x0j4xXzre92$5L@CK$RTruC;w&O?;K9K|YH8)vi)ikSo=r z@zr!R^@Fd4HvG$?&1g6sU7>4cGWIclEkqJu7LoGJc>3vu(WX_DE2O!9;B&~(@z@(f ztP#n#o|_+L^}=aDFBsTt-09`t6~A^r*Y&9Weoom{Lu4{*ybFt;7~LSxI$GF!`2h-u z3&1WQ}P~Z2YU_tHGzsR88UtSmAO*FzvMz zTW)`k<;LUIiMAMYRmj~`!`U=X-VWczI_H)jmDOuJ*m`i^mhTb%A=B$sDG8?1Wa@9m z_ZE=S%jWL|U9!+;$j)sKxGMn#*ic*?gMj%KAlGOxIV}YjqdrbTcEPmKtA8G&rh293 z_2?#_l#n=J7aMY*8(X2Fd5nnsm557Q|HM4G9JY&~Ome$QQ2Q7`(U-oQJWw9pv8iugY`T{2P zgoXZAyq&t?-@p6m`Zr5w-2L`nzt0BGS{KmY&$ literal 0 HcmV?d00001 diff --git a/x-pack/test/functional/es_archives/packaging/mappings.json b/x-pack/test/functional/es_archives/packaging/mappings.json new file mode 100644 index 0000000000000..182d281c9a3de --- /dev/null +++ b/x-pack/test/functional/es_archives/packaging/mappings.json @@ -0,0 +1,2561 @@ +{ + "type": "index", + "value": { + "aliases": { + ".kibana": { + } + }, + "index": ".kibana_1", + "mappings": { + "_meta": { + "migrationMappingPropertyHashes": { + "action": "6e96ac5e648f57523879661ea72525b7", + "action_task_params": "a9d49f184ee89641044be0ca2950fa3a", + "alert": "0359d7fcc04da9878ee9aadbda38ba55", + "api_key_pending_invalidation": "16f515278a295f6245149ad7c5ddedb7", + "apm-indices": "9bb9b2bf1fa636ed8619cbab5ce6a1dd", + "apm-telemetry": "3d1b76c39bfb2cc8296b024d73854724", + "app_search_telemetry": "3d1b76c39bfb2cc8296b024d73854724", + "application_usage_daily": "43b8830d5d0df85a6823d290885fc9fd", + "application_usage_totals": "3d1b76c39bfb2cc8296b024d73854724", + "application_usage_transactional": "3d1b76c39bfb2cc8296b024d73854724", + "background-session": "721df406dbb7e35ac22e4df6c3ad2b2a", + "canvas-element": "7390014e1091044523666d97247392fc", + "canvas-workpad": "b0a1706d356228dbdcb4a17e6b9eb231", + "canvas-workpad-template": "ae2673f678281e2c055d764b153e9715", + "cases": "477f214ff61acc3af26a7b7818e380c1", + "cases-comments": "8a50736330e953bca91747723a319593", + "cases-configure": "387c5f3a3bda7e0ae0dd4e106f914a69", + "cases-user-actions": "32277330ec6b721abe3b846cfd939a71", + "config": "c63748b75f39d0c54de12d12c1ccbc20", + "dashboard": "40554caf09725935e2c02e02563a2d07", + "endpoint:user-artifact": "4a11183eee21e6fbad864f7a30b39ad0", + "endpoint:user-artifact-manifest": "4b9c0e7cfaf86d82a7ee9ed68065e50d", + "enterprise_search_telemetry": "3d1b76c39bfb2cc8296b024d73854724", + "epm-packages": "2b83397e3eaaaa8ef15e38813f3721c3", + "exception-list": "67f055ab8c10abd7b2ebfd969b836788", + "exception-list-agnostic": "67f055ab8c10abd7b2ebfd969b836788", + "file-upload-telemetry": "0ed4d3e1983d1217a30982630897092e", + "fleet-agent-actions": "9511b565b1cc6441a42033db3d5de8e9", + "fleet-agent-events": "e20a508b6e805189356be381dbfac8db", + "fleet-agents": "cb661e8ede2b640c42c8e5ef99db0683", + "fleet-enrollment-api-keys": "a69ef7ae661dab31561d6c6f052ef2a7", + "graph-workspace": "cd7ba1330e6682e9cc00b78850874be1", + "index-pattern": "45915a1ad866812242df474eb0479052", + "infrastructure-ui-source": "3d1b76c39bfb2cc8296b024d73854724", + "ingest-agent-policies": "8b0733cce189659593659dad8db426f0", + "ingest-outputs": "8854f34453a47e26f86a29f8f3b80b4e", + "ingest-package-policies": "f74dfe498e1849267cda41580b2be110", + "ingest_manager_settings": "02a03095f0e05b7a538fa801b88a217f", + "inventory-view": "3d1b76c39bfb2cc8296b024d73854724", + "kql-telemetry": "d12a98a6f19a2d273696597547e064ee", + "lens": "52346cfec69ff7b47d5f0c12361a2797", + "lens-ui-telemetry": "509bfa5978586998e05f9e303c07a327", + "map": "4a05b35c3a3a58fbc72dd0202dc3487f", + "maps-telemetry": "5ef305b18111b77789afefbd36b66171", + "metrics-explorer-view": "3d1b76c39bfb2cc8296b024d73854724", + "migrationVersion": "4a1746014a75ade3a714e1db5763276f", + "ml-job": "3bb64c31915acf93fc724af137a0891b", + "ml-telemetry": "257fd1d4b4fdbb9cb4b8a3b27da201e9", + "monitoring-telemetry": "2669d5ec15e82391cf58df4294ee9c68", + "namespace": "2f4316de49999235636386fe51dc06c1", + "namespaces": "2f4316de49999235636386fe51dc06c1", + "originId": "2f4316de49999235636386fe51dc06c1", + "query": "11aaeb7f5f7fa5bb43f25e18ce26e7d9", + "references": "7997cf5a56cc02bdc9c93361bde732b0", + "sample-data-telemetry": "7d3cfeb915303c9641c59681967ffeb4", + "search": "43012c7ebc4cb57054e0a490e4b43023", + "search-telemetry": "3d1b76c39bfb2cc8296b024d73854724", + "siem-detection-engine-rule-actions": "6569b288c169539db10cb262bf79de18", + "siem-detection-engine-rule-status": "ae783f41c6937db6b7a2ef5c93a9e9b0", + "siem-ui-timeline": "d12c5474364d737d17252acf1dc4585c", + "siem-ui-timeline-note": "8874706eedc49059d4cf0f5094559084", + "siem-ui-timeline-pinned-event": "20638091112f0e14f0e443d512301c29", + "space": "c5ca8acafa0beaa4d08d014a97b6bc6b", + "tag": "83d55da58f6530f7055415717ec06474", + "telemetry": "36a616f7026dfa617d6655df850fe16d", + "timelion-sheet": "9a2a2748877c7a7b582fef201ab1d4cf", + "tsvb-validation-telemetry": "3a37ef6c8700ae6fc97d5c7da00e9215", + "type": "2f4316de49999235636386fe51dc06c1", + "ui-metric": "0d409297dc5ebe1e3a1da691c6ee32e3", + "updated_at": "00da57df13e94e9d98437d13ace4bfe0", + "upgrade-assistant-reindex-operation": "215107c281839ea9b3ad5f6419819763", + "upgrade-assistant-telemetry": "56702cec857e0a9dacfb696655b4ff7b", + "uptime-dynamic-settings": "3d1b76c39bfb2cc8296b024d73854724", + "url": "c7f66a0df8b1b52f17c28c4adb111105", + "visualization": "f819cf6636b75c9e76ba733a0c6ef355", + "workplace_search_telemetry": "3d1b76c39bfb2cc8296b024d73854724" + } + }, + "dynamic": "strict", + "properties": { + "action": { + "properties": { + "actionTypeId": { + "type": "keyword" + }, + "config": { + "enabled": false, + "type": "object" + }, + "name": { + "fields": { + "keyword": { + "type": "keyword" + } + }, + "type": "text" + }, + "secrets": { + "type": "binary" + } + } + }, + "action_task_params": { + "properties": { + "actionId": { + "type": "keyword" + }, + "apiKey": { + "type": "binary" + }, + "params": { + "enabled": false, + "type": "object" + } + } + }, + "alert": { + "properties": { + "actions": { + "properties": { + "actionRef": { + "type": "keyword" + }, + "actionTypeId": { + "type": "keyword" + }, + "group": { + "type": "keyword" + }, + "params": { + "enabled": false, + "type": "object" + } + }, + "type": "nested" + }, + "alertTypeId": { + "type": "keyword" + }, + "apiKey": { + "type": "binary" + }, + "apiKeyOwner": { + "type": "keyword" + }, + "consumer": { + "type": "keyword" + }, + "createdAt": { + "type": "date" + }, + "createdBy": { + "type": "keyword" + }, + "enabled": { + "type": "boolean" + }, + "executionStatus": { + "properties": { + "error": { + "properties": { + "message": { + "type": "keyword" + }, + "reason": { + "type": "keyword" + } + } + }, + "lastExecutionDate": { + "type": "date" + }, + "status": { + "type": "keyword" + } + } + }, + "meta": { + "properties": { + "versionApiKeyLastmodified": { + "type": "keyword" + } + } + }, + "muteAll": { + "type": "boolean" + }, + "mutedInstanceIds": { + "type": "keyword" + }, + "name": { + "fields": { + "keyword": { + "type": "keyword" + } + }, + "type": "text" + }, + "params": { + "enabled": false, + "type": "object" + }, + "schedule": { + "properties": { + "interval": { + "type": "keyword" + } + } + }, + "scheduledTaskId": { + "type": "keyword" + }, + "tags": { + "type": "keyword" + }, + "throttle": { + "type": "keyword" + }, + "updatedAt": { + "type": "date" + }, + "updatedBy": { + "type": "keyword" + } + } + }, + "api_key_pending_invalidation": { + "properties": { + "apiKeyId": { + "type": "keyword" + }, + "createdAt": { + "type": "date" + } + } + }, + "apm-indices": { + "properties": { + "apm_oss": { + "properties": { + "errorIndices": { + "type": "keyword" + }, + "metricsIndices": { + "type": "keyword" + }, + "onboardingIndices": { + "type": "keyword" + }, + "sourcemapIndices": { + "type": "keyword" + }, + "spanIndices": { + "type": "keyword" + }, + "transactionIndices": { + "type": "keyword" + } + } + } + } + }, + "apm-telemetry": { + "dynamic": "false", + "type": "object" + }, + "app_search_telemetry": { + "dynamic": "false", + "type": "object" + }, + "application_usage_daily": { + "dynamic": "false", + "properties": { + "timestamp": { + "type": "date" + } + } + }, + "application_usage_totals": { + "dynamic": "false", + "type": "object" + }, + "application_usage_transactional": { + "dynamic": "false", + "type": "object" + }, + "background-session": { + "properties": { + "created": { + "type": "date" + }, + "expires": { + "type": "date" + }, + "idMapping": { + "enabled": false, + "type": "object" + }, + "initialState": { + "enabled": false, + "type": "object" + }, + "name": { + "type": "keyword" + }, + "restoreState": { + "enabled": false, + "type": "object" + }, + "status": { + "type": "keyword" + } + } + }, + "canvas-element": { + "dynamic": "false", + "properties": { + "@created": { + "type": "date" + }, + "@timestamp": { + "type": "date" + }, + "content": { + "type": "text" + }, + "help": { + "type": "text" + }, + "image": { + "type": "text" + }, + "name": { + "fields": { + "keyword": { + "type": "keyword" + } + }, + "type": "text" + } + } + }, + "canvas-workpad": { + "dynamic": "false", + "properties": { + "@created": { + "type": "date" + }, + "@timestamp": { + "type": "date" + }, + "name": { + "fields": { + "keyword": { + "type": "keyword" + } + }, + "type": "text" + } + } + }, + "canvas-workpad-template": { + "dynamic": "false", + "properties": { + "help": { + "fields": { + "keyword": { + "type": "keyword" + } + }, + "type": "text" + }, + "name": { + "fields": { + "keyword": { + "type": "keyword" + } + }, + "type": "text" + }, + "tags": { + "fields": { + "keyword": { + "type": "keyword" + } + }, + "type": "text" + }, + "template_key": { + "type": "keyword" + } + } + }, + "cases": { + "properties": { + "closed_at": { + "type": "date" + }, + "closed_by": { + "properties": { + "email": { + "type": "keyword" + }, + "full_name": { + "type": "keyword" + }, + "username": { + "type": "keyword" + } + } + }, + "connector": { + "properties": { + "fields": { + "properties": { + "key": { + "type": "text" + }, + "value": { + "type": "text" + } + } + }, + "id": { + "type": "keyword" + }, + "name": { + "type": "text" + }, + "type": { + "type": "keyword" + } + } + }, + "created_at": { + "type": "date" + }, + "created_by": { + "properties": { + "email": { + "type": "keyword" + }, + "full_name": { + "type": "keyword" + }, + "username": { + "type": "keyword" + } + } + }, + "description": { + "type": "text" + }, + "external_service": { + "properties": { + "connector_id": { + "type": "keyword" + }, + "connector_name": { + "type": "keyword" + }, + "external_id": { + "type": "keyword" + }, + "external_title": { + "type": "text" + }, + "external_url": { + "type": "text" + }, + "pushed_at": { + "type": "date" + }, + "pushed_by": { + "properties": { + "email": { + "type": "keyword" + }, + "full_name": { + "type": "keyword" + }, + "username": { + "type": "keyword" + } + } + } + } + }, + "status": { + "type": "keyword" + }, + "tags": { + "type": "keyword" + }, + "title": { + "type": "keyword" + }, + "updated_at": { + "type": "date" + }, + "updated_by": { + "properties": { + "email": { + "type": "keyword" + }, + "full_name": { + "type": "keyword" + }, + "username": { + "type": "keyword" + } + } + } + } + }, + "cases-comments": { + "properties": { + "alertId": { + "type": "keyword" + }, + "comment": { + "type": "text" + }, + "created_at": { + "type": "date" + }, + "created_by": { + "properties": { + "email": { + "type": "keyword" + }, + "full_name": { + "type": "keyword" + }, + "username": { + "type": "keyword" + } + } + }, + "index": { + "type": "keyword" + }, + "pushed_at": { + "type": "date" + }, + "pushed_by": { + "properties": { + "email": { + "type": "keyword" + }, + "full_name": { + "type": "keyword" + }, + "username": { + "type": "keyword" + } + } + }, + "type": { + "type": "keyword" + }, + "updated_at": { + "type": "date" + }, + "updated_by": { + "properties": { + "email": { + "type": "keyword" + }, + "full_name": { + "type": "keyword" + }, + "username": { + "type": "keyword" + } + } + } + } + }, + "cases-configure": { + "properties": { + "closure_type": { + "type": "keyword" + }, + "connector": { + "properties": { + "fields": { + "properties": { + "key": { + "type": "text" + }, + "value": { + "type": "text" + } + } + }, + "id": { + "type": "keyword" + }, + "name": { + "type": "text" + }, + "type": { + "type": "keyword" + } + } + }, + "created_at": { + "type": "date" + }, + "created_by": { + "properties": { + "email": { + "type": "keyword" + }, + "full_name": { + "type": "keyword" + }, + "username": { + "type": "keyword" + } + } + }, + "updated_at": { + "type": "date" + }, + "updated_by": { + "properties": { + "email": { + "type": "keyword" + }, + "full_name": { + "type": "keyword" + }, + "username": { + "type": "keyword" + } + } + } + } + }, + "cases-user-actions": { + "properties": { + "action": { + "type": "keyword" + }, + "action_at": { + "type": "date" + }, + "action_by": { + "properties": { + "email": { + "type": "keyword" + }, + "full_name": { + "type": "keyword" + }, + "username": { + "type": "keyword" + } + } + }, + "action_field": { + "type": "keyword" + }, + "new_value": { + "type": "text" + }, + "old_value": { + "type": "text" + } + } + }, + "config": { + "dynamic": "false", + "properties": { + "buildNum": { + "type": "keyword" + } + } + }, + "dashboard": { + "properties": { + "description": { + "type": "text" + }, + "hits": { + "doc_values": false, + "index": false, + "type": "integer" + }, + "kibanaSavedObjectMeta": { + "properties": { + "searchSourceJSON": { + "index": false, + "type": "text" + } + } + }, + "optionsJSON": { + "index": false, + "type": "text" + }, + "panelsJSON": { + "index": false, + "type": "text" + }, + "refreshInterval": { + "properties": { + "display": { + "doc_values": false, + "index": false, + "type": "keyword" + }, + "pause": { + "doc_values": false, + "index": false, + "type": "boolean" + }, + "section": { + "doc_values": false, + "index": false, + "type": "integer" + }, + "value": { + "doc_values": false, + "index": false, + "type": "integer" + } + } + }, + "timeFrom": { + "doc_values": false, + "index": false, + "type": "keyword" + }, + "timeRestore": { + "doc_values": false, + "index": false, + "type": "boolean" + }, + "timeTo": { + "doc_values": false, + "index": false, + "type": "keyword" + }, + "title": { + "type": "text" + }, + "version": { + "type": "integer" + } + } + }, + "endpoint:user-artifact": { + "properties": { + "body": { + "type": "binary" + }, + "compressionAlgorithm": { + "index": false, + "type": "keyword" + }, + "created": { + "index": false, + "type": "date" + }, + "decodedSha256": { + "index": false, + "type": "keyword" + }, + "decodedSize": { + "index": false, + "type": "long" + }, + "encodedSha256": { + "type": "keyword" + }, + "encodedSize": { + "index": false, + "type": "long" + }, + "encryptionAlgorithm": { + "index": false, + "type": "keyword" + }, + "identifier": { + "type": "keyword" + } + } + }, + "endpoint:user-artifact-manifest": { + "properties": { + "created": { + "index": false, + "type": "date" + }, + "ids": { + "index": false, + "type": "keyword" + }, + "schemaVersion": { + "type": "keyword" + }, + "semanticVersion": { + "index": false, + "type": "keyword" + } + } + }, + "enterprise_search_telemetry": { + "dynamic": "false", + "type": "object" + }, + "epm-packages": { + "properties": { + "es_index_patterns": { + "enabled": false, + "type": "object" + }, + "install_source": { + "type": "keyword" + }, + "install_started_at": { + "type": "date" + }, + "install_status": { + "type": "keyword" + }, + "install_version": { + "type": "keyword" + }, + "installed_es": { + "properties": { + "id": { + "type": "keyword" + }, + "type": { + "type": "keyword" + } + }, + "type": "nested" + }, + "installed_kibana": { + "properties": { + "id": { + "type": "keyword" + }, + "type": { + "type": "keyword" + } + }, + "type": "nested" + }, + "internal": { + "type": "boolean" + }, + "name": { + "type": "keyword" + }, + "removable": { + "type": "boolean" + }, + "version": { + "type": "keyword" + } + } + }, + "exception-list": { + "properties": { + "_tags": { + "type": "keyword" + }, + "comments": { + "properties": { + "comment": { + "type": "keyword" + }, + "created_at": { + "type": "keyword" + }, + "created_by": { + "type": "keyword" + }, + "id": { + "type": "keyword" + }, + "updated_at": { + "type": "keyword" + }, + "updated_by": { + "type": "keyword" + } + } + }, + "created_at": { + "type": "keyword" + }, + "created_by": { + "type": "keyword" + }, + "description": { + "type": "keyword" + }, + "entries": { + "properties": { + "entries": { + "properties": { + "field": { + "type": "keyword" + }, + "operator": { + "type": "keyword" + }, + "type": { + "type": "keyword" + }, + "value": { + "fields": { + "text": { + "type": "text" + } + }, + "type": "keyword" + } + } + }, + "field": { + "type": "keyword" + }, + "list": { + "properties": { + "id": { + "type": "keyword" + }, + "type": { + "type": "keyword" + } + } + }, + "operator": { + "type": "keyword" + }, + "type": { + "type": "keyword" + }, + "value": { + "fields": { + "text": { + "type": "text" + } + }, + "type": "keyword" + } + } + }, + "immutable": { + "type": "boolean" + }, + "item_id": { + "type": "keyword" + }, + "list_id": { + "type": "keyword" + }, + "list_type": { + "type": "keyword" + }, + "meta": { + "type": "keyword" + }, + "name": { + "type": "keyword" + }, + "os_types": { + "type": "keyword" + }, + "tags": { + "type": "keyword" + }, + "tie_breaker_id": { + "type": "keyword" + }, + "type": { + "type": "keyword" + }, + "updated_by": { + "type": "keyword" + }, + "version": { + "type": "keyword" + } + } + }, + "exception-list-agnostic": { + "properties": { + "_tags": { + "type": "keyword" + }, + "comments": { + "properties": { + "comment": { + "type": "keyword" + }, + "created_at": { + "type": "keyword" + }, + "created_by": { + "type": "keyword" + }, + "id": { + "type": "keyword" + }, + "updated_at": { + "type": "keyword" + }, + "updated_by": { + "type": "keyword" + } + } + }, + "created_at": { + "type": "keyword" + }, + "created_by": { + "type": "keyword" + }, + "description": { + "type": "keyword" + }, + "entries": { + "properties": { + "entries": { + "properties": { + "field": { + "type": "keyword" + }, + "operator": { + "type": "keyword" + }, + "type": { + "type": "keyword" + }, + "value": { + "fields": { + "text": { + "type": "text" + } + }, + "type": "keyword" + } + } + }, + "field": { + "type": "keyword" + }, + "list": { + "properties": { + "id": { + "type": "keyword" + }, + "type": { + "type": "keyword" + } + } + }, + "operator": { + "type": "keyword" + }, + "type": { + "type": "keyword" + }, + "value": { + "fields": { + "text": { + "type": "text" + } + }, + "type": "keyword" + } + } + }, + "immutable": { + "type": "boolean" + }, + "item_id": { + "type": "keyword" + }, + "list_id": { + "type": "keyword" + }, + "list_type": { + "type": "keyword" + }, + "meta": { + "type": "keyword" + }, + "name": { + "type": "keyword" + }, + "os_types": { + "type": "keyword" + }, + "tags": { + "type": "keyword" + }, + "tie_breaker_id": { + "type": "keyword" + }, + "type": { + "type": "keyword" + }, + "updated_by": { + "type": "keyword" + }, + "version": { + "type": "keyword" + } + } + }, + "file-upload-telemetry": { + "properties": { + "filesUploadedTotalCount": { + "type": "long" + } + } + }, + "fleet-agent-actions": { + "properties": { + "ack_data": { + "type": "text" + }, + "agent_id": { + "type": "keyword" + }, + "created_at": { + "type": "date" + }, + "data": { + "type": "binary" + }, + "policy_id": { + "type": "keyword" + }, + "policy_revision": { + "type": "integer" + }, + "sent_at": { + "type": "date" + }, + "type": { + "type": "keyword" + } + } + }, + "fleet-agent-events": { + "properties": { + "action_id": { + "type": "keyword" + }, + "agent_id": { + "type": "keyword" + }, + "data": { + "type": "text" + }, + "message": { + "type": "text" + }, + "payload": { + "type": "text" + }, + "policy_id": { + "type": "keyword" + }, + "stream_id": { + "type": "keyword" + }, + "subtype": { + "type": "keyword" + }, + "timestamp": { + "type": "date" + }, + "type": { + "type": "keyword" + } + } + }, + "fleet-agents": { + "properties": { + "access_api_key_id": { + "type": "keyword" + }, + "active": { + "type": "boolean" + }, + "current_error_events": { + "index": false, + "type": "text" + }, + "default_api_key": { + "type": "binary" + }, + "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": { + "type": "flattened" + }, + "packages": { + "type": "keyword" + }, + "policy_id": { + "type": "keyword" + }, + "policy_revision": { + "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": "flattened" + }, + "version": { + "type": "keyword" + } + } + }, + "fleet-enrollment-api-keys": { + "properties": { + "active": { + "type": "boolean" + }, + "api_key": { + "type": "binary" + }, + "api_key_id": { + "type": "keyword" + }, + "created_at": { + "type": "date" + }, + "expire_at": { + "type": "date" + }, + "name": { + "type": "keyword" + }, + "policy_id": { + "type": "keyword" + }, + "type": { + "type": "keyword" + }, + "updated_at": { + "type": "date" + } + } + }, + "graph-workspace": { + "properties": { + "description": { + "type": "text" + }, + "kibanaSavedObjectMeta": { + "properties": { + "searchSourceJSON": { + "type": "text" + } + } + }, + "numLinks": { + "type": "integer" + }, + "numVertices": { + "type": "integer" + }, + "title": { + "type": "text" + }, + "version": { + "type": "integer" + }, + "wsState": { + "type": "text" + } + } + }, + "index-pattern": { + "dynamic": "false", + "properties": { + "title": { + "type": "text" + }, + "type": { + "type": "keyword" + } + } + }, + "infrastructure-ui-source": { + "dynamic": "false", + "type": "object" + }, + "ingest-agent-policies": { + "properties": { + "description": { + "type": "text" + }, + "is_default": { + "type": "boolean" + }, + "monitoring_enabled": { + "index": false, + "type": "keyword" + }, + "name": { + "type": "keyword" + }, + "namespace": { + "type": "keyword" + }, + "package_policies": { + "type": "keyword" + }, + "revision": { + "type": "integer" + }, + "status": { + "type": "keyword" + }, + "updated_at": { + "type": "date" + }, + "updated_by": { + "type": "keyword" + } + } + }, + "ingest-outputs": { + "properties": { + "ca_sha256": { + "index": false, + "type": "keyword" + }, + "config": { + "type": "flattened" + }, + "config_yaml": { + "type": "text" + }, + "fleet_enroll_password": { + "type": "binary" + }, + "fleet_enroll_username": { + "type": "binary" + }, + "hosts": { + "type": "keyword" + }, + "is_default": { + "type": "boolean" + }, + "name": { + "type": "keyword" + }, + "type": { + "type": "keyword" + } + } + }, + "ingest-package-policies": { + "properties": { + "created_at": { + "type": "date" + }, + "created_by": { + "type": "keyword" + }, + "description": { + "type": "text" + }, + "enabled": { + "type": "boolean" + }, + "inputs": { + "enabled": false, + "properties": { + "config": { + "type": "flattened" + }, + "enabled": { + "type": "boolean" + }, + "streams": { + "properties": { + "compiled_stream": { + "type": "flattened" + }, + "config": { + "type": "flattened" + }, + "data_stream": { + "properties": { + "dataset": { + "type": "keyword" + }, + "type": { + "type": "keyword" + } + } + }, + "enabled": { + "type": "boolean" + }, + "id": { + "type": "keyword" + }, + "vars": { + "type": "flattened" + } + }, + "type": "nested" + }, + "type": { + "type": "keyword" + }, + "vars": { + "type": "flattened" + } + }, + "type": "nested" + }, + "name": { + "type": "keyword" + }, + "namespace": { + "type": "keyword" + }, + "output_id": { + "type": "keyword" + }, + "package": { + "properties": { + "name": { + "type": "keyword" + }, + "title": { + "type": "keyword" + }, + "version": { + "type": "keyword" + } + } + }, + "policy_id": { + "type": "keyword" + }, + "revision": { + "type": "integer" + }, + "updated_at": { + "type": "date" + }, + "updated_by": { + "type": "keyword" + } + } + }, + "ingest_manager_settings": { + "properties": { + "agent_auto_upgrade": { + "type": "keyword" + }, + "has_seen_add_data_notice": { + "index": false, + "type": "boolean" + }, + "kibana_ca_sha256": { + "type": "keyword" + }, + "kibana_urls": { + "type": "keyword" + }, + "package_auto_upgrade": { + "type": "keyword" + } + } + }, + "inventory-view": { + "dynamic": "false", + "type": "object" + }, + "kql-telemetry": { + "properties": { + "optInCount": { + "type": "long" + }, + "optOutCount": { + "type": "long" + } + } + }, + "lens": { + "properties": { + "description": { + "type": "text" + }, + "expression": { + "doc_values": false, + "index": false, + "type": "keyword" + }, + "state": { + "type": "flattened" + }, + "title": { + "type": "text" + }, + "visualizationType": { + "type": "keyword" + } + } + }, + "lens-ui-telemetry": { + "properties": { + "count": { + "type": "integer" + }, + "date": { + "type": "date" + }, + "name": { + "type": "keyword" + }, + "type": { + "type": "keyword" + } + } + }, + "map": { + "properties": { + "description": { + "type": "text" + }, + "layerListJSON": { + "type": "text" + }, + "mapStateJSON": { + "type": "text" + }, + "title": { + "type": "text" + }, + "uiStateJSON": { + "type": "text" + }, + "version": { + "type": "integer" + } + } + }, + "maps-telemetry": { + "enabled": false, + "type": "object" + }, + "metrics-explorer-view": { + "dynamic": "false", + "type": "object" + }, + "migrationVersion": { + "dynamic": "true", + "properties": { + "config": { + "fields": { + "keyword": { + "ignore_above": 256, + "type": "keyword" + } + }, + "type": "text" + }, + "dashboard": { + "fields": { + "keyword": { + "ignore_above": 256, + "type": "keyword" + } + }, + "type": "text" + }, + "index-pattern": { + "fields": { + "keyword": { + "ignore_above": 256, + "type": "keyword" + } + }, + "type": "text" + }, + "lens": { + "fields": { + "keyword": { + "ignore_above": 256, + "type": "keyword" + } + }, + "type": "text" + }, + "search": { + "fields": { + "keyword": { + "ignore_above": 256, + "type": "keyword" + } + }, + "type": "text" + }, + "space": { + "fields": { + "keyword": { + "ignore_above": 256, + "type": "keyword" + } + }, + "type": "text" + } + } + }, + "ml-job": { + "properties": { + "datafeed_id": { + "fields": { + "keyword": { + "type": "keyword" + } + }, + "type": "text" + }, + "job_id": { + "fields": { + "keyword": { + "type": "keyword" + } + }, + "type": "text" + }, + "type": { + "type": "keyword" + } + } + }, + "ml-telemetry": { + "properties": { + "file_data_visualizer": { + "properties": { + "index_creation_count": { + "type": "long" + } + } + } + } + }, + "monitoring-telemetry": { + "properties": { + "reportedClusterUuids": { + "type": "keyword" + } + } + }, + "namespace": { + "type": "keyword" + }, + "namespaces": { + "type": "keyword" + }, + "originId": { + "type": "keyword" + }, + "query": { + "properties": { + "description": { + "type": "text" + }, + "filters": { + "enabled": false, + "type": "object" + }, + "query": { + "properties": { + "language": { + "type": "keyword" + }, + "query": { + "index": false, + "type": "keyword" + } + } + }, + "timefilter": { + "enabled": false, + "type": "object" + }, + "title": { + "type": "text" + } + } + }, + "references": { + "properties": { + "id": { + "type": "keyword" + }, + "name": { + "type": "keyword" + }, + "type": { + "type": "keyword" + } + }, + "type": "nested" + }, + "sample-data-telemetry": { + "properties": { + "installCount": { + "type": "long" + }, + "unInstallCount": { + "type": "long" + } + } + }, + "search": { + "properties": { + "columns": { + "doc_values": false, + "index": false, + "type": "keyword" + }, + "description": { + "type": "text" + }, + "hits": { + "doc_values": false, + "index": false, + "type": "integer" + }, + "kibanaSavedObjectMeta": { + "properties": { + "searchSourceJSON": { + "index": false, + "type": "text" + } + } + }, + "sort": { + "doc_values": false, + "index": false, + "type": "keyword" + }, + "title": { + "type": "text" + }, + "version": { + "type": "integer" + } + } + }, + "search-telemetry": { + "dynamic": "false", + "type": "object" + }, + "siem-detection-engine-rule-actions": { + "properties": { + "actions": { + "properties": { + "action_type_id": { + "type": "keyword" + }, + "group": { + "type": "keyword" + }, + "id": { + "type": "keyword" + }, + "params": { + "enabled": false, + "type": "object" + } + } + }, + "alertThrottle": { + "type": "keyword" + }, + "ruleAlertId": { + "type": "keyword" + }, + "ruleThrottle": { + "type": "keyword" + } + } + }, + "siem-detection-engine-rule-status": { + "properties": { + "alertId": { + "type": "keyword" + }, + "bulkCreateTimeDurations": { + "type": "float" + }, + "gap": { + "type": "text" + }, + "lastFailureAt": { + "type": "date" + }, + "lastFailureMessage": { + "type": "text" + }, + "lastLookBackDate": { + "type": "date" + }, + "lastSuccessAt": { + "type": "date" + }, + "lastSuccessMessage": { + "type": "text" + }, + "searchAfterTimeDurations": { + "type": "float" + }, + "status": { + "type": "keyword" + }, + "statusDate": { + "type": "date" + } + } + }, + "siem-ui-timeline": { + "properties": { + "columns": { + "properties": { + "aggregatable": { + "type": "boolean" + }, + "category": { + "type": "keyword" + }, + "columnHeaderType": { + "type": "keyword" + }, + "description": { + "type": "text" + }, + "example": { + "type": "text" + }, + "id": { + "type": "keyword" + }, + "indexes": { + "type": "keyword" + }, + "name": { + "type": "text" + }, + "placeholder": { + "type": "text" + }, + "searchable": { + "type": "boolean" + }, + "type": { + "type": "keyword" + } + } + }, + "created": { + "type": "date" + }, + "createdBy": { + "type": "text" + }, + "dataProviders": { + "properties": { + "and": { + "properties": { + "enabled": { + "type": "boolean" + }, + "excluded": { + "type": "boolean" + }, + "id": { + "type": "keyword" + }, + "kqlQuery": { + "type": "text" + }, + "name": { + "type": "text" + }, + "queryMatch": { + "properties": { + "displayField": { + "type": "text" + }, + "displayValue": { + "type": "text" + }, + "field": { + "type": "text" + }, + "operator": { + "type": "text" + }, + "value": { + "type": "text" + } + } + }, + "type": { + "type": "text" + } + } + }, + "enabled": { + "type": "boolean" + }, + "excluded": { + "type": "boolean" + }, + "id": { + "type": "keyword" + }, + "kqlQuery": { + "type": "text" + }, + "name": { + "type": "text" + }, + "queryMatch": { + "properties": { + "displayField": { + "type": "text" + }, + "displayValue": { + "type": "text" + }, + "field": { + "type": "text" + }, + "operator": { + "type": "text" + }, + "value": { + "type": "text" + } + } + }, + "type": { + "type": "text" + } + } + }, + "dateRange": { + "properties": { + "end": { + "type": "date" + }, + "start": { + "type": "date" + } + } + }, + "description": { + "type": "text" + }, + "eventType": { + "type": "keyword" + }, + "excludedRowRendererIds": { + "type": "text" + }, + "favorite": { + "properties": { + "favoriteDate": { + "type": "date" + }, + "fullName": { + "type": "text" + }, + "keySearch": { + "type": "text" + }, + "userName": { + "type": "text" + } + } + }, + "filters": { + "properties": { + "exists": { + "type": "text" + }, + "match_all": { + "type": "text" + }, + "meta": { + "properties": { + "alias": { + "type": "text" + }, + "controlledBy": { + "type": "text" + }, + "disabled": { + "type": "boolean" + }, + "field": { + "type": "text" + }, + "formattedValue": { + "type": "text" + }, + "index": { + "type": "keyword" + }, + "key": { + "type": "keyword" + }, + "negate": { + "type": "boolean" + }, + "params": { + "type": "text" + }, + "type": { + "type": "keyword" + }, + "value": { + "type": "text" + } + } + }, + "missing": { + "type": "text" + }, + "query": { + "type": "text" + }, + "range": { + "type": "text" + }, + "script": { + "type": "text" + } + } + }, + "indexNames": { + "type": "text" + }, + "kqlMode": { + "type": "keyword" + }, + "kqlQuery": { + "properties": { + "filterQuery": { + "properties": { + "kuery": { + "properties": { + "expression": { + "type": "text" + }, + "kind": { + "type": "keyword" + } + } + }, + "serializedQuery": { + "type": "text" + } + } + } + } + }, + "savedQueryId": { + "type": "keyword" + }, + "sort": { + "properties": { + "columnId": { + "type": "keyword" + }, + "sortDirection": { + "type": "keyword" + } + } + }, + "status": { + "type": "keyword" + }, + "templateTimelineId": { + "type": "text" + }, + "templateTimelineVersion": { + "type": "integer" + }, + "timelineType": { + "type": "keyword" + }, + "title": { + "type": "text" + }, + "updated": { + "type": "date" + }, + "updatedBy": { + "type": "text" + } + } + }, + "siem-ui-timeline-note": { + "properties": { + "created": { + "type": "date" + }, + "createdBy": { + "type": "text" + }, + "eventId": { + "type": "keyword" + }, + "note": { + "type": "text" + }, + "timelineId": { + "type": "keyword" + }, + "updated": { + "type": "date" + }, + "updatedBy": { + "type": "text" + } + } + }, + "siem-ui-timeline-pinned-event": { + "properties": { + "created": { + "type": "date" + }, + "createdBy": { + "type": "text" + }, + "eventId": { + "type": "keyword" + }, + "timelineId": { + "type": "keyword" + }, + "updated": { + "type": "date" + }, + "updatedBy": { + "type": "text" + } + } + }, + "space": { + "properties": { + "_reserved": { + "type": "boolean" + }, + "color": { + "type": "keyword" + }, + "description": { + "type": "text" + }, + "disabledFeatures": { + "type": "keyword" + }, + "imageUrl": { + "index": false, + "type": "text" + }, + "initials": { + "type": "keyword" + }, + "name": { + "fields": { + "keyword": { + "ignore_above": 2048, + "type": "keyword" + } + }, + "type": "text" + } + } + }, + "tag": { + "properties": { + "color": { + "type": "text" + }, + "description": { + "type": "text" + }, + "name": { + "type": "text" + } + } + }, + "telemetry": { + "properties": { + "allowChangingOptInStatus": { + "type": "boolean" + }, + "enabled": { + "type": "boolean" + }, + "lastReported": { + "type": "date" + }, + "lastVersionChecked": { + "type": "keyword" + }, + "reportFailureCount": { + "type": "integer" + }, + "reportFailureVersion": { + "type": "keyword" + }, + "sendUsageFrom": { + "type": "keyword" + }, + "userHasSeenNotice": { + "type": "boolean" + } + } + }, + "timelion-sheet": { + "properties": { + "description": { + "type": "text" + }, + "hits": { + "type": "integer" + }, + "kibanaSavedObjectMeta": { + "properties": { + "searchSourceJSON": { + "type": "text" + } + } + }, + "timelion_chart_height": { + "type": "integer" + }, + "timelion_columns": { + "type": "integer" + }, + "timelion_interval": { + "type": "keyword" + }, + "timelion_other_interval": { + "type": "keyword" + }, + "timelion_rows": { + "type": "integer" + }, + "timelion_sheet": { + "type": "text" + }, + "title": { + "type": "text" + }, + "version": { + "type": "integer" + } + } + }, + "tsvb-validation-telemetry": { + "properties": { + "failedRequests": { + "type": "long" + } + } + }, + "type": { + "type": "keyword" + }, + "ui-metric": { + "properties": { + "count": { + "type": "integer" + } + } + }, + "updated_at": { + "type": "date" + }, + "upgrade-assistant-reindex-operation": { + "properties": { + "errorMessage": { + "fields": { + "keyword": { + "ignore_above": 256, + "type": "keyword" + } + }, + "type": "text" + }, + "indexName": { + "type": "keyword" + }, + "lastCompletedStep": { + "type": "long" + }, + "locked": { + "type": "date" + }, + "newIndexName": { + "fields": { + "keyword": { + "ignore_above": 256, + "type": "keyword" + } + }, + "type": "text" + }, + "reindexOptions": { + "properties": { + "openAndClose": { + "type": "boolean" + }, + "queueSettings": { + "properties": { + "queuedAt": { + "type": "long" + }, + "startedAt": { + "type": "long" + } + } + } + } + }, + "reindexTaskId": { + "fields": { + "keyword": { + "ignore_above": 256, + "type": "keyword" + } + }, + "type": "text" + }, + "reindexTaskPercComplete": { + "type": "float" + }, + "runningReindexCount": { + "type": "integer" + }, + "status": { + "type": "integer" + } + } + }, + "upgrade-assistant-telemetry": { + "properties": { + "features": { + "properties": { + "deprecation_logging": { + "properties": { + "enabled": { + "null_value": true, + "type": "boolean" + } + } + } + } + }, + "ui_open": { + "properties": { + "cluster": { + "null_value": 0, + "type": "long" + }, + "indices": { + "null_value": 0, + "type": "long" + }, + "overview": { + "null_value": 0, + "type": "long" + } + } + }, + "ui_reindex": { + "properties": { + "close": { + "null_value": 0, + "type": "long" + }, + "open": { + "null_value": 0, + "type": "long" + }, + "start": { + "null_value": 0, + "type": "long" + }, + "stop": { + "null_value": 0, + "type": "long" + } + } + } + } + }, + "uptime-dynamic-settings": { + "dynamic": "false", + "type": "object" + }, + "url": { + "properties": { + "accessCount": { + "type": "long" + }, + "accessDate": { + "type": "date" + }, + "createDate": { + "type": "date" + }, + "url": { + "fields": { + "keyword": { + "ignore_above": 2048, + "type": "keyword" + } + }, + "type": "text" + } + } + }, + "visualization": { + "properties": { + "description": { + "type": "text" + }, + "kibanaSavedObjectMeta": { + "properties": { + "searchSourceJSON": { + "index": false, + "type": "text" + } + } + }, + "savedSearchRefName": { + "doc_values": false, + "index": false, + "type": "keyword" + }, + "title": { + "type": "text" + }, + "uiStateJSON": { + "index": false, + "type": "text" + }, + "version": { + "type": "integer" + }, + "visState": { + "index": false, + "type": "text" + } + } + }, + "workplace_search_telemetry": { + "dynamic": "false", + "type": "object" + } + } + }, + "settings": { + "index": { + "auto_expand_replicas": "0-1", + "number_of_replicas": "0", + "number_of_shards": "1" + } + } + } +} + +{ + "type": "index", + "value": { + "aliases": { + }, + "index": "foo", + "mappings": { + "properties": { + "field": { + "type": "long" + } + } + }, + "settings": { + "index": { + "number_of_replicas": "1", + "number_of_shards": "1" + } + } + } +} \ No newline at end of file From 71379b755a4b258376d4117e98e8e454b17c990c Mon Sep 17 00:00:00 2001 From: ymao1 Date: Thu, 27 May 2021 14:59:02 -0400 Subject: [PATCH 38/77] [Alerting] Split alerting feature privilege between rules and alerts and handle subfeature privilege specification (#100127) * WIP - creating alerting authorization client factory and exposing authorization client on plugin start contract * Updating alerting feature privilege builder to handle different alerting types * Passing in alerting authorization type to AlertingActions class string builder * Passing in authorization type in each function call * Passing in exempt consumer ids. Adding authorization type to audit logger * Changing alertType to ruleType * Changing alertType to ruleType * Updating unit tests * Updating unit tests * Passing field names into authorization query builder. Adding kql/es dsl option * Converting to es query if requested * Fixing functional tests * Removing ability to specify feature privilege name in constructor * Fixing some types and tests * Consolidating alerting authorization kuery filter options * Cleanup and tests * Cleanup and tests * Initial commit with changes needed for subfeature privilege * Throwing error when AlertingAuthorizationClientFactory is not defined * Renaming authorizationType to entity * Renaming AlertsAuthorization to AlertingAuthorization * Fixing unit tests * Changing schema of alerting feature privilege * Changing schema of alerting feature privilege * Updating feature privilege iterator * Updating feature privilege builder * Fixing types check * Updating privilege string terminology * Updating privilege string terminology * Wip * Fixing unit tests * Unit tests * Updating README and removing stack subfeature privilege changes * Fixing README Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../alerting_example/server/plugin.ts | 14 +- x-pack/plugins/alerting/README.md | 211 ++++++++-- .../alerting_authorization.test.ts | 369 +++++++++++++---- x-pack/plugins/apm/server/feature.ts | 14 +- .../common/feature_kibana_privileges.ts | 65 ++- .../__snapshots__/oss_features.test.ts.snap | 60 ++- .../feature_privilege_iterator.test.ts | 349 ++++++++++++---- .../feature_privilege_iterator.ts | 25 +- .../features/server/feature_registry.test.ts | 250 +++++++++++- .../plugins/features/server/feature_schema.ts | 32 +- x-pack/plugins/infra/server/features.ts | 28 +- .../plugins/ml/common/types/capabilities.ts | 16 +- x-pack/plugins/monitoring/server/plugin.ts | 7 +- .../alerting.test.ts | 376 +++++++++++++++--- .../feature_privilege_builder/alerting.ts | 35 +- .../security_solution/server/plugin.ts | 14 +- .../stack_alerts/server/feature.test.ts | 8 +- x-pack/plugins/stack_alerts/server/feature.ts | 19 +- x-pack/plugins/uptime/server/kibana.index.ts | 14 +- .../fixtures/plugins/alerts/server/plugin.ts | 64 +-- .../alerts_restricted/server/plugin.ts | 8 +- .../fixtures/plugins/alerts/server/plugin.ts | 8 +- 22 files changed, 1640 insertions(+), 346 deletions(-) diff --git a/x-pack/examples/alerting_example/server/plugin.ts b/x-pack/examples/alerting_example/server/plugin.ts index f6131679874db..2420be798ec84 100644 --- a/x-pack/examples/alerting_example/server/plugin.ts +++ b/x-pack/examples/alerting_example/server/plugin.ts @@ -44,7 +44,12 @@ export class AlertingExamplePlugin implements Plugin { expect(alertTypeRegistry.get).toHaveBeenCalledTimes(0); }); - test('ensures the user has privileges to execute the specified rule type, operation and alerting type without consumer when producer and consumer are the same', async () => { + test('ensures the user has privileges to execute rules for the specified rule type and operation without consumer when producer and consumer are the same', async () => { const { authorization } = mockSecurity(); const checkPrivileges: jest.MockedFunction< ReturnType @@ -325,7 +339,63 @@ describe('AlertingAuthorization', () => { `); }); - test('ensures the user has privileges to execute the specified rule type, operation and alerting type without consumer when consumer is exempt', async () => { + test('ensures the user has privileges to execute alerts for the specified rule type and operation without consumer when producer and consumer are the same', async () => { + const { authorization } = mockSecurity(); + const checkPrivileges: jest.MockedFunction< + ReturnType + > = jest.fn(); + authorization.checkPrivilegesDynamicallyWithRequest.mockReturnValue(checkPrivileges); + const alertAuthorization = new AlertingAuthorization({ + request, + authorization, + alertTypeRegistry, + features, + auditLogger, + getSpace, + exemptConsumerIds, + }); + + checkPrivileges.mockResolvedValueOnce({ + username: 'some-user', + hasAllRequested: true, + privileges: { kibana: [] }, + }); + + await alertAuthorization.ensureAuthorized({ + ruleTypeId: 'myType', + consumer: 'myApp', + operation: WriteOperations.Update, + entity: AlertingAuthorizationEntity.Alert, + }); + + expect(alertTypeRegistry.get).toHaveBeenCalledWith('myType'); + + expect(authorization.actions.alerting.get).toHaveBeenCalledTimes(2); + expect(authorization.actions.alerting.get).toHaveBeenCalledWith( + 'myType', + 'myApp', + 'alert', + 'update' + ); + expect(checkPrivileges).toHaveBeenCalledWith({ + kibana: [mockAuthorizationAction('myType', 'myApp', 'alert', 'update')], + }); + + expect(auditLogger.logAuthorizationSuccess).toHaveBeenCalledTimes(1); + expect(auditLogger.logAuthorizationFailure).not.toHaveBeenCalled(); + expect(auditLogger.logAuthorizationSuccess.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + "some-user", + "myType", + 0, + "myApp", + "update", + "alert", + ] + `); + }); + + test('ensures the user has privileges to execute rules for the specified rule type and operation without consumer when consumer is exempt', async () => { const { authorization } = mockSecurity(); const checkPrivileges: jest.MockedFunction< ReturnType @@ -387,7 +457,69 @@ describe('AlertingAuthorization', () => { `); }); - test('ensures the user has privileges to execute the specified rule type, operation, alerting type and producer when producer is different from consumer', async () => { + test('ensures the user has privileges to execute alerts for the specified rule type and operation without consumer when consumer is exempt', async () => { + const { authorization } = mockSecurity(); + const checkPrivileges: jest.MockedFunction< + ReturnType + > = jest.fn(); + authorization.checkPrivilegesDynamicallyWithRequest.mockReturnValue(checkPrivileges); + const alertAuthorization = new AlertingAuthorization({ + request, + authorization, + alertTypeRegistry, + features, + auditLogger, + getSpace, + exemptConsumerIds: ['exemptConsumer'], + }); + + checkPrivileges.mockResolvedValueOnce({ + username: 'some-user', + hasAllRequested: true, + privileges: { kibana: [] }, + }); + + await alertAuthorization.ensureAuthorized({ + ruleTypeId: 'myType', + consumer: 'exemptConsumer', + operation: WriteOperations.Update, + entity: AlertingAuthorizationEntity.Alert, + }); + + expect(alertTypeRegistry.get).toHaveBeenCalledWith('myType'); + + expect(authorization.actions.alerting.get).toHaveBeenCalledTimes(2); + expect(authorization.actions.alerting.get).toHaveBeenCalledWith( + 'myType', + 'exemptConsumer', + 'alert', + 'update' + ); + expect(authorization.actions.alerting.get).toHaveBeenCalledWith( + 'myType', + 'myApp', + 'alert', + 'update' + ); + expect(checkPrivileges).toHaveBeenCalledWith({ + kibana: [mockAuthorizationAction('myType', 'myApp', 'alert', 'update')], + }); + + expect(auditLogger.logAuthorizationSuccess).toHaveBeenCalledTimes(1); + expect(auditLogger.logAuthorizationFailure).not.toHaveBeenCalled(); + expect(auditLogger.logAuthorizationSuccess.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + "some-user", + "myType", + 0, + "exemptConsumer", + "update", + "alert", + ] + `); + }); + + test('ensures the user has privileges to execute rules for the specified rule type, operation and producer when producer is different from consumer', async () => { const { authorization } = mockSecurity(); const checkPrivileges: jest.MockedFunction< ReturnType @@ -452,7 +584,72 @@ describe('AlertingAuthorization', () => { `); }); - test('throws if user lacks the required privileges for the consumer', async () => { + test('ensures the user has privileges to execute alerts for the specified rule type, operation and producer when producer is different from consumer', async () => { + const { authorization } = mockSecurity(); + const checkPrivileges: jest.MockedFunction< + ReturnType + > = jest.fn(); + authorization.checkPrivilegesDynamicallyWithRequest.mockReturnValue(checkPrivileges); + checkPrivileges.mockResolvedValueOnce({ + username: 'some-user', + hasAllRequested: true, + privileges: { kibana: [] }, + }); + + const alertAuthorization = new AlertingAuthorization({ + request, + authorization, + alertTypeRegistry, + features, + auditLogger, + getSpace, + exemptConsumerIds, + }); + + await alertAuthorization.ensureAuthorized({ + ruleTypeId: 'myType', + consumer: 'myOtherApp', + operation: WriteOperations.Update, + entity: AlertingAuthorizationEntity.Alert, + }); + + expect(alertTypeRegistry.get).toHaveBeenCalledWith('myType'); + + expect(authorization.actions.alerting.get).toHaveBeenCalledTimes(2); + expect(authorization.actions.alerting.get).toHaveBeenCalledWith( + 'myType', + 'myApp', + 'alert', + 'update' + ); + expect(authorization.actions.alerting.get).toHaveBeenCalledWith( + 'myType', + 'myOtherApp', + 'alert', + 'update' + ); + expect(checkPrivileges).toHaveBeenCalledWith({ + kibana: [ + mockAuthorizationAction('myType', 'myOtherApp', 'alert', 'update'), + mockAuthorizationAction('myType', 'myApp', 'alert', 'update'), + ], + }); + + expect(auditLogger.logAuthorizationSuccess).toHaveBeenCalledTimes(1); + expect(auditLogger.logAuthorizationFailure).not.toHaveBeenCalled(); + expect(auditLogger.logAuthorizationSuccess.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + "some-user", + "myType", + 0, + "myOtherApp", + "update", + "alert", + ] + `); + }); + + test('throws if user lacks the required rule privileges for the consumer', async () => { const { authorization } = mockSecurity(); const checkPrivileges: jest.MockedFunction< ReturnType @@ -510,7 +707,7 @@ describe('AlertingAuthorization', () => { `); }); - test('throws if user lacks the required privieleges for the producer', async () => { + test('throws if user lacks the required alert privileges for the consumer', async () => { const { authorization } = mockSecurity(); const checkPrivileges: jest.MockedFunction< ReturnType @@ -532,11 +729,73 @@ describe('AlertingAuthorization', () => { privileges: { kibana: [ { - privilege: mockAuthorizationAction('myType', 'myOtherApp', 'alert', 'create'), + privilege: mockAuthorizationAction('myType', 'myOtherApp', 'alert', 'update'), + authorized: false, + }, + { + privilege: mockAuthorizationAction('myType', 'myApp', 'alert', 'update'), authorized: true, }, { - privilege: mockAuthorizationAction('myType', 'myApp', 'alert', 'create'), + privilege: mockAuthorizationAction('myType', 'myAppRulesOnly', 'alert', 'update'), + authorized: false, + }, + ], + }, + }); + + await expect( + alertAuthorization.ensureAuthorized({ + ruleTypeId: 'myType', + consumer: 'myAppRulesOnly', + operation: WriteOperations.Update, + entity: AlertingAuthorizationEntity.Alert, + }) + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"Unauthorized to update a \\"myType\\" alert for \\"myAppRulesOnly\\""` + ); + + expect(auditLogger.logAuthorizationSuccess).not.toHaveBeenCalled(); + expect(auditLogger.logAuthorizationFailure).toHaveBeenCalledTimes(1); + expect(auditLogger.logAuthorizationFailure.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + "some-user", + "myType", + 0, + "myAppRulesOnly", + "update", + "alert", + ] + `); + }); + + test('throws if user lacks the required privileges for the producer', async () => { + const { authorization } = mockSecurity(); + const checkPrivileges: jest.MockedFunction< + ReturnType + > = jest.fn(); + authorization.checkPrivilegesDynamicallyWithRequest.mockReturnValue(checkPrivileges); + const alertAuthorization = new AlertingAuthorization({ + request, + authorization, + alertTypeRegistry, + features, + auditLogger, + getSpace, + exemptConsumerIds, + }); + + checkPrivileges.mockResolvedValueOnce({ + username: 'some-user', + hasAllRequested: false, + privileges: { + kibana: [ + { + privilege: mockAuthorizationAction('myType', 'myOtherApp', 'alert', 'update'), + authorized: true, + }, + { + privilege: mockAuthorizationAction('myType', 'myApp', 'alert', 'update'), authorized: false, }, ], @@ -547,11 +806,11 @@ describe('AlertingAuthorization', () => { alertAuthorization.ensureAuthorized({ ruleTypeId: 'myType', consumer: 'myOtherApp', - operation: WriteOperations.Create, + operation: WriteOperations.Update, entity: AlertingAuthorizationEntity.Alert, }) ).rejects.toThrowErrorMatchingInlineSnapshot( - `"Unauthorized to create a \\"myType\\" alert by \\"myApp\\""` + `"Unauthorized to update a \\"myType\\" alert by \\"myApp\\""` ); expect(auditLogger.logAuthorizationSuccess).not.toHaveBeenCalled(); @@ -562,13 +821,13 @@ describe('AlertingAuthorization', () => { "myType", 1, "myApp", - "create", + "update", "alert", ] `); }); - test('throws if user lacks the required privieleges for both consumer and producer', async () => { + test('throws if user lacks the required privileges for both consumer and producer', async () => { const { authorization } = mockSecurity(); const checkPrivileges: jest.MockedFunction< ReturnType @@ -662,7 +921,6 @@ describe('AlertingAuthorization', () => { enabledInLicense: true, }; const setOfAlertTypes = new Set([myAppAlertType, myOtherAppAlertType, mySecondAppAlertType]); - test('omits filter when there is no authorization api', async () => { const alertAuthorization = new AlertingAuthorization({ request, @@ -672,7 +930,6 @@ describe('AlertingAuthorization', () => { getSpace, exemptConsumerIds, }); - const { filter, ensureRuleTypeIsAuthorized, @@ -683,13 +940,10 @@ describe('AlertingAuthorization', () => { consumer: 'consumer', }, }); - expect(() => ensureRuleTypeIsAuthorized('someMadeUpType', 'myApp', 'rule')).not.toThrow(); - expect(filter).toEqual(undefined); }); - - test('ensureAlertTypeIsAuthorized is no-op when there is no authorization api', async () => { + test('ensureRuleTypeIsAuthorized is no-op when there is no authorization api', async () => { const alertAuthorization = new AlertingAuthorization({ request, alertTypeRegistry, @@ -698,7 +952,6 @@ describe('AlertingAuthorization', () => { getSpace, exemptConsumerIds, }); - const { ensureRuleTypeIsAuthorized } = await alertAuthorization.getFindAuthorizationFilter( AlertingAuthorizationEntity.Rule, { @@ -709,13 +962,10 @@ describe('AlertingAuthorization', () => { }, } ); - ensureRuleTypeIsAuthorized('someMadeUpType', 'myApp', 'rule'); - expect(auditLogger.logAuthorizationSuccess).not.toHaveBeenCalled(); expect(auditLogger.logAuthorizationFailure).not.toHaveBeenCalled(); }); - test('creates a filter based on the privileged types', async () => { const { authorization } = mockSecurity(); const checkPrivileges: jest.MockedFunction< @@ -727,7 +977,6 @@ describe('AlertingAuthorization', () => { hasAllRequested: true, privileges: { kibana: [] }, }); - const alertAuthorization = new AlertingAuthorization({ request, authorization, @@ -738,7 +987,6 @@ describe('AlertingAuthorization', () => { exemptConsumerIds, }); alertTypeRegistry.list.mockReturnValue(setOfAlertTypes); - expect( ( await alertAuthorization.getFindAuthorizationFilter(AlertingAuthorizationEntity.Rule, { @@ -754,11 +1002,9 @@ describe('AlertingAuthorization', () => { `((path.to.rule.id:myAppAlertType and consumer-field:(myApp or myOtherApp or myAppWithSubFeature)) or (path.to.rule.id:myOtherAppAlertType and consumer-field:(myApp or myOtherApp or myAppWithSubFeature)) or (path.to.rule.id:mySecondAppAlertType and consumer-field:(myApp or myOtherApp or myAppWithSubFeature)))` ) ); - expect(auditLogger.logAuthorizationSuccess).not.toHaveBeenCalled(); }); - - test('creates an `ensureAlertTypeIsAuthorized` function which throws if type is unauthorized', async () => { + test('creates an `ensureRuleTypeIsAuthorized` function which throws if type is unauthorized', async () => { const { authorization } = mockSecurity(); const checkPrivileges: jest.MockedFunction< ReturnType @@ -793,7 +1039,6 @@ describe('AlertingAuthorization', () => { ], }, }); - const alertAuthorization = new AlertingAuthorization({ request, authorization, @@ -804,7 +1049,6 @@ describe('AlertingAuthorization', () => { exemptConsumerIds, }); alertTypeRegistry.list.mockReturnValue(setOfAlertTypes); - const { ensureRuleTypeIsAuthorized } = await alertAuthorization.getFindAuthorizationFilter( AlertingAuthorizationEntity.Alert, { @@ -820,22 +1064,20 @@ describe('AlertingAuthorization', () => { }).toThrowErrorMatchingInlineSnapshot( `"Unauthorized to find a \\"myAppAlertType\\" alert for \\"myOtherApp\\""` ); - expect(auditLogger.logAuthorizationSuccess).not.toHaveBeenCalled(); expect(auditLogger.logAuthorizationFailure).toHaveBeenCalledTimes(1); expect(auditLogger.logAuthorizationFailure.mock.calls[0]).toMatchInlineSnapshot(` - Array [ - "some-user", - "myAppAlertType", - 0, - "myOtherApp", - "find", - "alert", - ] - `); + Array [ + "some-user", + "myAppAlertType", + 0, + "myOtherApp", + "find", + "alert", + ] + `); }); - - test('creates an `ensureAlertTypeIsAuthorized` function which is no-op if type is authorized', async () => { + test('creates an `ensureRuleTypeIsAuthorized` function which is no-op if type is authorized', async () => { const { authorization } = mockSecurity(); const checkPrivileges: jest.MockedFunction< ReturnType @@ -870,7 +1112,6 @@ describe('AlertingAuthorization', () => { ], }, }); - const alertAuthorization = new AlertingAuthorization({ request, authorization, @@ -881,7 +1122,6 @@ describe('AlertingAuthorization', () => { exemptConsumerIds, }); alertTypeRegistry.list.mockReturnValue(setOfAlertTypes); - const { ensureRuleTypeIsAuthorized } = await alertAuthorization.getFindAuthorizationFilter( AlertingAuthorizationEntity.Rule, { @@ -895,11 +1135,9 @@ describe('AlertingAuthorization', () => { expect(() => { ensureRuleTypeIsAuthorized('myAppAlertType', 'myOtherApp', 'rule'); }).not.toThrow(); - expect(auditLogger.logAuthorizationSuccess).not.toHaveBeenCalled(); expect(auditLogger.logAuthorizationFailure).not.toHaveBeenCalled(); }); - test('creates an `logSuccessfulAuthorization` function which logs every authorized type', async () => { const { authorization } = mockSecurity(); const checkPrivileges: jest.MockedFunction< @@ -948,7 +1186,6 @@ describe('AlertingAuthorization', () => { ], }, }); - const alertAuthorization = new AlertingAuthorization({ request, authorization, @@ -959,7 +1196,6 @@ describe('AlertingAuthorization', () => { exemptConsumerIds, }); alertTypeRegistry.list.mockReturnValue(setOfAlertTypes); - const { ensureRuleTypeIsAuthorized, logSuccessfulAuthorization, @@ -975,35 +1211,32 @@ describe('AlertingAuthorization', () => { ensureRuleTypeIsAuthorized('mySecondAppAlertType', 'myOtherApp', 'rule'); ensureRuleTypeIsAuthorized('myAppAlertType', 'myOtherApp', 'rule'); }).not.toThrow(); - expect(auditLogger.logAuthorizationSuccess).not.toHaveBeenCalled(); expect(auditLogger.logAuthorizationFailure).not.toHaveBeenCalled(); - logSuccessfulAuthorization(); - expect(auditLogger.logBulkAuthorizationSuccess).toHaveBeenCalledTimes(1); expect(auditLogger.logBulkAuthorizationSuccess.mock.calls[0]).toMatchInlineSnapshot(` - Array [ - "some-user", Array [ + "some-user", Array [ - "myAppAlertType", - "myOtherApp", - ], - Array [ - "mySecondAppAlertType", - "myOtherApp", + Array [ + "myAppAlertType", + "myOtherApp", + ], + Array [ + "mySecondAppAlertType", + "myOtherApp", + ], ], - ], - 0, - "find", - "rule", - ] - `); + 0, + "find", + "rule", + ] + `); }); }); - describe('filterByAlertTypeAuthorization', () => { + describe('filterByRuleTypeAuthorization', () => { const myOtherAppAlertType: RegistryAlertType = { actionGroups: [], actionVariables: undefined, diff --git a/x-pack/plugins/apm/server/feature.ts b/x-pack/plugins/apm/server/feature.ts index a340a940f4a3b..fb0610dffb92e 100644 --- a/x-pack/plugins/apm/server/feature.ts +++ b/x-pack/plugins/apm/server/feature.ts @@ -38,7 +38,12 @@ export const APM_FEATURE = { read: [], }, alerting: { - all: Object.values(AlertType), + rule: { + all: Object.values(AlertType), + }, + alert: { + all: Object.values(AlertType), + }, }, management: { insightsAndAlerting: ['triggersActions'], @@ -54,7 +59,12 @@ export const APM_FEATURE = { read: [], }, alerting: { - read: Object.values(AlertType), + rule: { + read: Object.values(AlertType), + }, + alert: { + read: Object.values(AlertType), + }, }, management: { insightsAndAlerting: ['triggersActions'], diff --git a/x-pack/plugins/features/common/feature_kibana_privileges.ts b/x-pack/plugins/features/common/feature_kibana_privileges.ts index 7febba197647d..166ce5b62a067 100644 --- a/x-pack/plugins/features/common/feature_kibana_privileges.ts +++ b/x-pack/plugins/features/common/feature_kibana_privileges.ts @@ -82,27 +82,50 @@ export interface FeatureKibanaPrivileges { * Alert Types and Alert Types provided by other features to which you wish to grant access. */ alerting?: { - /** - * List of alert types which users should have full read/write access to when granted this privilege. - * @example - * ```ts - * { - * all: ['my-alert-type-within-my-feature'] - * } - * ``` - */ - all?: readonly string[]; - - /** - * List of alert types which users should have read-only access to when granted this privilege. - * @example - * ```ts - * { - * read: ['my-alert-type'] - * } - * ``` - */ - read?: readonly string[]; + rule?: { + /** + * List of rule types which users should have full read/write access to when granted this privilege. + * @example + * ```ts + * { + * all: ['my-alert-type-within-my-feature'] + * } + * ``` + */ + all?: readonly string[]; + /** + * List of rule types which users should have read-only access to when granted this privilege. + * @example + * ```ts + * { + * read: ['my-alert-type'] + * } + * ``` + */ + read?: readonly string[]; + }; + alert?: { + /** + * List of rule types for which users should have full read/write access their alert data to when granted this privilege. + * @example + * ```ts + * { + * all: ['my-alert-type-within-my-feature'] + * } + * ``` + */ + all?: readonly string[]; + /** + * List of rule types for which users should have read-only access to their alert data when granted this privilege. + * @example + * ```ts + * { + * read: ['my-alert-type'] + * } + * ``` + */ + read?: readonly string[]; + }; }; /** * If your feature requires access to specific saved objects, then specify your access needs here. diff --git a/x-pack/plugins/features/server/__snapshots__/oss_features.test.ts.snap b/x-pack/plugins/features/server/__snapshots__/oss_features.test.ts.snap index 88712f2ac14c0..64be725e02bbe 100644 --- a/x-pack/plugins/features/server/__snapshots__/oss_features.test.ts.snap +++ b/x-pack/plugins/features/server/__snapshots__/oss_features.test.ts.snap @@ -512,8 +512,14 @@ Array [ Object { "privilege": Object { "alerting": Object { - "all": Array [], - "read": Array [], + "alert": Object { + "all": Array [], + "read": Array [], + }, + "rule": Object { + "all": Array [], + "read": Array [], + }, }, "api": Array [ "store_search_session", @@ -651,8 +657,14 @@ Array [ Object { "privilege": Object { "alerting": Object { - "all": Array [], - "read": Array [], + "alert": Object { + "all": Array [], + "read": Array [], + }, + "rule": Object { + "all": Array [], + "read": Array [], + }, }, "api": Array [ "store_search_session", @@ -888,8 +900,14 @@ Array [ Object { "privilege": Object { "alerting": Object { - "all": Array [], - "read": Array [], + "alert": Object { + "all": Array [], + "read": Array [], + }, + "rule": Object { + "all": Array [], + "read": Array [], + }, }, "api": Array [], "app": Array [ @@ -1010,8 +1028,14 @@ Array [ Object { "privilege": Object { "alerting": Object { - "all": Array [], - "read": Array [], + "alert": Object { + "all": Array [], + "read": Array [], + }, + "rule": Object { + "all": Array [], + "read": Array [], + }, }, "api": Array [ "store_search_session", @@ -1149,8 +1173,14 @@ Array [ Object { "privilege": Object { "alerting": Object { - "all": Array [], - "read": Array [], + "alert": Object { + "all": Array [], + "read": Array [], + }, + "rule": Object { + "all": Array [], + "read": Array [], + }, }, "api": Array [ "store_search_session", @@ -1386,8 +1416,14 @@ Array [ Object { "privilege": Object { "alerting": Object { - "all": Array [], - "read": Array [], + "alert": Object { + "all": Array [], + "read": Array [], + }, + "rule": Object { + "all": Array [], + "read": Array [], + }, }, "api": Array [], "app": Array [ diff --git a/x-pack/plugins/features/server/feature_privilege_iterator/feature_privilege_iterator.test.ts b/x-pack/plugins/features/server/feature_privilege_iterator/feature_privilege_iterator.test.ts index 6acc29793797f..75e6eaa402091 100644 --- a/x-pack/plugins/features/server/feature_privilege_iterator/feature_privilege_iterator.test.ts +++ b/x-pack/plugins/features/server/feature_privilege_iterator/feature_privilege_iterator.test.ts @@ -46,8 +46,14 @@ describe('featurePrivilegeIterator', () => { read: ['read-type'], }, alerting: { - all: ['alerting-all-type'], - read: ['alerting-read-type'], + rule: { + all: ['alerting-all-type'], + read: ['alerting-read-type'], + }, + alert: { + all: ['alerting-all-type'], + read: [], + }, }, ui: ['ui-action'], }, @@ -63,7 +69,12 @@ describe('featurePrivilegeIterator', () => { read: ['read-type'], }, alerting: { - read: ['alerting-read-type'], + rule: { + read: ['alerting-read-type'], + }, + alert: { + read: ['alerting-read-type'], + }, }, ui: ['ui-action'], }, @@ -93,8 +104,14 @@ describe('featurePrivilegeIterator', () => { read: ['read-type'], }, alerting: { - all: ['alerting-all-type'], - read: ['alerting-read-type'], + rule: { + all: ['alerting-all-type'], + read: ['alerting-read-type'], + }, + alert: { + all: ['alerting-all-type'], + read: [], + }, }, ui: ['ui-action'], }, @@ -113,7 +130,12 @@ describe('featurePrivilegeIterator', () => { read: ['read-type'], }, alerting: { - read: ['alerting-read-type'], + rule: { + read: ['alerting-read-type'], + }, + alert: { + read: ['alerting-read-type'], + }, }, ui: ['ui-action'], }, @@ -139,8 +161,14 @@ describe('featurePrivilegeIterator', () => { read: ['read-type'], }, alerting: { - all: ['alerting-all-type'], - read: ['alerting-read-type'], + rule: { + all: ['alerting-all-type'], + read: ['alerting-read-type'], + }, + alert: { + all: ['alerting-all-type'], + read: ['alerting-read-type-alerts'], + }, }, ui: ['ui-action'], }, @@ -156,7 +184,12 @@ describe('featurePrivilegeIterator', () => { read: ['read-type'], }, alerting: { - read: ['alerting-read-type'], + rule: { + read: ['alerting-read-type'], + }, + alert: { + read: ['alerting-read-type'], + }, }, ui: ['ui-action'], }, @@ -187,8 +220,14 @@ describe('featurePrivilegeIterator', () => { read: ['read-type'], }, alerting: { - all: ['alerting-all-type'], - read: ['alerting-read-type'], + rule: { + all: ['alerting-all-type'], + read: ['alerting-read-type'], + }, + alert: { + all: ['alerting-all-type'], + read: ['alerting-read-type-alerts'], + }, }, ui: ['ui-action'], }, @@ -212,11 +251,15 @@ describe('featurePrivilegeIterator', () => { }, savedObject: { all: ['all-type'], - read: ['read-type'], + read: [], }, alerting: { - all: ['alerting-all-type'], - read: ['alerting-read-type'], + rule: { + all: ['alerting-all-type'], + }, + alert: { + read: ['alerting-another-read-type'], + }, }, ui: ['ui-action'], }, @@ -232,7 +275,12 @@ describe('featurePrivilegeIterator', () => { read: ['read-type'], }, alerting: { - read: ['alerting-read-type'], + rule: { + read: ['alerting-read-type'], + }, + alert: { + read: ['alerting-read-type'], + }, }, ui: ['ui-action'], }, @@ -259,8 +307,9 @@ describe('featurePrivilegeIterator', () => { read: ['read-sub-type'], }, alerting: { - all: ['alerting-all-sub-type'], - read: ['alerting-read-sub-type'], + alert: { + all: ['alerting-all-sub-type'], + }, }, ui: ['ui-sub-type'], }, @@ -290,11 +339,15 @@ describe('featurePrivilegeIterator', () => { }, savedObject: { all: ['all-type'], - read: ['read-type'], + read: [], }, alerting: { - all: ['alerting-all-type'], - read: ['alerting-read-type'], + rule: { + all: ['alerting-all-type'], + }, + alert: { + read: ['alerting-another-read-type'], + }, }, ui: ['ui-action'], }, @@ -313,7 +366,12 @@ describe('featurePrivilegeIterator', () => { read: ['read-type'], }, alerting: { - read: ['alerting-read-type'], + rule: { + read: ['alerting-read-type'], + }, + alert: { + read: ['alerting-read-type'], + }, }, ui: ['ui-action'], }, @@ -340,8 +398,12 @@ describe('featurePrivilegeIterator', () => { read: ['read-type'], }, alerting: { - all: ['alerting-all-type'], - read: ['alerting-read-type'], + rule: { + all: ['alerting-all-type'], + }, + alert: { + read: ['alerting-another-read-type'], + }, }, ui: ['ui-action'], }, @@ -357,7 +419,12 @@ describe('featurePrivilegeIterator', () => { read: ['read-type'], }, alerting: { - read: ['alerting-read-type'], + rule: { + read: ['alerting-read-type'], + }, + alert: { + read: ['alerting-read-type'], + }, }, ui: ['ui-action'], }, @@ -384,8 +451,9 @@ describe('featurePrivilegeIterator', () => { read: ['read-sub-type'], }, alerting: { - all: ['alerting-all-sub-type'], - read: ['alerting-read-sub-type'], + alert: { + all: ['alerting-all-sub-type'], + }, }, ui: ['ui-sub-type'], }, @@ -418,8 +486,12 @@ describe('featurePrivilegeIterator', () => { read: ['read-type'], }, alerting: { - all: ['alerting-all-type'], - read: ['alerting-read-type'], + rule: { + all: ['alerting-all-type'], + }, + alert: { + read: ['alerting-another-read-type'], + }, }, ui: ['ui-action'], }, @@ -438,7 +510,12 @@ describe('featurePrivilegeIterator', () => { read: ['read-type'], }, alerting: { - read: ['alerting-read-type'], + rule: { + read: ['alerting-read-type'], + }, + alert: { + read: ['alerting-read-type'], + }, }, ui: ['ui-action'], }, @@ -465,8 +542,12 @@ describe('featurePrivilegeIterator', () => { read: ['read-type'], }, alerting: { - all: ['alerting-all-type'], - read: ['alerting-read-type'], + rule: { + all: ['alerting-all-type'], + }, + alert: { + read: ['alerting-another-read-type'], + }, }, ui: ['ui-action'], }, @@ -482,7 +563,12 @@ describe('featurePrivilegeIterator', () => { read: ['read-type'], }, alerting: { - read: ['alerting-read-type'], + rule: { + read: ['alerting-read-type'], + }, + alert: { + read: ['alerting-read-type'], + }, }, ui: ['ui-action'], }, @@ -510,8 +596,9 @@ describe('featurePrivilegeIterator', () => { read: ['read-sub-type'], }, alerting: { - all: ['alerting-all-sub-type'], - read: ['alerting-read-sub-type'], + alert: { + all: ['alerting-all-sub-type'], + }, }, ui: ['ui-sub-type'], }, @@ -545,8 +632,14 @@ describe('featurePrivilegeIterator', () => { read: ['read-type', 'read-sub-type'], }, alerting: { - all: ['alerting-all-type', 'alerting-all-sub-type'], - read: ['alerting-read-type', 'alerting-read-sub-type'], + rule: { + all: ['alerting-all-type'], + read: [], + }, + alert: { + all: ['alerting-all-sub-type'], + read: ['alerting-another-read-type'], + }, }, ui: ['ui-action', 'ui-sub-type'], }, @@ -566,8 +659,14 @@ describe('featurePrivilegeIterator', () => { read: ['read-type', 'read-sub-type'], }, alerting: { - all: ['alerting-all-sub-type'], - read: ['alerting-read-type', 'alerting-read-sub-type'], + rule: { + all: [], + read: ['alerting-read-type'], + }, + alert: { + all: ['alerting-all-sub-type'], + read: ['alerting-read-type'], + }, }, ui: ['ui-action', 'ui-sub-type'], }, @@ -594,8 +693,14 @@ describe('featurePrivilegeIterator', () => { read: ['read-type'], }, alerting: { - all: ['alerting-all-type'], - read: ['alerting-read-type'], + rule: { + all: ['alerting-all-type'], + read: ['alerting-read-type'], + }, + alert: { + all: [], + read: ['alerting-read-type'], + }, }, ui: ['ui-action'], }, @@ -611,7 +716,12 @@ describe('featurePrivilegeIterator', () => { read: ['read-type'], }, alerting: { - read: ['alerting-read-type'], + rule: { + read: ['alerting-read-type'], + }, + alert: { + read: ['alerting-read-type'], + }, }, ui: ['ui-action'], }, @@ -638,7 +748,9 @@ describe('featurePrivilegeIterator', () => { read: ['read-type'], }, alerting: { - read: ['alerting-read-type'], + alert: { + all: ['alerting-read-type'], + }, }, ui: ['ui-action'], }, @@ -671,8 +783,14 @@ describe('featurePrivilegeIterator', () => { read: ['read-type'], }, alerting: { - all: ['alerting-all-type'], - read: ['alerting-read-type'], + rule: { + all: ['alerting-all-type'], + read: ['alerting-read-type'], + }, + alert: { + all: ['alerting-read-type'], + read: ['alerting-read-type'], + }, }, ui: ['ui-action'], }, @@ -691,8 +809,14 @@ describe('featurePrivilegeIterator', () => { read: ['read-type'], }, alerting: { - all: [], - read: ['alerting-read-type'], + rule: { + all: [], + read: ['alerting-read-type'], + }, + alert: { + all: ['alerting-read-type'], + read: ['alerting-read-type'], + }, }, ui: ['ui-action'], }, @@ -719,8 +843,12 @@ describe('featurePrivilegeIterator', () => { read: ['read-type'], }, alerting: { - all: ['alerting-all-type'], - read: ['alerting-read-type'], + rule: { + all: ['alerting-all-type'], + }, + alert: { + read: ['alerting-another-read-type'], + }, }, ui: ['ui-action'], }, @@ -736,7 +864,12 @@ describe('featurePrivilegeIterator', () => { read: ['read-type'], }, alerting: { - read: ['alerting-read-type'], + rule: { + read: ['alerting-read-type'], + }, + alert: { + read: ['alerting-read-type'], + }, }, ui: ['ui-action'], }, @@ -764,8 +897,9 @@ describe('featurePrivilegeIterator', () => { read: ['read-sub-type'], }, alerting: { - all: ['alerting-all-sub-type'], - read: ['alerting-read-sub-type'], + alert: { + all: ['alerting-all-sub-type'], + }, }, ui: ['ui-sub-type'], }, @@ -799,8 +933,14 @@ describe('featurePrivilegeIterator', () => { read: ['read-type', 'read-sub-type'], }, alerting: { - all: ['alerting-all-type', 'alerting-all-sub-type'], - read: ['alerting-read-type', 'alerting-read-sub-type'], + rule: { + all: ['alerting-all-type'], + read: [], + }, + alert: { + all: ['alerting-all-sub-type'], + read: ['alerting-another-read-type'], + }, }, ui: ['ui-action', 'ui-sub-type'], }, @@ -819,7 +959,12 @@ describe('featurePrivilegeIterator', () => { read: ['read-type'], }, alerting: { - read: ['alerting-read-type'], + rule: { + read: ['alerting-read-type'], + }, + alert: { + read: ['alerting-read-type'], + }, }, ui: ['ui-action'], }, @@ -846,8 +991,12 @@ describe('featurePrivilegeIterator', () => { read: ['read-type'], }, alerting: { - all: ['alerting-all-type'], - read: ['alerting-read-type'], + rule: { + all: ['alerting-all-type'], + }, + alert: { + read: ['alerting-another-read-type'], + }, }, ui: ['ui-action'], }, @@ -863,7 +1012,12 @@ describe('featurePrivilegeIterator', () => { read: ['read-type'], }, alerting: { - read: ['alerting-read-type'], + rule: { + read: ['alerting-read-type'], + }, + alert: { + read: ['alerting-read-type'], + }, }, ui: ['ui-action'], }, @@ -892,8 +1046,9 @@ describe('featurePrivilegeIterator', () => { read: ['read-sub-type'], }, alerting: { - all: ['alerting-all-sub-type'], - read: ['alerting-read-sub-type'], + alert: { + all: ['alerting-all-sub-type'], + }, }, ui: ['ui-sub-type'], }, @@ -926,8 +1081,12 @@ describe('featurePrivilegeIterator', () => { read: ['read-type'], }, alerting: { - all: ['alerting-all-type'], - read: ['alerting-read-type'], + rule: { + all: ['alerting-all-type'], + }, + alert: { + read: ['alerting-another-read-type'], + }, }, ui: ['ui-action'], }, @@ -946,7 +1105,12 @@ describe('featurePrivilegeIterator', () => { read: ['read-type'], }, alerting: { - read: ['alerting-read-type'], + rule: { + read: ['alerting-read-type'], + }, + alert: { + read: ['alerting-read-type'], + }, }, ui: ['ui-action'], }, @@ -999,8 +1163,10 @@ describe('featurePrivilegeIterator', () => { read: ['read-sub-type'], }, alerting: { - all: ['alerting-all-sub-type'], - read: ['alerting-read-sub-type'], + rule: { + all: ['alerting-all-sub-type'], + read: ['alerting-read-sub-type'], + }, }, ui: ['ui-sub-type'], }, @@ -1034,8 +1200,14 @@ describe('featurePrivilegeIterator', () => { read: ['read-sub-type'], }, alerting: { - all: ['alerting-all-sub-type'], - read: ['alerting-read-sub-type'], + rule: { + all: ['alerting-all-sub-type'], + read: ['alerting-read-sub-type'], + }, + alert: { + all: [], + read: [], + }, }, ui: ['ui-sub-type'], }, @@ -1055,8 +1227,14 @@ describe('featurePrivilegeIterator', () => { read: ['read-sub-type'], }, alerting: { - all: ['alerting-all-sub-type'], - read: ['alerting-read-sub-type'], + rule: { + all: ['alerting-all-sub-type'], + read: ['alerting-read-sub-type'], + }, + alert: { + all: [], + read: [], + }, }, ui: ['ui-sub-type'], }, @@ -1083,8 +1261,12 @@ describe('featurePrivilegeIterator', () => { read: ['read-type'], }, alerting: { - all: ['alerting-all-type'], - read: ['alerting-read-type'], + rule: { + all: ['alerting-all-type'], + }, + alert: { + read: ['alerting-another-read-type'], + }, }, ui: ['ui-action'], }, @@ -1100,7 +1282,12 @@ describe('featurePrivilegeIterator', () => { read: ['read-type'], }, alerting: { - read: ['alerting-read-type'], + rule: { + read: ['alerting-read-type'], + }, + alert: { + read: ['alerting-read-type'], + }, }, ui: ['ui-action'], }, @@ -1151,8 +1338,14 @@ describe('featurePrivilegeIterator', () => { read: ['read-type'], }, alerting: { - all: ['alerting-all-type'], - read: ['alerting-read-type'], + rule: { + all: ['alerting-all-type'], + read: [], + }, + alert: { + all: [], + read: ['alerting-another-read-type'], + }, }, ui: ['ui-action'], }, @@ -1171,8 +1364,14 @@ describe('featurePrivilegeIterator', () => { read: ['read-type'], }, alerting: { - all: [], - read: ['alerting-read-type'], + rule: { + all: [], + read: ['alerting-read-type'], + }, + alert: { + all: [], + read: ['alerting-read-type'], + }, }, ui: ['ui-action'], }, diff --git a/x-pack/plugins/features/server/feature_privilege_iterator/feature_privilege_iterator.ts b/x-pack/plugins/features/server/feature_privilege_iterator/feature_privilege_iterator.ts index e194a051c8a6e..b58f72b0fadc0 100644 --- a/x-pack/plugins/features/server/feature_privilege_iterator/feature_privilege_iterator.ts +++ b/x-pack/plugins/features/server/feature_privilege_iterator/feature_privilege_iterator.ts @@ -110,11 +110,26 @@ function mergeWithSubFeatures( ); mergedConfig.alerting = { - all: mergeArrays(mergedConfig.alerting?.all ?? [], subFeaturePrivilege.alerting?.all ?? []), - read: mergeArrays( - mergedConfig.alerting?.read ?? [], - subFeaturePrivilege.alerting?.read ?? [] - ), + rule: { + all: mergeArrays( + mergedConfig.alerting?.rule?.all ?? [], + subFeaturePrivilege.alerting?.rule?.all ?? [] + ), + read: mergeArrays( + mergedConfig.alerting?.rule?.read ?? [], + subFeaturePrivilege.alerting?.rule?.read ?? [] + ), + }, + alert: { + all: mergeArrays( + mergedConfig.alerting?.alert?.all ?? [], + subFeaturePrivilege.alerting?.alert?.all ?? [] + ), + read: mergeArrays( + mergedConfig.alerting?.alert?.read ?? [], + subFeaturePrivilege.alerting?.alert?.read ?? [] + ), + }, }; } return mergedConfig; diff --git a/x-pack/plugins/features/server/feature_registry.test.ts b/x-pack/plugins/features/server/feature_registry.test.ts index 0eb00b43d6f5d..8e7ed45f33f50 100644 --- a/x-pack/plugins/features/server/feature_registry.test.ts +++ b/x-pack/plugins/features/server/feature_registry.test.ts @@ -828,7 +828,7 @@ describe('FeatureRegistry', () => { ); }); - it(`prevents privileges from specifying alerting entries that don't exist at the root level`, () => { + it(`prevents privileges from specifying alerting/rule entries that don't exist at the root level`, () => { const feature: KibanaFeatureConfig = { id: 'test-feature', name: 'Test Feature', @@ -838,8 +838,57 @@ describe('FeatureRegistry', () => { privileges: { all: { alerting: { - all: ['foo', 'bar'], - read: ['baz'], + rule: { + all: ['foo', 'bar'], + read: ['baz'], + }, + }, + savedObject: { + all: [], + read: [], + }, + ui: [], + app: [], + }, + read: { + alerting: { + rule: { + read: ['foo', 'bar', 'baz'], + }, + }, + savedObject: { + all: [], + read: [], + }, + ui: [], + app: [], + }, + }, + }; + + const featureRegistry = new FeatureRegistry(); + + expect(() => + featureRegistry.registerKibanaFeature(feature) + ).toThrowErrorMatchingInlineSnapshot( + `"Feature privilege test-feature.all has unknown alerting entries: foo, baz"` + ); + }); + + it(`prevents privileges from specifying alerting/alert entries that don't exist at the root level`, () => { + const feature: KibanaFeatureConfig = { + id: 'test-feature', + name: 'Test Feature', + app: [], + category: { id: 'foo', label: 'foo' }, + alerting: ['bar'], + privileges: { + all: { + alerting: { + alert: { + all: ['foo', 'bar'], + read: ['baz'], + }, }, savedObject: { all: [], @@ -849,7 +898,11 @@ describe('FeatureRegistry', () => { app: [], }, read: { - alerting: { read: ['foo', 'bar', 'baz'] }, + alerting: { + alert: { + read: ['foo', 'bar', 'baz'], + }, + }, savedObject: { all: [], read: [], @@ -869,7 +922,80 @@ describe('FeatureRegistry', () => { ); }); - it(`prevents features from specifying alerting entries that don't exist at the privilege level`, () => { + it(`prevents features from specifying alerting/rule entries that don't exist at the privilege level`, () => { + const feature: KibanaFeatureConfig = { + id: 'test-feature', + name: 'Test Feature', + app: [], + category: { id: 'foo', label: 'foo' }, + alerting: ['foo', 'bar', 'baz'], + privileges: { + all: { + alerting: { + rule: { + all: ['foo'], + }, + }, + savedObject: { + all: [], + read: [], + }, + ui: [], + app: [], + }, + read: { + alerting: { + rule: { + all: ['foo'], + }, + }, + savedObject: { + all: [], + read: [], + }, + ui: [], + app: [], + }, + }, + subFeatures: [ + { + name: 'my sub feature', + privilegeGroups: [ + { + groupType: 'independent', + privileges: [ + { + id: 'cool-sub-feature-privilege', + name: 'cool privilege', + includeIn: 'none', + savedObject: { + all: [], + read: [], + }, + ui: [], + alerting: { + rule: { + all: ['bar'], + }, + }, + }, + ], + }, + ], + }, + ], + }; + + const featureRegistry = new FeatureRegistry(); + + expect(() => + featureRegistry.registerKibanaFeature(feature) + ).toThrowErrorMatchingInlineSnapshot( + `"Feature test-feature specifies alerting entries which are not granted to any privileges: baz"` + ); + }); + + it(`prevents features from specifying alerting/alert entries that don't exist at the privilege level`, () => { const feature: KibanaFeatureConfig = { id: 'test-feature', name: 'Test Feature', @@ -878,7 +1004,11 @@ describe('FeatureRegistry', () => { alerting: ['foo', 'bar', 'baz'], privileges: { all: { - alerting: { all: ['foo'] }, + alerting: { + alert: { + all: ['foo'], + }, + }, savedObject: { all: [], read: [], @@ -887,7 +1017,11 @@ describe('FeatureRegistry', () => { app: [], }, read: { - alerting: { all: ['foo'] }, + alerting: { + alert: { + all: ['foo'], + }, + }, savedObject: { all: [], read: [], @@ -912,7 +1046,11 @@ describe('FeatureRegistry', () => { read: [], }, ui: [], - alerting: { all: ['bar'] }, + alerting: { + alert: { + all: ['bar'], + }, + }, }, ], }, @@ -930,7 +1068,47 @@ describe('FeatureRegistry', () => { ); }); - it(`prevents reserved privileges from specifying alerting entries that don't exist at the root level`, () => { + it(`prevents reserved privileges from specifying alerting/rule entries that don't exist at the root level`, () => { + const feature: KibanaFeatureConfig = { + id: 'test-feature', + name: 'Test Feature', + app: [], + category: { id: 'foo', label: 'foo' }, + alerting: ['bar'], + privileges: null, + reserved: { + description: 'something', + privileges: [ + { + id: 'reserved', + privilege: { + alerting: { + rule: { + all: ['foo', 'bar', 'baz'], + }, + }, + savedObject: { + all: [], + read: [], + }, + ui: [], + app: [], + }, + }, + ], + }, + }; + + const featureRegistry = new FeatureRegistry(); + + expect(() => + featureRegistry.registerKibanaFeature(feature) + ).toThrowErrorMatchingInlineSnapshot( + `"Feature privilege test-feature.reserved has unknown alerting entries: foo, baz"` + ); + }); + + it(`prevents reserved privileges from specifying alerting/alert entries that don't exist at the root level`, () => { const feature: KibanaFeatureConfig = { id: 'test-feature', name: 'Test Feature', @@ -944,7 +1122,11 @@ describe('FeatureRegistry', () => { { id: 'reserved', privilege: { - alerting: { all: ['foo', 'bar', 'baz'] }, + alerting: { + alert: { + all: ['foo', 'bar', 'baz'], + }, + }, savedObject: { all: [], read: [], @@ -966,7 +1148,47 @@ describe('FeatureRegistry', () => { ); }); - it(`prevents features from specifying alerting entries that don't exist at the reserved privilege level`, () => { + it(`prevents features from specifying alerting/rule entries that don't exist at the reserved privilege level`, () => { + const feature: KibanaFeatureConfig = { + id: 'test-feature', + name: 'Test Feature', + app: [], + category: { id: 'foo', label: 'foo' }, + alerting: ['foo', 'bar', 'baz'], + privileges: null, + reserved: { + description: 'something', + privileges: [ + { + id: 'reserved', + privilege: { + alerting: { + rule: { + all: ['foo', 'bar'], + }, + }, + savedObject: { + all: [], + read: [], + }, + ui: [], + app: [], + }, + }, + ], + }, + }; + + const featureRegistry = new FeatureRegistry(); + + expect(() => + featureRegistry.registerKibanaFeature(feature) + ).toThrowErrorMatchingInlineSnapshot( + `"Feature test-feature specifies alerting entries which are not granted to any privileges: baz"` + ); + }); + + it(`prevents features from specifying alerting/alert entries that don't exist at the reserved privilege level`, () => { const feature: KibanaFeatureConfig = { id: 'test-feature', name: 'Test Feature', @@ -980,7 +1202,11 @@ describe('FeatureRegistry', () => { { id: 'reserved', privilege: { - alerting: { all: ['foo', 'bar'] }, + alerting: { + alert: { + all: ['foo', 'bar'], + }, + }, savedObject: { all: [], read: [], diff --git a/x-pack/plugins/features/server/feature_schema.ts b/x-pack/plugins/features/server/feature_schema.ts index 51d3331ac7da1..00272efc8aa78 100644 --- a/x-pack/plugins/features/server/feature_schema.ts +++ b/x-pack/plugins/features/server/feature_schema.ts @@ -80,8 +80,18 @@ const kibanaPrivilegeSchema = schema.object({ app: schema.maybe(schema.arrayOf(schema.string())), alerting: schema.maybe( schema.object({ - all: schema.maybe(alertingSchema), - read: schema.maybe(alertingSchema), + rule: schema.maybe( + schema.object({ + all: schema.maybe(alertingSchema), + read: schema.maybe(alertingSchema), + }) + ), + alert: schema.maybe( + schema.object({ + all: schema.maybe(alertingSchema), + read: schema.maybe(alertingSchema), + }) + ), }) ), savedObject: schema.object({ @@ -106,8 +116,18 @@ const kibanaIndependentSubFeaturePrivilegeSchema = schema.object({ catalogue: schema.maybe(catalogueSchema), alerting: schema.maybe( schema.object({ - all: schema.maybe(alertingSchema), - read: schema.maybe(alertingSchema), + rule: schema.maybe( + schema.object({ + all: schema.maybe(alertingSchema), + read: schema.maybe(alertingSchema), + }) + ), + alert: schema.maybe( + schema.object({ + all: schema.maybe(alertingSchema), + read: schema.maybe(alertingSchema), + }) + ), }) ), api: schema.maybe(schema.arrayOf(schema.string())), @@ -274,8 +294,8 @@ export function validateKibanaFeature(feature: KibanaFeatureConfig) { } function validateAlertingEntry(privilegeId: string, entry: FeatureKibanaPrivileges['alerting']) { - const all = entry?.all ?? []; - const read = entry?.read ?? []; + const all: string[] = [...(entry?.rule?.all ?? []), ...(entry?.alert?.all ?? [])]; + const read: string[] = [...(entry?.rule?.read ?? []), ...(entry?.alert?.read ?? [])]; all.forEach((privilegeAlertTypes) => unseenAlertTypes.delete(privilegeAlertTypes)); read.forEach((privilegeAlertTypes) => unseenAlertTypes.delete(privilegeAlertTypes)); diff --git a/x-pack/plugins/infra/server/features.ts b/x-pack/plugins/infra/server/features.ts index aa2c628a23ddd..91f82e82b33cd 100644 --- a/x-pack/plugins/infra/server/features.ts +++ b/x-pack/plugins/infra/server/features.ts @@ -34,7 +34,12 @@ export const METRICS_FEATURE = { read: ['index-pattern'], }, alerting: { - all: [METRIC_THRESHOLD_ALERT_TYPE_ID, METRIC_INVENTORY_THRESHOLD_ALERT_TYPE_ID], + rule: { + all: [METRIC_THRESHOLD_ALERT_TYPE_ID, METRIC_INVENTORY_THRESHOLD_ALERT_TYPE_ID], + }, + alert: { + all: [METRIC_THRESHOLD_ALERT_TYPE_ID, METRIC_INVENTORY_THRESHOLD_ALERT_TYPE_ID], + }, }, management: { insightsAndAlerting: ['triggersActions'], @@ -50,7 +55,12 @@ export const METRICS_FEATURE = { read: ['infrastructure-ui-source', 'index-pattern'], }, alerting: { - read: [METRIC_THRESHOLD_ALERT_TYPE_ID, METRIC_INVENTORY_THRESHOLD_ALERT_TYPE_ID], + rule: { + read: [METRIC_THRESHOLD_ALERT_TYPE_ID, METRIC_INVENTORY_THRESHOLD_ALERT_TYPE_ID], + }, + alert: { + read: [METRIC_THRESHOLD_ALERT_TYPE_ID, METRIC_INVENTORY_THRESHOLD_ALERT_TYPE_ID], + }, }, management: { insightsAndAlerting: ['triggersActions'], @@ -83,7 +93,12 @@ export const LOGS_FEATURE = { read: [], }, alerting: { - all: [LOG_DOCUMENT_COUNT_ALERT_TYPE_ID], + rule: { + all: [LOG_DOCUMENT_COUNT_ALERT_TYPE_ID], + }, + alert: { + all: [LOG_DOCUMENT_COUNT_ALERT_TYPE_ID], + }, }, management: { insightsAndAlerting: ['triggersActions'], @@ -95,7 +110,12 @@ export const LOGS_FEATURE = { catalogue: ['infralogging', 'logs'], api: ['infra'], alerting: { - read: [LOG_DOCUMENT_COUNT_ALERT_TYPE_ID], + rule: { + read: [LOG_DOCUMENT_COUNT_ALERT_TYPE_ID], + }, + alert: { + read: [LOG_DOCUMENT_COUNT_ALERT_TYPE_ID], + }, }, management: { insightsAndAlerting: ['triggersActions'], diff --git a/x-pack/plugins/ml/common/types/capabilities.ts b/x-pack/plugins/ml/common/types/capabilities.ts index 1e6a76caf70e9..3545a85305c17 100644 --- a/x-pack/plugins/ml/common/types/capabilities.ts +++ b/x-pack/plugins/ml/common/types/capabilities.ts @@ -117,8 +117,12 @@ export function getPluginPrivileges() { read: savedObjects, }, alerting: { - all: Object.values(ML_ALERT_TYPES), - read: [], + rule: { + all: Object.values(ML_ALERT_TYPES), + }, + alert: { + all: Object.values(ML_ALERT_TYPES), + }, }, }, user: { @@ -132,8 +136,12 @@ export function getPluginPrivileges() { read: savedObjects, }, alerting: { - all: [], - read: Object.values(ML_ALERT_TYPES), + rule: { + read: Object.values(ML_ALERT_TYPES), + }, + alert: { + read: Object.values(ML_ALERT_TYPES), + }, }, }, apmUser: { diff --git a/x-pack/plugins/monitoring/server/plugin.ts b/x-pack/plugins/monitoring/server/plugin.ts index 56c654963d340..10724594ce576 100644 --- a/x-pack/plugins/monitoring/server/plugin.ts +++ b/x-pack/plugins/monitoring/server/plugin.ts @@ -262,7 +262,12 @@ export class MonitoringPlugin read: [], }, alerting: { - all: ALERTS, + rule: { + all: ALERTS, + }, + alert: { + all: ALERTS, + }, }, ui: [], }, diff --git a/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/alerting.test.ts b/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/alerting.test.ts index e06e40b86e01b..861f6900fda58 100644 --- a/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/alerting.test.ts +++ b/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/alerting.test.ts @@ -20,8 +20,14 @@ describe(`feature_privilege_builder`, () => { const privilege: FeatureKibanaPrivileges = { alerting: { - all: [], - read: [], + rule: { + all: [], + read: [], + }, + alert: { + all: [], + read: [], + }, }, savedObject: { @@ -46,14 +52,16 @@ describe(`feature_privilege_builder`, () => { }); describe(`within feature`, () => { - test('grants `read` privileges under feature consumer', () => { + test('grants `read` privileges to rules under feature consumer', () => { const actions = new Actions(version); const alertingFeaturePrivileges = new FeaturePrivilegeAlertingBuilder(actions); const privilege: FeatureKibanaPrivileges = { alerting: { - all: [], - read: ['alert-type'], + rule: { + all: [], + read: ['alert-type'], + }, }, savedObject: { @@ -80,20 +88,20 @@ describe(`feature_privilege_builder`, () => { "alerting:1.0.0-zeta1:alert-type/my-feature/rule/getRuleState", "alerting:1.0.0-zeta1:alert-type/my-feature/rule/getAlertSummary", "alerting:1.0.0-zeta1:alert-type/my-feature/rule/find", - "alerting:1.0.0-zeta1:alert-type/my-feature/alert/get", - "alerting:1.0.0-zeta1:alert-type/my-feature/alert/find", ] `); }); - test('grants `all` privileges under feature consumer', () => { + test('grants `read` privileges to alerts under feature consumer', () => { const actions = new Actions(version); const alertingFeaturePrivileges = new FeaturePrivilegeAlertingBuilder(actions); const privilege: FeatureKibanaPrivileges = { alerting: { - all: ['alert-type'], - read: [], + alert: { + all: [], + read: ['alert-type'], + }, }, savedObject: { @@ -116,35 +124,26 @@ describe(`feature_privilege_builder`, () => { expect(alertingFeaturePrivileges.getActions(privilege, feature)).toMatchInlineSnapshot(` Array [ - "alerting:1.0.0-zeta1:alert-type/my-feature/rule/get", - "alerting:1.0.0-zeta1:alert-type/my-feature/rule/getRuleState", - "alerting:1.0.0-zeta1:alert-type/my-feature/rule/getAlertSummary", - "alerting:1.0.0-zeta1:alert-type/my-feature/rule/find", - "alerting:1.0.0-zeta1:alert-type/my-feature/rule/create", - "alerting:1.0.0-zeta1:alert-type/my-feature/rule/delete", - "alerting:1.0.0-zeta1:alert-type/my-feature/rule/update", - "alerting:1.0.0-zeta1:alert-type/my-feature/rule/updateApiKey", - "alerting:1.0.0-zeta1:alert-type/my-feature/rule/enable", - "alerting:1.0.0-zeta1:alert-type/my-feature/rule/disable", - "alerting:1.0.0-zeta1:alert-type/my-feature/rule/muteAll", - "alerting:1.0.0-zeta1:alert-type/my-feature/rule/unmuteAll", - "alerting:1.0.0-zeta1:alert-type/my-feature/rule/muteAlert", - "alerting:1.0.0-zeta1:alert-type/my-feature/rule/unmuteAlert", "alerting:1.0.0-zeta1:alert-type/my-feature/alert/get", "alerting:1.0.0-zeta1:alert-type/my-feature/alert/find", - "alerting:1.0.0-zeta1:alert-type/my-feature/alert/update", ] `); }); - test('grants both `all` and `read` privileges under feature consumer', () => { + test('grants `read` privileges to rules and alerts under feature consumer', () => { const actions = new Actions(version); const alertingFeaturePrivileges = new FeaturePrivilegeAlertingBuilder(actions); const privilege: FeatureKibanaPrivileges = { alerting: { - all: ['alert-type'], - read: ['readonly-alert-type'], + rule: { + all: [], + read: ['alert-type'], + }, + alert: { + all: [], + read: ['alert-type'], + }, }, savedObject: { @@ -171,28 +170,315 @@ describe(`feature_privilege_builder`, () => { "alerting:1.0.0-zeta1:alert-type/my-feature/rule/getRuleState", "alerting:1.0.0-zeta1:alert-type/my-feature/rule/getAlertSummary", "alerting:1.0.0-zeta1:alert-type/my-feature/rule/find", - "alerting:1.0.0-zeta1:alert-type/my-feature/rule/create", - "alerting:1.0.0-zeta1:alert-type/my-feature/rule/delete", - "alerting:1.0.0-zeta1:alert-type/my-feature/rule/update", - "alerting:1.0.0-zeta1:alert-type/my-feature/rule/updateApiKey", - "alerting:1.0.0-zeta1:alert-type/my-feature/rule/enable", - "alerting:1.0.0-zeta1:alert-type/my-feature/rule/disable", - "alerting:1.0.0-zeta1:alert-type/my-feature/rule/muteAll", - "alerting:1.0.0-zeta1:alert-type/my-feature/rule/unmuteAll", - "alerting:1.0.0-zeta1:alert-type/my-feature/rule/muteAlert", - "alerting:1.0.0-zeta1:alert-type/my-feature/rule/unmuteAlert", "alerting:1.0.0-zeta1:alert-type/my-feature/alert/get", "alerting:1.0.0-zeta1:alert-type/my-feature/alert/find", - "alerting:1.0.0-zeta1:alert-type/my-feature/alert/update", - "alerting:1.0.0-zeta1:readonly-alert-type/my-feature/rule/get", - "alerting:1.0.0-zeta1:readonly-alert-type/my-feature/rule/getRuleState", - "alerting:1.0.0-zeta1:readonly-alert-type/my-feature/rule/getAlertSummary", - "alerting:1.0.0-zeta1:readonly-alert-type/my-feature/rule/find", - "alerting:1.0.0-zeta1:readonly-alert-type/my-feature/alert/get", - "alerting:1.0.0-zeta1:readonly-alert-type/my-feature/alert/find", ] `); }); + + test('grants `all` privileges to rules under feature consumer', () => { + const actions = new Actions(version); + const alertingFeaturePrivileges = new FeaturePrivilegeAlertingBuilder(actions); + + const privilege: FeatureKibanaPrivileges = { + alerting: { + rule: { + all: ['alert-type'], + read: [], + }, + }, + + savedObject: { + all: [], + read: [], + }, + ui: [], + }; + + const feature = new KibanaFeature({ + id: 'my-feature', + name: 'my-feature', + app: [], + category: { id: 'foo', label: 'foo' }, + privileges: { + all: privilege, + read: privilege, + }, + }); + + expect(alertingFeaturePrivileges.getActions(privilege, feature)).toMatchInlineSnapshot(` + Array [ + "alerting:1.0.0-zeta1:alert-type/my-feature/rule/get", + "alerting:1.0.0-zeta1:alert-type/my-feature/rule/getRuleState", + "alerting:1.0.0-zeta1:alert-type/my-feature/rule/getAlertSummary", + "alerting:1.0.0-zeta1:alert-type/my-feature/rule/find", + "alerting:1.0.0-zeta1:alert-type/my-feature/rule/create", + "alerting:1.0.0-zeta1:alert-type/my-feature/rule/delete", + "alerting:1.0.0-zeta1:alert-type/my-feature/rule/update", + "alerting:1.0.0-zeta1:alert-type/my-feature/rule/updateApiKey", + "alerting:1.0.0-zeta1:alert-type/my-feature/rule/enable", + "alerting:1.0.0-zeta1:alert-type/my-feature/rule/disable", + "alerting:1.0.0-zeta1:alert-type/my-feature/rule/muteAll", + "alerting:1.0.0-zeta1:alert-type/my-feature/rule/unmuteAll", + "alerting:1.0.0-zeta1:alert-type/my-feature/rule/muteAlert", + "alerting:1.0.0-zeta1:alert-type/my-feature/rule/unmuteAlert", + ] + `); + }); + + test('grants `all` privileges to alerts under feature consumer', () => { + const actions = new Actions(version); + const alertingFeaturePrivileges = new FeaturePrivilegeAlertingBuilder(actions); + + const privilege: FeatureKibanaPrivileges = { + alerting: { + alert: { + all: ['alert-type'], + read: [], + }, + }, + + savedObject: { + all: [], + read: [], + }, + ui: [], + }; + + const feature = new KibanaFeature({ + id: 'my-feature', + name: 'my-feature', + app: [], + category: { id: 'foo', label: 'foo' }, + privileges: { + all: privilege, + read: privilege, + }, + }); + + expect(alertingFeaturePrivileges.getActions(privilege, feature)).toMatchInlineSnapshot(` + Array [ + "alerting:1.0.0-zeta1:alert-type/my-feature/alert/get", + "alerting:1.0.0-zeta1:alert-type/my-feature/alert/find", + "alerting:1.0.0-zeta1:alert-type/my-feature/alert/update", + ] + `); + }); + + test('grants `all` privileges to rules and alerts under feature consumer', () => { + const actions = new Actions(version); + const alertingFeaturePrivileges = new FeaturePrivilegeAlertingBuilder(actions); + + const privilege: FeatureKibanaPrivileges = { + alerting: { + rule: { + all: ['alert-type'], + read: [], + }, + alert: { + all: ['alert-type'], + read: [], + }, + }, + + savedObject: { + all: [], + read: [], + }, + ui: [], + }; + + const feature = new KibanaFeature({ + id: 'my-feature', + name: 'my-feature', + app: [], + category: { id: 'foo', label: 'foo' }, + privileges: { + all: privilege, + read: privilege, + }, + }); + + expect(alertingFeaturePrivileges.getActions(privilege, feature)).toMatchInlineSnapshot(` + Array [ + "alerting:1.0.0-zeta1:alert-type/my-feature/rule/get", + "alerting:1.0.0-zeta1:alert-type/my-feature/rule/getRuleState", + "alerting:1.0.0-zeta1:alert-type/my-feature/rule/getAlertSummary", + "alerting:1.0.0-zeta1:alert-type/my-feature/rule/find", + "alerting:1.0.0-zeta1:alert-type/my-feature/rule/create", + "alerting:1.0.0-zeta1:alert-type/my-feature/rule/delete", + "alerting:1.0.0-zeta1:alert-type/my-feature/rule/update", + "alerting:1.0.0-zeta1:alert-type/my-feature/rule/updateApiKey", + "alerting:1.0.0-zeta1:alert-type/my-feature/rule/enable", + "alerting:1.0.0-zeta1:alert-type/my-feature/rule/disable", + "alerting:1.0.0-zeta1:alert-type/my-feature/rule/muteAll", + "alerting:1.0.0-zeta1:alert-type/my-feature/rule/unmuteAll", + "alerting:1.0.0-zeta1:alert-type/my-feature/rule/muteAlert", + "alerting:1.0.0-zeta1:alert-type/my-feature/rule/unmuteAlert", + "alerting:1.0.0-zeta1:alert-type/my-feature/alert/get", + "alerting:1.0.0-zeta1:alert-type/my-feature/alert/find", + "alerting:1.0.0-zeta1:alert-type/my-feature/alert/update", + ] + `); + }); + + test('grants both `all` and `read` to rules privileges under feature consumer', () => { + const actions = new Actions(version); + const alertingFeaturePrivileges = new FeaturePrivilegeAlertingBuilder(actions); + + const privilege: FeatureKibanaPrivileges = { + alerting: { + rule: { + all: ['alert-type'], + read: ['readonly-alert-type'], + }, + }, + + savedObject: { + all: [], + read: [], + }, + ui: [], + }; + + const feature = new KibanaFeature({ + id: 'my-feature', + name: 'my-feature', + app: [], + category: { id: 'foo', label: 'foo' }, + privileges: { + all: privilege, + read: privilege, + }, + }); + + expect(alertingFeaturePrivileges.getActions(privilege, feature)).toMatchInlineSnapshot(` + Array [ + "alerting:1.0.0-zeta1:alert-type/my-feature/rule/get", + "alerting:1.0.0-zeta1:alert-type/my-feature/rule/getRuleState", + "alerting:1.0.0-zeta1:alert-type/my-feature/rule/getAlertSummary", + "alerting:1.0.0-zeta1:alert-type/my-feature/rule/find", + "alerting:1.0.0-zeta1:alert-type/my-feature/rule/create", + "alerting:1.0.0-zeta1:alert-type/my-feature/rule/delete", + "alerting:1.0.0-zeta1:alert-type/my-feature/rule/update", + "alerting:1.0.0-zeta1:alert-type/my-feature/rule/updateApiKey", + "alerting:1.0.0-zeta1:alert-type/my-feature/rule/enable", + "alerting:1.0.0-zeta1:alert-type/my-feature/rule/disable", + "alerting:1.0.0-zeta1:alert-type/my-feature/rule/muteAll", + "alerting:1.0.0-zeta1:alert-type/my-feature/rule/unmuteAll", + "alerting:1.0.0-zeta1:alert-type/my-feature/rule/muteAlert", + "alerting:1.0.0-zeta1:alert-type/my-feature/rule/unmuteAlert", + "alerting:1.0.0-zeta1:readonly-alert-type/my-feature/rule/get", + "alerting:1.0.0-zeta1:readonly-alert-type/my-feature/rule/getRuleState", + "alerting:1.0.0-zeta1:readonly-alert-type/my-feature/rule/getAlertSummary", + "alerting:1.0.0-zeta1:readonly-alert-type/my-feature/rule/find", + ] + `); + }); + + test('grants both `all` and `read` to alerts privileges under feature consumer', () => { + const actions = new Actions(version); + const alertingFeaturePrivileges = new FeaturePrivilegeAlertingBuilder(actions); + + const privilege: FeatureKibanaPrivileges = { + alerting: { + alert: { + all: ['alert-type'], + read: ['readonly-alert-type'], + }, + }, + + savedObject: { + all: [], + read: [], + }, + ui: [], + }; + + const feature = new KibanaFeature({ + id: 'my-feature', + name: 'my-feature', + app: [], + category: { id: 'foo', label: 'foo' }, + privileges: { + all: privilege, + read: privilege, + }, + }); + + expect(alertingFeaturePrivileges.getActions(privilege, feature)).toMatchInlineSnapshot(` + Array [ + "alerting:1.0.0-zeta1:alert-type/my-feature/alert/get", + "alerting:1.0.0-zeta1:alert-type/my-feature/alert/find", + "alerting:1.0.0-zeta1:alert-type/my-feature/alert/update", + "alerting:1.0.0-zeta1:readonly-alert-type/my-feature/alert/get", + "alerting:1.0.0-zeta1:readonly-alert-type/my-feature/alert/find", + ] + `); + }); + + test('grants both `all` and `read` to rules and alerts privileges under feature consumer', () => { + const actions = new Actions(version); + const alertingFeaturePrivileges = new FeaturePrivilegeAlertingBuilder(actions); + + const privilege: FeatureKibanaPrivileges = { + alerting: { + rule: { + all: ['alert-type'], + read: ['readonly-alert-type'], + }, + alert: { + all: ['another-alert-type'], + read: ['readonly-alert-type'], + }, + }, + + savedObject: { + all: [], + read: [], + }, + ui: [], + }; + + const feature = new KibanaFeature({ + id: 'my-feature', + name: 'my-feature', + app: [], + category: { id: 'foo', label: 'foo' }, + privileges: { + all: privilege, + read: privilege, + }, + }); + + expect(alertingFeaturePrivileges.getActions(privilege, feature)).toMatchInlineSnapshot(` + Array [ + "alerting:1.0.0-zeta1:alert-type/my-feature/rule/get", + "alerting:1.0.0-zeta1:alert-type/my-feature/rule/getRuleState", + "alerting:1.0.0-zeta1:alert-type/my-feature/rule/getAlertSummary", + "alerting:1.0.0-zeta1:alert-type/my-feature/rule/find", + "alerting:1.0.0-zeta1:alert-type/my-feature/rule/create", + "alerting:1.0.0-zeta1:alert-type/my-feature/rule/delete", + "alerting:1.0.0-zeta1:alert-type/my-feature/rule/update", + "alerting:1.0.0-zeta1:alert-type/my-feature/rule/updateApiKey", + "alerting:1.0.0-zeta1:alert-type/my-feature/rule/enable", + "alerting:1.0.0-zeta1:alert-type/my-feature/rule/disable", + "alerting:1.0.0-zeta1:alert-type/my-feature/rule/muteAll", + "alerting:1.0.0-zeta1:alert-type/my-feature/rule/unmuteAll", + "alerting:1.0.0-zeta1:alert-type/my-feature/rule/muteAlert", + "alerting:1.0.0-zeta1:alert-type/my-feature/rule/unmuteAlert", + "alerting:1.0.0-zeta1:readonly-alert-type/my-feature/rule/get", + "alerting:1.0.0-zeta1:readonly-alert-type/my-feature/rule/getRuleState", + "alerting:1.0.0-zeta1:readonly-alert-type/my-feature/rule/getAlertSummary", + "alerting:1.0.0-zeta1:readonly-alert-type/my-feature/rule/find", + "alerting:1.0.0-zeta1:another-alert-type/my-feature/alert/get", + "alerting:1.0.0-zeta1:another-alert-type/my-feature/alert/find", + "alerting:1.0.0-zeta1:another-alert-type/my-feature/alert/update", + "alerting:1.0.0-zeta1:readonly-alert-type/my-feature/alert/get", + "alerting:1.0.0-zeta1:readonly-alert-type/my-feature/alert/find", + ] + `); + }); }); }); }); diff --git a/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/alerting.ts b/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/alerting.ts index 1d0a2b0e12943..f536959a910cd 100644 --- a/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/alerting.ts +++ b/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/alerting.ts @@ -5,22 +5,22 @@ * 2.0. */ -import { uniq } from 'lodash'; +import { get, uniq } from 'lodash'; import type { FeatureKibanaPrivileges, KibanaFeature } from '../../../../../features/server'; import { BaseFeaturePrivilegeBuilder } from './feature_privilege_builder'; -enum AlertingType { +enum AlertingEntity { RULE = 'rule', ALERT = 'alert', } -const readOperations: Record = { +const readOperations: Record = { rule: ['get', 'getRuleState', 'getAlertSummary', 'find'], alert: ['get', 'find'], }; -const writeOperations: Record = { +const writeOperations: Record = { rule: [ 'create', 'delete', @@ -35,7 +35,7 @@ const writeOperations: Record = { ], alert: ['update'], }; -const allOperations: Record = { +const allOperations: Record = { rule: [...readOperations.rule, ...writeOperations.rule], alert: [...readOperations.alert, ...writeOperations.alert], }; @@ -46,21 +46,30 @@ export class FeaturePrivilegeAlertingBuilder extends BaseFeaturePrivilegeBuilder feature: KibanaFeature ): string[] { const getAlertingPrivilege = ( - operations: Record, + operations: string[], privilegedTypes: readonly string[], + alertingEntity: string, consumer: string ) => - privilegedTypes.flatMap((privilegedType) => - Object.values(AlertingType).flatMap((alertingType) => - operations[alertingType].map((operation) => - this.actions.alerting.get(privilegedType, consumer, alertingType, operation) - ) + privilegedTypes.flatMap((type) => + operations.map((operation) => + this.actions.alerting.get(type, consumer, alertingEntity, operation) ) ); + const getPrivilegesForEntity = (entity: AlertingEntity) => { + const all = get(privilegeDefinition.alerting, `${entity}.all`) ?? []; + const read = get(privilegeDefinition.alerting, `${entity}.read`) ?? []; + + return uniq([ + ...getAlertingPrivilege(allOperations[entity], all, entity, feature.id), + ...getAlertingPrivilege(readOperations[entity], read, entity, feature.id), + ]); + }; + return uniq([ - ...getAlertingPrivilege(allOperations, privilegeDefinition.alerting?.all ?? [], feature.id), - ...getAlertingPrivilege(readOperations, privilegeDefinition.alerting?.read ?? [], feature.id), + ...getPrivilegesForEntity(AlertingEntity.RULE), + ...getPrivilegesForEntity(AlertingEntity.ALERT), ]); } } diff --git a/x-pack/plugins/security_solution/server/plugin.ts b/x-pack/plugins/security_solution/server/plugin.ts index 72db0be6ce278..aa37a0dc1f627 100644 --- a/x-pack/plugins/security_solution/server/plugin.ts +++ b/x-pack/plugins/security_solution/server/plugin.ts @@ -239,7 +239,12 @@ export class Plugin implements IPlugin { const featuresSetup = featuresPluginMock.createSetup(); await plugin.setup(coreSetup, { alerting: alertingSetup, features: featuresSetup }); - const typesInFeaturePrivilege = BUILT_IN_ALERTS_FEATURE.alerting; - const typesInFeaturePrivilegeAll = BUILT_IN_ALERTS_FEATURE.privileges.all.alerting.all; - const typesInFeaturePrivilegeRead = BUILT_IN_ALERTS_FEATURE.privileges.read.alerting.read; + const typesInFeaturePrivilege = BUILT_IN_ALERTS_FEATURE.alerting ?? []; + const typesInFeaturePrivilegeAll = + BUILT_IN_ALERTS_FEATURE.privileges?.all?.alerting?.rule?.all ?? []; + const typesInFeaturePrivilegeRead = + BUILT_IN_ALERTS_FEATURE.privileges?.read?.alerting?.rule?.read ?? []; expect(alertingSetup.registerType.mock.calls.length).toEqual(typesInFeaturePrivilege.length); expect(alertingSetup.registerType.mock.calls.length).toEqual(typesInFeaturePrivilegeAll.length); expect(alertingSetup.registerType.mock.calls.length).toEqual( diff --git a/x-pack/plugins/stack_alerts/server/feature.ts b/x-pack/plugins/stack_alerts/server/feature.ts index e168ec21438c0..70e68c2b7ced3 100644 --- a/x-pack/plugins/stack_alerts/server/feature.ts +++ b/x-pack/plugins/stack_alerts/server/feature.ts @@ -6,13 +6,14 @@ */ import { i18n } from '@kbn/i18n'; +import { KibanaFeatureConfig } from '../../../plugins/features/common'; import { ID as IndexThreshold } from './alert_types/index_threshold/alert_type'; import { GEO_CONTAINMENT_ID as GeoContainment } from './alert_types/geo_containment/alert_type'; import { ES_QUERY_ID as ElasticsearchQuery } from './alert_types/es_query/alert_type'; import { STACK_ALERTS_FEATURE_ID } from '../common'; import { DEFAULT_APP_CATEGORIES } from '../../../../src/core/server'; -export const BUILT_IN_ALERTS_FEATURE = { +export const BUILT_IN_ALERTS_FEATURE: KibanaFeatureConfig = { id: STACK_ALERTS_FEATURE_ID, name: i18n.translate('xpack.stackAlerts.featureRegistry.actionsFeatureName', { defaultMessage: 'Stack Rules', @@ -31,8 +32,12 @@ export const BUILT_IN_ALERTS_FEATURE = { insightsAndAlerting: ['triggersActions'], }, alerting: { - all: [IndexThreshold, GeoContainment, ElasticsearchQuery], - read: [], + rule: { + all: [IndexThreshold, GeoContainment, ElasticsearchQuery], + }, + alert: { + all: [IndexThreshold, GeoContainment, ElasticsearchQuery], + }, }, savedObject: { all: [], @@ -48,8 +53,12 @@ export const BUILT_IN_ALERTS_FEATURE = { insightsAndAlerting: ['triggersActions'], }, alerting: { - all: [], - read: [IndexThreshold, GeoContainment, ElasticsearchQuery], + rule: { + read: [IndexThreshold, GeoContainment, ElasticsearchQuery], + }, + alert: { + read: [IndexThreshold, GeoContainment, ElasticsearchQuery], + }, }, savedObject: { all: [], diff --git a/x-pack/plugins/uptime/server/kibana.index.ts b/x-pack/plugins/uptime/server/kibana.index.ts index 0afe804de9717..82ba70155608c 100644 --- a/x-pack/plugins/uptime/server/kibana.index.ts +++ b/x-pack/plugins/uptime/server/kibana.index.ts @@ -50,7 +50,12 @@ export const initServerWithKibana = (server: UptimeCoreSetup, plugins: UptimeCor read: [], }, alerting: { - all: ['xpack.uptime.alerts.tls', 'xpack.uptime.alerts.monitorStatus'], + rule: { + all: ['xpack.uptime.alerts.tls', 'xpack.uptime.alerts.monitorStatus'], + }, + alert: { + all: ['xpack.uptime.alerts.tls', 'xpack.uptime.alerts.monitorStatus'], + }, }, management: { insightsAndAlerting: ['triggersActions'], @@ -66,7 +71,12 @@ export const initServerWithKibana = (server: UptimeCoreSetup, plugins: UptimeCor read: [umDynamicSettings.name], }, alerting: { - read: ['xpack.uptime.alerts.tls', 'xpack.uptime.alerts.monitorStatus'], + rule: { + read: ['xpack.uptime.alerts.tls', 'xpack.uptime.alerts.monitorStatus'], + }, + alert: { + read: ['xpack.uptime.alerts.tls', 'xpack.uptime.alerts.monitorStatus'], + }, }, management: { insightsAndAlerting: ['triggersActions'], diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/server/plugin.ts b/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/server/plugin.ts index 9a7cd8d333b44..e98b7af075d64 100644 --- a/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/server/plugin.ts +++ b/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/server/plugin.ts @@ -69,21 +69,23 @@ export class FixturePlugin implements Plugin Date: Thu, 27 May 2021 20:10:01 +0100 Subject: [PATCH 39/77] Remove / Consolidate legacy usage adoption metrics (#100480) * Remove legacydetection rule stat summaries * Remove ML usage summary and consolidate with ML metric telemetry. * Remove ML usage summary and consolidate with ML metric telemetry. * Move legacy helper constructs into index. * Separate rule logic from ml logic. Add ml unit tests. * Abstract types away into their own file. * Update telemetry schema. Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../server/usage/collector.ts | 338 +++++++-------- .../detections/detection_ml_helpers.test.ts | 74 ++++ .../usage/detections/detection_ml_helpers.ts | 175 ++++++++ ...test.ts => detection_rule_helpers.test.ts} | 4 +- ...s_helpers.ts => detection_rule_helpers.ts} | 104 +---- .../detections/detection_telemetry_helpers.ts | 46 -- .../usage/detections/detections.mocks.ts | 16 - .../usage/detections/detections.test.ts | 197 +++------ .../detections/detections_usage_helpers.ts | 191 -------- .../server/usage/detections/index.ts | 159 +------ .../server/usage/detections/types.ts | 162 +++++++ .../schema/xpack_plugins.json | 408 ++++++++---------- 12 files changed, 838 insertions(+), 1036 deletions(-) create mode 100644 x-pack/plugins/security_solution/server/usage/detections/detection_ml_helpers.test.ts create mode 100644 x-pack/plugins/security_solution/server/usage/detections/detection_ml_helpers.ts rename x-pack/plugins/security_solution/server/usage/detections/{dectections_metrics_helpers.test.ts => detection_rule_helpers.test.ts} (98%) rename x-pack/plugins/security_solution/server/usage/detections/{detections_metrics_helpers.ts => detection_rule_helpers.ts} (68%) delete mode 100644 x-pack/plugins/security_solution/server/usage/detections/detection_telemetry_helpers.ts delete mode 100644 x-pack/plugins/security_solution/server/usage/detections/detections_usage_helpers.ts create mode 100644 x-pack/plugins/security_solution/server/usage/detections/types.ts diff --git a/x-pack/plugins/security_solution/server/usage/collector.ts b/x-pack/plugins/security_solution/server/usage/collector.ts index 3db1e7034c5e4..204da762bba8f 100644 --- a/x-pack/plugins/security_solution/server/usage/collector.ts +++ b/x-pack/plugins/security_solution/server/usage/collector.ts @@ -8,17 +8,11 @@ import { CoreSetup, SavedObjectsClientContract } from '../../../../../src/core/server'; import { CollectorFetchContext } from '../../../../../src/plugins/usage_collection/server'; import { CollectorDependencies } from './types'; -import { - DetectionsUsage, - fetchDetectionsUsage, - defaultDetectionsUsage, - fetchDetectionsMetrics, -} from './detections'; +import { fetchDetectionsMetrics } from './detections'; import { EndpointUsage, getEndpointTelemetryFromFleet } from './endpoints'; export type RegisterCollector = (deps: CollectorDependencies) => void; export interface UsageData { - detections: DetectionsUsage; endpoints: EndpointUsage | {}; detectionMetrics: {}; } @@ -40,55 +34,10 @@ export const registerCollector: RegisterCollector = ({ if (!usageCollection) { return; } + const collector = usageCollection.makeUsageCollector({ type: 'security_solution', schema: { - detections: { - detection_rules: { - custom: { - enabled: { - type: 'long', - _meta: { description: 'The number of custom detection rules enabled' }, - }, - disabled: { - type: 'long', - _meta: { description: 'The number of custom detection rules disabled' }, - }, - }, - elastic: { - enabled: { - type: 'long', - _meta: { description: 'The number of elastic prebuilt detection rules enabled' }, - }, - disabled: { - type: 'long', - _meta: { description: 'The number of elastic prebuilt detection rules disabled' }, - }, - }, - }, - ml_jobs: { - custom: { - enabled: { - type: 'long', - _meta: { description: 'The number of custom ML jobs rules enabled' }, - }, - disabled: { - type: 'long', - _meta: { description: 'The number of custom ML jobs rules disabled' }, - }, - }, - elastic: { - enabled: { - type: 'long', - _meta: { description: 'The number of elastic provided ML jobs rules enabled' }, - }, - disabled: { - type: 'long', - _meta: { description: 'The number of elastic provided ML jobs rules disabled' }, - }, - }, - }, - }, detectionMetrics: { detection_rules: { detection_rule_usage: { @@ -248,172 +197,199 @@ export const registerCollector: RegisterCollector = ({ }, }, ml_jobs: { - type: 'array', - items: { - job_id: { - type: 'keyword', - _meta: { description: 'Identifier for the anomaly detection job' }, - }, - open_time: { - type: 'keyword', - _meta: { - description: 'For open jobs only, the elapsed time for which the job has been open', - }, - }, - create_time: { - type: 'keyword', - _meta: { description: 'The time the job was created' }, - }, - finished_time: { - type: 'keyword', - _meta: { - description: 'If the job closed or failed, this is the time the job finished', - }, - }, - state: { - type: 'keyword', - _meta: { description: 'The status of the anomaly detection job' }, - }, - data_counts: { - bucket_count: { + ml_job_usage: { + custom: { + enabled: { type: 'long', - _meta: { description: 'The number of buckets processed' }, + _meta: { description: 'The number of custom ML jobs rules enabled' }, }, - empty_bucket_count: { + disabled: { type: 'long', - _meta: { description: 'The number of buckets which did not contain any data' }, + _meta: { description: 'The number of custom ML jobs rules disabled' }, }, - input_bytes: { + }, + elastic: { + enabled: { type: 'long', - _meta: { - description: - 'The number of bytes of input data posted to the anomaly detection job', - }, + _meta: { description: 'The number of elastic provided ML jobs rules enabled' }, }, - input_record_count: { + disabled: { type: 'long', - _meta: { - description: 'The number of input documents posted to the anomaly detection job', - }, + _meta: { description: 'The number of elastic provided ML jobs rules disabled' }, }, - last_data_time: { - type: 'long', - _meta: { - description: - 'The timestamp at which data was last analyzed, according to server time', - }, + }, + }, + ml_job_metrics: { + type: 'array', + items: { + job_id: { + type: 'keyword', + _meta: { description: 'Identifier for the anomaly detection job' }, }, - processed_record_count: { - type: 'long', + open_time: { + type: 'keyword', _meta: { description: - 'The number of input documents that have been processed by the anomaly detection job', + 'For open jobs only, the elapsed time for which the job has been open', }, }, - }, - model_size_stats: { - bucket_allocation_failures_count: { - type: 'long', + create_time: { + type: 'keyword', + _meta: { description: 'The time the job was created' }, + }, + finished_time: { + type: 'keyword', _meta: { - description: - 'The number of buckets for which new entities in incoming data were not processed due to insufficient model memory', + description: 'If the job closed or failed, this is the time the job finished', }, }, - model_bytes: { - type: 'long', - _meta: { description: 'The number of bytes of memory used by the models' }, + state: { + type: 'keyword', + _meta: { description: 'The status of the anomaly detection job' }, }, - model_bytes_exceeded: { - type: 'long', - _meta: { - description: - 'The number of bytes over the high limit for memory usage at the last allocation failure', + data_counts: { + bucket_count: { + type: 'long', + _meta: { description: 'The number of buckets processed' }, }, - }, - model_bytes_memory_limit: { - type: 'long', - _meta: { - description: - 'The upper limit for model memory usage, checked on increasing values', + empty_bucket_count: { + type: 'long', + _meta: { description: 'The number of buckets which did not contain any data' }, }, - }, - peak_model_bytes: { - type: 'long', - _meta: { - description: 'The peak number of bytes of memory ever used by the models', + input_bytes: { + type: 'long', + _meta: { + description: + 'The number of bytes of input data posted to the anomaly detection job', + }, }, - }, - }, - timing_stats: { - bucket_count: { - type: 'long', - _meta: { description: 'The number of buckets processed' }, - }, - exponential_average_bucket_processing_time_ms: { - type: 'long', - _meta: { - description: - 'Exponential moving average of all bucket processing times, in milliseconds', + input_record_count: { + type: 'long', + _meta: { + description: + 'The number of input documents posted to the anomaly detection job', + }, }, - }, - exponential_average_bucket_processing_time_per_hour_ms: { - type: 'long', - _meta: { - description: - 'Exponentially-weighted moving average of bucket processing times calculated in a 1 hour time window, in milliseconds', + last_data_time: { + type: 'long', + _meta: { + description: + 'The timestamp at which data was last analyzed, according to server time', + }, }, - }, - maximum_bucket_processing_time_ms: { - type: 'long', - _meta: { - description: 'Maximum among all bucket processing times, in milliseconds', + processed_record_count: { + type: 'long', + _meta: { + description: + 'The number of input documents that have been processed by the anomaly detection job', + }, }, }, - minimum_bucket_processing_time_ms: { - type: 'long', - _meta: { - description: 'Minimum among all bucket processing times, in milliseconds', + model_size_stats: { + bucket_allocation_failures_count: { + type: 'long', + _meta: { + description: + 'The number of buckets for which new entities in incoming data were not processed due to insufficient model memory', + }, }, - }, - total_bucket_processing_time_ms: { - type: 'long', - _meta: { description: 'Sum of all bucket processing times, in milliseconds' }, - }, - }, - datafeed: { - datafeed_id: { - type: 'keyword', - _meta: { - description: 'A numerical character string that uniquely identifies the datafeed', + model_bytes: { + type: 'long', + _meta: { description: 'The number of bytes of memory used by the models' }, }, - }, - state: { - type: 'keyword', - _meta: { description: 'The status of the datafeed' }, - }, - timing_stats: { - average_search_time_per_bucket_ms: { + model_bytes_exceeded: { + type: 'long', + _meta: { + description: + 'The number of bytes over the high limit for memory usage at the last allocation failure', + }, + }, + model_bytes_memory_limit: { + type: 'long', + _meta: { + description: + 'The upper limit for model memory usage, checked on increasing values', + }, + }, + peak_model_bytes: { type: 'long', - _meta: { description: 'The average search time per bucket, in milliseconds' }, + _meta: { + description: 'The peak number of bytes of memory ever used by the models', + }, }, + }, + timing_stats: { bucket_count: { type: 'long', _meta: { description: 'The number of buckets processed' }, }, - exponential_average_search_time_per_hour_ms: { + exponential_average_bucket_processing_time_ms: { + type: 'long', + _meta: { + description: + 'Exponential moving average of all bucket processing times, in milliseconds', + }, + }, + exponential_average_bucket_processing_time_per_hour_ms: { type: 'long', _meta: { - description: 'The exponential average search time per hour, in milliseconds', + description: + 'Exponentially-weighted moving average of bucket processing times calculated in a 1 hour time window, in milliseconds', }, }, - search_count: { + maximum_bucket_processing_time_ms: { type: 'long', - _meta: { description: 'The number of searches run by the datafeed' }, + _meta: { + description: 'Maximum among all bucket processing times, in milliseconds', + }, + }, + minimum_bucket_processing_time_ms: { + type: 'long', + _meta: { + description: 'Minimum among all bucket processing times, in milliseconds', + }, }, - total_search_time_ms: { + total_bucket_processing_time_ms: { type: 'long', + _meta: { description: 'Sum of all bucket processing times, in milliseconds' }, + }, + }, + datafeed: { + datafeed_id: { + type: 'keyword', _meta: { - description: 'The total time the datafeed spent searching, in milliseconds', + description: + 'A numerical character string that uniquely identifies the datafeed', + }, + }, + state: { + type: 'keyword', + _meta: { description: 'The status of the datafeed' }, + }, + timing_stats: { + average_search_time_per_bucket_ms: { + type: 'long', + _meta: { description: 'The average search time per bucket, in milliseconds' }, + }, + bucket_count: { + type: 'long', + _meta: { description: 'The number of buckets processed' }, + }, + exponential_average_search_time_per_hour_ms: { + type: 'long', + _meta: { + description: 'The exponential average search time per hour, in milliseconds', + }, + }, + search_count: { + type: 'long', + _meta: { description: 'The number of searches run by the datafeed' }, + }, + total_search_time_ms: { + type: 'long', + _meta: { + description: 'The total time the datafeed spent searching, in milliseconds', + }, }, }, }, @@ -476,14 +452,12 @@ export const registerCollector: RegisterCollector = ({ fetch: async ({ esClient }: CollectorFetchContext): Promise => { const internalSavedObjectsClient = await getInternalSavedObjectsClient(core); const savedObjectsClient = (internalSavedObjectsClient as unknown) as SavedObjectsClientContract; - const [detections, detectionMetrics, endpoints] = await Promise.allSettled([ - fetchDetectionsUsage(kibanaIndex, esClient, ml, savedObjectsClient), + const [detectionMetrics, endpoints] = await Promise.allSettled([ fetchDetectionsMetrics(kibanaIndex, signalsIndex, esClient, ml, savedObjectsClient), getEndpointTelemetryFromFleet(savedObjectsClient, endpointAppContext, esClient), ]); return { - detections: detections.status === 'fulfilled' ? detections.value : defaultDetectionsUsage, detectionMetrics: detectionMetrics.status === 'fulfilled' ? detectionMetrics.value : {}, endpoints: endpoints.status === 'fulfilled' ? endpoints.value : {}, }; diff --git a/x-pack/plugins/security_solution/server/usage/detections/detection_ml_helpers.test.ts b/x-pack/plugins/security_solution/server/usage/detections/detection_ml_helpers.test.ts new file mode 100644 index 0000000000000..3ca0faeca7d36 --- /dev/null +++ b/x-pack/plugins/security_solution/server/usage/detections/detection_ml_helpers.test.ts @@ -0,0 +1,74 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { initialMlJobsUsage, updateMlJobsUsage } from './detection_ml_helpers'; + +describe('Security Machine Learning usage metrics', () => { + describe('Updates metrics with job information', () => { + it('Should update ML total for elastic rules', async () => { + const initialUsage = initialMlJobsUsage; + const isElastic = true; + const isEnabled = true; + + const updatedUsage = updateMlJobsUsage({ isElastic, isEnabled }, initialUsage); + + expect(updatedUsage).toEqual( + expect.objectContaining({ + custom: { + disabled: 0, + enabled: 0, + }, + elastic: { + disabled: 0, + enabled: 1, + }, + }) + ); + }); + + it('Should update ML total for custom rules', async () => { + const initialUsage = initialMlJobsUsage; + const isElastic = false; + const isEnabled = true; + + const updatedUsage = updateMlJobsUsage({ isElastic, isEnabled }, initialUsage); + + expect(updatedUsage).toEqual( + expect.objectContaining({ + custom: { + disabled: 0, + enabled: 1, + }, + elastic: { + disabled: 0, + enabled: 0, + }, + }) + ); + }); + + it('Should update ML total for both elastic and custom rules', async () => { + const initialUsage = initialMlJobsUsage; + + let updatedUsage = updateMlJobsUsage({ isElastic: true, isEnabled: true }, initialUsage); + updatedUsage = updateMlJobsUsage({ isElastic: false, isEnabled: true }, updatedUsage); + + expect(updatedUsage).toEqual( + expect.objectContaining({ + custom: { + disabled: 0, + enabled: 1, + }, + elastic: { + disabled: 0, + enabled: 1, + }, + }) + ); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/server/usage/detections/detection_ml_helpers.ts b/x-pack/plugins/security_solution/server/usage/detections/detection_ml_helpers.ts new file mode 100644 index 0000000000000..f9571b98c9d59 --- /dev/null +++ b/x-pack/plugins/security_solution/server/usage/detections/detection_ml_helpers.ts @@ -0,0 +1,175 @@ +/* + * 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 { KibanaRequest, SavedObjectsClientContract } from '../../../../../../src/core/server'; +import { DatafeedStats, Job, MlPluginSetup } from '../../../../ml/server'; +import { isJobStarted } from '../../../common/machine_learning/helpers'; +import { isSecurityJob } from '../../../common/machine_learning/is_security_job'; +import { DetectionsMetric, MlJobMetric, MlJobsUsage, MlJobUsage } from './types'; + +/** + * Default ml job usage count + */ +export const initialMlJobsUsage: MlJobsUsage = { + custom: { + enabled: 0, + disabled: 0, + }, + elastic: { + enabled: 0, + disabled: 0, + }, +}; + +export const updateMlJobsUsage = (jobMetric: DetectionsMetric, usage: MlJobsUsage): MlJobsUsage => { + const { isEnabled, isElastic } = jobMetric; + if (isEnabled && isElastic) { + return { + ...usage, + elastic: { + ...usage.elastic, + enabled: usage.elastic.enabled + 1, + }, + }; + } else if (!isEnabled && isElastic) { + return { + ...usage, + elastic: { + ...usage.elastic, + disabled: usage.elastic.disabled + 1, + }, + }; + } else if (isEnabled && !isElastic) { + return { + ...usage, + custom: { + ...usage.custom, + enabled: usage.custom.enabled + 1, + }, + }; + } else if (!isEnabled && !isElastic) { + return { + ...usage, + custom: { + ...usage.custom, + disabled: usage.custom.disabled + 1, + }, + }; + } else { + return usage; + } +}; + +export const getMlJobMetrics = async ( + ml: MlPluginSetup | undefined, + savedObjectClient: SavedObjectsClientContract +): Promise => { + let jobsUsage: MlJobsUsage = initialMlJobsUsage; + + if (ml) { + try { + const fakeRequest = { headers: {} } as KibanaRequest; + + const modules = await ml.modulesProvider(fakeRequest, savedObjectClient).listModules(); + const moduleJobs = modules.flatMap((module) => module.jobs); + const jobs = await ml.jobServiceProvider(fakeRequest, savedObjectClient).jobsSummary(); + + jobsUsage = jobs.filter(isSecurityJob).reduce((usage, job) => { + const isElastic = moduleJobs.some((moduleJob) => moduleJob.id === job.id); + const isEnabled = isJobStarted(job.jobState, job.datafeedState); + + return updateMlJobsUsage({ isElastic, isEnabled }, usage); + }, initialMlJobsUsage); + + const jobsType = 'security'; + const securityJobStats = await ml + .anomalyDetectorsProvider(fakeRequest, savedObjectClient) + .jobStats(jobsType); + + const jobDetails = await ml + .anomalyDetectorsProvider(fakeRequest, savedObjectClient) + .jobs(jobsType); + + const jobDetailsCache = new Map(); + jobDetails.jobs.forEach((detail) => jobDetailsCache.set(detail.job_id, detail)); + + const datafeedStats = await ml + .anomalyDetectorsProvider(fakeRequest, savedObjectClient) + .datafeedStats(); + + const datafeedStatsCache = new Map(); + datafeedStats.datafeeds.forEach((datafeedStat) => + datafeedStatsCache.set(`${datafeedStat.datafeed_id}`, datafeedStat) + ); + + const jobMetrics: MlJobMetric[] = securityJobStats.jobs.map((stat) => { + const jobId = stat.job_id; + const jobDetail = jobDetailsCache.get(stat.job_id); + const datafeed = datafeedStatsCache.get(`datafeed-${jobId}`); + + return { + job_id: jobId, + open_time: stat.open_time, + create_time: jobDetail?.create_time, + finished_time: jobDetail?.finished_time, + state: stat.state, + data_counts: { + bucket_count: stat.data_counts.bucket_count, + empty_bucket_count: stat.data_counts.empty_bucket_count, + input_bytes: stat.data_counts.input_bytes, + input_record_count: stat.data_counts.input_record_count, + last_data_time: stat.data_counts.last_data_time, + processed_record_count: stat.data_counts.processed_record_count, + }, + model_size_stats: { + bucket_allocation_failures_count: + stat.model_size_stats.bucket_allocation_failures_count, + memory_status: stat.model_size_stats.memory_status, + model_bytes: stat.model_size_stats.model_bytes, + model_bytes_exceeded: stat.model_size_stats.model_bytes_exceeded, + model_bytes_memory_limit: stat.model_size_stats.model_bytes_memory_limit, + peak_model_bytes: stat.model_size_stats.peak_model_bytes, + }, + timing_stats: { + average_bucket_processing_time_ms: stat.timing_stats.average_bucket_processing_time_ms, + bucket_count: stat.timing_stats.bucket_count, + exponential_average_bucket_processing_time_ms: + stat.timing_stats.exponential_average_bucket_processing_time_ms, + exponential_average_bucket_processing_time_per_hour_ms: + stat.timing_stats.exponential_average_bucket_processing_time_per_hour_ms, + maximum_bucket_processing_time_ms: stat.timing_stats.maximum_bucket_processing_time_ms, + minimum_bucket_processing_time_ms: stat.timing_stats.minimum_bucket_processing_time_ms, + total_bucket_processing_time_ms: stat.timing_stats.total_bucket_processing_time_ms, + }, + datafeed: { + datafeed_id: datafeed?.datafeed_id, + state: datafeed?.state, + timing_stats: { + bucket_count: datafeed?.timing_stats.bucket_count, + exponential_average_search_time_per_hour_ms: + datafeed?.timing_stats.exponential_average_search_time_per_hour_ms, + search_count: datafeed?.timing_stats.search_count, + total_search_time_ms: datafeed?.timing_stats.total_search_time_ms, + }, + }, + } as MlJobMetric; + }); + + return { + ml_job_usage: jobsUsage, + ml_job_metrics: jobMetrics, + }; + } catch (e) { + // ignore failure, usage will be zeroed + } + } + + return { + ml_job_usage: initialMlJobsUsage, + ml_job_metrics: [], + }; +}; diff --git a/x-pack/plugins/security_solution/server/usage/detections/dectections_metrics_helpers.test.ts b/x-pack/plugins/security_solution/server/usage/detections/detection_rule_helpers.test.ts similarity index 98% rename from x-pack/plugins/security_solution/server/usage/detections/dectections_metrics_helpers.test.ts rename to x-pack/plugins/security_solution/server/usage/detections/detection_rule_helpers.test.ts index 55bd372e9dd79..d1846caf4ec22 100644 --- a/x-pack/plugins/security_solution/server/usage/detections/dectections_metrics_helpers.test.ts +++ b/x-pack/plugins/security_solution/server/usage/detections/detection_rule_helpers.test.ts @@ -5,8 +5,8 @@ * 2.0. */ -import { initialDetectionRulesUsage, updateDetectionRuleUsage } from './detections_metrics_helpers'; -import { DetectionRuleMetric, DetectionRulesTypeUsage } from './index'; +import { initialDetectionRulesUsage, updateDetectionRuleUsage } from './detection_rule_helpers'; +import { DetectionRuleMetric, DetectionRulesTypeUsage } from './types'; import { v4 as uuid } from 'uuid'; const createStubRule = ( diff --git a/x-pack/plugins/security_solution/server/usage/detections/detections_metrics_helpers.ts b/x-pack/plugins/security_solution/server/usage/detections/detection_rule_helpers.ts similarity index 68% rename from x-pack/plugins/security_solution/server/usage/detections/detections_metrics_helpers.ts rename to x-pack/plugins/security_solution/server/usage/detections/detection_rule_helpers.ts index a84ea108c5f12..ebcda69441135 100644 --- a/x-pack/plugins/security_solution/server/usage/detections/detections_metrics_helpers.ts +++ b/x-pack/plugins/security_solution/server/usage/detections/detection_rule_helpers.ts @@ -5,22 +5,18 @@ * 2.0. */ -import { - ElasticsearchClient, - KibanaRequest, - SavedObjectsClientContract, -} from '../../../../../../src/core/server'; +import { ElasticsearchClient, SavedObjectsClientContract } from '../../../../../../src/core/server'; +import { SIGNALS_ID } from '../../../common/constants'; +import { isElasticRule } from './index'; import { AlertsAggregationResponse, CasesSavedObject, DetectionRulesTypeUsage, DetectionRuleMetric, DetectionRuleAdoption, - MlJobMetric, -} from './index'; -import { SIGNALS_ID } from '../../../common/constants'; -import { DatafeedStats, Job, MlPluginSetup } from '../../../../ml/server'; -import { isElasticRule, RuleSearchParams, RuleSearchResult } from './detection_telemetry_helpers'; + RuleSearchParams, + RuleSearchResult, +} from './types'; /** * Default detection rule usage count, split by type + elastic/custom @@ -288,91 +284,3 @@ export const getDetectionRuleMetrics = async ( detection_rule_usage: rulesUsage, }; }; - -export const getMlJobMetrics = async ( - ml: MlPluginSetup | undefined, - savedObjectClient: SavedObjectsClientContract -): Promise => { - if (ml) { - try { - const fakeRequest = { headers: {} } as KibanaRequest; - const jobsType = 'security'; - const securityJobStats = await ml - .anomalyDetectorsProvider(fakeRequest, savedObjectClient) - .jobStats(jobsType); - - const jobDetails = await ml - .anomalyDetectorsProvider(fakeRequest, savedObjectClient) - .jobs(jobsType); - - const jobDetailsCache = new Map(); - jobDetails.jobs.forEach((detail) => jobDetailsCache.set(detail.job_id, detail)); - - const datafeedStats = await ml - .anomalyDetectorsProvider(fakeRequest, savedObjectClient) - .datafeedStats(); - - const datafeedStatsCache = new Map(); - datafeedStats.datafeeds.forEach((datafeedStat) => - datafeedStatsCache.set(`${datafeedStat.datafeed_id}`, datafeedStat) - ); - - return securityJobStats.jobs.map((stat) => { - const jobId = stat.job_id; - const jobDetail = jobDetailsCache.get(stat.job_id); - const datafeed = datafeedStatsCache.get(`datafeed-${jobId}`); - - return { - job_id: jobId, - open_time: stat.open_time, - create_time: jobDetail?.create_time, - finished_time: jobDetail?.finished_time, - state: stat.state, - data_counts: { - bucket_count: stat.data_counts.bucket_count, - empty_bucket_count: stat.data_counts.empty_bucket_count, - input_bytes: stat.data_counts.input_bytes, - input_record_count: stat.data_counts.input_record_count, - last_data_time: stat.data_counts.last_data_time, - processed_record_count: stat.data_counts.processed_record_count, - }, - model_size_stats: { - bucket_allocation_failures_count: - stat.model_size_stats.bucket_allocation_failures_count, - memory_status: stat.model_size_stats.memory_status, - model_bytes: stat.model_size_stats.model_bytes, - model_bytes_exceeded: stat.model_size_stats.model_bytes_exceeded, - model_bytes_memory_limit: stat.model_size_stats.model_bytes_memory_limit, - peak_model_bytes: stat.model_size_stats.peak_model_bytes, - }, - timing_stats: { - average_bucket_processing_time_ms: stat.timing_stats.average_bucket_processing_time_ms, - bucket_count: stat.timing_stats.bucket_count, - exponential_average_bucket_processing_time_ms: - stat.timing_stats.exponential_average_bucket_processing_time_ms, - exponential_average_bucket_processing_time_per_hour_ms: - stat.timing_stats.exponential_average_bucket_processing_time_per_hour_ms, - maximum_bucket_processing_time_ms: stat.timing_stats.maximum_bucket_processing_time_ms, - minimum_bucket_processing_time_ms: stat.timing_stats.minimum_bucket_processing_time_ms, - total_bucket_processing_time_ms: stat.timing_stats.total_bucket_processing_time_ms, - }, - datafeed: { - datafeed_id: datafeed?.datafeed_id, - state: datafeed?.state, - timing_stats: { - bucket_count: datafeed?.timing_stats.bucket_count, - exponential_average_search_time_per_hour_ms: - datafeed?.timing_stats.exponential_average_search_time_per_hour_ms, - search_count: datafeed?.timing_stats.search_count, - total_search_time_ms: datafeed?.timing_stats.total_search_time_ms, - }, - }, - } as MlJobMetric; - }); - } catch (e) { - // ignore failure, usage will be zeroed - } - } - - return []; -}; diff --git a/x-pack/plugins/security_solution/server/usage/detections/detection_telemetry_helpers.ts b/x-pack/plugins/security_solution/server/usage/detections/detection_telemetry_helpers.ts deleted file mode 100644 index bc1e734e4cc3a..0000000000000 --- a/x-pack/plugins/security_solution/server/usage/detections/detection_telemetry_helpers.ts +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { INTERNAL_IMMUTABLE_KEY } from '../../../common/constants'; - -export const isElasticRule = (tags: string[] = []) => - tags.includes(`${INTERNAL_IMMUTABLE_KEY}:true`); - -interface RuleSearchBody { - query: { - bool: { - filter: { - term: { [key: string]: string }; - }; - }; - }; -} - -export interface RuleSearchParams { - body: RuleSearchBody; - filterPath: string[]; - ignoreUnavailable: boolean; - index: string; - size: number; -} - -export interface RuleSearchResult { - alert: { - name: string; - enabled: boolean; - tags: string[]; - createdAt: string; - updatedAt: string; - params: DetectionRuleParms; - }; -} - -interface DetectionRuleParms { - ruleId: string; - version: string; - type: string; -} diff --git a/x-pack/plugins/security_solution/server/usage/detections/detections.mocks.ts b/x-pack/plugins/security_solution/server/usage/detections/detections.mocks.ts index f90841ff4e596..c4ab55127f5d3 100644 --- a/x-pack/plugins/security_solution/server/usage/detections/detections.mocks.ts +++ b/x-pack/plugins/security_solution/server/usage/detections/detections.mocks.ts @@ -5,8 +5,6 @@ * 2.0. */ -import { INTERNAL_IMMUTABLE_KEY } from '../../../common/constants'; - export const getMockJobSummaryResponse = () => [ { id: 'linux_anomalous_network_activity_ecs', @@ -162,20 +160,6 @@ export const getMockListModulesResponse = () => [ }, ]; -export const getMockRulesResponse = () => ({ - hits: { - hits: [ - { _source: { alert: { enabled: true, tags: [`${INTERNAL_IMMUTABLE_KEY}:true`] } } }, - { _source: { alert: { enabled: true, tags: [`${INTERNAL_IMMUTABLE_KEY}:false`] } } }, - { _source: { alert: { enabled: false, tags: [`${INTERNAL_IMMUTABLE_KEY}:true`] } } }, - { _source: { alert: { enabled: true, tags: [`${INTERNAL_IMMUTABLE_KEY}:true`] } } }, - { _source: { alert: { enabled: false, tags: [`${INTERNAL_IMMUTABLE_KEY}:false`] } } }, - { _source: { alert: { enabled: false, tags: [`${INTERNAL_IMMUTABLE_KEY}:true`] } } }, - { _source: { alert: { enabled: false, tags: [`${INTERNAL_IMMUTABLE_KEY}:true`] } } }, - ], - }, -}); - export const getMockMlJobDetailsResponse = () => ({ count: 20, jobs: [ diff --git a/x-pack/plugins/security_solution/server/usage/detections/detections.test.ts b/x-pack/plugins/security_solution/server/usage/detections/detections.test.ts index a020f49464007..7365c210172fe 100644 --- a/x-pack/plugins/security_solution/server/usage/detections/detections.test.ts +++ b/x-pack/plugins/security_solution/server/usage/detections/detections.test.ts @@ -11,10 +11,11 @@ import { savedObjectsClientMock, } from '../../../../../../src/core/server/mocks'; import { mlServicesMock } from '../../lib/machine_learning/mocks'; +import { fetchDetectionsMetrics } from './index'; +import { initialMlJobsUsage } from './detection_ml_helpers'; import { getMockJobSummaryResponse, getMockListModulesResponse, - getMockRulesResponse, getMockMlJobDetailsResponse, getMockMlJobStatsResponse, getMockMlDatafeedStatsResponse, @@ -22,7 +23,6 @@ import { getMockRuleAlertsResponse, getMockAlertCasesResponse, } from './detections.mocks'; -import { fetchDetectionsUsage, fetchDetectionsMetrics } from './index'; const savedObjectsClient = savedObjectsClientMock.create(); @@ -30,89 +30,6 @@ describe('Detections Usage and Metrics', () => { let esClientMock: jest.Mocked; let mlMock: ReturnType; - describe('fetchDetectionsUsage()', () => { - beforeEach(() => { - esClientMock = elasticsearchServiceMock.createClusterClient().asInternalUser; - mlMock = mlServicesMock.createSetupContract(); - }); - - it('returns zeroed counts if both calls are empty', async () => { - const result = await fetchDetectionsUsage('', esClientMock, mlMock, savedObjectsClient); - - expect(result).toEqual({ - detection_rules: { - custom: { - enabled: 0, - disabled: 0, - }, - elastic: { - enabled: 0, - disabled: 0, - }, - }, - ml_jobs: { - custom: { - enabled: 0, - disabled: 0, - }, - elastic: { - enabled: 0, - disabled: 0, - }, - }, - }); - }); - - it('tallies rules data given rules results', async () => { - (esClientMock.search as jest.Mock).mockResolvedValue({ body: getMockRulesResponse() }); - - const result = await fetchDetectionsUsage('', esClientMock, mlMock, savedObjectsClient); - - expect(result).toEqual( - expect.objectContaining({ - detection_rules: { - custom: { - enabled: 1, - disabled: 1, - }, - elastic: { - enabled: 2, - disabled: 3, - }, - }, - }) - ); - }); - - it('tallies jobs data given jobs results', async () => { - const mockJobSummary = jest.fn().mockResolvedValue(getMockJobSummaryResponse()); - const mockListModules = jest.fn().mockResolvedValue(getMockListModulesResponse()); - mlMock.modulesProvider.mockReturnValue(({ - listModules: mockListModules, - } as unknown) as ReturnType); - mlMock.jobServiceProvider.mockReturnValue({ - jobsSummary: mockJobSummary, - }); - - const result = await fetchDetectionsUsage('', esClientMock, mlMock, savedObjectsClient); - - expect(result).toEqual( - expect.objectContaining({ - ml_jobs: { - custom: { - enabled: 1, - disabled: 1, - }, - elastic: { - enabled: 1, - disabled: 1, - }, - }, - }) - ); - }); - }); - describe('getDetectionRuleMetrics()', () => { beforeEach(() => { esClientMock = elasticsearchServiceMock.createClusterClient().asInternalUser; @@ -171,7 +88,7 @@ describe('Detections Usage and Metrics', () => { }, }, }, - ml_jobs: [], + ml_jobs: { ml_job_metrics: [], ml_job_usage: initialMlJobsUsage }, }) ); }); @@ -246,7 +163,7 @@ describe('Detections Usage and Metrics', () => { }, }, }, - ml_jobs: [], + ml_jobs: { ml_job_metrics: [], ml_job_usage: initialMlJobsUsage }, }) ); }); @@ -308,7 +225,7 @@ describe('Detections Usage and Metrics', () => { }, }, }, - ml_jobs: [], + ml_jobs: { ml_job_metrics: [], ml_job_usage: initialMlJobsUsage }, }) ); }); @@ -383,7 +300,7 @@ describe('Detections Usage and Metrics', () => { }, }, }, - ml_jobs: [], + ml_jobs: { ml_job_metrics: [], ml_job_usage: initialMlJobsUsage }, }) ); }); @@ -404,12 +321,20 @@ describe('Detections Usage and Metrics', () => { expect(result).toEqual( expect.objectContaining({ - ml_jobs: [], + ml_jobs: { ml_job_metrics: [], ml_job_usage: initialMlJobsUsage }, }) ); }); it('returns an ml job telemetry object from anomaly detectors provider', async () => { + const mockJobSummary = jest.fn().mockResolvedValue(getMockJobSummaryResponse()); + const mockListModules = jest.fn().mockResolvedValue(getMockListModulesResponse()); + mlMock.modulesProvider.mockReturnValue(({ + listModules: mockListModules, + } as unknown) as ReturnType); + mlMock.jobServiceProvider.mockReturnValue({ + jobsSummary: mockJobSummary, + }); const mockJobsResponse = jest.fn().mockResolvedValue(getMockMlJobDetailsResponse()); const mockJobStatsResponse = jest.fn().mockResolvedValue(getMockMlJobStatsResponse()); const mockDatafeedStatsResponse = jest @@ -426,49 +351,61 @@ describe('Detections Usage and Metrics', () => { expect(result).toEqual( expect.objectContaining({ - ml_jobs: [ - { - job_id: 'high_distinct_count_error_message', - create_time: 1603838214983, - finished_time: 1611739871669, - state: 'closed', - data_counts: { - bucket_count: 8612, - empty_bucket_count: 8590, - input_bytes: 45957, - input_record_count: 162, - last_data_time: 1610470367123, - processed_record_count: 162, - }, - model_size_stats: { - bucket_allocation_failures_count: 0, - memory_status: 'ok', - model_bytes: 72574, - model_bytes_exceeded: 0, - model_bytes_memory_limit: 16777216, - peak_model_bytes: 78682, - }, - timing_stats: { - average_bucket_processing_time_ms: 0.4900837644740133, - bucket_count: 16236, - exponential_average_bucket_processing_time_ms: 0.23614068552903306, - exponential_average_bucket_processing_time_per_hour_ms: 1.5551298175461634, - maximum_bucket_processing_time_ms: 392, - minimum_bucket_processing_time_ms: 0, - total_bucket_processing_time_ms: 7957.00000000008, - }, - datafeed: { - datafeed_id: 'datafeed-high_distinct_count_error_message', - state: 'stopped', - timing_stats: { + ml_jobs: { + ml_job_usage: { + custom: { + disabled: 1, + enabled: 1, + }, + elastic: { + disabled: 1, + enabled: 1, + }, + }, + ml_job_metrics: [ + { + job_id: 'high_distinct_count_error_message', + create_time: 1603838214983, + finished_time: 1611739871669, + state: 'closed', + data_counts: { bucket_count: 8612, - exponential_average_search_time_per_hour_ms: 86145.39799630083, - search_count: 7202, - total_search_time_ms: 3107147, + empty_bucket_count: 8590, + input_bytes: 45957, + input_record_count: 162, + last_data_time: 1610470367123, + processed_record_count: 162, + }, + model_size_stats: { + bucket_allocation_failures_count: 0, + memory_status: 'ok', + model_bytes: 72574, + model_bytes_exceeded: 0, + model_bytes_memory_limit: 16777216, + peak_model_bytes: 78682, + }, + timing_stats: { + average_bucket_processing_time_ms: 0.4900837644740133, + bucket_count: 16236, + exponential_average_bucket_processing_time_ms: 0.23614068552903306, + exponential_average_bucket_processing_time_per_hour_ms: 1.5551298175461634, + maximum_bucket_processing_time_ms: 392, + minimum_bucket_processing_time_ms: 0, + total_bucket_processing_time_ms: 7957.00000000008, + }, + datafeed: { + datafeed_id: 'datafeed-high_distinct_count_error_message', + state: 'stopped', + timing_stats: { + bucket_count: 8612, + exponential_average_search_time_per_hour_ms: 86145.39799630083, + search_count: 7202, + total_search_time_ms: 3107147, + }, }, }, - }, - ], + ], + }, }) ); }); diff --git a/x-pack/plugins/security_solution/server/usage/detections/detections_usage_helpers.ts b/x-pack/plugins/security_solution/server/usage/detections/detections_usage_helpers.ts deleted file mode 100644 index 3c666d4d21780..0000000000000 --- a/x-pack/plugins/security_solution/server/usage/detections/detections_usage_helpers.ts +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { - ElasticsearchClient, - KibanaRequest, - SavedObjectsClientContract, -} from '../../../../../../src/core/server'; -import { SIGNALS_ID } from '../../../common/constants'; -import { isJobStarted } from '../../../common/machine_learning/helpers'; -import { isSecurityJob } from '../../../common/machine_learning/is_security_job'; -import { MlPluginSetup } from '../../../../ml/server'; -import { DetectionRulesUsage, MlJobsUsage } from './index'; -import { isElasticRule, RuleSearchParams, RuleSearchResult } from './detection_telemetry_helpers'; - -interface DetectionsMetric { - isElastic: boolean; - isEnabled: boolean; -} - -/** - * Default detection rule usage count - */ -export const initialRulesUsage: DetectionRulesUsage = { - custom: { - enabled: 0, - disabled: 0, - }, - elastic: { - enabled: 0, - disabled: 0, - }, -}; - -/** - * Default ml job usage count - */ -export const initialMlJobsUsage: MlJobsUsage = { - custom: { - enabled: 0, - disabled: 0, - }, - elastic: { - enabled: 0, - disabled: 0, - }, -}; - -const updateRulesUsage = ( - ruleMetric: DetectionsMetric, - usage: DetectionRulesUsage -): DetectionRulesUsage => { - const { isEnabled, isElastic } = ruleMetric; - if (isEnabled && isElastic) { - return { - ...usage, - elastic: { - ...usage.elastic, - enabled: usage.elastic.enabled + 1, - }, - }; - } else if (!isEnabled && isElastic) { - return { - ...usage, - elastic: { - ...usage.elastic, - disabled: usage.elastic.disabled + 1, - }, - }; - } else if (isEnabled && !isElastic) { - return { - ...usage, - custom: { - ...usage.custom, - enabled: usage.custom.enabled + 1, - }, - }; - } else if (!isEnabled && !isElastic) { - return { - ...usage, - custom: { - ...usage.custom, - disabled: usage.custom.disabled + 1, - }, - }; - } else { - return usage; - } -}; - -const updateMlJobsUsage = (jobMetric: DetectionsMetric, usage: MlJobsUsage): MlJobsUsage => { - const { isEnabled, isElastic } = jobMetric; - if (isEnabled && isElastic) { - return { - ...usage, - elastic: { - ...usage.elastic, - enabled: usage.elastic.enabled + 1, - }, - }; - } else if (!isEnabled && isElastic) { - return { - ...usage, - elastic: { - ...usage.elastic, - disabled: usage.elastic.disabled + 1, - }, - }; - } else if (isEnabled && !isElastic) { - return { - ...usage, - custom: { - ...usage.custom, - enabled: usage.custom.enabled + 1, - }, - }; - } else if (!isEnabled && !isElastic) { - return { - ...usage, - custom: { - ...usage.custom, - disabled: usage.custom.disabled + 1, - }, - }; - } else { - return usage; - } -}; - -export const getRulesUsage = async ( - index: string, - esClient: ElasticsearchClient -): Promise => { - let rulesUsage: DetectionRulesUsage = initialRulesUsage; - const ruleSearchOptions: RuleSearchParams = { - body: { query: { bool: { filter: { term: { 'alert.alertTypeId': SIGNALS_ID } } } } }, - filterPath: ['hits.hits._source.alert.enabled', 'hits.hits._source.alert.tags'], - ignoreUnavailable: true, - index, - size: 10000, // elasticsearch index.max_result_window default value - }; - - try { - const { body: ruleResults } = await esClient.search(ruleSearchOptions); - - if (ruleResults.hits?.hits?.length > 0) { - rulesUsage = ruleResults.hits.hits.reduce((usage, hit) => { - const isElastic = isElasticRule(hit._source?.alert.tags); - const isEnabled = Boolean(hit._source?.alert.enabled); - - return updateRulesUsage({ isElastic, isEnabled }, usage); - }, initialRulesUsage); - } - } catch (e) { - // ignore failure, usage will be zeroed - } - - return rulesUsage; -}; - -export const getMlJobsUsage = async ( - ml: MlPluginSetup | undefined, - savedObjectClient: SavedObjectsClientContract -): Promise => { - let jobsUsage: MlJobsUsage = initialMlJobsUsage; - - if (ml) { - try { - const fakeRequest = { headers: {} } as KibanaRequest; - - const modules = await ml.modulesProvider(fakeRequest, savedObjectClient).listModules(); - const moduleJobs = modules.flatMap((module) => module.jobs); - const jobs = await ml.jobServiceProvider(fakeRequest, savedObjectClient).jobsSummary(); - - jobsUsage = jobs.filter(isSecurityJob).reduce((usage, job) => { - const isElastic = moduleJobs.some((moduleJob) => moduleJob.id === job.id); - const isEnabled = isJobStarted(job.jobState, job.datafeedState); - - return updateMlJobsUsage({ isElastic, isEnabled }, usage); - }, initialMlJobsUsage); - } catch (e) { - // ignore failure, usage will be zeroed - } - } - - return jobsUsage; -}; diff --git a/x-pack/plugins/security_solution/server/usage/detections/index.ts b/x-pack/plugins/security_solution/server/usage/detections/index.ts index ea3df7b1f2230..823e29fd0dd30 100644 --- a/x-pack/plugins/security_solution/server/usage/detections/index.ts +++ b/x-pack/plugins/security_solution/server/usage/detections/index.ts @@ -6,157 +6,15 @@ */ import { ElasticsearchClient, SavedObjectsClientContract } from '../../../../../../src/core/server'; -import { - getMlJobsUsage, - getRulesUsage, - initialRulesUsage, - initialMlJobsUsage, -} from './detections_usage_helpers'; -import { - getMlJobMetrics, - getDetectionRuleMetrics, - initialDetectionRulesUsage, -} from './detections_metrics_helpers'; import { MlPluginSetup } from '../../../../ml/server'; +import { getDetectionRuleMetrics, initialDetectionRulesUsage } from './detection_rule_helpers'; +import { getMlJobMetrics, initialMlJobsUsage } from './detection_ml_helpers'; +import { DetectionMetrics } from './types'; -interface FeatureUsage { - enabled: number; - disabled: number; -} +import { INTERNAL_IMMUTABLE_KEY } from '../../../common/constants'; -interface FeatureTypeUsage { - enabled: number; - disabled: number; - alerts: number; - cases: number; -} - -export interface DetectionRulesTypeUsage { - query: FeatureTypeUsage; - threshold: FeatureTypeUsage; - eql: FeatureTypeUsage; - machine_learning: FeatureTypeUsage; - threat_match: FeatureTypeUsage; - elastic_total: FeatureTypeUsage; - custom_total: FeatureTypeUsage; -} - -export interface DetectionRulesUsage { - custom: FeatureUsage; - elastic: FeatureUsage; -} - -export interface MlJobsUsage { - custom: FeatureUsage; - elastic: FeatureUsage; -} - -export interface DetectionsUsage { - detection_rules: DetectionRulesUsage; - ml_jobs: MlJobsUsage; -} - -export interface DetectionMetrics { - ml_jobs: MlJobMetric[]; - detection_rules: DetectionRuleAdoption; -} - -export interface MlJobDataCount { - bucket_count: number; - empty_bucket_count: number; - input_bytes: number; - input_record_count: number; - last_data_time: number; - processed_record_count: number; -} - -export interface MlJobModelSize { - bucket_allocation_failures_count: number; - memory_status: string; - model_bytes: number; - model_bytes_exceeded: number; - model_bytes_memory_limit: number; - peak_model_bytes: number; -} - -export interface MlTimingStats { - bucket_count: number; - exponential_average_bucket_processing_time_ms: number; - exponential_average_bucket_processing_time_per_hour_ms: number; - maximum_bucket_processing_time_ms: number; - minimum_bucket_processing_time_ms: number; - total_bucket_processing_time_ms: number; -} - -export interface MlJobMetric { - job_id: string; - open_time: string; - state: string; - data_counts: MlJobDataCount; - model_size_stats: MlJobModelSize; - timing_stats: MlTimingStats; -} - -export interface DetectionRuleMetric { - rule_name: string; - rule_id: string; - rule_type: string; - enabled: boolean; - elastic_rule: boolean; - created_on: string; - updated_on: string; - alert_count_daily: number; - cases_count_total: number; -} - -export interface DetectionRuleAdoption { - detection_rule_detail: DetectionRuleMetric[]; - detection_rule_usage: DetectionRulesTypeUsage; -} - -export interface AlertsAggregationResponse { - hits: { - total: { value: number }; - }; - aggregations: { - [aggName: string]: { - buckets: Array<{ key: string; doc_count: number }>; - }; - }; -} - -export interface CasesSavedObject { - associationType: string; - type: string; - alertId: string; - index: string; - rule: { - id: string; - name: string; - }; -} - -export const defaultDetectionsUsage = { - detection_rules: initialRulesUsage, - ml_jobs: initialMlJobsUsage, -}; - -export const fetchDetectionsUsage = async ( - kibanaIndex: string, - esClient: ElasticsearchClient, - ml: MlPluginSetup | undefined, - savedObjectClient: SavedObjectsClientContract -): Promise => { - const [rulesUsage, mlJobsUsage] = await Promise.allSettled([ - getRulesUsage(kibanaIndex, esClient), - getMlJobsUsage(ml, savedObjectClient), - ]); - - return { - detection_rules: rulesUsage.status === 'fulfilled' ? rulesUsage.value : initialRulesUsage, - ml_jobs: mlJobsUsage.status === 'fulfilled' ? mlJobsUsage.value : initialMlJobsUsage, - }; -}; +export const isElasticRule = (tags: string[] = []) => + tags.includes(`${INTERNAL_IMMUTABLE_KEY}:true`); export const fetchDetectionsMetrics = async ( kibanaIndex: string, @@ -171,7 +29,10 @@ export const fetchDetectionsMetrics = async ( ]); return { - ml_jobs: mlJobMetrics.status === 'fulfilled' ? mlJobMetrics.value : [], + ml_jobs: + mlJobMetrics.status === 'fulfilled' + ? mlJobMetrics.value + : { ml_job_metrics: [], ml_job_usage: initialMlJobsUsage }, detection_rules: detectionRuleMetrics.status === 'fulfilled' ? detectionRuleMetrics.value diff --git a/x-pack/plugins/security_solution/server/usage/detections/types.ts b/x-pack/plugins/security_solution/server/usage/detections/types.ts new file mode 100644 index 0000000000000..0e3ba97ca0f7c --- /dev/null +++ b/x-pack/plugins/security_solution/server/usage/detections/types.ts @@ -0,0 +1,162 @@ +/* + * 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. + */ + +interface RuleSearchBody { + query: { + bool: { + filter: { + term: { [key: string]: string }; + }; + }; + }; +} + +export interface RuleSearchParams { + body: RuleSearchBody; + filterPath: string[]; + ignoreUnavailable: boolean; + index: string; + size: number; +} + +export interface RuleSearchResult { + alert: { + name: string; + enabled: boolean; + tags: string[]; + createdAt: string; + updatedAt: string; + params: DetectionRuleParms; + }; +} + +export interface DetectionsMetric { + isElastic: boolean; + isEnabled: boolean; +} + +interface DetectionRuleParms { + ruleId: string; + version: string; + type: string; +} + +interface FeatureUsage { + enabled: number; + disabled: number; +} + +interface FeatureTypeUsage { + enabled: number; + disabled: number; + alerts: number; + cases: number; +} + +export interface DetectionRulesTypeUsage { + query: FeatureTypeUsage; + threshold: FeatureTypeUsage; + eql: FeatureTypeUsage; + machine_learning: FeatureTypeUsage; + threat_match: FeatureTypeUsage; + elastic_total: FeatureTypeUsage; + custom_total: FeatureTypeUsage; +} + +export interface MlJobsUsage { + custom: FeatureUsage; + elastic: FeatureUsage; +} + +export interface DetectionsUsage { + ml_jobs: MlJobsUsage; +} + +export interface DetectionMetrics { + ml_jobs: MlJobUsage; + detection_rules: DetectionRuleAdoption; +} + +export interface MlJobDataCount { + bucket_count: number; + empty_bucket_count: number; + input_bytes: number; + input_record_count: number; + last_data_time: number; + processed_record_count: number; +} + +export interface MlJobModelSize { + bucket_allocation_failures_count: number; + memory_status: string; + model_bytes: number; + model_bytes_exceeded: number; + model_bytes_memory_limit: number; + peak_model_bytes: number; +} + +export interface MlTimingStats { + bucket_count: number; + exponential_average_bucket_processing_time_ms: number; + exponential_average_bucket_processing_time_per_hour_ms: number; + maximum_bucket_processing_time_ms: number; + minimum_bucket_processing_time_ms: number; + total_bucket_processing_time_ms: number; +} + +export interface MlJobMetric { + job_id: string; + open_time: string; + state: string; + data_counts: MlJobDataCount; + model_size_stats: MlJobModelSize; + timing_stats: MlTimingStats; +} + +export interface DetectionRuleMetric { + rule_name: string; + rule_id: string; + rule_type: string; + enabled: boolean; + elastic_rule: boolean; + created_on: string; + updated_on: string; + alert_count_daily: number; + cases_count_total: number; +} + +export interface AlertsAggregationResponse { + hits: { + total: { value: number }; + }; + aggregations: { + [aggName: string]: { + buckets: Array<{ key: string; doc_count: number }>; + }; + }; +} + +export interface CasesSavedObject { + associationType: string; + type: string; + alertId: string; + index: string; + rule: { + id: string; + name: string; + }; +} + +export interface MlJobUsage { + ml_job_usage: MlJobsUsage; + ml_job_metrics: MlJobMetric[]; +} + +export interface DetectionRuleAdoption { + detection_rule_detail: DetectionRuleMetric[]; + detection_rule_usage: DetectionRulesTypeUsage; +} diff --git a/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json b/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json index b85fd8bf8989e..12e83008b2e5a 100644 --- a/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json +++ b/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json @@ -4664,82 +4664,6 @@ }, "security_solution": { "properties": { - "detections": { - "properties": { - "detection_rules": { - "properties": { - "custom": { - "properties": { - "enabled": { - "type": "long", - "_meta": { - "description": "The number of custom detection rules enabled" - } - }, - "disabled": { - "type": "long", - "_meta": { - "description": "The number of custom detection rules disabled" - } - } - } - }, - "elastic": { - "properties": { - "enabled": { - "type": "long", - "_meta": { - "description": "The number of elastic prebuilt detection rules enabled" - } - }, - "disabled": { - "type": "long", - "_meta": { - "description": "The number of elastic prebuilt detection rules disabled" - } - } - } - } - } - }, - "ml_jobs": { - "properties": { - "custom": { - "properties": { - "enabled": { - "type": "long", - "_meta": { - "description": "The number of custom ML jobs rules enabled" - } - }, - "disabled": { - "type": "long", - "_meta": { - "description": "The number of custom ML jobs rules disabled" - } - } - } - }, - "elastic": { - "properties": { - "enabled": { - "type": "long", - "_meta": { - "description": "The number of elastic provided ML jobs rules enabled" - } - }, - "disabled": { - "type": "long", - "_meta": { - "description": "The number of elastic provided ML jobs rules disabled" - } - } - } - } - } - } - } - }, "detectionMetrics": { "properties": { "detection_rules": { @@ -5014,197 +4938,237 @@ } }, "ml_jobs": { - "type": "array", - "items": { - "properties": { - "job_id": { - "type": "keyword", - "_meta": { - "description": "Identifier for the anomaly detection job" - } - }, - "open_time": { - "type": "keyword", - "_meta": { - "description": "For open jobs only, the elapsed time for which the job has been open" - } - }, - "create_time": { - "type": "keyword", - "_meta": { - "description": "The time the job was created" - } - }, - "finished_time": { - "type": "keyword", - "_meta": { - "description": "If the job closed or failed, this is the time the job finished" - } - }, - "state": { - "type": "keyword", - "_meta": { - "description": "The status of the anomaly detection job" - } - }, - "data_counts": { - "properties": { - "bucket_count": { - "type": "long", - "_meta": { - "description": "The number of buckets processed" - } - }, - "empty_bucket_count": { - "type": "long", - "_meta": { - "description": "The number of buckets which did not contain any data" - } - }, - "input_bytes": { - "type": "long", - "_meta": { - "description": "The number of bytes of input data posted to the anomaly detection job" - } - }, - "input_record_count": { - "type": "long", - "_meta": { - "description": "The number of input documents posted to the anomaly detection job" - } - }, - "last_data_time": { - "type": "long", - "_meta": { - "description": "The timestamp at which data was last analyzed, according to server time" - } - }, - "processed_record_count": { - "type": "long", - "_meta": { - "description": "The number of input documents that have been processed by the anomaly detection job" + "properties": { + "ml_job_usage": { + "properties": { + "custom": { + "properties": { + "enabled": { + "type": "long", + "_meta": { + "description": "The number of custom ML jobs rules enabled" + } + }, + "disabled": { + "type": "long", + "_meta": { + "description": "The number of custom ML jobs rules disabled" + } } } - } - }, - "model_size_stats": { - "properties": { - "bucket_allocation_failures_count": { - "type": "long", - "_meta": { - "description": "The number of buckets for which new entities in incoming data were not processed due to insufficient model memory" - } - }, - "model_bytes": { - "type": "long", - "_meta": { - "description": "The number of bytes of memory used by the models" - } - }, - "model_bytes_exceeded": { - "type": "long", - "_meta": { - "description": "The number of bytes over the high limit for memory usage at the last allocation failure" - } - }, - "model_bytes_memory_limit": { - "type": "long", - "_meta": { - "description": "The upper limit for model memory usage, checked on increasing values" - } - }, - "peak_model_bytes": { - "type": "long", - "_meta": { - "description": "The peak number of bytes of memory ever used by the models" + }, + "elastic": { + "properties": { + "enabled": { + "type": "long", + "_meta": { + "description": "The number of elastic provided ML jobs rules enabled" + } + }, + "disabled": { + "type": "long", + "_meta": { + "description": "The number of elastic provided ML jobs rules disabled" + } } } } - }, - "timing_stats": { + } + }, + "ml_job_metrics": { + "type": "array", + "items": { "properties": { - "bucket_count": { - "type": "long", - "_meta": { - "description": "The number of buckets processed" - } - }, - "exponential_average_bucket_processing_time_ms": { - "type": "long", - "_meta": { - "description": "Exponential moving average of all bucket processing times, in milliseconds" - } - }, - "exponential_average_bucket_processing_time_per_hour_ms": { - "type": "long", + "job_id": { + "type": "keyword", "_meta": { - "description": "Exponentially-weighted moving average of bucket processing times calculated in a 1 hour time window, in milliseconds" + "description": "Identifier for the anomaly detection job" } }, - "maximum_bucket_processing_time_ms": { - "type": "long", + "open_time": { + "type": "keyword", "_meta": { - "description": "Maximum among all bucket processing times, in milliseconds" + "description": "For open jobs only, the elapsed time for which the job has been open" } }, - "minimum_bucket_processing_time_ms": { - "type": "long", + "create_time": { + "type": "keyword", "_meta": { - "description": "Minimum among all bucket processing times, in milliseconds" + "description": "The time the job was created" } }, - "total_bucket_processing_time_ms": { - "type": "long", - "_meta": { - "description": "Sum of all bucket processing times, in milliseconds" - } - } - } - }, - "datafeed": { - "properties": { - "datafeed_id": { + "finished_time": { "type": "keyword", "_meta": { - "description": "A numerical character string that uniquely identifies the datafeed" + "description": "If the job closed or failed, this is the time the job finished" } }, "state": { "type": "keyword", "_meta": { - "description": "The status of the datafeed" + "description": "The status of the anomaly detection job" } }, - "timing_stats": { + "data_counts": { + "properties": { + "bucket_count": { + "type": "long", + "_meta": { + "description": "The number of buckets processed" + } + }, + "empty_bucket_count": { + "type": "long", + "_meta": { + "description": "The number of buckets which did not contain any data" + } + }, + "input_bytes": { + "type": "long", + "_meta": { + "description": "The number of bytes of input data posted to the anomaly detection job" + } + }, + "input_record_count": { + "type": "long", + "_meta": { + "description": "The number of input documents posted to the anomaly detection job" + } + }, + "last_data_time": { + "type": "long", + "_meta": { + "description": "The timestamp at which data was last analyzed, according to server time" + } + }, + "processed_record_count": { + "type": "long", + "_meta": { + "description": "The number of input documents that have been processed by the anomaly detection job" + } + } + } + }, + "model_size_stats": { "properties": { - "average_search_time_per_bucket_ms": { + "bucket_allocation_failures_count": { + "type": "long", + "_meta": { + "description": "The number of buckets for which new entities in incoming data were not processed due to insufficient model memory" + } + }, + "model_bytes": { + "type": "long", + "_meta": { + "description": "The number of bytes of memory used by the models" + } + }, + "model_bytes_exceeded": { + "type": "long", + "_meta": { + "description": "The number of bytes over the high limit for memory usage at the last allocation failure" + } + }, + "model_bytes_memory_limit": { "type": "long", "_meta": { - "description": "The average search time per bucket, in milliseconds" + "description": "The upper limit for model memory usage, checked on increasing values" } }, + "peak_model_bytes": { + "type": "long", + "_meta": { + "description": "The peak number of bytes of memory ever used by the models" + } + } + } + }, + "timing_stats": { + "properties": { "bucket_count": { "type": "long", "_meta": { "description": "The number of buckets processed" } }, - "exponential_average_search_time_per_hour_ms": { + "exponential_average_bucket_processing_time_ms": { + "type": "long", + "_meta": { + "description": "Exponential moving average of all bucket processing times, in milliseconds" + } + }, + "exponential_average_bucket_processing_time_per_hour_ms": { "type": "long", "_meta": { - "description": "The exponential average search time per hour, in milliseconds" + "description": "Exponentially-weighted moving average of bucket processing times calculated in a 1 hour time window, in milliseconds" } }, - "search_count": { + "maximum_bucket_processing_time_ms": { "type": "long", "_meta": { - "description": "The number of searches run by the datafeed" + "description": "Maximum among all bucket processing times, in milliseconds" } }, - "total_search_time_ms": { + "minimum_bucket_processing_time_ms": { "type": "long", "_meta": { - "description": "The total time the datafeed spent searching, in milliseconds" + "description": "Minimum among all bucket processing times, in milliseconds" + } + }, + "total_bucket_processing_time_ms": { + "type": "long", + "_meta": { + "description": "Sum of all bucket processing times, in milliseconds" + } + } + } + }, + "datafeed": { + "properties": { + "datafeed_id": { + "type": "keyword", + "_meta": { + "description": "A numerical character string that uniquely identifies the datafeed" + } + }, + "state": { + "type": "keyword", + "_meta": { + "description": "The status of the datafeed" + } + }, + "timing_stats": { + "properties": { + "average_search_time_per_bucket_ms": { + "type": "long", + "_meta": { + "description": "The average search time per bucket, in milliseconds" + } + }, + "bucket_count": { + "type": "long", + "_meta": { + "description": "The number of buckets processed" + } + }, + "exponential_average_search_time_per_hour_ms": { + "type": "long", + "_meta": { + "description": "The exponential average search time per hour, in milliseconds" + } + }, + "search_count": { + "type": "long", + "_meta": { + "description": "The number of searches run by the datafeed" + } + }, + "total_search_time_ms": { + "type": "long", + "_meta": { + "description": "The total time the datafeed spent searching, in milliseconds" + } + } } } } From de2f3c468a25fa5e48c9e986ac3d1dad2728ecfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Casper=20H=C3=BCbertz?= Date: Thu, 27 May 2021 21:27:16 +0200 Subject: [PATCH 40/77] [Observability] Fix README.md link to component (#100801) --- x-pack/plugins/observability/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/observability/README.md b/x-pack/plugins/observability/README.md index 8d87bacc431e0..f0f66f01def53 100644 --- a/x-pack/plugins/observability/README.md +++ b/x-pack/plugins/observability/README.md @@ -34,7 +34,7 @@ When both of the these are set to `true`, your alerts should show on the alerts ## Shared navigation -The Observability plugin maintains a navigation registry for Observability solutions, and exposes a shared page template component. Please refer to the docs in [the component directory](./components/shared/page_template/README.md) for more information on registering your solution's navigation structure, and rendering the navigation via the shared component. +The Observability plugin maintains a navigation registry for Observability solutions, and exposes a shared page template component. Please refer to the docs in [the component directory](public/components/shared/page_template) for more information on registering your solution's navigation structure, and rendering the navigation via the shared component. ## Unit testing From ca82b9b10a30e228530eacf2a82ccfd23b74ec09 Mon Sep 17 00:00:00 2001 From: Devon Thomson Date: Thu, 27 May 2021 15:37:58 -0400 Subject: [PATCH 41/77] [Lens] By Value Migrations for 7.13 (#100622) * quick fix for 7.13 lens migration not being run on by value panels Co-authored-by: Joe Reuter --- .../embeddable/lens_embeddable_factory.ts | 29 +++++ .../saved_object_migrations.test.ts.snap} | 0 .../server/migrations/common_migrations.ts | 46 +++++++ .../saved_object_migrations.test.ts} | 30 ++++- .../saved_object_migrations.ts} | 120 ++---------------- .../plugins/lens/server/migrations/types.ts | 89 +++++++++++++ x-pack/plugins/lens/server/plugin.tsx | 4 + x-pack/plugins/lens/server/saved_objects.ts | 2 +- 8 files changed, 201 insertions(+), 119 deletions(-) create mode 100644 x-pack/plugins/lens/server/embeddable/lens_embeddable_factory.ts rename x-pack/plugins/lens/server/{__snapshots__/migrations.test.ts.snap => migrations/__snapshots__/saved_object_migrations.test.ts.snap} (100%) create mode 100644 x-pack/plugins/lens/server/migrations/common_migrations.ts rename x-pack/plugins/lens/server/{migrations.test.ts => migrations/saved_object_migrations.test.ts} (98%) rename x-pack/plugins/lens/server/{migrations.ts => migrations/saved_object_migrations.ts} (80%) create mode 100644 x-pack/plugins/lens/server/migrations/types.ts diff --git a/x-pack/plugins/lens/server/embeddable/lens_embeddable_factory.ts b/x-pack/plugins/lens/server/embeddable/lens_embeddable_factory.ts new file mode 100644 index 0000000000000..ddc822f37b95b --- /dev/null +++ b/x-pack/plugins/lens/server/embeddable/lens_embeddable_factory.ts @@ -0,0 +1,29 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { EmbeddableRegistryDefinition } from 'src/plugins/embeddable/server'; +import { SerializableState } from '../../../../../src/plugins/kibana_utils/common'; +import { DOC_TYPE } from '../../common'; +import { commonRenameOperationsForFormula } from '../migrations/common_migrations'; +import { LensDocShapePre712 } from '../migrations/types'; + +export const lensEmbeddableFactory = (): EmbeddableRegistryDefinition => { + return { + id: DOC_TYPE, + migrations: { + // This migration is run in 7.13.1 for `by value` panels because the 7.13 release window was missed. + '7.13.1': (state) => { + const lensState = (state as unknown) as { attributes: LensDocShapePre712 }; + const migratedLensState = commonRenameOperationsForFormula(lensState.attributes); + return ({ + ...lensState, + attributes: migratedLensState, + } as unknown) as SerializableState; + }, + }, + }; +}; diff --git a/x-pack/plugins/lens/server/__snapshots__/migrations.test.ts.snap b/x-pack/plugins/lens/server/migrations/__snapshots__/saved_object_migrations.test.ts.snap similarity index 100% rename from x-pack/plugins/lens/server/__snapshots__/migrations.test.ts.snap rename to x-pack/plugins/lens/server/migrations/__snapshots__/saved_object_migrations.test.ts.snap diff --git a/x-pack/plugins/lens/server/migrations/common_migrations.ts b/x-pack/plugins/lens/server/migrations/common_migrations.ts new file mode 100644 index 0000000000000..85055e471bac9 --- /dev/null +++ b/x-pack/plugins/lens/server/migrations/common_migrations.ts @@ -0,0 +1,46 @@ +/* + * 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 { cloneDeep } from 'lodash'; +import { LensDocShapePre712, OperationTypePre712, LensDocShapePost712 } from './types'; + +export const commonRenameOperationsForFormula = ( + attributes: LensDocShapePre712 +): LensDocShapePost712 => { + const renameMapping = { + avg: 'average', + cardinality: 'unique_count', + derivative: 'differences', + } as const; + function shouldBeRenamed(op: OperationTypePre712): op is keyof typeof renameMapping { + return op in renameMapping; + } + const newAttributes = cloneDeep(attributes); + const datasourceLayers = newAttributes.state.datasourceStates.indexpattern.layers || {}; + (newAttributes as LensDocShapePost712).state.datasourceStates.indexpattern.layers = Object.fromEntries( + Object.entries(datasourceLayers).map(([layerId, layer]) => { + return [ + layerId, + { + ...layer, + columns: Object.fromEntries( + Object.entries(layer.columns).map(([columnId, column]) => { + const copy = { + ...column, + operationType: shouldBeRenamed(column.operationType) + ? renameMapping[column.operationType] + : column.operationType, + }; + return [columnId, copy]; + }) + ), + }, + ]; + }) + ); + return newAttributes as LensDocShapePost712; +}; diff --git a/x-pack/plugins/lens/server/migrations.test.ts b/x-pack/plugins/lens/server/migrations/saved_object_migrations.test.ts similarity index 98% rename from x-pack/plugins/lens/server/migrations.test.ts rename to x-pack/plugins/lens/server/migrations/saved_object_migrations.test.ts index bed19942e52bc..5478d86e9b14c 100644 --- a/x-pack/plugins/lens/server/migrations.test.ts +++ b/x-pack/plugins/lens/server/migrations/saved_object_migrations.test.ts @@ -5,8 +5,12 @@ * 2.0. */ -import { migrations, LensDocShape } from './migrations'; -import { SavedObjectMigrationContext, SavedObjectMigrationFn } from 'src/core/server'; +import { migrations, LensDocShape } from './saved_object_migrations'; +import { + SavedObjectMigrationContext, + SavedObjectMigrationFn, + SavedObjectUnsanitizedDoc, +} from 'src/core/server'; describe('Lens migrations', () => { describe('7.7.0 missing dimensions in XY', () => { @@ -767,10 +771,7 @@ describe('Lens migrations', () => { }, }; - it('should rename only specific operation types', () => { - const result = migrations['7.13.0'](example, context) as ReturnType< - SavedObjectMigrationFn - >; + const validate = (result: SavedObjectUnsanitizedDoc>) => { const layers = result.attributes.state.datasourceStates.indexpattern.layers; expect(layers).toEqual({ '5ab74ddc-93ca-44e2-9857-ecf85c86b53e': { @@ -832,6 +833,23 @@ describe('Lens migrations', () => { expect(result.attributes.state.query).toEqual(example.attributes.state.query); expect(result.attributes.state.filters).toEqual(example.attributes.state.filters); expect(result.attributes.title).toEqual(example.attributes.title); + }; + + it('should rename only specific operation types', () => { + const result = migrations['7.13.0'](example, context) as ReturnType< + SavedObjectMigrationFn + >; + validate(result); + }); + + it('can be applied multiple times', () => { + const result1 = migrations['7.13.0'](example, context) as ReturnType< + SavedObjectMigrationFn + >; + const result2 = migrations['7.13.1'](result1, context) as ReturnType< + SavedObjectMigrationFn + >; + validate(result2); }); }); }); diff --git a/x-pack/plugins/lens/server/migrations.ts b/x-pack/plugins/lens/server/migrations/saved_object_migrations.ts similarity index 80% rename from x-pack/plugins/lens/server/migrations.ts rename to x-pack/plugins/lens/server/migrations/saved_object_migrations.ts index 430c1a6caa667..ba7004ba67a95 100644 --- a/x-pack/plugins/lens/server/migrations.ts +++ b/x-pack/plugins/lens/server/migrations/saved_object_migrations.ts @@ -14,7 +14,9 @@ import { SavedObjectUnsanitizedDoc, } from 'src/core/server'; import { Query, Filter } from 'src/plugins/data/public'; -import { PersistableFilter } from '../common'; +import { PersistableFilter } from '../../common'; +import { LensDocShapePost712, LensDocShapePre712 } from './types'; +import { commonRenameOperationsForFormula } from './common_migrations'; interface LensDocShapePre710 { visualizationType: string | null; @@ -106,86 +108,6 @@ interface DatatableStatePost711 { }; } -type OperationTypePre712 = - | 'avg' - | 'cardinality' - | 'derivative' - | 'filters' - | 'terms' - | 'date_histogram' - | 'min' - | 'max' - | 'sum' - | 'median' - | 'percentile' - | 'last_value' - | 'count' - | 'range' - | 'cumulative_sum' - | 'counter_rate' - | 'moving_average'; -type OperationTypePost712 = Exclude< - OperationTypePre712 | 'average' | 'unique_count' | 'differences', - 'avg' | 'cardinality' | 'derivative' ->; -interface LensDocShapePre712 { - visualizationType: string | null; - title: string; - expression: string | null; - state: { - datasourceStates: { - // This is hardcoded as our only datasource - indexpattern: { - layers: Record< - string, - { - columns: Record< - string, - { - operationType: OperationTypePre712; - } - >; - } - >; - }; - }; - visualization: VisualizationState; - query: Query; - filters: Filter[]; - }; -} - -interface LensDocShapePost712 { - visualizationType: string | null; - title: string; - expression: string | null; - state: { - datasourceMetaData: { - filterableIndexPatterns: Array<{ id: string; title: string }>; - }; - datasourceStates: { - // This is hardcoded as our only datasource - indexpattern: { - currentIndexPatternId: string; - layers: Record< - string, - { - columns: Record< - string, - { - operationType: OperationTypePost712; - } - >; - } - >; - }; - }; - visualization: VisualizationState; - query: Query; - filters: Filter[]; - }; -} - /** * Removes the `lens_auto_date` subexpression from a stored expression * string. For example: aggConfigs={lens_auto_date aggConfigs="JSON string"} @@ -471,38 +393,11 @@ const renameOperationsForFormula: SavedObjectMigrationFn< LensDocShapePre712, LensDocShapePost712 > = (doc) => { - const renameMapping = { - avg: 'average', - cardinality: 'unique_count', - derivative: 'differences', - } as const; - function shouldBeRenamed(op: OperationTypePre712): op is keyof typeof renameMapping { - return op in renameMapping; - } const newDoc = cloneDeep(doc); - const datasourceLayers = newDoc.attributes.state.datasourceStates.indexpattern.layers || {}; - (newDoc.attributes as LensDocShapePost712).state.datasourceStates.indexpattern.layers = Object.fromEntries( - Object.entries(datasourceLayers).map(([layerId, layer]) => { - return [ - layerId, - { - ...layer, - columns: Object.fromEntries( - Object.entries(layer.columns).map(([columnId, column]) => { - const copy = { - ...column, - operationType: shouldBeRenamed(column.operationType) - ? renameMapping[column.operationType] - : column.operationType, - }; - return [columnId, copy]; - }) - ), - }, - ]; - }) - ); - return newDoc as SavedObjectUnsanitizedDoc; + return { + ...newDoc, + attributes: commonRenameOperationsForFormula(newDoc.attributes), + }; }; export const migrations: SavedObjectMigrationMap = { @@ -514,4 +409,5 @@ export const migrations: SavedObjectMigrationMap = { '7.11.0': removeSuggestedPriority, '7.12.0': transformTableState, '7.13.0': renameOperationsForFormula, + '7.13.1': renameOperationsForFormula, // duplicate this migration in case a broken by value panel is added to the library }; diff --git a/x-pack/plugins/lens/server/migrations/types.ts b/x-pack/plugins/lens/server/migrations/types.ts new file mode 100644 index 0000000000000..38e079ff38051 --- /dev/null +++ b/x-pack/plugins/lens/server/migrations/types.ts @@ -0,0 +1,89 @@ +/* + * 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 { Query, Filter } from 'src/plugins/data/public'; + +export type OperationTypePre712 = + | 'avg' + | 'cardinality' + | 'derivative' + | 'filters' + | 'terms' + | 'date_histogram' + | 'min' + | 'max' + | 'sum' + | 'median' + | 'percentile' + | 'last_value' + | 'count' + | 'range' + | 'cumulative_sum' + | 'counter_rate' + | 'moving_average'; +export type OperationTypePost712 = Exclude< + OperationTypePre712 | 'average' | 'unique_count' | 'differences', + 'avg' | 'cardinality' | 'derivative' +>; + +export interface LensDocShapePre712 { + visualizationType: string | null; + title: string; + expression: string | null; + state: { + datasourceStates: { + // This is hardcoded as our only datasource + indexpattern: { + layers: Record< + string, + { + columns: Record< + string, + { + operationType: OperationTypePre712; + } + >; + } + >; + }; + }; + query: Query; + visualization: VisualizationState; + filters: Filter[]; + }; +} + +export interface LensDocShapePost712 { + visualizationType: string | null; + title: string; + expression: string | null; + state: { + datasourceMetaData: { + filterableIndexPatterns: Array<{ id: string; title: string }>; + }; + datasourceStates: { + // This is hardcoded as our only datasource + indexpattern: { + currentIndexPatternId: string; + layers: Record< + string, + { + columns: Record< + string, + { + operationType: OperationTypePost712; + } + >; + } + >; + }; + }; + visualization: VisualizationState; + query: Query; + filters: Filter[]; + }; +} diff --git a/x-pack/plugins/lens/server/plugin.tsx b/x-pack/plugins/lens/server/plugin.tsx index 92b14ba509bae..c23c98cd12aec 100644 --- a/x-pack/plugins/lens/server/plugin.tsx +++ b/x-pack/plugins/lens/server/plugin.tsx @@ -17,10 +17,13 @@ import { scheduleLensTelemetry, } from './usage'; import { setupSavedObjects } from './saved_objects'; +import { EmbeddableSetup } from '../../../../src/plugins/embeddable/server'; +import { lensEmbeddableFactory } from './embeddable/lens_embeddable_factory'; export interface PluginSetupContract { usageCollection?: UsageCollectionSetup; taskManager?: TaskManagerSetupContract; + embeddable: EmbeddableSetup; } export interface PluginStartContract { @@ -53,6 +56,7 @@ export class LensServerPlugin implements Plugin<{}, {}, {}, {}> { plugins.taskManager ); } + plugins.embeddable.registerEmbeddableFactory(lensEmbeddableFactory()); return {}; } diff --git a/x-pack/plugins/lens/server/saved_objects.ts b/x-pack/plugins/lens/server/saved_objects.ts index 202439abf0376..0266378981fd6 100644 --- a/x-pack/plugins/lens/server/saved_objects.ts +++ b/x-pack/plugins/lens/server/saved_objects.ts @@ -7,7 +7,7 @@ import { CoreSetup } from 'kibana/server'; import { getEditPath } from '../common'; -import { migrations } from './migrations'; +import { migrations } from './migrations/saved_object_migrations'; export function setupSavedObjects(core: CoreSetup) { core.savedObjects.registerType({ From be001f2aa689a2a6271a7d4c747f3ca18bb09be6 Mon Sep 17 00:00:00 2001 From: Jason Stoltzfus Date: Thu, 27 May 2021 15:39:16 -0400 Subject: [PATCH 42/77] [App Search] Added a query tester button (#100560) --- .../layout/kibana_header_actions.test.tsx | 40 +++++++++++++++++++ .../layout/kibana_header_actions.tsx | 33 +++++++++++++++ .../applications/app_search/index.test.tsx | 8 +++- .../public/applications/app_search/index.tsx | 8 +++- .../layout/kibana_header_actions.tsx | 8 ++-- 5 files changed, 92 insertions(+), 5 deletions(-) create mode 100644 x-pack/plugins/enterprise_search/public/applications/app_search/components/layout/kibana_header_actions.test.tsx create mode 100644 x-pack/plugins/enterprise_search/public/applications/app_search/components/layout/kibana_header_actions.tsx diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/layout/kibana_header_actions.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/layout/kibana_header_actions.test.tsx new file mode 100644 index 0000000000000..21fc2b235d83c --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/layout/kibana_header_actions.test.tsx @@ -0,0 +1,40 @@ +/* + * 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 { setMockValues } from '../../../__mocks__'; + +import React from 'react'; + +import { shallow } from 'enzyme'; + +import { EuiButtonEmpty } from '@elastic/eui'; + +import { KibanaHeaderActions } from './kibana_header_actions'; + +describe('KibanaHeaderActions', () => { + const values = { + engineName: 'foo', + }; + + beforeEach(() => { + jest.clearAllMocks(); + setMockValues(values); + }); + + it('renders', () => { + const wrapper = shallow(); + expect(wrapper.find(EuiButtonEmpty).exists()).toBe(true); + }); + + it('does not render a "Query Tester" button if there is no engine available', () => { + setMockValues({ + engineName: '', + }); + const wrapper = shallow(); + expect(wrapper.find(EuiButtonEmpty).exists()).toBe(false); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/layout/kibana_header_actions.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/layout/kibana_header_actions.tsx new file mode 100644 index 0000000000000..b2e810962df02 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/layout/kibana_header_actions.tsx @@ -0,0 +1,33 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; + +import { useValues } from 'kea'; + +import { EuiButtonEmpty, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; + +import { EngineLogic } from '../engine'; + +export const KibanaHeaderActions: React.FC = () => { + const { engineName } = useValues(EngineLogic); + + return ( + + {engineName && ( + + + {i18n.translate('xpack.enterpriseSearch.appSearch.engine.queryTesterButtonLabel', { + defaultMessage: 'Query tester', + })} + + + )} + + ); +}; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/index.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/index.test.tsx index 2a7f256398381..287d46c2dec75 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/index.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/index.test.tsx @@ -7,6 +7,7 @@ import { DEFAULT_INITIAL_APP_DATA } from '../../../common/__mocks__'; import { setMockValues, rerender } from '../__mocks__'; +import '../__mocks__/shallow_useeffect.mock'; import '../__mocks__/enterprise_search_url.mock'; import '../__mocks__/react_router_history.mock'; @@ -70,9 +71,10 @@ describe('AppSearchUnconfigured', () => { describe('AppSearchConfigured', () => { let wrapper: ShallowWrapper; + const renderHeaderActions = jest.fn(); beforeAll(() => { - setMockValues({ myRole: {} }); + setMockValues({ myRole: {}, renderHeaderActions }); wrapper = shallow(); }); @@ -83,6 +85,10 @@ describe('AppSearchConfigured', () => { expect(wrapper.find(EngineRouter)).toHaveLength(1); }); + it('renders header actions', () => { + expect(renderHeaderActions).toHaveBeenCalled(); + }); + it('mounts AppLogic with passed initial data props', () => { expect(AppLogic).toHaveBeenCalledWith(DEFAULT_INITIAL_APP_DATA); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/index.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/index.tsx index 0b87321d87535..9b59e0e19a5da 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/index.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/index.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React from 'react'; +import React, { useEffect } from 'react'; import { Route, Redirect, Switch, useRouteMatch } from 'react-router-dom'; import { useValues } from 'kea'; @@ -25,6 +25,7 @@ import { EngineNav, EngineRouter } from './components/engine'; import { EngineCreation } from './components/engine_creation'; import { EnginesOverview, ENGINES_TITLE } from './components/engines'; import { ErrorConnecting } from './components/error_connecting'; +import { KibanaHeaderActions } from './components/layout/kibana_header_actions'; import { Library } from './components/library'; import { MetaEngineCreation } from './components/meta_engine_creation'; import { RoleMappingsRouter } from './components/role_mappings'; @@ -77,8 +78,13 @@ export const AppSearchConfigured: React.FC> = (props) = const { myRole: { canManageEngines, canManageMetaEngines, canViewRoleMappings }, } = useValues(AppLogic(props)); + const { renderHeaderActions } = useValues(KibanaLogic); const { readOnlyMode } = useValues(HttpLogic); + useEffect(() => { + renderHeaderActions(KibanaHeaderActions); + }, []); + return ( {process.env.NODE_ENV === 'development' && ( diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/layout/kibana_header_actions.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/layout/kibana_header_actions.tsx index 0875e8cf0ec08..1dddf54faa7af 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/layout/kibana_header_actions.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/layout/kibana_header_actions.tsx @@ -7,7 +7,7 @@ import React from 'react'; -import { EuiButtonEmpty, EuiText, EuiFlexGroup, EuiFlexItem, EuiHeaderLinks } from '@elastic/eui'; +import { EuiButtonEmpty, EuiFlexGroup, EuiFlexItem, EuiHeaderLinks } from '@elastic/eui'; import { externalUrl, getWorkplaceSearchUrl } from '../../../shared/enterprise_search_url'; import { EuiButtonEmptyTo } from '../../../shared/react_router_helpers'; @@ -25,8 +25,9 @@ export const WorkplaceSearchHeaderActions: React.FC = () => { data-test-subj="PersonalDashboardButton" iconType="user" to={PERSONAL_SOURCES_PATH} + size="s" > - {NAV.PERSONAL_DASHBOARD} + {NAV.PERSONAL_DASHBOARD} @@ -35,8 +36,9 @@ export const WorkplaceSearchHeaderActions: React.FC = () => { href={getWorkplaceSearchUrl('/search')} target="_blank" iconType="search" + size="s" > - {NAV.SEARCH} + {NAV.SEARCH} From 780d23e7afa1857f875b8ffaee04b17c4a42a1e7 Mon Sep 17 00:00:00 2001 From: Zacqary Adam Xeper Date: Thu, 27 May 2021 15:11:58 -0500 Subject: [PATCH 43/77] [Fleet] Link to docs for Fleet Server and ES hosts (#100698) * [Fleet] Link to docs for Fleet Server and ES hosts * Fix CN/JP i18n Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../components/settings_flyout/index.tsx | 25 ++++++++++++++++--- .../translations/translations/ja-JP.json | 2 +- .../translations/translations/zh-CN.json | 2 +- 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/x-pack/plugins/fleet/public/applications/fleet/components/settings_flyout/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/components/settings_flyout/index.tsx index d741874a7504c..b802854791009 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/components/settings_flyout/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/components/settings_flyout/index.tsx @@ -277,7 +277,7 @@ export const SettingFlyout: React.FunctionComponent = ({ onClose }) => { values={{ link: ( @@ -301,9 +301,26 @@ export const SettingFlyout: React.FunctionComponent = ({ onClose }) => { label={i18n.translate('xpack.fleet.settings.elasticsearchUrlLabel', { defaultMessage: 'Elasticsearch hosts', })} - helpText={i18n.translate('xpack.fleet.settings.elasticsearchUrlsHelpTect', { - defaultMessage: 'Specify the Elasticsearch URLs where agents send data.', - })} + helpText={ + + + + ), + }} + /> + } {...inputs.elasticsearchUrl.formRowProps} > diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index f694b2b39c605..d829c8eb22a98 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -9490,7 +9490,7 @@ "xpack.fleet.settings.cancelButtonLabel": "キャンセル", "xpack.fleet.settings.elasticHostError": "無効なURL", "xpack.fleet.settings.elasticsearchUrlLabel": "Elasticsearchホスト", - "xpack.fleet.settings.elasticsearchUrlsHelpTect": "エージェントがデータを送信するElasticsearch URLを指定します。", + "xpack.fleet.settings.elasticsearchUrlsHelpTect": "エージェントがデータを送信するElasticsearch URLを指定します。{link}を参照してください。", "xpack.fleet.settings.fleetServerHostsDifferentPathOrProtocolError": "各URLのプロトコルとパスは同じでなければなりません", "xpack.fleet.settings.fleetServerHostsEmptyError": "1つ以上のURLが必要です。", "xpack.fleet.settings.fleetServerHostsError": "無効なURL", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 36985a729ec2f..a7cd8b5fe8d51 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -9575,7 +9575,7 @@ "xpack.fleet.settings.cancelButtonLabel": "取消", "xpack.fleet.settings.elasticHostError": "URL 无效", "xpack.fleet.settings.elasticsearchUrlLabel": "Elasticsearch 主机", - "xpack.fleet.settings.elasticsearchUrlsHelpTect": "指定代理用于发送数据的 Elasticsearch URL。", + "xpack.fleet.settings.elasticsearchUrlsHelpTect": "指定代理用于发送数据的 Elasticsearch URL。请参阅 {link}。", "xpack.fleet.settings.fleetServerHostsDifferentPathOrProtocolError": "对于每个 URL,协议和路径必须相同", "xpack.fleet.settings.fleetServerHostsEmptyError": "至少需要一个 URL", "xpack.fleet.settings.fleetServerHostsError": "URL 无效", From 697b00f7d5637d05ffb531a62c894f273734d512 Mon Sep 17 00:00:00 2001 From: Craig Chamberlain Date: Thu, 27 May 2021 16:45:56 -0400 Subject: [PATCH 44/77] Fixes Field used in RDP ML job to event.type (#100000) * Update datafeed_windows_rare_user_type10_remote_login.json refactor df query to work with newer field values * Update datafeed_windows_rare_user_type10_remote_login.json remove event.code test - was failing a test on the build server using the original data b/c this field was not there when the query was first developed. Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- ...windows_rare_user_type10_remote_login.json | 32 +++++++++++++++++-- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_winlogbeat_auth/ml/datafeed_windows_rare_user_type10_remote_login.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_winlogbeat_auth/ml/datafeed_windows_rare_user_type10_remote_login.json index 719adf68207b0..a66f0a7c2607f 100644 --- a/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_winlogbeat_auth/ml/datafeed_windows_rare_user_type10_remote_login.json +++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_winlogbeat_auth/ml/datafeed_windows_rare_user_type10_remote_login.json @@ -7,9 +7,35 @@ "query": { "bool": { "filter": [ - {"term": {"event.type": "authentication_success"}}, - {"term": {"winlog.event_data.LogonType": "10"}}, - {"term": {"agent.type": "winlogbeat"}} + { + "term": { + "winlog.event_data.LogonType": "10" + } + } + ], + "must": [ + { + "bool": { + "should": [ + { + "match": { + "event.type": { + "query": "authentication_success", + "operator": "OR" + } + } + }, + { + "match": { + "event.action": { + "query": "logged-in", + "operator": "OR" + } + } + } + ] + } + } ] } } From a6bbf1b2199be4226d290bc6ee43fe44b26f812f Mon Sep 17 00:00:00 2001 From: spalger Date: Thu, 27 May 2021 14:10:49 -0700 Subject: [PATCH 45/77] skip suite failing es promotion (#100697) --- .../security_solution_endpoint_api_int/apis/resolver/entity.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/test/security_solution_endpoint_api_int/apis/resolver/entity.ts b/x-pack/test/security_solution_endpoint_api_int/apis/resolver/entity.ts index 3cca9213b4554..534cb12c3fc65 100644 --- a/x-pack/test/security_solution_endpoint_api_int/apis/resolver/entity.ts +++ b/x-pack/test/security_solution_endpoint_api_int/apis/resolver/entity.ts @@ -14,7 +14,8 @@ export default function ({ getService }: FtrProviderContext) { const supertest = getService('supertest'); const esArchiver = getService('esArchiver'); - describe('Resolver tests for the entity route', () => { + // FAILING ES PROMOTION: https://github.com/elastic/kibana/issues/100697 + describe.skip('Resolver tests for the entity route', () => { describe('winlogbeat tests', () => { before(async () => { await esArchiver.load('endpoint/resolver/winlogbeat'); From 134a3def037789ca4cae5cdcdcbd1f12eeb15852 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Thu, 27 May 2021 14:20:57 -0700 Subject: [PATCH 46/77] [Actions] Converted `rejectUnauthorized` config usages to `verificationMode`. (#100179) * [Actions] Converted `rejectUnauthorized` config usages to `verificationMode`. * added new verificationMode config options for tls, proxy tls and custom hosts * added unit tests * added unit tests * added kibana docker * Apply suggestions from code review Co-authored-by: gchaps <33642766+gchaps@users.noreply.github.com> * Update alert-action-settings.asciidoc * Apply suggestions from code review Co-authored-by: Joe Portner <5295965+jportner@users.noreply.github.com> * removed legacyRegectUnauthorized logic from getNodeTLSOptions * added deprecations * fixed doc links * fixed docs * Update x-pack/plugins/actions/server/builtin_action_types/lib/send_email.ts Co-authored-by: Joe Portner <5295965+jportner@users.noreply.github.com> * [DOCS] Fixes build error * fixed deprecations to set custom message * fixed doc * changed to not throw exception on non existing verification mode * added tests * fixed tests * fixed tests * added integration tests for legacy rejectUnauthorized fale * fixed tests Co-authored-by: gchaps <33642766+gchaps@users.noreply.github.com> Co-authored-by: Joe Portner <5295965+jportner@users.noreply.github.com> Co-authored-by: lcawl Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- docs/settings/alert-action-settings.asciidoc | 46 +++- .../resources/base/bin/kibana-docker | 2 + .../actions/server/actions_client.test.ts | 8 +- .../actions/server/actions_config.mock.ts | 4 +- .../actions/server/actions_config.test.ts | 63 +++++- .../plugins/actions/server/actions_config.ts | 14 +- .../server/builtin_action_types/email.test.ts | 4 +- .../lib/axios_utils.test.ts | 28 ++- .../lib/axios_utils_connection.test.ts | 26 ++- .../lib/get_custom_agents.test.ts | 75 ++++--- .../lib/get_custom_agents.ts | 23 +- .../lib/get_node_tls_options.test.ts | 70 ++++++ .../lib/get_node_tls_options.ts | 57 +++++ .../lib/send_email.test.ts | 22 +- .../builtin_action_types/lib/send_email.ts | 25 ++- .../server/builtin_action_types/slack.test.ts | 20 +- .../server/builtin_action_types/teams.test.ts | 4 +- .../builtin_action_types/webhook.test.ts | 4 +- x-pack/plugins/actions/server/config.test.ts | 38 ++++ x-pack/plugins/actions/server/config.ts | 31 +++ x-pack/plugins/actions/server/index.ts | 34 ++- x-pack/plugins/actions/server/types.ts | 6 +- .../alerting_api_integration/common/config.ts | 13 +- .../spaces_only/config.ts | 2 +- .../spaces_only_legacy/config.ts | 19 ++ .../spaces_only_legacy/scenarios.ts | 35 +++ .../actions/builtin_action_types/webhook.ts | 201 ++++++++++++++++++ .../spaces_only_legacy/tests/index.ts | 33 +++ 28 files changed, 800 insertions(+), 107 deletions(-) create mode 100644 x-pack/plugins/actions/server/builtin_action_types/lib/get_node_tls_options.test.ts create mode 100644 x-pack/plugins/actions/server/builtin_action_types/lib/get_node_tls_options.ts create mode 100644 x-pack/test/alerting_api_integration/spaces_only_legacy/config.ts create mode 100644 x-pack/test/alerting_api_integration/spaces_only_legacy/scenarios.ts create mode 100644 x-pack/test/alerting_api_integration/spaces_only_legacy/tests/actions/builtin_action_types/webhook.ts create mode 100644 x-pack/test/alerting_api_integration/spaces_only_legacy/tests/index.ts diff --git a/docs/settings/alert-action-settings.asciidoc b/docs/settings/alert-action-settings.asciidoc index 50ed0d2652c6f..71f141d1ed5d6 100644 --- a/docs/settings/alert-action-settings.asciidoc +++ b/docs/settings/alert-action-settings.asciidoc @@ -41,7 +41,7 @@ You can configure the following settings in the `kibana.yml` file. [cols="2*<"] |=== | `xpack.actions.enabled` - | Feature toggle that enables Actions in {kib}. Defaults to `true`. + | Feature toggle that enables Actions in {kib}. Default: `true`. | `xpack.actions.allowedHosts` {ess-icon} | A list of hostnames that {kib} is allowed to connect to when built-in actions are triggered. It defaults to `[*]`, allowing any host, but keep in mind the potential for SSRF attacks when hosts are not explicitly added to the allowed hosts. An empty list `[]` can be used to block built-in actions from making any external connections. + @@ -50,7 +50,7 @@ You can configure the following settings in the `kibana.yml` file. | `xpack.actions.customHostSettings` {ess-icon} | A list of custom host settings to override existing global settings. - Defaults to an empty list. + + Default: an empty list. + + Each entry in the list must have a `url` property, to associate a connection type (mail or https), hostname and port with the remaining options in the @@ -70,6 +70,7 @@ You can configure the following settings in the `kibana.yml` file. xpack.actions.customHostSettings: - url: smtp://mail.example.com:465 tls: + verificationMode: 'full' certificateAuthoritiesFiles: [ 'one.crt' ] certificateAuthoritiesData: | -----BEGIN CERTIFICATE----- @@ -79,7 +80,9 @@ xpack.actions.customHostSettings: requireTLS: true - url: https://webhook.example.com tls: + // legacy rejectUnauthorized: false + verificationMode: 'none' -- [cols="2*<"] @@ -115,10 +118,16 @@ xpack.actions.customHostSettings: | `xpack.actions.customHostSettings[n]` `.tls.rejectUnauthorized` {ess-icon} - | A boolean value indicating whether to bypass server certificate validation. + | Deprecated. Use <> instead. A boolean value indicating whether to bypass server certificate validation. Overrides the general `xpack.actions.rejectUnauthorized` configuration for requests made for this hostname/port. +|[[action-config-custom-host-verification-mode]] `xpack.actions.customHostSettings[n]` +`.tls.verificationMode` + | Controls the verification of the server certificate that {hosted-ems} receives when making an outbound SSL/TLS connection to the host server. Valid values are `full`, `certificate`, and `none`. + Use `full` to perform hostname verification, `certificate` to skip hostname verification, and `none` to skip verification. Default: `full`. <>. Overrides the general `xpack.actions.tls.verificationMode` configuration + for requests made for this hostname/port. + | `xpack.actions.customHostSettings[n]` `.tls.certificateAuthoritiesFiles` | A file name or list of file names of PEM-encoded certificate files to use @@ -137,10 +146,10 @@ xpack.actions.customHostSettings: | `xpack.actions` `.preconfiguredAlertHistoryEsIndex` {ess-icon} - | Enables a preconfigured alert history {es} <> connector. Defaults to `false`. + | Enables a preconfigured alert history {es} <> connector. Default: `false`. | `xpack.actions.preconfigured` - | Specifies preconfigured connector IDs and configs. Defaults to {}. + | Specifies preconfigured connector IDs and configs. Default: {}. | `xpack.actions.proxyUrl` {ess-icon} | Specifies the proxy URL to use, if using a proxy for actions. By default, no proxy is used. @@ -152,27 +161,44 @@ xpack.actions.customHostSettings: | Specifies hostnames which should only use the proxy, if using a proxy for actions. The value is an array of hostnames as strings. By default, no hosts will use the proxy, but if an action's hostname is in this list, the proxy will be used. The settings `xpack.actions.proxyBypassHosts` and `xpack.actions.proxyOnlyHosts` cannot be used at the same time. | `xpack.actions.proxyHeaders` {ess-icon} - | Specifies HTTP headers for the proxy, if using a proxy for actions. Defaults to {}. + | Specifies HTTP headers for the proxy, if using a proxy for actions. Default: {}. a|`xpack.actions.` `proxyRejectUnauthorizedCertificates` {ess-icon} - | Set to `false` to bypass certificate validation for the proxy, if using a proxy for actions. Defaults to `true`. + | Deprecated. Use <> instead. Set to `false` to bypass certificate validation for the proxy, if using a proxy for actions. Default: `true`. + +|[[action-config-proxy-verification-mode]] +`xpack.actions[n]` +`.tls.proxyVerificationMode` {ess-icon} +| Controls the verification for the proxy server certificate that {hosted-ems} receives when making an outbound SSL/TLS connection to the proxy server. Valid values are `full`, `certificate`, and `none`. +Use `full` to perform hostname verification, `certificate` to skip hostname verification, and `none` to skip verification. Default: `full`. <>. | `xpack.actions.rejectUnauthorized` {ess-icon} - | Set to `false` to bypass certificate validation for actions. Defaults to `true`. + + | Deprecated. Use <> instead. Set to `false` to bypass certificate validation for actions. Default: `true`. + + As an alternative to setting `xpack.actions.rejectUnauthorized`, you can use the setting `xpack.actions.customHostSettings` to set TLS options for specific servers. +|[[action-config-verification-mode]] +`xpack.actions[n]` +`.tls.verificationMode` {ess-icon} +| Controls the verification for the server certificate that {hosted-ems} receives when making an outbound SSL/TLS connection for actions. Valid values are `full`, `certificate`, and `none`. + Use `full` to perform hostname verification, `certificate` to skip hostname verification, and `none` to skip verification. Default: `full`. <>. + + + + As an alternative to setting `xpack.actions.tls.verificationMode`, you can use the setting + `xpack.actions.customHostSettings` to set TLS options for specific servers. + + + | `xpack.actions.maxResponseContentLength` {ess-icon} - | Specifies the max number of bytes of the http response for requests to external resources. Defaults to 1000000 (1MB). + | Specifies the max number of bytes of the http response for requests to external resources. Default: 1000000 (1MB). | `xpack.actions.responseTimeout` {ess-icon} | Specifies the time allowed for requests to external resources. Requests that take longer are aborted. The time is formatted as: + + `[ms,s,m,h,d,w,M,Y]` + + - For example, `20m`, `24h`, `7d`, `1w`. Defaults to `60s`. + For example, `20m`, `24h`, `7d`, `1w`. Default: `60s`. |=== diff --git a/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker b/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker index 47b5888da4ce8..a1838c571ea0b 100755 --- a/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker +++ b/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker @@ -175,6 +175,8 @@ kibana_vars=( xpack.actions.rejectUnauthorized xpack.actions.maxResponseContentLength xpack.actions.responseTimeout + xpack.actions.tls.verificationMode + xpack.actions.tls.proxyVerificationMode xpack.alerts.healthCheck.interval xpack.alerts.invalidateApiKeysTask.interval xpack.alerts.invalidateApiKeysTask.removalDelay diff --git a/x-pack/plugins/actions/server/actions_client.test.ts b/x-pack/plugins/actions/server/actions_client.test.ts index 30108a0777819..3b91b07eb30f4 100644 --- a/x-pack/plugins/actions/server/actions_client.test.ts +++ b/x-pack/plugins/actions/server/actions_client.test.ts @@ -417,8 +417,8 @@ describe('create()', () => { allowedHosts: ['*'], preconfiguredAlertHistoryEsIndex: false, preconfigured: {}, - proxyRejectUnauthorizedCertificates: true, - rejectUnauthorized: true, + proxyRejectUnauthorizedCertificates: true, // legacy + rejectUnauthorized: true, // legacy proxyBypassHosts: undefined, proxyOnlyHosts: undefined, maxResponseContentLength: new ByteSizeValue(1000000), @@ -429,6 +429,10 @@ describe('create()', () => { idleInterval: schema.duration().validate('1h'), pageSize: 100, }, + tls: { + verificationMode: 'full', + proxyVerificationMode: 'full', + }, }); const localActionTypeRegistryParams = { diff --git a/x-pack/plugins/actions/server/actions_config.mock.ts b/x-pack/plugins/actions/server/actions_config.mock.ts index fbd9a8cddbdcb..19a43951377b6 100644 --- a/x-pack/plugins/actions/server/actions_config.mock.ts +++ b/x-pack/plugins/actions/server/actions_config.mock.ts @@ -15,7 +15,9 @@ const createActionsConfigMock = () => { ensureHostnameAllowed: jest.fn().mockReturnValue({}), ensureUriAllowed: jest.fn().mockReturnValue({}), ensureActionTypeEnabled: jest.fn().mockReturnValue({}), - isRejectUnauthorizedCertificatesEnabled: jest.fn().mockReturnValue(true), + getTLSSettings: jest.fn().mockReturnValue({ + verificationMode: 'full', + }), getProxySettings: jest.fn().mockReturnValue(undefined), getResponseSettings: jest.fn().mockReturnValue({ maxContentLength: 1000000, diff --git a/x-pack/plugins/actions/server/actions_config.test.ts b/x-pack/plugins/actions/server/actions_config.test.ts index 925e77ca85fb2..93dad226e0c99 100644 --- a/x-pack/plugins/actions/server/actions_config.test.ts +++ b/x-pack/plugins/actions/server/actions_config.test.ts @@ -27,8 +27,8 @@ const defaultActionsConfig: ActionsConfig = { enabledActionTypes: [], preconfiguredAlertHistoryEsIndex: false, preconfigured: {}, - proxyRejectUnauthorizedCertificates: true, - rejectUnauthorized: true, + proxyRejectUnauthorizedCertificates: true, // legacy + rejectUnauthorized: true, // legacy maxResponseContentLength: new ByteSizeValue(1000000), responseTimeout: moment.duration(60000), cleanupFailedExecutionsTask: { @@ -37,6 +37,10 @@ const defaultActionsConfig: ActionsConfig = { idleInterval: schema.duration().validate('1h'), pageSize: 100, }, + tls: { + proxyVerificationMode: 'full', + verificationMode: 'full', + }, }; describe('ensureUriAllowed', () => { @@ -305,22 +309,45 @@ describe('getProxySettings', () => { expect(proxySettings?.proxyUrl).toBe(config.proxyUrl); }); - test('returns proxyRejectUnauthorizedCertificates', () => { + test('returns proper verificationMode values, beased on the legacy config option proxyRejectUnauthorizedCertificates', () => { const configTrue: ActionsConfig = { ...defaultActionsConfig, proxyUrl: 'https://proxy.elastic.co', proxyRejectUnauthorizedCertificates: true, }; let proxySettings = getActionsConfigurationUtilities(configTrue).getProxySettings(); - expect(proxySettings?.proxyRejectUnauthorizedCertificates).toBe(true); + expect(proxySettings?.proxyTLSSettings.verificationMode).toBe('full'); const configFalse: ActionsConfig = { ...defaultActionsConfig, proxyUrl: 'https://proxy.elastic.co', proxyRejectUnauthorizedCertificates: false, + tls: {}, + }; + proxySettings = getActionsConfigurationUtilities(configFalse).getProxySettings(); + expect(proxySettings?.proxyTLSSettings.verificationMode).toBe('none'); + }); + + test('returns proper verificationMode value, based on the TLS proxy configuration', () => { + const configTrue: ActionsConfig = { + ...defaultActionsConfig, + proxyUrl: 'https://proxy.elastic.co', + tls: { + proxyVerificationMode: 'full', + }, + }; + let proxySettings = getActionsConfigurationUtilities(configTrue).getProxySettings(); + expect(proxySettings?.proxyTLSSettings.verificationMode).toBe('full'); + + const configFalse: ActionsConfig = { + ...defaultActionsConfig, + proxyUrl: 'https://proxy.elastic.co', + tls: { + proxyVerificationMode: 'none', + }, }; proxySettings = getActionsConfigurationUtilities(configFalse).getProxySettings(); - expect(proxySettings?.proxyRejectUnauthorizedCertificates).toBe(false); + expect(proxySettings?.proxyTLSSettings.verificationMode).toBe('none'); }); test('returns proxy headers', () => { @@ -406,13 +433,13 @@ describe('getProxySettings', () => { { url: 'https://elastic.co', tls: { - rejectUnauthorized: true, + verificationMode: 'full', }, }, { url: 'smtp://elastic.co:123', tls: { - rejectUnauthorized: false, + verificationMode: 'none', }, smtp: { ignoreTLS: true, @@ -437,3 +464,25 @@ describe('getProxySettings', () => { expect(chs).toEqual(undefined); }); }); + +describe('getTLSSettings', () => { + test('returns proper verificationMode value, based on the TLS proxy configuration', () => { + const configTrue: ActionsConfig = { + ...defaultActionsConfig, + tls: { + verificationMode: 'full', + }, + }; + let tlsSettings = getActionsConfigurationUtilities(configTrue).getTLSSettings(); + expect(tlsSettings.verificationMode).toBe('full'); + + const configFalse: ActionsConfig = { + ...defaultActionsConfig, + tls: { + verificationMode: 'none', + }, + }; + tlsSettings = getActionsConfigurationUtilities(configFalse).getTLSSettings(); + expect(tlsSettings.verificationMode).toBe('none'); + }); +}); diff --git a/x-pack/plugins/actions/server/actions_config.ts b/x-pack/plugins/actions/server/actions_config.ts index b8cd5878a8972..d25101f8279f8 100644 --- a/x-pack/plugins/actions/server/actions_config.ts +++ b/x-pack/plugins/actions/server/actions_config.ts @@ -14,7 +14,8 @@ import { pipe } from 'fp-ts/lib/pipeable'; import { ActionsConfig, AllowedHosts, EnabledActionTypes, CustomHostSettings } from './config'; import { getCanonicalCustomHostUrl } from './lib/custom_host_settings'; import { ActionTypeDisabledError } from './lib'; -import { ProxySettings, ResponseSettings } from './types'; +import { ProxySettings, ResponseSettings, TLSSettings } from './types'; +import { getTLSSettingsFromConfig } from './builtin_action_types/lib/get_node_tls_options'; export { AllowedHosts, EnabledActionTypes } from './config'; @@ -30,7 +31,7 @@ export interface ActionsConfigurationUtilities { ensureHostnameAllowed: (hostname: string) => void; ensureUriAllowed: (uri: string) => void; ensureActionTypeEnabled: (actionType: string) => void; - isRejectUnauthorizedCertificatesEnabled: () => boolean; + getTLSSettings: () => TLSSettings; getProxySettings: () => undefined | ProxySettings; getResponseSettings: () => ResponseSettings; getCustomHostSettings: (targetUrl: string) => CustomHostSettings | undefined; @@ -93,7 +94,10 @@ function getProxySettingsFromConfig(config: ActionsConfig): undefined | ProxySet proxyBypassHosts: arrayAsSet(config.proxyBypassHosts), proxyOnlyHosts: arrayAsSet(config.proxyOnlyHosts), proxyHeaders: config.proxyHeaders, - proxyRejectUnauthorizedCertificates: config.proxyRejectUnauthorizedCertificates, + proxyTLSSettings: getTLSSettingsFromConfig( + config.tls?.proxyVerificationMode, + config.proxyRejectUnauthorizedCertificates + ), }; } @@ -142,8 +146,8 @@ export function getActionsConfigurationUtilities( isActionTypeEnabled, getProxySettings: () => getProxySettingsFromConfig(config), getResponseSettings: () => getResponseSettingsFromConfig(config), - // returns the global rejectUnauthorized setting - isRejectUnauthorizedCertificatesEnabled: () => config.rejectUnauthorized, + getTLSSettings: () => + getTLSSettingsFromConfig(config.tls?.verificationMode, config.rejectUnauthorized), ensureUriAllowed(uri: string) { if (!isUriAllowed(uri)) { throw new Error(allowListErrorMessage(AllowListingField.URL, uri)); diff --git a/x-pack/plugins/actions/server/builtin_action_types/email.test.ts b/x-pack/plugins/actions/server/builtin_action_types/email.test.ts index 5747b4bbb28f4..98ea436b17f3e 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/email.test.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/email.test.ts @@ -285,9 +285,9 @@ describe('execute()', () => { "getCustomHostSettings": [MockFunction], "getProxySettings": [MockFunction], "getResponseSettings": [MockFunction], + "getTLSSettings": [MockFunction], "isActionTypeEnabled": [MockFunction], "isHostnameAllowed": [MockFunction], - "isRejectUnauthorizedCertificatesEnabled": [MockFunction], "isUriAllowed": [MockFunction], }, "content": Object { @@ -346,9 +346,9 @@ describe('execute()', () => { "getCustomHostSettings": [MockFunction], "getProxySettings": [MockFunction], "getResponseSettings": [MockFunction], + "getTLSSettings": [MockFunction], "isActionTypeEnabled": [MockFunction], "isHostnameAllowed": [MockFunction], - "isRejectUnauthorizedCertificatesEnabled": [MockFunction], "isUriAllowed": [MockFunction], }, "content": Object { diff --git a/x-pack/plugins/actions/server/builtin_action_types/lib/axios_utils.test.ts b/x-pack/plugins/actions/server/builtin_action_types/lib/axios_utils.test.ts index edc9429e4fac6..ccd5a044971df 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/lib/axios_utils.test.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/lib/axios_utils.test.ts @@ -18,7 +18,7 @@ import { getCustomAgents } from './get_custom_agents'; const TestUrl = 'https://elastic.co/foo/bar/baz'; const logger = loggingSystemMock.create().get() as jest.Mocked; -const configurationUtilities = actionsConfigMock.create(); +let configurationUtilities = actionsConfigMock.create(); jest.mock('axios'); const axiosMock = (axios as unknown) as jest.Mock; @@ -42,6 +42,7 @@ describe('request', () => { headers: { 'content-type': 'application/json' }, data: { incidentId: '123' }, })); + configurationUtilities = actionsConfigMock.create(); configurationUtilities.getResponseSettings.mockReturnValue({ maxContentLength: 1000000, timeout: 360000, @@ -74,7 +75,9 @@ describe('request', () => { test('it have been called with proper proxy agent for a valid url', async () => { configurationUtilities.getProxySettings.mockReturnValue({ - proxyRejectUnauthorizedCertificates: true, + proxyTLSSettings: { + verificationMode: 'full', + }, proxyUrl: 'https://localhost:1212', proxyBypassHosts: undefined, proxyOnlyHosts: undefined, @@ -107,7 +110,9 @@ describe('request', () => { test('it have been called with proper proxy agent for an invalid url', async () => { configurationUtilities.getProxySettings.mockReturnValue({ proxyUrl: ':nope:', - proxyRejectUnauthorizedCertificates: false, + proxyTLSSettings: { + verificationMode: 'none', + }, proxyBypassHosts: undefined, proxyOnlyHosts: undefined, }); @@ -136,7 +141,9 @@ describe('request', () => { test('it bypasses with proxyBypassHosts when expected', async () => { configurationUtilities.getProxySettings.mockReturnValue({ - proxyRejectUnauthorizedCertificates: true, + proxyTLSSettings: { + verificationMode: 'full', + }, proxyUrl: 'https://elastic.proxy.co', proxyBypassHosts: new Set(['elastic.co']), proxyOnlyHosts: undefined, @@ -157,7 +164,9 @@ describe('request', () => { test('it does not bypass with proxyBypassHosts when expected', async () => { configurationUtilities.getProxySettings.mockReturnValue({ - proxyRejectUnauthorizedCertificates: true, + proxyTLSSettings: { + verificationMode: 'full', + }, proxyUrl: 'https://elastic.proxy.co', proxyBypassHosts: new Set(['not-elastic.co']), proxyOnlyHosts: undefined, @@ -178,7 +187,9 @@ describe('request', () => { test('it proxies with proxyOnlyHosts when expected', async () => { configurationUtilities.getProxySettings.mockReturnValue({ - proxyRejectUnauthorizedCertificates: true, + proxyTLSSettings: { + verificationMode: 'full', + }, proxyUrl: 'https://elastic.proxy.co', proxyBypassHosts: undefined, proxyOnlyHosts: new Set(['elastic.co']), @@ -199,7 +210,9 @@ describe('request', () => { test('it does not proxy with proxyOnlyHosts when expected', async () => { configurationUtilities.getProxySettings.mockReturnValue({ - proxyRejectUnauthorizedCertificates: true, + proxyTLSSettings: { + verificationMode: 'full', + }, proxyUrl: 'https://elastic.proxy.co', proxyBypassHosts: undefined, proxyOnlyHosts: new Set(['not-elastic.co']), @@ -252,6 +265,7 @@ describe('patch', () => { status: 200, headers: { 'content-type': 'application/json' }, })); + configurationUtilities = actionsConfigMock.create(); configurationUtilities.getResponseSettings.mockReturnValue({ maxContentLength: 1000000, timeout: 360000, diff --git a/x-pack/plugins/actions/server/builtin_action_types/lib/axios_utils_connection.test.ts b/x-pack/plugins/actions/server/builtin_action_types/lib/axios_utils_connection.test.ts index 80bf51e19c379..235fca005e225 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/lib/axios_utils_connection.test.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/lib/axios_utils_connection.test.ts @@ -81,23 +81,25 @@ describe('axios connections', () => { await expect(fn()).rejects.toThrow('certificate'); }); - test('it works with rejectUnauthorized false config', async () => { + test('it works with verificationMode "none" config', async () => { const { url, server } = await createServer(true); testServer = server; const configurationUtilities = getACUfromConfig({ - rejectUnauthorized: false, + tls: { + verificationMode: 'none', + }, }); const res = await request({ axios, url, logger, configurationUtilities }); expect(res.status).toBe(200); }); - test('it works with rejectUnauthorized custom host config', async () => { + test('it works with verificationMode "none" for custom host config', async () => { const { url, server } = await createServer(true); testServer = server; const configurationUtilities = getACUfromConfig({ - customHostSettings: [{ url, tls: { rejectUnauthorized: false } }], + customHostSettings: [{ url, tls: { verificationMode: 'none' } }], }); const res = await request({ axios, url, logger, configurationUtilities }); expect(res.status).toBe(200); @@ -125,7 +127,7 @@ describe('axios connections', () => { await expect(fn()).rejects.toThrow('certificate'); }); - test('it works with incorrect ca in custom host config but rejectUnauthorized false', async () => { + test('it works with incorrect ca in custom host config but verificationMode "none"', async () => { const { url, server } = await createServer(true); testServer = server; @@ -135,7 +137,7 @@ describe('axios connections', () => { url, tls: { certificateAuthoritiesData: CA, - rejectUnauthorized: false, + verificationMode: 'none', }, }, ], @@ -144,12 +146,14 @@ describe('axios connections', () => { expect(res.status).toBe(200); }); - test('it works with incorrect ca in custom host config but rejectUnauthorized config true', async () => { + test('it works with incorrect ca in custom host config but verificationMode config "full"', async () => { const { url, server } = await createServer(true); testServer = server; const configurationUtilities = getACUfromConfig({ - rejectUnauthorized: false, + tls: { + verificationMode: 'none', + }, customHostSettings: [ { url, @@ -169,7 +173,7 @@ describe('axios connections', () => { testServer = server; const configurationUtilities = getACUfromConfig({ - customHostSettings: [{ url: otherUrl, tls: { rejectUnauthorized: false } }], + customHostSettings: [{ url: otherUrl, tls: { verificationMode: 'none' } }], }); const fn = async () => await request({ axios, url, logger, configurationUtilities }); await expect(fn()).rejects.toThrow('certificate'); @@ -251,6 +255,10 @@ const BaseActionsConfig: ActionsConfig = { proxyUrl: undefined, proxyHeaders: undefined, proxyRejectUnauthorizedCertificates: true, + tls: { + proxyVerificationMode: 'full', + verificationMode: 'full', + }, proxyBypassHosts: undefined, proxyOnlyHosts: undefined, rejectUnauthorized: true, diff --git a/x-pack/plugins/actions/server/builtin_action_types/lib/get_custom_agents.test.ts b/x-pack/plugins/actions/server/builtin_action_types/lib/get_custom_agents.test.ts index 805c22806ce4c..8b4abe86e271a 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/lib/get_custom_agents.test.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/lib/get_custom_agents.test.ts @@ -20,16 +20,19 @@ const targetUrlCanonical = `https://${targetHost}:443`; const nonMatchingUrl = `https://${targetHost}m/foo/bar/baz`; describe('getCustomAgents', () => { - const configurationUtilities = actionsConfigMock.create(); + let configurationUtilities = actionsConfigMock.create(); beforeEach(() => { jest.resetAllMocks(); + configurationUtilities = actionsConfigMock.create(); }); test('get agents for valid proxy URL', () => { configurationUtilities.getProxySettings.mockReturnValue({ proxyUrl: 'https://someproxyhost', - proxyRejectUnauthorizedCertificates: false, + proxyTLSSettings: { + verificationMode: 'none', + }, proxyBypassHosts: undefined, proxyOnlyHosts: undefined, }); @@ -41,7 +44,9 @@ describe('getCustomAgents', () => { test('return default agents for invalid proxy URL', () => { configurationUtilities.getProxySettings.mockReturnValue({ proxyUrl: ':nope: not a valid URL', - proxyRejectUnauthorizedCertificates: false, + proxyTLSSettings: { + verificationMode: 'none', + }, proxyBypassHosts: undefined, proxyOnlyHosts: undefined, }); @@ -59,7 +64,9 @@ describe('getCustomAgents', () => { test('returns non-proxy agents for matching proxyBypassHosts', () => { configurationUtilities.getProxySettings.mockReturnValue({ proxyUrl: 'https://someproxyhost', - proxyRejectUnauthorizedCertificates: false, + proxyTLSSettings: { + verificationMode: 'none', + }, proxyBypassHosts: new Set([targetHost]), proxyOnlyHosts: undefined, }); @@ -71,7 +78,9 @@ describe('getCustomAgents', () => { test('returns proxy agents for non-matching proxyBypassHosts', () => { configurationUtilities.getProxySettings.mockReturnValue({ proxyUrl: 'https://someproxyhost', - proxyRejectUnauthorizedCertificates: false, + proxyTLSSettings: { + verificationMode: 'none', + }, proxyBypassHosts: new Set([targetHost]), proxyOnlyHosts: undefined, }); @@ -87,7 +96,9 @@ describe('getCustomAgents', () => { test('returns proxy agents for matching proxyOnlyHosts', () => { configurationUtilities.getProxySettings.mockReturnValue({ proxyUrl: 'https://someproxyhost', - proxyRejectUnauthorizedCertificates: false, + proxyTLSSettings: { + verificationMode: 'none', + }, proxyBypassHosts: undefined, proxyOnlyHosts: new Set([targetHost]), }); @@ -99,7 +110,9 @@ describe('getCustomAgents', () => { test('returns non-proxy agents for non-matching proxyOnlyHosts', () => { configurationUtilities.getProxySettings.mockReturnValue({ proxyUrl: 'https://someproxyhost', - proxyRejectUnauthorizedCertificates: false, + proxyTLSSettings: { + verificationMode: 'none', + }, proxyBypassHosts: undefined, proxyOnlyHosts: new Set([targetHost]), }); @@ -116,7 +129,7 @@ describe('getCustomAgents', () => { configurationUtilities.getCustomHostSettings.mockReturnValue({ url: targetUrlCanonical, tls: { - rejectUnauthorized: false, + verificationMode: 'none', certificateAuthoritiesData: 'ca data here', }, }); @@ -128,14 +141,16 @@ describe('getCustomAgents', () => { test('handles custom host settings with proxy', () => { configurationUtilities.getProxySettings.mockReturnValue({ proxyUrl: 'https://someproxyhost', - proxyRejectUnauthorizedCertificates: false, + proxyTLSSettings: { + verificationMode: 'none', + }, proxyBypassHosts: undefined, proxyOnlyHosts: undefined, }); configurationUtilities.getCustomHostSettings.mockReturnValue({ url: targetUrlCanonical, tls: { - rejectUnauthorized: false, + verificationMode: 'none', certificateAuthoritiesData: 'ca data here', }, }); @@ -147,12 +162,14 @@ describe('getCustomAgents', () => { expect(httpsAgent?.options.rejectUnauthorized).toBe(false); }); - test('handles overriding global rejectUnauthorized false', () => { - configurationUtilities.isRejectUnauthorizedCertificatesEnabled.mockReturnValue(false); + test('handles overriding global verificationMode "none"', () => { + configurationUtilities.getTLSSettings.mockReturnValue({ + verificationMode: 'none', + }); configurationUtilities.getCustomHostSettings.mockReturnValue({ url: targetUrlCanonical, tls: { - rejectUnauthorized: true, + verificationMode: 'certificate', }, }); @@ -163,12 +180,14 @@ describe('getCustomAgents', () => { expect(httpsAgent?.options.rejectUnauthorized).toBeTruthy(); }); - test('handles overriding global rejectUnauthorized true', () => { - configurationUtilities.isRejectUnauthorizedCertificatesEnabled.mockReturnValue(true); + test('handles overriding global verificationMode "full"', () => { + configurationUtilities.getTLSSettings.mockReturnValue({ + verificationMode: 'full', + }); configurationUtilities.getCustomHostSettings.mockReturnValue({ url: targetUrlCanonical, tls: { - rejectUnauthorized: false, + verificationMode: 'none', }, }); @@ -179,19 +198,23 @@ describe('getCustomAgents', () => { expect(httpsAgent?.options.rejectUnauthorized).toBeFalsy(); }); - test('handles overriding global rejectUnauthorized false with a proxy', () => { - configurationUtilities.isRejectUnauthorizedCertificatesEnabled.mockReturnValue(false); + test('handles overriding global verificationMode "none" with a proxy', () => { + configurationUtilities.getTLSSettings.mockReturnValue({ + verificationMode: 'none', + }); configurationUtilities.getCustomHostSettings.mockReturnValue({ url: targetUrlCanonical, tls: { - rejectUnauthorized: true, + verificationMode: 'full', }, }); configurationUtilities.getProxySettings.mockReturnValue({ proxyUrl: 'https://someproxyhost', // note: this setting doesn't come into play, it's for the connection to // the proxy, not the target url - proxyRejectUnauthorizedCertificates: false, + proxyTLSSettings: { + verificationMode: 'none', + }, proxyBypassHosts: undefined, proxyOnlyHosts: undefined, }); @@ -202,19 +225,23 @@ describe('getCustomAgents', () => { expect(httpsAgent?.options.rejectUnauthorized).toBeTruthy(); }); - test('handles overriding global rejectUnauthorized true with a proxy', () => { - configurationUtilities.isRejectUnauthorizedCertificatesEnabled.mockReturnValue(true); + test('handles overriding global verificationMode "full" with a proxy', () => { + configurationUtilities.getTLSSettings.mockReturnValue({ + verificationMode: 'full', + }); configurationUtilities.getCustomHostSettings.mockReturnValue({ url: targetUrlCanonical, tls: { - rejectUnauthorized: false, + verificationMode: 'none', }, }); configurationUtilities.getProxySettings.mockReturnValue({ proxyUrl: 'https://someproxyhost', // note: this setting doesn't come into play, it's for the connection to // the proxy, not the target url - proxyRejectUnauthorizedCertificates: false, + proxyTLSSettings: { + verificationMode: 'none', + }, proxyBypassHosts: undefined, proxyOnlyHosts: undefined, }); diff --git a/x-pack/plugins/actions/server/builtin_action_types/lib/get_custom_agents.ts b/x-pack/plugins/actions/server/builtin_action_types/lib/get_custom_agents.ts index 6ec926004e73e..a327ee3ffe931 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/lib/get_custom_agents.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/lib/get_custom_agents.ts @@ -11,6 +11,7 @@ import HttpProxyAgent from 'http-proxy-agent'; import { HttpsProxyAgent } from 'https-proxy-agent'; import { Logger } from '../../../../../../src/core/server'; import { ActionsConfigurationUtilities } from '../../actions_config'; +import { getNodeTLSOptions, getTLSSettingsFromConfig } from './get_node_tls_options'; interface GetCustomAgentsResponse { httpAgent: HttpAgent | undefined; @@ -22,12 +23,14 @@ export function getCustomAgents( logger: Logger, url: string ): GetCustomAgentsResponse { + const generalTLSSettings = configurationUtilities.getTLSSettings(); + const agentTLSOptions = getNodeTLSOptions(logger, generalTLSSettings.verificationMode); // the default for rejectUnauthorized is the global setting, which can // be overridden (below) with a custom host setting const defaultAgents = { httpAgent: undefined, httpsAgent: new HttpsAgent({ - rejectUnauthorized: configurationUtilities.isRejectUnauthorizedCertificatesEnabled(), + ...agentTLSOptions, }), }; @@ -50,10 +53,18 @@ export function getCustomAgents( agentOptions.ca = tlsSettings.certificateAuthoritiesData; } + const tlsSettingsFromConfig = getTLSSettingsFromConfig( + tlsSettings.verificationMode, + tlsSettings.rejectUnauthorized + ); // see: src/core/server/elasticsearch/legacy/elasticsearch_client_config.ts // This is where the global rejectUnauthorized is overridden by a custom host - if (tlsSettings.rejectUnauthorized !== undefined) { - agentOptions.rejectUnauthorized = tlsSettings.rejectUnauthorized; + const customHostNodeTLSOptions = getNodeTLSOptions( + logger, + tlsSettingsFromConfig.verificationMode + ); + if (customHostNodeTLSOptions.rejectUnauthorized !== undefined) { + agentOptions.rejectUnauthorized = customHostNodeTLSOptions.rejectUnauthorized; } } @@ -96,6 +107,10 @@ export function getCustomAgents( return defaultAgents; } + const proxyNodeTLSOptions = getNodeTLSOptions( + logger, + proxySettings.proxyTLSSettings.verificationMode + ); // At this point, we are going to use a proxy, so we need new agents. // We will though, copy over the calculated tls options from above, into // the https agent. @@ -106,7 +121,7 @@ export function getCustomAgents( protocol: proxyUrl.protocol, headers: proxySettings.proxyHeaders, // do not fail on invalid certs if value is false - rejectUnauthorized: proxySettings.proxyRejectUnauthorizedCertificates, + ...proxyNodeTLSOptions, }) as unknown) as HttpsAgent; // vsCode wasn't convinced HttpsProxyAgent is an https.Agent, so we convinced it diff --git a/x-pack/plugins/actions/server/builtin_action_types/lib/get_node_tls_options.test.ts b/x-pack/plugins/actions/server/builtin_action_types/lib/get_node_tls_options.test.ts new file mode 100644 index 0000000000000..7d131985053f1 --- /dev/null +++ b/x-pack/plugins/actions/server/builtin_action_types/lib/get_node_tls_options.test.ts @@ -0,0 +1,70 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { getNodeTLSOptions, getTLSSettingsFromConfig } from './get_node_tls_options'; +import { Logger } from '../../../../../../src/core/server'; +import { loggingSystemMock } from '../../../../../../src/core/server/mocks'; + +const logger = loggingSystemMock.create().get() as jest.Mocked; + +describe('getNodeTLSOptions', () => { + test('get node.js TLS options: rejectUnauthorized eql true for the verification mode "full"', () => { + const nodeOption = getNodeTLSOptions(logger, 'full'); + expect(nodeOption).toMatchObject({ + rejectUnauthorized: true, + }); + }); + + test('get node.js TLS options: rejectUnauthorized eql true for the verification mode "certificate"', () => { + const nodeOption = getNodeTLSOptions(logger, 'certificate'); + expect(nodeOption.checkServerIdentity).not.toBeNull(); + expect(nodeOption.rejectUnauthorized).toBeTruthy(); + }); + + test('get node.js TLS options: rejectUnauthorized eql false for the verification mode "none"', () => { + const nodeOption = getNodeTLSOptions(logger, 'none'); + expect(nodeOption).toMatchObject({ + rejectUnauthorized: false, + }); + }); + + test('get node.js TLS options: rejectUnauthorized eql true for the verification mode value which does not exist, the logger called with the proper warning message', () => { + const nodeOption = getNodeTLSOptions(logger, 'notexist'); + expect(loggingSystemMock.collect(logger).warn).toMatchInlineSnapshot(` + Array [ + Array [ + "Unknown ssl verificationMode: notexist", + ], + ] + `); + expect(nodeOption).toMatchObject({ + rejectUnauthorized: true, + }); + }); +}); + +describe('getTLSSettingsFromConfig', () => { + test('get verificationMode eql "none" if legacy rejectUnauthorized eql false', () => { + const nodeOption = getTLSSettingsFromConfig(undefined, false); + expect(nodeOption).toMatchObject({ + verificationMode: 'none', + }); + }); + + test('get verificationMode eql "none" if legacy rejectUnauthorized eql true', () => { + const nodeOption = getTLSSettingsFromConfig(undefined, true); + expect(nodeOption).toMatchObject({ + verificationMode: 'full', + }); + }); + + test('get verificationMode eql "certificate", ignore rejectUnauthorized', () => { + const nodeOption = getTLSSettingsFromConfig('certificate', false); + expect(nodeOption).toMatchObject({ + verificationMode: 'certificate', + }); + }); +}); diff --git a/x-pack/plugins/actions/server/builtin_action_types/lib/get_node_tls_options.ts b/x-pack/plugins/actions/server/builtin_action_types/lib/get_node_tls_options.ts new file mode 100644 index 0000000000000..423e9756b13f8 --- /dev/null +++ b/x-pack/plugins/actions/server/builtin_action_types/lib/get_node_tls_options.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 { PeerCertificate } from 'tls'; +import { TLSSettings } from '../../types'; +import { Logger } from '../../../../../../src/core/server'; + +export function getNodeTLSOptions( + logger: Logger, + verificationMode?: string +): { + rejectUnauthorized?: boolean; + checkServerIdentity?: ((host: string, cert: PeerCertificate) => Error | undefined) | undefined; +} { + const agentOptions: { + rejectUnauthorized?: boolean; + checkServerIdentity?: ((host: string, cert: PeerCertificate) => Error | undefined) | undefined; + } = {}; + if (!!verificationMode) { + switch (verificationMode) { + case 'none': + agentOptions.rejectUnauthorized = false; + break; + case 'certificate': + agentOptions.rejectUnauthorized = true; + // by default, NodeJS is checking the server identify + agentOptions.checkServerIdentity = () => undefined; + break; + case 'full': + agentOptions.rejectUnauthorized = true; + break; + default: { + logger.warn(`Unknown ssl verificationMode: ${verificationMode}`); + agentOptions.rejectUnauthorized = true; + } + } + // see: src/core/server/elasticsearch/legacy/elasticsearch_client_config.ts + // This is where the global rejectUnauthorized is overridden by a custom host + } + return agentOptions; +} + +export function getTLSSettingsFromConfig( + verificationMode?: 'none' | 'certificate' | 'full', + rejectUnauthorized?: boolean +): TLSSettings { + if (verificationMode) { + return { verificationMode }; + } else if (rejectUnauthorized !== undefined) { + return { verificationMode: rejectUnauthorized ? 'full' : 'none' }; + } + return {}; +} diff --git a/x-pack/plugins/actions/server/builtin_action_types/lib/send_email.test.ts b/x-pack/plugins/actions/server/builtin_action_types/lib/send_email.test.ts index cceeefde71dc2..9bdb2d9481142 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/lib/send_email.test.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/lib/send_email.test.ts @@ -76,7 +76,9 @@ describe('send_email module', () => { }, { proxyUrl: 'https://example.com', - proxyRejectUnauthorizedCertificates: false, + proxyTLSSettings: { + verificationMode: 'none', + }, proxyBypassHosts: undefined, proxyOnlyHosts: undefined, } @@ -119,7 +121,7 @@ describe('send_email module', () => { `); }); - test('rejectUnauthorized default setting email using not secure host/port', async () => { + test('verificationMode default setting email using not secure host/port', async () => { const sendEmailOptions = getSendEmailOptions({ transport: { host: 'example.com', @@ -236,7 +238,9 @@ describe('send_email module', () => { }, { proxyUrl: 'https://proxy.com', - proxyRejectUnauthorizedCertificates: false, + proxyTLSSettings: { + verificationMode: 'none', + }, proxyBypassHosts: new Set(['example.com']), proxyOnlyHosts: undefined, } @@ -268,7 +272,9 @@ describe('send_email module', () => { }, { proxyUrl: 'https://proxy.com', - proxyRejectUnauthorizedCertificates: false, + proxyTLSSettings: { + verificationMode: 'none', + }, proxyBypassHosts: new Set(['not-example.com']), proxyOnlyHosts: undefined, } @@ -302,7 +308,9 @@ describe('send_email module', () => { }, { proxyUrl: 'https://proxy.com', - proxyRejectUnauthorizedCertificates: false, + proxyTLSSettings: { + verificationMode: 'none', + }, proxyBypassHosts: undefined, proxyOnlyHosts: new Set(['example.com']), } @@ -336,7 +344,7 @@ describe('send_email module', () => { }, { proxyUrl: 'https://proxy.com', - proxyRejectUnauthorizedCertificates: false, + proxyTLSSettings: {}, proxyBypassHosts: undefined, proxyOnlyHosts: new Set(['not-example.com']), } @@ -453,7 +461,7 @@ describe('send_email module', () => { }, { proxyUrl: 'https://proxy.com', - proxyRejectUnauthorizedCertificates: false, + proxyTLSSettings: {}, proxyBypassHosts: undefined, proxyOnlyHosts: undefined, }, diff --git a/x-pack/plugins/actions/server/builtin_action_types/lib/send_email.ts b/x-pack/plugins/actions/server/builtin_action_types/lib/send_email.ts index 005e73b1fc2f7..9f601840bc982 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/lib/send_email.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/lib/send_email.ts @@ -12,6 +12,7 @@ import { default as MarkdownIt } from 'markdown-it'; import { Logger } from '../../../../../../src/core/server'; import { ActionsConfigurationUtilities } from '../../actions_config'; import { CustomHostSettings } from '../../config'; +import { getNodeTLSOptions, getTLSSettingsFromConfig } from './get_node_tls_options'; // an email "service" which doesn't actually send, just returns what it would send export const JSON_TRANSPORT_SERVICE = '__json'; @@ -58,7 +59,7 @@ export async function sendEmail(logger: Logger, options: SendEmailOptions): Prom // eslint-disable-next-line @typescript-eslint/no-explicit-any const transportConfig: Record = {}; const proxySettings = configurationUtilities.getProxySettings(); - const rejectUnauthorized = configurationUtilities.isRejectUnauthorizedCertificatesEnabled(); + const generalTLSSettings = configurationUtilities.getTLSSettings(); if (hasAuth && user != null && password != null) { transportConfig.auth = { @@ -91,10 +92,10 @@ export async function sendEmail(logger: Logger, options: SendEmailOptions): Prom customHostSettings = configurationUtilities.getCustomHostSettings(`smtp://${host}:${port}`); if (proxySettings && useProxy) { - transportConfig.tls = { - // do not fail on invalid certs if value is false - rejectUnauthorized: proxySettings?.proxyRejectUnauthorizedCertificates, - }; + transportConfig.tls = getNodeTLSOptions( + logger, + proxySettings?.proxyTLSSettings.verificationMode + ); transportConfig.proxy = proxySettings.proxyUrl; transportConfig.headers = proxySettings.proxyHeaders; } else if (!transportConfig.secure && user == null && password == null) { @@ -103,7 +104,7 @@ export async function sendEmail(logger: Logger, options: SendEmailOptions): Prom // authenticate rarely have valid certs; eg cloud proxy, and npm maildev transportConfig.tls = { rejectUnauthorized: false }; } else { - transportConfig.tls = { rejectUnauthorized }; + transportConfig.tls = getNodeTLSOptions(logger, generalTLSSettings.verificationMode); } // finally, allow customHostSettings to override some of the settings @@ -116,14 +117,16 @@ export async function sendEmail(logger: Logger, options: SendEmailOptions): Prom if (tlsSettings?.certificateAuthoritiesData) { tlsConfig.ca = tlsSettings?.certificateAuthoritiesData; } - if (tlsSettings?.rejectUnauthorized !== undefined) { - tlsConfig.rejectUnauthorized = tlsSettings?.rejectUnauthorized; - } + const tlsSettingsFromConfig = getTLSSettingsFromConfig( + tlsSettings?.verificationMode, + tlsSettings?.rejectUnauthorized + ); + const nodeTLSOptions = getNodeTLSOptions(logger, tlsSettingsFromConfig.verificationMode); if (!transportConfig.tls) { - transportConfig.tls = tlsConfig; + transportConfig.tls = { ...tlsConfig, ...nodeTLSOptions }; } else { - transportConfig.tls = { ...transportConfig.tls, ...tlsConfig }; + transportConfig.tls = { ...transportConfig.tls, ...tlsConfig, ...nodeTLSOptions }; } if (smtpSettings?.ignoreTLS) { diff --git a/x-pack/plugins/actions/server/builtin_action_types/slack.test.ts b/x-pack/plugins/actions/server/builtin_action_types/slack.test.ts index 76612696e8e58..4108424e26ac4 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/slack.test.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/slack.test.ts @@ -194,7 +194,9 @@ describe('execute()', () => { const configurationUtilities = actionsConfigMock.create(); configurationUtilities.getProxySettings.mockReturnValue({ proxyUrl: 'https://someproxyhost', - proxyRejectUnauthorizedCertificates: false, + proxyTLSSettings: { + verificationMode: 'none', + }, proxyBypassHosts: undefined, proxyOnlyHosts: undefined, }); @@ -219,7 +221,9 @@ describe('execute()', () => { const configurationUtilities = actionsConfigMock.create(); configurationUtilities.getProxySettings.mockReturnValue({ proxyUrl: 'https://someproxyhost', - proxyRejectUnauthorizedCertificates: false, + proxyTLSSettings: { + verificationMode: 'none', + }, proxyBypassHosts: new Set(['example.com']), proxyOnlyHosts: undefined, }); @@ -244,7 +248,9 @@ describe('execute()', () => { const configurationUtilities = actionsConfigMock.create(); configurationUtilities.getProxySettings.mockReturnValue({ proxyUrl: 'https://someproxyhost', - proxyRejectUnauthorizedCertificates: false, + proxyTLSSettings: { + verificationMode: 'none', + }, proxyBypassHosts: new Set(['not-example.com']), proxyOnlyHosts: undefined, }); @@ -269,7 +275,9 @@ describe('execute()', () => { const configurationUtilities = actionsConfigMock.create(); configurationUtilities.getProxySettings.mockReturnValue({ proxyUrl: 'https://someproxyhost', - proxyRejectUnauthorizedCertificates: false, + proxyTLSSettings: { + verificationMode: 'none', + }, proxyBypassHosts: undefined, proxyOnlyHosts: new Set(['example.com']), }); @@ -294,7 +302,9 @@ describe('execute()', () => { const configurationUtilities = actionsConfigMock.create(); configurationUtilities.getProxySettings.mockReturnValue({ proxyUrl: 'https://someproxyhost', - proxyRejectUnauthorizedCertificates: false, + proxyTLSSettings: { + verificationMode: 'none', + }, proxyBypassHosts: undefined, proxyOnlyHosts: new Set(['not-example.com']), }); diff --git a/x-pack/plugins/actions/server/builtin_action_types/teams.test.ts b/x-pack/plugins/actions/server/builtin_action_types/teams.test.ts index 95088fa5f7965..bf34789e03fae 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/teams.test.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/teams.test.ts @@ -170,9 +170,9 @@ describe('execute()', () => { "getCustomHostSettings": [MockFunction], "getProxySettings": [MockFunction], "getResponseSettings": [MockFunction], + "getTLSSettings": [MockFunction], "isActionTypeEnabled": [MockFunction], "isHostnameAllowed": [MockFunction], - "isRejectUnauthorizedCertificatesEnabled": [MockFunction], "isUriAllowed": [MockFunction], }, "data": Object { @@ -234,9 +234,9 @@ describe('execute()', () => { "getCustomHostSettings": [MockFunction], "getProxySettings": [MockFunction], "getResponseSettings": [MockFunction], + "getTLSSettings": [MockFunction], "isActionTypeEnabled": [MockFunction], "isHostnameAllowed": [MockFunction], - "isRejectUnauthorizedCertificatesEnabled": [MockFunction], "isUriAllowed": [MockFunction], }, "data": Object { diff --git a/x-pack/plugins/actions/server/builtin_action_types/webhook.test.ts b/x-pack/plugins/actions/server/builtin_action_types/webhook.test.ts index 00e56303dbe22..b2c865c2f5374 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/webhook.test.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/webhook.test.ts @@ -293,9 +293,9 @@ describe('execute()', () => { "getCustomHostSettings": [MockFunction], "getProxySettings": [MockFunction], "getResponseSettings": [MockFunction], + "getTLSSettings": [MockFunction], "isActionTypeEnabled": [MockFunction], "isHostnameAllowed": [MockFunction], - "isRejectUnauthorizedCertificatesEnabled": [MockFunction], "isUriAllowed": [MockFunction], }, "data": "some data", @@ -386,9 +386,9 @@ describe('execute()', () => { "getCustomHostSettings": [MockFunction], "getProxySettings": [MockFunction], "getResponseSettings": [MockFunction], + "getTLSSettings": [MockFunction], "isActionTypeEnabled": [MockFunction], "isHostnameAllowed": [MockFunction], - "isRejectUnauthorizedCertificatesEnabled": [MockFunction], "isUriAllowed": [MockFunction], }, "data": "some data", diff --git a/x-pack/plugins/actions/server/config.test.ts b/x-pack/plugins/actions/server/config.test.ts index 4c4fd143369e1..9774bfb05d4ff 100644 --- a/x-pack/plugins/actions/server/config.test.ts +++ b/x-pack/plugins/actions/server/config.test.ts @@ -177,6 +177,44 @@ describe('config validation', () => { `"[customHostSettings.0.url]: expected value of type [string] but got [undefined]"` ); }); + + test('action with tls configuration', () => { + const config: Record = { + tls: { + verificationMode: 'none', + proxyVerificationMode: 'none', + }, + }; + expect(configSchema.validate(config)).toMatchInlineSnapshot(` + Object { + "allowedHosts": Array [ + "*", + ], + "cleanupFailedExecutionsTask": Object { + "cleanupInterval": "PT5M", + "enabled": true, + "idleInterval": "PT1H", + "pageSize": 100, + }, + "enabled": true, + "enabledActionTypes": Array [ + "*", + ], + "maxResponseContentLength": ByteSizeValue { + "valueInBytes": 1048576, + }, + "preconfigured": Object {}, + "preconfiguredAlertHistoryEsIndex": false, + "proxyRejectUnauthorizedCertificates": true, + "rejectUnauthorized": true, + "responseTimeout": "PT1M", + "tls": Object { + "proxyVerificationMode": "none", + "verificationMode": "none", + }, + } + `); + }); }); // object creator that ensures we can create a property named __proto__ on an diff --git a/x-pack/plugins/actions/server/config.ts b/x-pack/plugins/actions/server/config.ts index 0dc1aed68f4d0..8859a2d8881a2 100644 --- a/x-pack/plugins/actions/server/config.ts +++ b/x-pack/plugins/actions/server/config.ts @@ -33,7 +33,16 @@ const customHostSettingsSchema = schema.object({ ), tls: schema.maybe( schema.object({ + /** + * @deprecated in favor of `verificationMode` + **/ rejectUnauthorized: schema.maybe(schema.boolean()), + verificationMode: schema.maybe( + schema.oneOf( + [schema.literal('none'), schema.literal('certificate'), schema.literal('full')], + { defaultValue: 'full' } + ) + ), certificateAuthoritiesFiles: schema.maybe( schema.oneOf([ schema.string({ minLength: 1 }), @@ -68,10 +77,32 @@ export const configSchema = schema.object({ }), proxyUrl: schema.maybe(schema.string()), proxyHeaders: schema.maybe(schema.recordOf(schema.string(), schema.string())), + /** + * @deprecated in favor of `tls.proxyVerificationMode` + **/ proxyRejectUnauthorizedCertificates: schema.boolean({ defaultValue: true }), proxyBypassHosts: schema.maybe(schema.arrayOf(schema.string({ hostname: true }))), proxyOnlyHosts: schema.maybe(schema.arrayOf(schema.string({ hostname: true }))), + /** + * @deprecated in favor of `tls.verificationMode` + **/ rejectUnauthorized: schema.boolean({ defaultValue: true }), + tls: schema.maybe( + schema.object({ + verificationMode: schema.maybe( + schema.oneOf( + [schema.literal('none'), schema.literal('certificate'), schema.literal('full')], + { defaultValue: 'full' } + ) + ), + proxyVerificationMode: schema.maybe( + schema.oneOf( + [schema.literal('none'), schema.literal('certificate'), schema.literal('full')], + { defaultValue: 'full' } + ) + ), + }) + ), maxResponseContentLength: schema.byteSize({ defaultValue: '1mb' }), responseTimeout: schema.duration({ defaultValue: '60s' }), customHostSettings: schema.maybe(schema.arrayOf(customHostSettingsSchema)), diff --git a/x-pack/plugins/actions/server/index.ts b/x-pack/plugins/actions/server/index.ts index 99c6326d60e26..6a0f06b34d670 100644 --- a/x-pack/plugins/actions/server/index.ts +++ b/x-pack/plugins/actions/server/index.ts @@ -8,7 +8,7 @@ import type { PublicMethodsOf } from '@kbn/utility-types'; import { PluginInitializerContext, PluginConfigDescriptor } from '../../../../src/core/server'; import { ActionsPlugin } from './plugin'; -import { configSchema, ActionsConfig } from './config'; +import { configSchema, ActionsConfig, CustomHostSettings } from './config'; import { ActionsClient as ActionsClientClass } from './actions_client'; import { ActionsAuthorization as ActionsAuthorizationClass } from './authorization/actions_authorization'; @@ -57,7 +57,37 @@ export const plugin = (initContext: PluginInitializerContext) => new ActionsPlug export const config: PluginConfigDescriptor = { schema: configSchema, - deprecations: ({ renameFromRoot }) => [ + deprecations: ({ renameFromRoot, unused }) => [ renameFromRoot('xpack.actions.whitelistedHosts', 'xpack.actions.allowedHosts'), + (settings, fromPath, addDeprecation) => { + const customHostSettings = settings?.xpack?.actions?.customHostSettings ?? []; + if ( + customHostSettings.find( + (customHostSchema: CustomHostSettings) => + !!customHostSchema.tls && !!customHostSchema.tls.rejectUnauthorized + ) + ) { + addDeprecation({ + message: + '`xpack.actions.customHostSettings[].tls.rejectUnauthorized` is deprecated. Use `xpack.actions.customHostSettings[].tls.verificationMode` instead, with the setting `verificationMode:full` eql to `rejectUnauthorized:true`, and `verificationMode:none` eql to `rejectUnauthorized:false`.', + }); + } + }, + (settings, fromPath, addDeprecation) => { + if (!!settings?.xpack?.actions?.rejectUnauthorized) { + addDeprecation({ + message: + '`xpack.actions.rejectUnauthorized` is deprecated. Use `xpack.actions.verificationMode` instead, with the setting `verificationMode:full` eql to `rejectUnauthorized:true`, and `verificationMode:none` eql to `rejectUnauthorized:false`.', + }); + } + }, + (settings, fromPath, addDeprecation) => { + if (!!settings?.xpack?.actions?.proxyRejectUnauthorizedCertificates) { + addDeprecation({ + message: + '`xpack.actions.proxyRejectUnauthorizedCertificates` is deprecated. Use `xpack.actions.proxyVerificationMode` instead, with the setting `proxyVerificationMode:full` eql to `rejectUnauthorized:true`, and `proxyVerificationMode:none` eql to `rejectUnauthorized:false`.', + }); + } + }, ], }; diff --git a/x-pack/plugins/actions/server/types.ts b/x-pack/plugins/actions/server/types.ts index ea22e90dfed40..c8c9967afca1a 100644 --- a/x-pack/plugins/actions/server/types.ts +++ b/x-pack/plugins/actions/server/types.ts @@ -142,10 +142,14 @@ export interface ProxySettings { proxyBypassHosts: Set | undefined; proxyOnlyHosts: Set | undefined; proxyHeaders?: Record; - proxyRejectUnauthorizedCertificates: boolean; + proxyTLSSettings: TLSSettings; } export interface ResponseSettings { maxContentLength: number; timeout: number; } + +export interface TLSSettings { + verificationMode?: 'none' | 'certificate' | 'full'; +} diff --git a/x-pack/test/alerting_api_integration/common/config.ts b/x-pack/test/alerting_api_integration/common/config.ts index 8647c5951b7f3..c56e8adfbe34f 100644 --- a/x-pack/test/alerting_api_integration/common/config.ts +++ b/x-pack/test/alerting_api_integration/common/config.ts @@ -19,10 +19,11 @@ interface CreateTestConfigOptions { disabledPlugins?: string[]; ssl?: boolean; enableActionsProxy: boolean; - rejectUnauthorized?: boolean; + verificationMode?: 'full' | 'none' | 'certificate'; publicBaseUrl?: boolean; preconfiguredAlertHistoryEsIndex?: boolean; customizeLocalHostTls?: boolean; + rejectUnauthorized?: boolean; // legacy } // test.not-enabled is specifically not enabled @@ -49,9 +50,10 @@ export function createTestConfig(name: string, options: CreateTestConfigOptions) license = 'trial', disabledPlugins = [], ssl = false, - rejectUnauthorized = true, + verificationMode = 'full', preconfiguredAlertHistoryEsIndex = false, customizeLocalHostTls = false, + rejectUnauthorized = true, // legacy } = options; return async ({ readConfigFile }: FtrConfigProviderContext) => { @@ -101,19 +103,19 @@ export function createTestConfig(name: string, options: CreateTestConfigOptions) { url: tlsWebhookServers.rejectUnauthorizedFalse, tls: { - rejectUnauthorized: false, + verificationMode: 'none', }, }, { url: tlsWebhookServers.rejectUnauthorizedTrue, tls: { - rejectUnauthorized: true, + verificationMode: 'full', }, }, { url: tlsWebhookServers.caFile, tls: { - rejectUnauthorized: true, + verificationMode: 'certificate', certificateAuthoritiesFiles: [CA_CERT_PATH], }, }, @@ -151,6 +153,7 @@ export function createTestConfig(name: string, options: CreateTestConfigOptions) '--xpack.alerting.invalidateApiKeysTask.interval="15s"', `--xpack.actions.enabledActionTypes=${JSON.stringify(enabledActionTypes)}`, `--xpack.actions.rejectUnauthorized=${rejectUnauthorized}`, + `--xpack.actions.tls.verificationMode=${verificationMode}`, ...actionsProxyUrl, ...customHostSettings, '--xpack.eventLog.logEntries=true', diff --git a/x-pack/test/alerting_api_integration/spaces_only/config.ts b/x-pack/test/alerting_api_integration/spaces_only/config.ts index 3b3a15b6d62e4..788d9d0698a19 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/config.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/config.ts @@ -12,7 +12,7 @@ export default createTestConfig('spaces_only', { disabledPlugins: ['security'], license: 'trial', enableActionsProxy: false, - rejectUnauthorized: false, + verificationMode: 'none', customizeLocalHostTls: true, preconfiguredAlertHistoryEsIndex: true, }); diff --git a/x-pack/test/alerting_api_integration/spaces_only_legacy/config.ts b/x-pack/test/alerting_api_integration/spaces_only_legacy/config.ts new file mode 100644 index 0000000000000..511e97b96e35d --- /dev/null +++ b/x-pack/test/alerting_api_integration/spaces_only_legacy/config.ts @@ -0,0 +1,19 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { createTestConfig } from '../common/config'; + +// eslint-disable-next-line import/no-default-export +export default createTestConfig('spaces_only', { + disabledPlugins: ['security'], + license: 'trial', + enableActionsProxy: false, + rejectUnauthorized: false, + verificationMode: undefined, + customizeLocalHostTls: true, + preconfiguredAlertHistoryEsIndex: true, +}); diff --git a/x-pack/test/alerting_api_integration/spaces_only_legacy/scenarios.ts b/x-pack/test/alerting_api_integration/spaces_only_legacy/scenarios.ts new file mode 100644 index 0000000000000..5c00ad2f4f70f --- /dev/null +++ b/x-pack/test/alerting_api_integration/spaces_only_legacy/scenarios.ts @@ -0,0 +1,35 @@ +/* + * 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 { Space } from '../common/types'; + +const Space1: Space = { + id: 'space1', + namespace: 'space1', + name: 'Space 1', + disabledFeatures: [], +}; + +const Other: Space = { + id: 'other', + namespace: 'other', + name: 'Other', + disabledFeatures: [], +}; + +const Default: Space = { + id: 'default', + namespace: undefined, + name: 'Default', + disabledFeatures: [], +}; + +export const Spaces = { + space1: Space1, + other: Other, + default: Default, +}; diff --git a/x-pack/test/alerting_api_integration/spaces_only_legacy/tests/actions/builtin_action_types/webhook.ts b/x-pack/test/alerting_api_integration/spaces_only_legacy/tests/actions/builtin_action_types/webhook.ts new file mode 100644 index 0000000000000..4af33136cd42c --- /dev/null +++ b/x-pack/test/alerting_api_integration/spaces_only_legacy/tests/actions/builtin_action_types/webhook.ts @@ -0,0 +1,201 @@ +/* + * 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 http from 'http'; +import https from 'https'; +import getPort from 'get-port'; +import expect from '@kbn/expect'; +import { URL, format as formatUrl } from 'url'; +import { FtrProviderContext } from '../../../../common/ftr_provider_context'; +import { + getWebhookServer, + getHttpsWebhookServer, +} from '../../../../common/fixtures/plugins/actions_simulators/server/plugin'; +import { createTlsWebhookServer } from '../../../../common/lib/get_tls_webhook_servers'; + +// eslint-disable-next-line import/no-default-export +export default function webhookTest({ getService }: FtrProviderContext) { + const supertest = getService('supertest'); + + async function createWebhookAction( + webhookSimulatorURL: string, + config: Record> = {} + ): Promise { + const url = formatUrl(new URL(webhookSimulatorURL), { auth: false }); + const composedConfig = { + headers: { + 'Content-Type': 'text/plain', + }, + ...config, + url, + }; + + const { body: createdAction } = await supertest + .post('/api/actions/action') + .set('kbn-xsrf', 'test') + .send({ + name: 'A generic Webhook action', + actionTypeId: '.webhook', + secrets: {}, + config: composedConfig, + }) + .expect(200); + + return createdAction.id; + } + + async function getPortOfConnector(connectorId: string): Promise { + const response = await supertest.get(`/api/actions/connectors`).expect(200); + const connector = response.body.find((conn: { id: string }) => conn.id === connectorId); + if (connector === undefined) { + throw new Error(`unable to find connector with id ${connectorId}`); + } + + // server URL is the connector name + const url = connector.name; + const parsedUrl = new URL(url); + return parsedUrl.port; + } + + describe('webhook action', () => { + describe('with http endpoint', () => { + let webhookSimulatorURL: string = ''; + let webhookServer: http.Server; + before(async () => { + webhookServer = await getWebhookServer(); + const availablePort = await getPort({ port: 9000 }); + webhookServer.listen(availablePort); + webhookSimulatorURL = `http://localhost:${availablePort}`; + }); + + it('webhook can be executed without username and password', async () => { + const webhookActionId = await createWebhookAction(webhookSimulatorURL); + const { body: result } = await supertest + .post(`/api/actions/action/${webhookActionId}/_execute`) + .set('kbn-xsrf', 'test') + .send({ + params: { + body: 'success', + }, + }) + .expect(200); + + expect(result.status).to.eql('ok'); + }); + + after(() => { + webhookServer.close(); + }); + }); + + describe('with https endpoint and rejectUnauthorized=false', () => { + let webhookSimulatorURL: string = ''; + let webhookServer: https.Server; + + before(async () => { + webhookServer = await getHttpsWebhookServer(); + const availablePort = await getPort({ port: getPort.makeRange(9000, 9100) }); + webhookServer.listen(availablePort); + webhookSimulatorURL = `https://localhost:${availablePort}`; + }); + + it('should support the POST method against webhook target', async () => { + const webhookActionId = await createWebhookAction(webhookSimulatorURL, { method: 'post' }); + const { body: result } = await supertest + .post(`/api/actions/action/${webhookActionId}/_execute`) + .set('kbn-xsrf', 'test') + .send({ + params: { + body: 'success_post_method', + }, + }) + .expect(200); + + expect(result.status).to.eql('ok'); + }); + + after(() => { + webhookServer.close(); + }); + }); + + describe('tls customization', () => { + it('should handle the xpack.actions.rejectUnauthorized: false', async () => { + const connectorId = 'custom.tls.noCustom'; + const port = await getPortOfConnector(connectorId); + const server = await createTlsWebhookServer(port); + const { status, body } = await supertest + .post(`/api/actions/connector/${connectorId}/_execute`) + .set('kbn-xsrf', 'test') + .send({ + params: { + body: 'foo', + }, + }); + expect(status).to.eql(200); + server.close(); + + expect(body.status).to.eql('ok'); + }); + + it('should handle the customized rejectUnauthorized: false', async () => { + const connectorId = 'custom.tls.rejectUnauthorizedFalse'; + const port = await getPortOfConnector(connectorId); + const server = await createTlsWebhookServer(port); + const { status, body } = await supertest + .post(`/api/actions/connector/custom.tls.rejectUnauthorizedFalse/_execute`) + .set('kbn-xsrf', 'test') + .send({ + params: { + body: 'foo', + }, + }); + expect(status).to.eql(200); + server.close(); + + expect(body.status).to.eql('ok'); + }); + + it('should handle the customized rejectUnauthorized: true', async () => { + const connectorId = 'custom.tls.rejectUnauthorizedTrue'; + const port = await getPortOfConnector(connectorId); + const server = await createTlsWebhookServer(port); + const { status, body } = await supertest + .post(`/api/actions/connector/custom.tls.rejectUnauthorizedTrue/_execute`) + .set('kbn-xsrf', 'test') + .send({ + params: { + body: 'foo', + }, + }); + expect(status).to.eql(200); + server.close(); + + expect(body.status).to.eql('error'); + expect(body.service_message.indexOf('certificate')).to.be.greaterThan(0); + }); + + it('should handle the customized ca file', async () => { + const connectorId = 'custom.tls.caFile'; + const port = await getPortOfConnector(connectorId); + const server = await createTlsWebhookServer(port); + const { status, body } = await supertest + .post(`/api/actions/connector/custom.tls.caFile/_execute`) + .set('kbn-xsrf', 'test') + .send({ + params: { + body: 'foo', + }, + }); + expect(status).to.eql(200); + server.close(); + + expect(body.status).to.eql('ok'); + }); + }); + }); +} diff --git a/x-pack/test/alerting_api_integration/spaces_only_legacy/tests/index.ts b/x-pack/test/alerting_api_integration/spaces_only_legacy/tests/index.ts new file mode 100644 index 0000000000000..a5a046dcbbe86 --- /dev/null +++ b/x-pack/test/alerting_api_integration/spaces_only_legacy/tests/index.ts @@ -0,0 +1,33 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../../common/ftr_provider_context'; +import { Spaces } from '../scenarios'; + +// eslint-disable-next-line import/no-default-export +export default function alertingApiIntegrationTests({ loadTestFile }: FtrProviderContext) { + describe('alerting api integration spaces only legacy configuration', function () { + this.tags('ciGroup12'); + + loadTestFile(require.resolve('./actions/builtin_action_types/webhook')); + }); +} + +export async function buildUp(getService: FtrProviderContext['getService']) { + const spacesService = getService('spaces'); + for (const space of Object.values(Spaces)) { + if (space.id === 'default') continue; + + const { id, name, disabledFeatures } = space; + await spacesService.create({ id, name, disabledFeatures }); + } +} + +export async function tearDown(getService: FtrProviderContext['getService']) { + const esArchiver = getService('esArchiver'); + await esArchiver.unload('empty_kibana'); +} From 66867bbede848d907edd01ee6a2db0c5e626a6b9 Mon Sep 17 00:00:00 2001 From: spalger Date: Thu, 27 May 2021 14:27:10 -0700 Subject: [PATCH 47/77] Revert a terrible mistake Revert "save" This reverts commit 4272bfb9720ac68fe7638128836697a578863c18. --- .../src/lib/docs/index_doc_records_stream.ts | 2 -- .../src/lib/indices/create_index_stream.ts | 15 --------------- .../src/lib/indices/delete_index.ts | 13 +------------ packages/kbn-es-archiver/src/lib/stats.ts | 2 -- 4 files changed, 1 insertion(+), 31 deletions(-) diff --git a/packages/kbn-es-archiver/src/lib/docs/index_doc_records_stream.ts b/packages/kbn-es-archiver/src/lib/docs/index_doc_records_stream.ts index 99fb31a8c942a..028ff16c9afb2 100644 --- a/packages/kbn-es-archiver/src/lib/docs/index_doc_records_stream.ts +++ b/packages/kbn-es-archiver/src/lib/docs/index_doc_records_stream.ts @@ -66,8 +66,6 @@ export function createIndexDocRecordsStream( async write(record, enc, callback) { try { - stats.log.info('index doc records stream write()', record); - await indexDocs([record.value]); progress.addToComplete(1); callback(null); diff --git a/packages/kbn-es-archiver/src/lib/indices/create_index_stream.ts b/packages/kbn-es-archiver/src/lib/indices/create_index_stream.ts index 4cbec1488104e..b45a8b18a5776 100644 --- a/packages/kbn-es-archiver/src/lib/indices/create_index_stream.ts +++ b/packages/kbn-es-archiver/src/lib/indices/create_index_stream.ts @@ -62,13 +62,6 @@ export function createCreateIndexStream({ kibanaIndexAlreadyDeleted = true; } - await new Promise((resolve) => setTimeout(resolve, 6000)); - - stats.log.info('calling client.indices.create', { - index, - body: { settings, mappings, aliases }, - }); - await client.indices.create( { index, @@ -102,10 +95,6 @@ export function createCreateIndexStream({ err?.meta?.body?.error?.type !== 'resource_already_exists_exception' || attemptNumber >= 3 ) { - stats.log.info('throwing error', { - message: err.message, - meta: err.meta, - }); throw err; } @@ -115,10 +104,6 @@ export function createCreateIndexStream({ return; } - stats.log.info('trying to delete existing index', { - message: err.message, - meta: err.meta, - }); await deleteIndex({ client, stats, index, log }); await attemptToCreate(attemptNumber + 1); return; diff --git a/packages/kbn-es-archiver/src/lib/indices/delete_index.ts b/packages/kbn-es-archiver/src/lib/indices/delete_index.ts index f0ad76435eeef..2a42d52e2ca80 100644 --- a/packages/kbn-es-archiver/src/lib/indices/delete_index.ts +++ b/packages/kbn-es-archiver/src/lib/indices/delete_index.ts @@ -35,32 +35,21 @@ export async function deleteIndex(options: { } ); - stats.log.info('attempt to get aliases for', indices, resp); - return resp.statusCode === 404 ? indices : Object.keys(resp.body); }; try { const indicesToDelete = await getIndicesToDelete(); - - stats.log.info('indices to delete', indicesToDelete); - - const resp = await client.indices.delete( + await client.indices.delete( { index: indicesToDelete }, { headers: ES_CLIENT_HEADERS, } ); - stats.log.info('deleted indices with response', resp.body); for (const index of indices) { stats.deletedIndex(index); } } catch (error) { - stats.log.info('error while deleting indices', { - message: error.message, - meta: error.meta, - }); - if (retryIfSnapshottingCount > 0 && isDeleteWhileSnapshotInProgressError(error)) { for (const index of indices) { stats.waitingForInProgressSnapshot(index); diff --git a/packages/kbn-es-archiver/src/lib/stats.ts b/packages/kbn-es-archiver/src/lib/stats.ts index 9f8c1b6fa99ef..64dd6a9273efe 100644 --- a/packages/kbn-es-archiver/src/lib/stats.ts +++ b/packages/kbn-es-archiver/src/lib/stats.ts @@ -56,8 +56,6 @@ export function createStats(name: string, log: ToolingLog) { }; return new (class Stats { - public readonly log = log; - /** * Record that an index was not restored because it already existed * @param index From 868e5df87d852a63f8d986b45ebe477c1d0d5a08 Mon Sep 17 00:00:00 2001 From: spalger Date: Thu, 27 May 2021 14:30:32 -0700 Subject: [PATCH 48/77] disable build buddy temproarily --- packages/kbn-pm/dist/index.js | 4 ++-- packages/kbn-pm/src/utils/bazel/run.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/kbn-pm/dist/index.js b/packages/kbn-pm/dist/index.js index 29c0457c316f0..f676db6611072 100644 --- a/packages/kbn-pm/dist/index.js +++ b/packages/kbn-pm/dist/index.js @@ -48470,8 +48470,8 @@ async function runBazelCommandWithRunner(bazelCommandRunner, bazelArgs, offline stdio: 'pipe' }); - if (offline) { - bazelArgs.push('--config=offline'); + if (offline || !offline) { + bazelArgs = [...bazelArgs, '--config=offline']; } const bazelProc = Object(_child_process__WEBPACK_IMPORTED_MODULE_4__["spawn"])(bazelCommandRunner, bazelArgs, bazelOpts); diff --git a/packages/kbn-pm/src/utils/bazel/run.ts b/packages/kbn-pm/src/utils/bazel/run.ts index 7b20ea43982e6..5f3743876e0e4 100644 --- a/packages/kbn-pm/src/utils/bazel/run.ts +++ b/packages/kbn-pm/src/utils/bazel/run.ts @@ -29,8 +29,8 @@ async function runBazelCommandWithRunner( stdio: 'pipe', }; - if (offline) { - bazelArgs.push('--config=offline'); + if (offline || !offline) { + bazelArgs = [...bazelArgs, '--config=offline']; } const bazelProc = spawn(bazelCommandRunner, bazelArgs, bazelOpts); From 48f7a479b58434441cee393cb956ee83eb813f9a Mon Sep 17 00:00:00 2001 From: Marta Bondyra Date: Fri, 28 May 2021 00:24:38 +0200 Subject: [PATCH 49/77] [Lens] fix error when adding a new layer (#100766) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- x-pack/plugins/lens/public/xy_visualization/xy_config_panel.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/lens/public/xy_visualization/xy_config_panel.tsx b/x-pack/plugins/lens/public/xy_visualization/xy_config_panel.tsx index 3037513ccd56e..a6517894654ed 100644 --- a/x-pack/plugins/lens/public/xy_visualization/xy_config_panel.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/xy_config_panel.tsx @@ -140,7 +140,7 @@ const getDataBounds = function ( let min = Number.MAX_VALUE; let max = Number.MIN_VALUE; axis.series.forEach((series) => { - activeData?.[series.layer].rows.forEach((row) => { + activeData?.[series.layer]?.rows.forEach((row) => { const value = row[series.accessor]; if (!Number.isNaN(value)) { if (value < min) { From fd561dda1bcc59da210ee039e9afdf5dd7f81602 Mon Sep 17 00:00:00 2001 From: spalger Date: Thu, 27 May 2021 16:36:19 -0700 Subject: [PATCH 50/77] Revert "disable build buddy temproarily" This reverts commit 868e5df87d852a63f8d986b45ebe477c1d0d5a08. --- packages/kbn-pm/dist/index.js | 4 ++-- packages/kbn-pm/src/utils/bazel/run.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/kbn-pm/dist/index.js b/packages/kbn-pm/dist/index.js index f676db6611072..29c0457c316f0 100644 --- a/packages/kbn-pm/dist/index.js +++ b/packages/kbn-pm/dist/index.js @@ -48470,8 +48470,8 @@ async function runBazelCommandWithRunner(bazelCommandRunner, bazelArgs, offline stdio: 'pipe' }); - if (offline || !offline) { - bazelArgs = [...bazelArgs, '--config=offline']; + if (offline) { + bazelArgs.push('--config=offline'); } const bazelProc = Object(_child_process__WEBPACK_IMPORTED_MODULE_4__["spawn"])(bazelCommandRunner, bazelArgs, bazelOpts); diff --git a/packages/kbn-pm/src/utils/bazel/run.ts b/packages/kbn-pm/src/utils/bazel/run.ts index 5f3743876e0e4..7b20ea43982e6 100644 --- a/packages/kbn-pm/src/utils/bazel/run.ts +++ b/packages/kbn-pm/src/utils/bazel/run.ts @@ -29,8 +29,8 @@ async function runBazelCommandWithRunner( stdio: 'pipe', }; - if (offline || !offline) { - bazelArgs = [...bazelArgs, '--config=offline']; + if (offline) { + bazelArgs.push('--config=offline'); } const bazelProc = spawn(bazelCommandRunner, bazelArgs, bazelOpts); From 74682bc55d07d3a1c4de7b9d3c05d80e95dcd44a Mon Sep 17 00:00:00 2001 From: Spencer Date: Thu, 27 May 2021 22:05:28 -0700 Subject: [PATCH 51/77] [ftr] migrate "embedding" and "renderable" services to FtrService class (#100596) Co-authored-by: spalger --- test/functional/services/embedding.ts | 30 +++++------- test/functional/services/index.ts | 8 +-- test/functional/services/renderable.ts | 68 ++++++++++++-------------- 3 files changed, 49 insertions(+), 57 deletions(-) diff --git a/test/functional/services/embedding.ts b/test/functional/services/embedding.ts index f3d5340e41fa6..e394aff19ab8b 100644 --- a/test/functional/services/embedding.ts +++ b/test/functional/services/embedding.ts @@ -6,24 +6,20 @@ * Side Public License, v 1. */ -import { FtrProviderContext } from '../ftr_provider_context'; +import { FtrService } from '../ftr_provider_context'; -export function EmbeddingProvider({ getService, getPageObjects }: FtrProviderContext) { - const browser = getService('browser'); - const log = getService('log'); - const PageObjects = getPageObjects(['header']); +export class EmbeddingService extends FtrService { + private readonly browser = this.ctx.getService('browser'); + private readonly log = this.ctx.getService('log'); + private readonly PageObjects = this.ctx.getPageObjects(['header']); - class Embedding { - /** - * Opens current page in embeded mode - */ - public async openInEmbeddedMode(): Promise { - const currentUrl = await browser.getCurrentUrl(); - log.debug(`Opening in embedded mode: ${currentUrl}`); - await browser.get(`${currentUrl}&embed=true`); - await PageObjects.header.waitUntilLoadingHasFinished(); - } + /** + * Opens current page in embeded mode + */ + public async openInEmbeddedMode(): Promise { + const currentUrl = await this.browser.getCurrentUrl(); + this.log.debug(`Opening in embedded mode: ${currentUrl}`); + await this.browser.get(`${currentUrl}&embed=true`); + await this.PageObjects.header.waitUntilLoadingHasFinished(); } - - return new Embedding(); } diff --git a/test/functional/services/index.ts b/test/functional/services/index.ts index 03c43ffc30214..99648fe207070 100644 --- a/test/functional/services/index.ts +++ b/test/functional/services/index.ts @@ -26,7 +26,7 @@ import { DashboardVisualizationsService, } from './dashboard'; import { DocTableService } from './doc_table'; -import { EmbeddingProvider } from './embedding'; +import { EmbeddingService } from './embedding'; import { FilterBarService } from './filter_bar'; import { FlyoutService } from './flyout'; import { GlobalNavService } from './global_nav'; @@ -35,7 +35,7 @@ import { FieldEditorService } from './field_editor'; import { ManagementMenuService } from './management'; import { QueryBarProvider } from './query_bar'; import { RemoteProvider } from './remote'; -import { RenderableProvider } from './renderable'; +import { RenderableService } from './renderable'; import { ToastsService } from './toasts'; import { DataGridService } from './data_grid'; import { @@ -70,8 +70,8 @@ export const services = { flyout: FlyoutService, comboBox: ComboBoxService, dataGrid: DataGridService, - embedding: EmbeddingProvider, - renderable: RenderableProvider, + embedding: EmbeddingService, + renderable: RenderableService, browser: BrowserProvider, pieChart: PieChartService, inspector: InspectorService, diff --git a/test/functional/services/renderable.ts b/test/functional/services/renderable.ts index 42ea808bd64ba..da298b6ec0343 100644 --- a/test/functional/services/renderable.ts +++ b/test/functional/services/renderable.ts @@ -6,49 +6,45 @@ * Side Public License, v 1. */ -import { FtrProviderContext } from '../ftr_provider_context'; +import { FtrService } from '../ftr_provider_context'; const RENDER_COMPLETE_SELECTOR = '[data-render-complete="true"]'; const RENDER_COMPLETE_PENDING_SELECTOR = '[data-render-complete="false"]'; const DATA_LOADING_SELECTOR = '[data-loading]'; -export function RenderableProvider({ getService }: FtrProviderContext) { - const log = getService('log'); - const retry = getService('retry'); - const find = getService('find'); +export class RenderableService extends FtrService { + private readonly log = this.ctx.getService('log'); + private readonly retry = this.ctx.getService('retry'); + private readonly find = this.ctx.getService('find'); - class Renderable { - /** - * This method waits for a certain number of objects to finish rendering and loading, which is indicated - * by a couple tags. The RENDER_COMPLETE_SELECTOR indicates that it's done initially loading up. Some - * visualizations also add a DATA_LOADING_SELECTOR when the internal data is loading. This test will not - * return if any of those tags are found. - * @param count {Number} Number of RENDER_COMPLETE_SELECTORs to wait for. - */ - public async waitForRender(count: number = 1): Promise { - log.debug(`Renderable.waitForRender for ${count} elements`); - await retry.try(async () => { - const completedElements = await find.allByCssSelector(RENDER_COMPLETE_SELECTOR); - if (completedElements.length < count) { - const pendingElements = await find.allByCssSelector(RENDER_COMPLETE_PENDING_SELECTOR); - const pendingElementNames = []; - for (const pendingElement of pendingElements) { - const title = await pendingElement.getAttribute('data-title'); - pendingElementNames.push(title); - } - throw new Error(`${ - completedElements.length - } elements completed rendering, still waiting on a total of ${count} - specifically:\n${pendingElementNames.join('\n')}`); + /** + * This method waits for a certain number of objects to finish rendering and loading, which is indicated + * by a couple tags. The RENDER_COMPLETE_SELECTOR indicates that it's done initially loading up. Some + * visualizations also add a DATA_LOADING_SELECTOR when the internal data is loading. This test will not + * return if any of those tags are found. + * @param count {Number} Number of RENDER_COMPLETE_SELECTORs to wait for. + */ + public async waitForRender(count: number = 1): Promise { + this.log.debug(`Renderable.waitForRender for ${count} elements`); + await this.retry.try(async () => { + const completedElements = await this.find.allByCssSelector(RENDER_COMPLETE_SELECTOR); + if (completedElements.length < count) { + const pendingElements = await this.find.allByCssSelector(RENDER_COMPLETE_PENDING_SELECTOR); + const pendingElementNames = []; + for (const pendingElement of pendingElements) { + const title = await pendingElement.getAttribute('data-title'); + pendingElementNames.push(title); } + throw new Error(`${ + completedElements.length + } elements completed rendering, still waiting on a total of ${count} + specifically:\n${pendingElementNames.join('\n')}`); + } - const stillLoadingElements = await find.allByCssSelector(DATA_LOADING_SELECTOR, 1000); - if (stillLoadingElements.length > 0) { - throw new Error(`${stillLoadingElements.length} elements still loading contents`); - } - }); - } + const stillLoadingElements = await this.find.allByCssSelector(DATA_LOADING_SELECTOR, 1000); + if (stillLoadingElements.length > 0) { + throw new Error(`${stillLoadingElements.length} elements still loading contents`); + } + }); } - - return new Renderable(); } From 9538788611987a56f692d3e72501e0f1b599715e Mon Sep 17 00:00:00 2001 From: Spencer Date: Thu, 27 May 2021 22:10:32 -0700 Subject: [PATCH 52/77] [ftr] migrate "MenuToggle" service to FtrService class (#100608) Co-authored-by: spalger Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- test/functional/page_objects/time_picker.ts | 4 +- test/functional/services/index.ts | 4 +- test/functional/services/menu_toggle.ts | 65 +++++++++---------- .../test/functional/page_objects/gis_page.ts | 4 +- 4 files changed, 36 insertions(+), 41 deletions(-) diff --git a/test/functional/page_objects/time_picker.ts b/test/functional/page_objects/time_picker.ts index d3b6edaffdbd3..4d0930c3ff932 100644 --- a/test/functional/page_objects/time_picker.ts +++ b/test/functional/page_objects/time_picker.ts @@ -30,9 +30,9 @@ export function TimePickerProvider({ getService, getPageObjects }: FtrProviderCo const testSubjects = getService('testSubjects'); const { header } = getPageObjects(['header']); const kibanaServer = getService('kibanaServer'); - const MenuToggle = getService('MenuToggle'); + const menuToggle = getService('menuToggle'); - const quickSelectTimeMenuToggle = new MenuToggle({ + const quickSelectTimeMenuToggle = menuToggle.create({ name: 'QuickSelectTime Menu', menuTestSubject: 'superDatePickerQuickMenu', toggleButtonTestSubject: 'superDatePickerToggleQuickMenuButton', diff --git a/test/functional/services/index.ts b/test/functional/services/index.ts index 99648fe207070..9e58500c40c05 100644 --- a/test/functional/services/index.ts +++ b/test/functional/services/index.ts @@ -46,7 +46,7 @@ import { import { ListingTableService } from './listing_table'; import { SavedQueryManagementComponentProvider } from './saved_query_management_component'; import { KibanaSupertestProvider } from './supertest'; -import { MenuToggleProvider } from './menu_toggle'; +import { MenuToggleService } from './menu_toggle'; import { MonacoEditorProvider } from './monaco_editor'; export const services = { @@ -85,5 +85,5 @@ export const services = { supertest: KibanaSupertestProvider, managementMenu: ManagementMenuService, monacoEditor: MonacoEditorProvider, - MenuToggle: MenuToggleProvider, + menuToggle: MenuToggleService, }; diff --git a/test/functional/services/menu_toggle.ts b/test/functional/services/menu_toggle.ts index 866d73bd9df25..4de66a5697775 100644 --- a/test/functional/services/menu_toggle.ts +++ b/test/functional/services/menu_toggle.ts @@ -6,61 +6,56 @@ * Side Public License, v 1. */ -import { FtrProviderContext } from '../ftr_provider_context'; +import { FtrService } from '../ftr_provider_context'; -export function MenuToggleProvider({ getService }: FtrProviderContext) { - const log = getService('log'); - const retry = getService('retry'); - const testSubjects = getService('testSubjects'); - - interface Options { - name: string; - menuTestSubject: string; - toggleButtonTestSubject: string; - } - - return class MenuToggle { - private readonly name: string; - private readonly menuTestSubject: string; - private readonly toggleButtonTestSubject: string; +interface Options { + name: string; + menuTestSubject: string; + toggleButtonTestSubject: string; +} - constructor(options: Options) { - this.name = options.name; - this.menuTestSubject = options.menuTestSubject; - this.toggleButtonTestSubject = options.toggleButtonTestSubject; - } +export class MenuToggleService extends FtrService { + private readonly log = this.ctx.getService('log'); + private readonly retry = this.ctx.getService('retry'); + private readonly testSubjects = this.ctx.getService('testSubjects'); - async open() { - await this.setState(true); - } + create(options: Options) { + const { log, retry, testSubjects } = this; + const { name, menuTestSubject, toggleButtonTestSubject } = options; - async close() { - await this.setState(false); - } - - private async setState(expectedState: boolean) { + async function setState(expectedState: boolean) { log.debug( - `setting menu open state [name=${this.name}] [state=${expectedState ? 'open' : 'closed'}]` + `setting menu open state [name=${name}] [state=${expectedState ? 'open' : 'closed'}]` ); await retry.try(async () => { // if the menu is clearly in the expected state already, bail out quickly if so - const isOpen = await testSubjects.exists(this.menuTestSubject, { timeout: 1000 }); + const isOpen = await testSubjects.exists(menuTestSubject, { timeout: 1000 }); if (isOpen === expectedState) { return; } // toggle the view state by clicking the button - await testSubjects.click(this.toggleButtonTestSubject); + await testSubjects.click(toggleButtonTestSubject); if (expectedState === true) { // wait for up to 10 seconds for the menu to show up, otherwise fail and retry - await testSubjects.existOrFail(this.menuTestSubject, { timeout: 10000 }); + await testSubjects.existOrFail(menuTestSubject, { timeout: 10000 }); } else { // wait for the form to hide, otherwise fail and retry - await testSubjects.waitForDeleted(this.menuTestSubject); + await testSubjects.waitForDeleted(menuTestSubject); } }); } - }; + + return { + async open() { + await setState(true); + }, + + async close() { + await setState(false); + }, + }; + } } diff --git a/x-pack/test/functional/page_objects/gis_page.ts b/x-pack/test/functional/page_objects/gis_page.ts index 4a898967419b6..99d7172651a4d 100644 --- a/x-pack/test/functional/page_objects/gis_page.ts +++ b/x-pack/test/functional/page_objects/gis_page.ts @@ -21,12 +21,12 @@ export function GisPageProvider({ getService, getPageObjects }: FtrProviderConte const comboBox = getService('comboBox'); const renderable = getService('renderable'); const browser = getService('browser'); - const MenuToggle = getService('MenuToggle'); + const menuToggle = getService('menuToggle'); const listingTable = getService('listingTable'); const monacoEditor = getService('monacoEditor'); const dashboardPanelActions = getService('dashboardPanelActions'); - const setViewPopoverToggle = new MenuToggle({ + const setViewPopoverToggle = menuToggle.create({ name: 'SetView Popover', menuTestSubject: 'mapSetViewForm', toggleButtonTestSubject: 'toggleSetViewVisibilityButton', From 9f5a61c59b2c54806bd75d4933b023e12e2a4e3b Mon Sep 17 00:00:00 2001 From: Spencer Date: Thu, 27 May 2021 22:14:07 -0700 Subject: [PATCH 53/77] [ftr] migrate "queryBar" service to FtrService class (#100612) Co-authored-by: spalger --- test/functional/services/index.ts | 4 +- test/functional/services/query_bar.ts | 124 ++++++++++++-------------- 2 files changed, 61 insertions(+), 67 deletions(-) diff --git a/test/functional/services/index.ts b/test/functional/services/index.ts index 9e58500c40c05..56f3b13e38e98 100644 --- a/test/functional/services/index.ts +++ b/test/functional/services/index.ts @@ -33,7 +33,7 @@ import { GlobalNavService } from './global_nav'; import { InspectorService } from './inspector'; import { FieldEditorService } from './field_editor'; import { ManagementMenuService } from './management'; -import { QueryBarProvider } from './query_bar'; +import { QueryBarService } from './query_bar'; import { RemoteProvider } from './remote'; import { RenderableService } from './renderable'; import { ToastsService } from './toasts'; @@ -54,7 +54,7 @@ export const services = { __webdriver__: RemoteProvider, filterBar: FilterBarService, - queryBar: QueryBarProvider, + queryBar: QueryBarService, find: FindProvider, testSubjects: TestSubjects, docTable: DocTableService, diff --git a/test/functional/services/query_bar.ts b/test/functional/services/query_bar.ts index 2c4cd3b8db131..31586d92d92a9 100644 --- a/test/functional/services/query_bar.ts +++ b/test/functional/services/query_bar.ts @@ -7,82 +7,76 @@ */ import expect from '@kbn/expect'; -import { FtrProviderContext } from '../ftr_provider_context'; +import { FtrService } from '../ftr_provider_context'; -export function QueryBarProvider({ getService, getPageObjects }: FtrProviderContext) { - const testSubjects = getService('testSubjects'); - const retry = getService('retry'); - const log = getService('log'); - const PageObjects = getPageObjects(['header', 'common']); - const find = getService('find'); - const browser = getService('browser'); +export class QueryBarService extends FtrService { + private readonly testSubjects = this.ctx.getService('testSubjects'); + private readonly retry = this.ctx.getService('retry'); + private readonly log = this.ctx.getService('log'); + private readonly PageObjects = this.ctx.getPageObjects(['header', 'common']); + private readonly find = this.ctx.getService('find'); + private readonly browser = this.ctx.getService('browser'); - class QueryBar { - async getQueryString(): Promise { - return await testSubjects.getAttribute('queryInput', 'value'); - } + async getQueryString(): Promise { + return await this.testSubjects.getAttribute('queryInput', 'value'); + } - public async setQuery(query: string): Promise { - log.debug(`QueryBar.setQuery(${query})`); - // Extra caution used because of flaky test here: https://github.com/elastic/kibana/issues/16978 doesn't seem - // to be actually setting the query in the query input based off - await retry.try(async () => { - await testSubjects.click('queryInput'); + public async setQuery(query: string): Promise { + this.log.debug(`QueryBar.setQuery(${query})`); + // Extra caution used because of flaky test here: https://github.com/elastic/kibana/issues/16978 doesn't seem + // to be actually setting the query in the query input based off + await this.retry.try(async () => { + await this.testSubjects.click('queryInput'); - // testSubjects.setValue uses input.clearValue which wasn't working, but input.clearValueWithKeyboard does. - // So the following lines do the same thing as input.setValue but with input.clearValueWithKeyboard instead. - const input = await find.activeElement(); - await input.clearValueWithKeyboard(); - await input.type(query); - const currentQuery = await this.getQueryString(); - if (currentQuery !== query) { - throw new Error( - `Failed to set query input to ${query}, instead query is ${currentQuery}` - ); - } - }); - } - - public async clearQuery(): Promise { - await this.setQuery(''); - await PageObjects.common.pressTabKey(); // move outside of input into language switcher - await PageObjects.common.pressTabKey(); // move outside of language switcher so time picker appears - } + // this.testSubjects.setValue uses input.clearValue which wasn't working, but input.clearValueWithKeyboard does. + // So the following lines do the same thing as input.setValue but with input.clearValueWithKeyboard instead. + const input = await this.find.activeElement(); + await input.clearValueWithKeyboard(); + await input.type(query); + const currentQuery = await this.getQueryString(); + if (currentQuery !== query) { + throw new Error(`Failed to set query input to ${query}, instead query is ${currentQuery}`); + } + }); + } - public async submitQuery(): Promise { - log.debug('QueryBar.submitQuery'); - await testSubjects.click('queryInput'); - await PageObjects.common.pressEnterKey(); - await PageObjects.header.waitUntilLoadingHasFinished(); - } + public async clearQuery(): Promise { + await this.setQuery(''); + await this.PageObjects.common.pressTabKey(); // move outside of input into language switcher + await this.PageObjects.common.pressTabKey(); // move outside of language switcher so time picker appears + } - public async clickQuerySubmitButton(): Promise { - await testSubjects.click('querySubmitButton'); - } + public async submitQuery(): Promise { + this.log.debug('QueryBar.submitQuery'); + await this.testSubjects.click('queryInput'); + await this.PageObjects.common.pressEnterKey(); + await this.PageObjects.header.waitUntilLoadingHasFinished(); + } - public async switchQueryLanguage(lang: 'kql' | 'lucene'): Promise { - await testSubjects.click('switchQueryLanguageButton'); - const kqlToggle = await testSubjects.find('languageToggle'); - const currentLang = - (await kqlToggle.getAttribute('aria-checked')) === 'true' ? 'kql' : 'lucene'; - if (lang !== currentLang) { - await kqlToggle.click(); - } + public async clickQuerySubmitButton(): Promise { + await this.testSubjects.click('querySubmitButton'); + } - await browser.pressKeys(browser.keys.ESCAPE); // close popover - await this.expectQueryLanguageOrFail(lang); // make sure lang is switched + public async switchQueryLanguage(lang: 'kql' | 'lucene'): Promise { + await this.testSubjects.click('switchQueryLanguageButton'); + const kqlToggle = await this.testSubjects.find('languageToggle'); + const currentLang = + (await kqlToggle.getAttribute('aria-checked')) === 'true' ? 'kql' : 'lucene'; + if (lang !== currentLang) { + await kqlToggle.click(); } - public async expectQueryLanguageOrFail(lang: 'kql' | 'lucene'): Promise { - const queryLanguageButton = await testSubjects.find('switchQueryLanguageButton'); - expect((await queryLanguageButton.getVisibleText()).toLowerCase()).to.eql(lang); - } + await this.browser.pressKeys(this.browser.keys.ESCAPE); // close popover + await this.expectQueryLanguageOrFail(lang); // make sure lang is switched + } - public async getSuggestions() { - const suggestions = await testSubjects.findAll('autoCompleteSuggestionText'); - return Promise.all(suggestions.map((suggestion) => suggestion.getVisibleText())); - } + public async expectQueryLanguageOrFail(lang: 'kql' | 'lucene'): Promise { + const queryLanguageButton = await this.testSubjects.find('switchQueryLanguageButton'); + expect((await queryLanguageButton.getVisibleText()).toLowerCase()).to.eql(lang); } - return new QueryBar(); + public async getSuggestions() { + const suggestions = await this.testSubjects.findAll('autoCompleteSuggestionText'); + return Promise.all(suggestions.map((suggestion) => suggestion.getVisibleText())); + } } From fcaded750fd1c04c713a87c12af612712773f1be Mon Sep 17 00:00:00 2001 From: Spencer Date: Fri, 28 May 2021 00:01:09 -0700 Subject: [PATCH 54/77] [ftr] migrate "savedObjectManagementComponent" service to FtrService class (#100614) Co-authored-by: spalger --- test/functional/services/index.ts | 4 +- .../saved_query_management_component.ts | 347 +++++++++--------- 2 files changed, 173 insertions(+), 178 deletions(-) diff --git a/test/functional/services/index.ts b/test/functional/services/index.ts index 56f3b13e38e98..a509141390f67 100644 --- a/test/functional/services/index.ts +++ b/test/functional/services/index.ts @@ -44,7 +44,7 @@ import { VegaDebugInspectorViewService, } from './visualizations'; import { ListingTableService } from './listing_table'; -import { SavedQueryManagementComponentProvider } from './saved_query_management_component'; +import { SavedQueryManagementComponentService } from './saved_query_management_component'; import { KibanaSupertestProvider } from './supertest'; import { MenuToggleService } from './menu_toggle'; import { MonacoEditorProvider } from './monaco_editor'; @@ -80,7 +80,7 @@ export const services = { appsMenu: AppsMenuService, globalNav: GlobalNavService, toasts: ToastsService, - savedQueryManagementComponent: SavedQueryManagementComponentProvider, + savedQueryManagementComponent: SavedQueryManagementComponentService, elasticChart: ElasticChartService, supertest: KibanaSupertestProvider, managementMenu: ManagementMenuService, diff --git a/test/functional/services/saved_query_management_component.ts b/test/functional/services/saved_query_management_component.ts index d4fa34f224547..aabe8c0aebb0c 100644 --- a/test/functional/services/saved_query_management_component.ts +++ b/test/functional/services/saved_query_management_component.ts @@ -7,210 +7,205 @@ */ import expect from '@kbn/expect'; -import { FtrProviderContext } from '../ftr_provider_context'; - -export function SavedQueryManagementComponentProvider({ - getService, - getPageObjects, -}: FtrProviderContext) { - const testSubjects = getService('testSubjects'); - const queryBar = getService('queryBar'); - const retry = getService('retry'); - const config = getService('config'); - const PageObjects = getPageObjects(['common']); - - class SavedQueryManagementComponent { - public async getCurrentlyLoadedQueryID() { - await this.openSavedQueryManagementComponent(); - try { - return await testSubjects.getVisibleText('~saved-query-list-item-selected'); - } catch { - return undefined; - } - } - - public async saveNewQuery( - name: string, - description: string, - includeFilters: boolean, - includeTimeFilter: boolean - ) { - await this.openSaveCurrentQueryModal(); - await this.submitSaveQueryForm(name, description, includeFilters, includeTimeFilter); +import { FtrService } from '../ftr_provider_context'; + +export class SavedQueryManagementComponentService extends FtrService { + private readonly testSubjects = this.ctx.getService('testSubjects'); + private readonly queryBar = this.ctx.getService('queryBar'); + private readonly retry = this.ctx.getService('retry'); + private readonly config = this.ctx.getService('config'); + private readonly PageObjects = this.ctx.getPageObjects(['common']); + + public async getCurrentlyLoadedQueryID() { + await this.openSavedQueryManagementComponent(); + try { + return await this.testSubjects.getVisibleText('~saved-query-list-item-selected'); + } catch { + return undefined; } + } - public async saveNewQueryWithNameError(name?: string) { - await this.openSaveCurrentQueryModal(); - if (name) { - await testSubjects.setValue('saveQueryFormTitle', name); - } - - // Form input validation only happens onBlur. Clicking the save button should de-focus the - // input element and the validation should prevent a save from actually happening if there's - // an error. - await testSubjects.click('savedQueryFormSaveButton'); - - await retry.waitForWithTimeout('save button to be disabled', 1000, async () => { - const saveQueryFormSaveButtonStatus = await testSubjects.isEnabled( - 'savedQueryFormSaveButton' - ); - return saveQueryFormSaveButtonStatus === false; - }); + public async saveNewQuery( + name: string, + description: string, + includeFilters: boolean, + includeTimeFilter: boolean + ) { + await this.openSaveCurrentQueryModal(); + await this.submitSaveQueryForm(name, description, includeFilters, includeTimeFilter); + } - await testSubjects.click('savedQueryFormCancelButton'); + public async saveNewQueryWithNameError(name?: string) { + await this.openSaveCurrentQueryModal(); + if (name) { + await this.testSubjects.setValue('saveQueryFormTitle', name); } - public async saveCurrentlyLoadedAsNewQuery( - name: string, - description: string, - includeFilters: boolean, - includeTimeFilter: boolean - ) { - await this.openSavedQueryManagementComponent(); - await testSubjects.click('saved-query-management-save-as-new-button'); - await this.submitSaveQueryForm(name, description, includeFilters, includeTimeFilter); - } + // Form input validation only happens onBlur. Clicking the save button should de-focus the + // input element and the validation should prevent a save from actually happening if there's + // an error. + await this.testSubjects.click('savedQueryFormSaveButton'); - public async updateCurrentlyLoadedQuery( - description: string, - includeFilters: boolean, - includeTimeFilter: boolean - ) { - await this.openSavedQueryManagementComponent(); - await testSubjects.click('saved-query-management-save-changes-button'); - await this.submitSaveQueryForm(null, description, includeFilters, includeTimeFilter); - } + await this.retry.waitForWithTimeout('save button to be disabled', 1000, async () => { + const saveQueryFormSaveButtonStatus = await this.testSubjects.isEnabled( + 'savedQueryFormSaveButton' + ); + return saveQueryFormSaveButtonStatus === false; + }); - public async loadSavedQuery(title: string) { - await this.openSavedQueryManagementComponent(); - await testSubjects.click(`~load-saved-query-${title}-button`); - await retry.try(async () => { - await this.openSavedQueryManagementComponent(); - const selectedSavedQueryText = await testSubjects.getVisibleText( - '~saved-query-list-item-selected' - ); - expect(selectedSavedQueryText).to.eql(title); - }); - await this.closeSavedQueryManagementComponent(); - } + await this.testSubjects.click('savedQueryFormCancelButton'); + } - public async deleteSavedQuery(title: string) { - await this.openSavedQueryManagementComponent(); - await testSubjects.click(`~delete-saved-query-${title}-button`); - await PageObjects.common.clickConfirmOnModal(); - } + public async saveCurrentlyLoadedAsNewQuery( + name: string, + description: string, + includeFilters: boolean, + includeTimeFilter: boolean + ) { + await this.openSavedQueryManagementComponent(); + await this.testSubjects.click('saved-query-management-save-as-new-button'); + await this.submitSaveQueryForm(name, description, includeFilters, includeTimeFilter); + } - async clearCurrentlyLoadedQuery() { + public async updateCurrentlyLoadedQuery( + description: string, + includeFilters: boolean, + includeTimeFilter: boolean + ) { + await this.openSavedQueryManagementComponent(); + await this.testSubjects.click('saved-query-management-save-changes-button'); + await this.submitSaveQueryForm(null, description, includeFilters, includeTimeFilter); + } + + public async loadSavedQuery(title: string) { + await this.openSavedQueryManagementComponent(); + await this.testSubjects.click(`~load-saved-query-${title}-button`); + await this.retry.try(async () => { await this.openSavedQueryManagementComponent(); - await testSubjects.click('saved-query-management-clear-button'); - await this.closeSavedQueryManagementComponent(); - const queryString = await queryBar.getQueryString(); - expect(queryString).to.be.empty(); - } + const selectedSavedQueryText = await this.testSubjects.getVisibleText( + '~saved-query-list-item-selected' + ); + expect(selectedSavedQueryText).to.eql(title); + }); + await this.closeSavedQueryManagementComponent(); + } - async submitSaveQueryForm( - title: string | null, - description: string, - includeFilters: boolean, - includeTimeFilter: boolean - ) { - if (title) { - await testSubjects.setValue('saveQueryFormTitle', title); - } - await testSubjects.setValue('saveQueryFormDescription', description); - - const currentIncludeFiltersValue = - (await testSubjects.getAttribute('saveQueryFormIncludeFiltersOption', 'aria-checked')) === - 'true'; - if (currentIncludeFiltersValue !== includeFilters) { - await testSubjects.click('saveQueryFormIncludeFiltersOption'); - } - - const currentIncludeTimeFilterValue = - (await testSubjects.getAttribute( - 'saveQueryFormIncludeTimeFilterOption', - 'aria-checked' - )) === 'true'; - if (currentIncludeTimeFilterValue !== includeTimeFilter) { - await testSubjects.click('saveQueryFormIncludeTimeFilterOption'); - } - - await testSubjects.click('savedQueryFormSaveButton'); - } + public async deleteSavedQuery(title: string) { + await this.openSavedQueryManagementComponent(); + await this.testSubjects.click(`~delete-saved-query-${title}-button`); + await this.PageObjects.common.clickConfirmOnModal(); + } - async savedQueryExist(title: string) { - await this.openSavedQueryManagementComponent(); - const exists = testSubjects.exists(`~load-saved-query-${title}-button`); - await this.closeSavedQueryManagementComponent(); - return exists; - } + async clearCurrentlyLoadedQuery() { + await this.openSavedQueryManagementComponent(); + await this.testSubjects.click('saved-query-management-clear-button'); + await this.closeSavedQueryManagementComponent(); + const queryString = await this.queryBar.getQueryString(); + expect(queryString).to.be.empty(); + } - async savedQueryExistOrFail(title: string) { - await this.openSavedQueryManagementComponent(); - await testSubjects.existOrFail(`~load-saved-query-${title}-button`); + async submitSaveQueryForm( + title: string | null, + description: string, + includeFilters: boolean, + includeTimeFilter: boolean + ) { + if (title) { + await this.testSubjects.setValue('saveQueryFormTitle', title); } + await this.testSubjects.setValue('saveQueryFormDescription', description); - async savedQueryTextExist(text: string) { - await this.openSavedQueryManagementComponent(); - const queryString = await queryBar.getQueryString(); - expect(queryString).to.eql(text); + const currentIncludeFiltersValue = + (await this.testSubjects.getAttribute( + 'saveQueryFormIncludeFiltersOption', + 'aria-checked' + )) === 'true'; + if (currentIncludeFiltersValue !== includeFilters) { + await this.testSubjects.click('saveQueryFormIncludeFiltersOption'); } - async savedQueryMissingOrFail(title: string) { - await retry.try(async () => { - await this.openSavedQueryManagementComponent(); - await testSubjects.missingOrFail(`~load-saved-query-${title}-button`); - }); - await this.closeSavedQueryManagementComponent(); + const currentIncludeTimeFilterValue = + (await this.testSubjects.getAttribute( + 'saveQueryFormIncludeTimeFilterOption', + 'aria-checked' + )) === 'true'; + if (currentIncludeTimeFilterValue !== includeTimeFilter) { + await this.testSubjects.click('saveQueryFormIncludeTimeFilterOption'); } - async openSavedQueryManagementComponent() { - const isOpenAlready = await testSubjects.exists('saved-query-management-popover'); - if (isOpenAlready) return; + await this.testSubjects.click('savedQueryFormSaveButton'); + } - await retry.waitFor('saved query management popover to have any text', async () => { - await testSubjects.click('saved-query-management-popover-button'); - const queryText = await testSubjects.getVisibleText('saved-query-management-popover'); - return queryText.length > 0; - }); - } + async savedQueryExist(title: string) { + await this.openSavedQueryManagementComponent(); + const exists = this.testSubjects.exists(`~load-saved-query-${title}-button`); + await this.closeSavedQueryManagementComponent(); + return exists; + } - async closeSavedQueryManagementComponent() { - const isOpenAlready = await testSubjects.exists('saved-query-management-popover'); - if (!isOpenAlready) return; + async savedQueryExistOrFail(title: string) { + await this.openSavedQueryManagementComponent(); + await this.testSubjects.existOrFail(`~load-saved-query-${title}-button`); + } - await retry.try(async () => { - await testSubjects.click('saved-query-management-popover-button'); - await testSubjects.missingOrFail('saved-query-management-popover'); - }); - } + async savedQueryTextExist(text: string) { + await this.openSavedQueryManagementComponent(); + const queryString = await this.queryBar.getQueryString(); + expect(queryString).to.eql(text); + } - async openSaveCurrentQueryModal() { + async savedQueryMissingOrFail(title: string) { + await this.retry.try(async () => { await this.openSavedQueryManagementComponent(); + await this.testSubjects.missingOrFail(`~load-saved-query-${title}-button`); + }); + await this.closeSavedQueryManagementComponent(); + } - await retry.try(async () => { - await testSubjects.click('saved-query-management-save-button'); - await testSubjects.existOrFail('saveQueryForm', { - timeout: config.get('timeouts.waitForExists'), - }); - }); - } + async openSavedQueryManagementComponent() { + const isOpenAlready = await this.testSubjects.exists('saved-query-management-popover'); + if (isOpenAlready) return; - async saveNewQueryMissingOrFail() { - await this.openSavedQueryManagementComponent(); - await testSubjects.missingOrFail('saved-query-management-save-button'); - } + await this.retry.waitFor('saved query management popover to have any text', async () => { + await this.testSubjects.click('saved-query-management-popover-button'); + const queryText = await this.testSubjects.getVisibleText('saved-query-management-popover'); + return queryText.length > 0; + }); + } - async updateCurrentlyLoadedQueryMissingOrFail() { - await this.openSavedQueryManagementComponent(); - await testSubjects.missingOrFail('saved-query-management-save-changes-button'); - } + async closeSavedQueryManagementComponent() { + const isOpenAlready = await this.testSubjects.exists('saved-query-management-popover'); + if (!isOpenAlready) return; - async deleteSavedQueryMissingOrFail(title: string) { - await this.openSavedQueryManagementComponent(); - await testSubjects.missingOrFail(`delete-saved-query-${title}-button`); - } + await this.retry.try(async () => { + await this.testSubjects.click('saved-query-management-popover-button'); + await this.testSubjects.missingOrFail('saved-query-management-popover'); + }); + } + + async openSaveCurrentQueryModal() { + await this.openSavedQueryManagementComponent(); + + await this.retry.try(async () => { + await this.testSubjects.click('saved-query-management-save-button'); + await this.testSubjects.existOrFail('saveQueryForm', { + timeout: this.config.get('timeouts.waitForExists'), + }); + }); + } + + async saveNewQueryMissingOrFail() { + await this.openSavedQueryManagementComponent(); + await this.testSubjects.missingOrFail('saved-query-management-save-button'); } - return new SavedQueryManagementComponent(); + async updateCurrentlyLoadedQueryMissingOrFail() { + await this.openSavedQueryManagementComponent(); + await this.testSubjects.missingOrFail('saved-query-management-save-changes-button'); + } + + async deleteSavedQueryMissingOrFail(title: string) { + await this.openSavedQueryManagementComponent(); + await this.testSubjects.missingOrFail(`delete-saved-query-${title}-button`); + } } From a4f6d43783f556f00ceef33e458049fd3715aeb6 Mon Sep 17 00:00:00 2001 From: Marta Bondyra Date: Fri, 28 May 2021 10:06:06 +0200 Subject: [PATCH 55/77] [Lens] Move app state to redux toolkit (#100338) --- package.json | 3 + .../lens/public/app_plugin/app.test.tsx | 1164 +++++-------- x-pack/plugins/lens/public/app_plugin/app.tsx | 533 +----- .../lens/public/app_plugin/lens_top_nav.tsx | 199 ++- .../lens/public/app_plugin/mounter.test.tsx | 150 ++ .../lens/public/app_plugin/mounter.tsx | 153 +- .../lens/public/app_plugin/time_range.ts | 84 - .../plugins/lens/public/app_plugin/types.ts | 57 +- .../editor_frame/editor_frame.test.tsx | 1501 ++++++++--------- .../editor_frame/editor_frame.tsx | 175 +- .../editor_frame_service/editor_frame/save.ts | 7 +- .../editor_frame/state_management.test.ts | 11 +- .../editor_frame/state_management.ts | 43 +- .../editor_frame/suggestion_helpers.ts | 8 +- .../workspace_panel/workspace_panel.test.tsx | 224 ++- .../workspace_panel/workspace_panel.tsx | 10 +- .../public/editor_frame_service/service.tsx | 31 +- x-pack/plugins/lens/public/mocks.tsx | 276 +++ .../shared_components/debounced_value.ts | 4 +- .../lens/public/state_management/app_slice.ts | 55 + .../external_context_middleware.ts | 103 ++ .../lens/public/state_management/index.ts | 76 + .../time_range_middleware.test.ts | 198 +++ .../state_management/time_range_middleware.ts | 61 + .../lens/public/state_management/types.ts | 42 + x-pack/plugins/lens/public/types.ts | 18 +- x-pack/plugins/lens/public/utils.ts | 30 + .../public/xy_visualization/visualization.tsx | 17 +- yarn.lock | 29 + 29 files changed, 2909 insertions(+), 2353 deletions(-) create mode 100644 x-pack/plugins/lens/public/app_plugin/mounter.test.tsx delete mode 100644 x-pack/plugins/lens/public/app_plugin/time_range.ts create mode 100644 x-pack/plugins/lens/public/state_management/app_slice.ts create mode 100644 x-pack/plugins/lens/public/state_management/external_context_middleware.ts create mode 100644 x-pack/plugins/lens/public/state_management/index.ts create mode 100644 x-pack/plugins/lens/public/state_management/time_range_middleware.test.ts create mode 100644 x-pack/plugins/lens/public/state_management/time_range_middleware.ts create mode 100644 x-pack/plugins/lens/public/state_management/types.ts diff --git a/package.json b/package.json index 1369b1d105aa4..627e8abd9d259 100644 --- a/package.json +++ b/package.json @@ -161,6 +161,7 @@ "@mapbox/mapbox-gl-draw": "1.3.0", "@mapbox/mapbox-gl-rtl-text": "0.2.3", "@mapbox/vector-tile": "1.3.1", + "@reduxjs/toolkit": "^1.5.1", "@scant/router": "^0.1.1", "@slack/webhook": "^5.0.4", "@turf/along": "6.0.1", @@ -173,6 +174,7 @@ "@turf/distance": "6.0.1", "@turf/helpers": "6.0.1", "@turf/length": "^6.0.2", + "@types/redux-logger": "^3.0.8", "JSONStream": "1.3.5", "abort-controller": "^3.0.0", "abortcontroller-polyfill": "^1.4.0", @@ -365,6 +367,7 @@ "redux": "^4.0.5", "redux-actions": "^2.6.5", "redux-devtools-extension": "^2.13.8", + "redux-logger": "^3.0.6", "redux-observable": "^1.2.0", "redux-saga": "^1.1.3", "redux-thunk": "^2.3.0", diff --git a/x-pack/plugins/lens/public/app_plugin/app.test.tsx b/x-pack/plugins/lens/public/app_plugin/app.test.tsx index 72b8bfa38491a..30b4e2d954d2b 100644 --- a/x-pack/plugins/lens/public/app_plugin/app.test.tsx +++ b/x-pack/plugins/lens/public/app_plugin/app.test.tsx @@ -6,15 +6,14 @@ */ import React from 'react'; -import { Observable, Subject } from 'rxjs'; +import { Subject } from 'rxjs'; import { ReactWrapper } from 'enzyme'; import { act } from 'react-dom/test-utils'; import { App } from './app'; import { LensAppProps, LensAppServices } from './types'; import { EditorFrameInstance, EditorFrameProps } from '../types'; import { Document } from '../persistence'; -import { DOC_TYPE } from '../../common'; -import { mount } from 'enzyme'; +import { makeDefaultServices, mountWithProvider } from '../mocks'; import { I18nProvider } from '@kbn/i18n/react'; import { SavedObjectSaveModal, @@ -22,31 +21,20 @@ import { } from '../../../../../src/plugins/saved_objects/public'; import { createMemoryHistory } from 'history'; import { - DataPublicPluginStart, esFilters, FilterManager, IFieldType, IIndexPattern, - UI_SETTINGS, + IndexPattern, + Query, } from '../../../../../src/plugins/data/public'; -import { navigationPluginMock } from '../../../../../src/plugins/navigation/public/mocks'; import { TopNavMenuData } from '../../../../../src/plugins/navigation/public'; -import { coreMock } from 'src/core/public/mocks'; -import { - LensByValueInput, - LensSavedObjectAttributes, - LensByReferenceInput, -} from '../editor_frame_service/embeddable/embeddable'; +import { LensByValueInput } from '../editor_frame_service/embeddable/embeddable'; import { SavedObjectReference } from '../../../../../src/core/types'; -import { - mockAttributeService, - createEmbeddableStateTransferMock, -} from '../../../../../src/plugins/embeddable/public/mocks'; -import { LensAttributeService } from '../lens_attribute_service'; import { KibanaContextProvider } from '../../../../../src/plugins/kibana_react/public'; -import { EmbeddableStateTransfer } from '../../../../../src/plugins/embeddable/public'; import moment from 'moment'; +import { setState, LensAppState } from '../state_management/index'; jest.mock('../editor_frame_service/editor_frame/expression_helpers'); jest.mock('src/core/public'); jest.mock('../../../../../src/plugins/saved_objects/public', () => { @@ -61,13 +49,16 @@ jest.mock('../../../../../src/plugins/saved_objects/public', () => { }; }); -const navigationStartMock = navigationPluginMock.createStartContract(); +jest.mock('lodash', () => { + const original = jest.requireActual('lodash'); -jest.spyOn(navigationStartMock.ui.TopNavMenu.prototype, 'constructor').mockImplementation(() => { - return

    ; + return { + ...original, + debounce: (fn: unknown) => fn, + }; }); -const { TopNavMenu } = navigationStartMock.ui; +// const navigationStartMock = navigationPluginMock.createStartContract(); function createMockFrame(): jest.Mocked { return { @@ -77,91 +68,7 @@ function createMockFrame(): jest.Mocked { const sessionIdSubject = new Subject(); -function createMockSearchService() { - let sessionIdCounter = 1; - return { - session: { - start: jest.fn(() => `sessionId-${sessionIdCounter++}`), - clear: jest.fn(), - getSessionId: jest.fn(() => `sessionId-${sessionIdCounter}`), - getSession$: jest.fn(() => sessionIdSubject.asObservable()), - }, - }; -} - -function createMockFilterManager() { - const unsubscribe = jest.fn(); - - let subscriber: () => void; - let filters: unknown = []; - - return { - getUpdates$: () => ({ - subscribe: ({ next }: { next: () => void }) => { - subscriber = next; - return unsubscribe; - }, - }), - setFilters: jest.fn((newFilters: unknown[]) => { - filters = newFilters; - if (subscriber) subscriber(); - }), - setAppFilters: jest.fn((newFilters: unknown[]) => { - filters = newFilters; - if (subscriber) subscriber(); - }), - getFilters: () => filters, - getGlobalFilters: () => { - // @ts-ignore - return filters.filter(esFilters.isFilterPinned); - }, - removeAll: () => { - filters = []; - subscriber(); - }, - }; -} - -function createMockQueryString() { - return { - getQuery: jest.fn(() => ({ query: '', language: 'kuery' })), - setQuery: jest.fn(), - getDefaultQuery: jest.fn(() => ({ query: '', language: 'kuery' })), - }; -} - -function createMockTimefilter() { - const unsubscribe = jest.fn(); - - let timeFilter = { from: 'now-7d', to: 'now' }; - let subscriber: () => void; - return { - getTime: jest.fn(() => timeFilter), - setTime: jest.fn((newTimeFilter) => { - timeFilter = newTimeFilter; - if (subscriber) { - subscriber(); - } - }), - getTimeUpdate$: () => ({ - subscribe: ({ next }: { next: () => void }) => { - subscriber = next; - return unsubscribe; - }, - }), - calculateBounds: jest.fn(() => ({ - min: moment('2021-01-10T04:00:00.000Z'), - max: moment('2021-01-10T08:00:00.000Z'), - })), - getBounds: jest.fn(() => timeFilter), - getRefreshInterval: () => {}, - getRefreshIntervalDefaults: () => {}, - getAutoRefreshFetch$: () => new Observable(), - }; -} - describe('Lens App', () => { - let core: ReturnType; let defaultDoc: Document; let defaultSavedObjectId: string; @@ -171,27 +78,6 @@ describe('Lens App', () => { expectedSaveAndReturnButton: { emphasize: true, testId: 'lnsApp_saveAndReturnButton' }, }; - function makeAttributeService(): LensAttributeService { - const attributeServiceMock = mockAttributeService< - LensSavedObjectAttributes, - LensByValueInput, - LensByReferenceInput - >( - DOC_TYPE, - { - saveMethod: jest.fn(), - unwrapMethod: jest.fn(), - checkForDuplicateTitle: jest.fn(), - }, - core - ); - attributeServiceMock.unwrapAttributes = jest.fn().mockResolvedValue(defaultDoc); - attributeServiceMock.wrapAttributes = jest - .fn() - .mockResolvedValue({ savedObjectId: defaultSavedObjectId }); - return attributeServiceMock; - } - function makeDefaultProps(): jest.Mocked { return { editorFrame: createMockFrame(), @@ -203,64 +89,15 @@ describe('Lens App', () => { }; } - function makeDefaultServices(): jest.Mocked { - return { - http: core.http, - chrome: core.chrome, - overlays: core.overlays, - uiSettings: core.uiSettings, - navigation: navigationStartMock, - notifications: core.notifications, - attributeService: makeAttributeService(), - savedObjectsClient: core.savedObjects.client, - dashboardFeatureFlag: { allowByValueEmbeddables: false }, - stateTransfer: createEmbeddableStateTransferMock() as EmbeddableStateTransfer, - getOriginatingAppName: jest.fn(() => 'defaultOriginatingApp'), - application: { - ...core.application, - capabilities: { - ...core.application.capabilities, - visualize: { save: true, saveQuery: true, show: true }, - }, - getUrlForApp: jest.fn((appId: string) => `/testbasepath/app/${appId}#/`), - }, - data: ({ - query: { - filterManager: createMockFilterManager(), - timefilter: { - timefilter: createMockTimefilter(), - }, - queryString: createMockQueryString(), - state$: new Observable(), - }, - indexPatterns: { - get: jest.fn((id) => { - return new Promise((resolve) => resolve({ id })); - }), - }, - search: createMockSearchService(), - nowProvider: { - get: jest.fn(), - }, - } as unknown) as DataPublicPluginStart, - storage: { - get: jest.fn(), - set: jest.fn(), - remove: jest.fn(), - clear: jest.fn(), - }, - }; - } - - function mountWith({ - props: incomingProps, - services: incomingServices, + async function mountWith({ + props = makeDefaultProps(), + services = makeDefaultServices(sessionIdSubject), + storePreloadedState, }: { props?: jest.Mocked; services?: jest.Mocked; + storePreloadedState?: Partial; }) { - const props = incomingProps ?? makeDefaultProps(); - const services = incomingServices ?? makeDefaultServices(); const wrappingComponent: React.FC<{ children: React.ReactNode; }> = ({ children }) => { @@ -270,61 +107,40 @@ describe('Lens App', () => { ); }; + + const { instance, lensStore } = await mountWithProvider( + , + services.data, + storePreloadedState, + wrappingComponent + ); + const frame = props.editorFrame as ReturnType; - const component = mount(, { wrappingComponent }); - return { component, frame, props, services }; + return { instance, frame, props, services, lensStore }; } beforeEach(() => { - core = coreMock.createStart({ basePath: '/testbasepath' }); defaultSavedObjectId = '1234'; defaultDoc = ({ savedObjectId: defaultSavedObjectId, title: 'An extremely cool default document!', expression: 'definitely a valid expression', state: { - query: 'kuery', + query: 'lucene', filters: [{ query: { match_phrase: { src: 'test' } } }], }, references: [{ type: 'index-pattern', id: '1', name: 'index-pattern-0' }], } as unknown) as Document; - - core.uiSettings.get.mockImplementation( - jest.fn((type) => { - if (type === UI_SETTINGS.TIMEPICKER_TIME_DEFAULTS) { - return { from: 'now-7d', to: 'now' }; - } else if (type === UI_SETTINGS.SEARCH_QUERY_LANGUAGE) { - return 'kuery'; - } else if (type === 'state:storeInSessionStorage') { - return false; - } else { - return []; - } - }) - ); }); - it('renders the editor frame', () => { - const { frame } = mountWith({}); + it('renders the editor frame', async () => { + const { frame } = await mountWith({}); expect(frame.EditorFrameContainer.mock.calls).toMatchInlineSnapshot(` Array [ Array [ Object { - "dateRange": Object { - "fromDate": "2021-01-10T04:00:00.000Z", - "toDate": "2021-01-10T08:00:00.000Z", - }, - "doc": undefined, - "filters": Array [], "initialContext": undefined, - "onChange": [Function], "onError": [Function], - "query": Object { - "language": "kuery", - "query": "", - }, - "savedQuery": undefined, - "searchSessionId": "sessionId-1", "showNoDataPopover": [Function], }, Object {}, @@ -333,13 +149,8 @@ describe('Lens App', () => { `); }); - it('clears app filters on load', () => { - const { services } = mountWith({}); - expect(services.data.query.filterManager.setAppFilters).toHaveBeenCalledWith([]); - }); - - it('passes global filters to frame', async () => { - const services = makeDefaultServices(); + it('updates global filters with store state', async () => { + const services = makeDefaultServices(sessionIdSubject); const indexPattern = ({ id: 'index1' } as unknown) as IIndexPattern; const pinnedField = ({ name: 'pinnedField' } as unknown) as IFieldType; const pinnedFilter = esFilters.buildExistsFilter(pinnedField, indexPattern); @@ -349,25 +160,28 @@ describe('Lens App', () => { services.data.query.filterManager.getGlobalFilters = jest.fn().mockImplementation(() => { return [pinnedFilter]; }); - const { component, frame } = mountWith({ services }); + const { instance, lensStore } = await mountWith({ services }); - component.update(); - expect(frame.EditorFrameContainer).toHaveBeenCalledWith( - expect.objectContaining({ - dateRange: { fromDate: '2021-01-10T04:00:00.000Z', toDate: '2021-01-10T08:00:00.000Z' }, - query: { query: '', language: 'kuery' }, + instance.update(); + expect(lensStore.getState()).toEqual({ + app: expect.objectContaining({ + query: { query: '', language: 'lucene' }, filters: [pinnedFilter], + resolvedDateRange: { + fromDate: '2021-01-10T04:00:00.000Z', + toDate: '2021-01-10T08:00:00.000Z', + }, }), - {} - ); + }); + expect(services.data.query.filterManager.getFilters).not.toHaveBeenCalled(); }); - it('displays errors from the frame in a toast', () => { - const { component, frame, services } = mountWith({}); + it('displays errors from the frame in a toast', async () => { + const { instance, frame, services } = await mountWith({}); const onError = frame.EditorFrameContainer.mock.calls[0][0].onError; onError({ message: 'error' }); - component.update(); + instance.update(); expect(services.notifications.toasts.addDanger).toHaveBeenCalled(); }); @@ -384,7 +198,7 @@ describe('Lens App', () => { } as unknown) as Document; it('sets breadcrumbs when the document title changes', async () => { - const { component, services } = mountWith({}); + const { instance, services, lensStore } = await mountWith({}); expect(services.chrome.setBreadcrumbs).toHaveBeenCalledWith([ { @@ -395,9 +209,13 @@ describe('Lens App', () => { { text: 'Create' }, ]); - services.attributeService.unwrapAttributes = jest.fn().mockResolvedValue(breadcrumbDoc); await act(async () => { - component.setProps({ initialInput: { savedObjectId: breadcrumbDocSavedObjectId } }); + instance.setProps({ initialInput: { savedObjectId: breadcrumbDocSavedObjectId } }); + lensStore.dispatch( + setState({ + persistedDoc: breadcrumbDoc, + }) + ); }); expect(services.chrome.setBreadcrumbs).toHaveBeenCalledWith([ @@ -412,10 +230,17 @@ describe('Lens App', () => { it('sets originatingApp breadcrumb when the document title changes', async () => { const props = makeDefaultProps(); - const services = makeDefaultServices(); + const services = makeDefaultServices(sessionIdSubject); props.incomingState = { originatingApp: 'coolContainer' }; services.getOriginatingAppName = jest.fn(() => 'The Coolest Container Ever Made'); - const { component } = mountWith({ props, services }); + + const { instance, lensStore } = await mountWith({ + props, + services, + storePreloadedState: { + isLinkedToOriginatingApp: true, + }, + }); expect(services.chrome.setBreadcrumbs).toHaveBeenCalledWith([ { text: 'The Coolest Container Ever Made', onClick: expect.anything() }, @@ -427,9 +252,14 @@ describe('Lens App', () => { { text: 'Create' }, ]); - services.attributeService.unwrapAttributes = jest.fn().mockResolvedValue(breadcrumbDoc); await act(async () => { - component.setProps({ initialInput: { savedObjectId: breadcrumbDocSavedObjectId } }); + instance.setProps({ initialInput: { savedObjectId: breadcrumbDocSavedObjectId } }); + + lensStore.dispatch( + setState({ + persistedDoc: breadcrumbDoc, + }) + ); }); expect(services.chrome.setBreadcrumbs).toHaveBeenCalledWith([ @@ -445,99 +275,36 @@ describe('Lens App', () => { }); describe('persistence', () => { - it('does not load a document if there is no initial input', () => { - const { services } = mountWith({}); - expect(services.attributeService.unwrapAttributes).not.toHaveBeenCalled(); - }); - it('loads a document and uses query and filters if initial input is provided', async () => { - const { component, frame, services } = mountWith({}); - services.attributeService.unwrapAttributes = jest.fn().mockResolvedValue({ + const { instance, lensStore, services } = await mountWith({}); + const document = ({ savedObjectId: defaultSavedObjectId, state: { query: 'fake query', filters: [{ query: { match_phrase: { src: 'test' } } }], }, references: [{ type: 'index-pattern', id: '1', name: 'index-pattern-0' }], - }); + } as unknown) as Document; - await act(async () => { - component.setProps({ initialInput: { savedObjectId: defaultSavedObjectId } }); + act(() => { + lensStore.dispatch( + setState({ + query: ('fake query' as unknown) as Query, + indexPatternsForTopNav: ([{ id: '1' }] as unknown) as IndexPattern[], + lastKnownDoc: document, + persistedDoc: document, + }) + ); }); + instance.update(); - expect(services.attributeService.unwrapAttributes).toHaveBeenCalledWith({ - savedObjectId: defaultSavedObjectId, - }); - expect(services.data.indexPatterns.get).toHaveBeenCalledWith('1'); - expect(services.data.query.filterManager.setAppFilters).toHaveBeenCalledWith([ - { query: { match_phrase: { src: 'test' } } }, - ]); - expect(TopNavMenu).toHaveBeenCalledWith( + expect(services.navigation.ui.TopNavMenu).toHaveBeenCalledWith( expect.objectContaining({ query: 'fake query', indexPatterns: [{ id: '1' }], }), {} ); - expect(frame.EditorFrameContainer).toHaveBeenCalledWith( - expect.objectContaining({ - doc: expect.objectContaining({ - savedObjectId: defaultSavedObjectId, - state: expect.objectContaining({ - query: 'fake query', - filters: [{ query: { match_phrase: { src: 'test' } } }], - }), - }), - }), - {} - ); - }); - - it('does not load documents on sequential renders unless the id changes', async () => { - const { services, component } = mountWith({}); - - await act(async () => { - component.setProps({ initialInput: { savedObjectId: defaultSavedObjectId } }); - }); - await act(async () => { - component.setProps({ initialInput: { savedObjectId: defaultSavedObjectId } }); - }); - expect(services.attributeService.unwrapAttributes).toHaveBeenCalledTimes(1); - - await act(async () => { - component.setProps({ initialInput: { savedObjectId: '5678' } }); - }); - - expect(services.attributeService.unwrapAttributes).toHaveBeenCalledTimes(2); - }); - - it('handles document load errors', async () => { - const services = makeDefaultServices(); - services.attributeService.unwrapAttributes = jest.fn().mockRejectedValue('failed to load'); - const { component, props } = mountWith({ services }); - - await act(async () => { - component.setProps({ initialInput: { savedObjectId: defaultSavedObjectId } }); - }); - - expect(services.attributeService.unwrapAttributes).toHaveBeenCalledWith({ - savedObjectId: defaultSavedObjectId, - }); - expect(services.notifications.toasts.addDanger).toHaveBeenCalled(); - expect(props.redirectTo).toHaveBeenCalled(); - }); - - it('adds to the recently accessed list on load', async () => { - const { component, services } = mountWith({}); - - await act(async () => { - component.setProps({ initialInput: { savedObjectId: defaultSavedObjectId } }); - }); - expect(services.chrome.recentlyAccessed.add).toHaveBeenCalledWith( - '/app/lens#/edit/1234', - 'An extremely cool default document!', - '1234' - ); }); describe('save buttons', () => { @@ -584,7 +351,7 @@ describe('Lens App', () => { : undefined, }; - const services = makeDefaultServices(); + const services = makeDefaultServices(sessionIdSubject); services.attributeService.wrapAttributes = jest .fn() .mockImplementation(async ({ savedObjectId }) => ({ @@ -599,39 +366,27 @@ describe('Lens App', () => { }, } as jest.ResolvedValue); - let frame: jest.Mocked = {} as jest.Mocked; - let component: ReactWrapper = {} as ReactWrapper; - await act(async () => { - const { frame: newFrame, component: newComponent } = mountWith({ services, props }); - frame = newFrame; - component = newComponent; - }); - - if (initialSavedObjectId) { - expect(services.attributeService.unwrapAttributes).toHaveBeenCalledTimes(1); - } else { - expect(services.attributeService.unwrapAttributes).not.toHaveBeenCalled(); - } + const { frame, instance, lensStore } = await mountWith({ services, props }); - const onChange = frame.EditorFrameContainer.mock.calls[0][0].onChange; + act(() => { + lensStore.dispatch( + setState({ + isSaveable: true, + lastKnownDoc: { savedObjectId: initialSavedObjectId, ...lastKnownDoc } as Document, + }) + ); + }); - act(() => - onChange({ - filterableIndexPatterns: [], - doc: { savedObjectId: initialSavedObjectId, ...lastKnownDoc } as Document, - isSaveable: true, - }) - ); - component.update(); - expect(getButton(component).disableButton).toEqual(false); + instance.update(); + expect(getButton(instance).disableButton).toEqual(false); await act(async () => { - testSave(component, { ...saveProps }); + testSave(instance, { ...saveProps }); }); - return { props, services, component, frame }; + return { props, services, instance, frame, lensStore }; } it('shows a disabled save button when the user does not have permissions', async () => { - const services = makeDefaultServices(); + const services = makeDefaultServices(sessionIdSubject); services.application = { ...services.application, capabilities: { @@ -639,36 +394,36 @@ describe('Lens App', () => { visualize: { save: false, saveQuery: false, show: true }, }, }; - const { component, frame } = mountWith({ services }); - expect(getButton(component).disableButton).toEqual(true); - const onChange = frame.EditorFrameContainer.mock.calls[0][0].onChange; - act(() => - onChange({ - filterableIndexPatterns: [], - doc: ({ savedObjectId: 'will save this' } as unknown) as Document, - isSaveable: true, - }) - ); - component.update(); - expect(getButton(component).disableButton).toEqual(true); + const { instance, lensStore } = await mountWith({ services }); + expect(getButton(instance).disableButton).toEqual(true); + act(() => { + lensStore.dispatch( + setState({ + lastKnownDoc: ({ savedObjectId: 'will save this' } as unknown) as Document, + isSaveable: true, + }) + ); + }); + instance.update(); + expect(getButton(instance).disableButton).toEqual(true); }); it('shows a save button that is enabled when the frame has provided its state and does not show save and return or save as', async () => { - const { component, frame } = mountWith({}); - expect(getButton(component).disableButton).toEqual(true); - const onChange = frame.EditorFrameContainer.mock.calls[0][0].onChange; - act(() => - onChange({ - filterableIndexPatterns: [], - doc: ({ savedObjectId: 'will save this' } as unknown) as Document, - isSaveable: true, - }) - ); - component.update(); - expect(getButton(component).disableButton).toEqual(false); + const { instance, lensStore, services } = await mountWith({}); + expect(getButton(instance).disableButton).toEqual(true); + act(() => { + lensStore.dispatch( + setState({ + isSaveable: true, + lastKnownDoc: ({ savedObjectId: 'will save this' } as unknown) as Document, + }) + ); + }); + instance.update(); + expect(getButton(instance).disableButton).toEqual(false); await act(async () => { - const topNavMenuConfig = component.find(TopNavMenu).prop('config'); + const topNavMenuConfig = instance.find(services.navigation.ui.TopNavMenu).prop('config'); expect(topNavMenuConfig).not.toContainEqual( expect.objectContaining(navMenuItems.expectedSaveAndReturnButton) ); @@ -683,7 +438,7 @@ describe('Lens App', () => { it('Shows Save and Return and Save As buttons in create by value mode with originating app', async () => { const props = makeDefaultProps(); - const services = makeDefaultServices(); + const services = makeDefaultServices(sessionIdSubject); services.dashboardFeatureFlag = { allowByValueEmbeddables: true }; props.incomingState = { originatingApp: 'ultraDashboard', @@ -697,10 +452,16 @@ describe('Lens App', () => { } as LensByValueInput, }; - const { component } = mountWith({ props, services }); + const { instance } = await mountWith({ + props, + services, + storePreloadedState: { + isLinkedToOriginatingApp: true, + }, + }); await act(async () => { - const topNavMenuConfig = component.find(TopNavMenu).prop('config'); + const topNavMenuConfig = instance.find(services.navigation.ui.TopNavMenu).prop('config'); expect(topNavMenuConfig).toContainEqual( expect.objectContaining(navMenuItems.expectedSaveAndReturnButton) ); @@ -720,10 +481,15 @@ describe('Lens App', () => { originatingApp: 'ultraDashboard', }; - const { component } = mountWith({ props }); + const { instance, services } = await mountWith({ + props, + storePreloadedState: { + isLinkedToOriginatingApp: true, + }, + }); await act(async () => { - const topNavMenuConfig = component.find(TopNavMenu).prop('config'); + const topNavMenuConfig = instance.find(services.navigation.ui.TopNavMenu).prop('config'); expect(topNavMenuConfig).toContainEqual( expect.objectContaining(navMenuItems.expectedSaveAndReturnButton) ); @@ -770,7 +536,7 @@ describe('Lens App', () => { }); it('saves the latest doc as a copy', async () => { - const { props, services, component } = await save({ + const { props, services, instance } = await save({ initialSavedObjectId: defaultSavedObjectId, newCopyOnSave: true, newTitle: 'hello there', @@ -784,7 +550,7 @@ describe('Lens App', () => { ); expect(props.redirectTo).toHaveBeenCalledWith(defaultSavedObjectId); await act(async () => { - component.setProps({ initialInput: { savedObjectId: defaultSavedObjectId } }); + instance.setProps({ initialInput: { savedObjectId: defaultSavedObjectId } }); }); expect(services.attributeService.wrapAttributes).toHaveBeenCalledTimes(1); expect(services.notifications.toasts.addSuccess).toHaveBeenCalledWith( @@ -793,7 +559,7 @@ describe('Lens App', () => { }); it('saves existing docs', async () => { - const { props, services, component } = await save({ + const { props, services, instance, lensStore } = await save({ initialSavedObjectId: defaultSavedObjectId, newCopyOnSave: false, newTitle: 'hello there', @@ -808,35 +574,51 @@ describe('Lens App', () => { ); expect(props.redirectTo).not.toHaveBeenCalled(); await act(async () => { - component.setProps({ initialInput: { savedObjectId: defaultSavedObjectId } }); + instance.setProps({ initialInput: { savedObjectId: defaultSavedObjectId } }); }); - expect(services.attributeService.unwrapAttributes).toHaveBeenCalledTimes(1); + + expect(lensStore.dispatch).toHaveBeenCalledWith({ + payload: { + lastKnownDoc: expect.objectContaining({ + savedObjectId: defaultSavedObjectId, + title: 'hello there', + }), + persistedDoc: expect.objectContaining({ + savedObjectId: defaultSavedObjectId, + title: 'hello there', + }), + isLinkedToOriginatingApp: false, + }, + type: 'app/setState', + }); + expect(services.notifications.toasts.addSuccess).toHaveBeenCalledWith( "Saved 'hello there'" ); }); it('handles save failure by showing a warning, but still allows another save', async () => { - const services = makeDefaultServices(); + const services = makeDefaultServices(sessionIdSubject); services.attributeService.wrapAttributes = jest .fn() .mockRejectedValue({ message: 'failed' }); - const { component, props, frame } = mountWith({ services }); - const onChange = frame.EditorFrameContainer.mock.calls[0][0].onChange; - act(() => - onChange({ - filterableIndexPatterns: [], - doc: ({ id: undefined } as unknown) as Document, - isSaveable: true, - }) - ); - component.update(); + const { instance, props, lensStore } = await mountWith({ services }); + act(() => { + lensStore.dispatch( + setState({ + isSaveable: true, + lastKnownDoc: ({ id: undefined } as unknown) as Document, + }) + ); + }); + + instance.update(); await act(async () => { - testSave(component, { newCopyOnSave: false, newTitle: 'hello there' }); + testSave(instance, { newCopyOnSave: false, newTitle: 'hello there' }); }); expect(props.redirectTo).not.toHaveBeenCalled(); - expect(getButton(component).disableButton).toEqual(false); + expect(getButton(instance).disableButton).toEqual(false); }); it('saves new doc and redirects to originating app', async () => { @@ -895,28 +677,29 @@ describe('Lens App', () => { }); it('checks for duplicate title before saving', async () => { - const services = makeDefaultServices(); + const services = makeDefaultServices(sessionIdSubject); services.attributeService.wrapAttributes = jest .fn() .mockReturnValue(Promise.resolve({ savedObjectId: '123' })); - const { component, frame } = mountWith({ services }); - const onChange = frame.EditorFrameContainer.mock.calls[0][0].onChange; - await act(async () => - onChange({ - filterableIndexPatterns: [], - doc: ({ savedObjectId: '123' } as unknown) as Document, - isSaveable: true, - }) - ); - component.update(); + const { instance, lensStore } = await mountWith({ services }); await act(async () => { - component.setProps({ initialInput: { savedObjectId: '123' } }); - getButton(component).run(component.getDOMNode()); + lensStore.dispatch( + setState({ + isSaveable: true, + lastKnownDoc: ({ savedObjectId: '123' } as unknown) as Document, + }) + ); }); - component.update(); + + instance.update(); + await act(async () => { + instance.setProps({ initialInput: { savedObjectId: '123' } }); + getButton(instance).run(instance.getDOMNode()); + }); + instance.update(); const onTitleDuplicate = jest.fn(); await act(async () => { - component.find(SavedObjectSaveModal).prop('onSave')({ + instance.find(SavedObjectSaveModal).prop('onSave')({ onTitleDuplicate, isTitleDuplicateConfirmed: false, newCopyOnSave: false, @@ -933,19 +716,20 @@ describe('Lens App', () => { }); it('does not show the copy button on first save', async () => { - const { component, frame } = mountWith({}); - const onChange = frame.EditorFrameContainer.mock.calls[0][0].onChange; - await act(async () => - onChange({ - filterableIndexPatterns: [], - doc: ({} as unknown) as Document, - isSaveable: true, - }) - ); - component.update(); - await act(async () => getButton(component).run(component.getDOMNode())); - component.update(); - expect(component.find(SavedObjectSaveModal).prop('showCopyOnSave')).toEqual(false); + const { instance, lensStore } = await mountWith({}); + await act(async () => { + lensStore.dispatch( + setState({ + isSaveable: true, + lastKnownDoc: ({} as unknown) as Document, + }) + ); + }); + + instance.update(); + await act(async () => getButton(instance).run(instance.getDOMNode())); + instance.update(); + expect(instance.find(SavedObjectSaveModal).prop('showCopyOnSave')).toEqual(false); }); }); }); @@ -960,38 +744,38 @@ describe('Lens App', () => { } it('should be disabled when no data is available', async () => { - const { component, frame } = mountWith({}); - const onChange = frame.EditorFrameContainer.mock.calls[0][0].onChange; - await act(async () => - onChange({ - filterableIndexPatterns: [], - doc: ({} as unknown) as Document, - isSaveable: true, - }) - ); - component.update(); - expect(getButton(component).disableButton).toEqual(true); + const { instance, lensStore } = await mountWith({}); + await act(async () => { + lensStore.dispatch( + setState({ + isSaveable: true, + lastKnownDoc: ({} as unknown) as Document, + }) + ); + }); + instance.update(); + expect(getButton(instance).disableButton).toEqual(true); }); it('should disable download when not saveable', async () => { - const { component, frame } = mountWith({}); - const onChange = frame.EditorFrameContainer.mock.calls[0][0].onChange; - - await act(async () => - onChange({ - filterableIndexPatterns: [], - doc: ({} as unknown) as Document, - isSaveable: false, - activeData: { layer1: { type: 'datatable', columns: [], rows: [] } }, - }) - ); + const { instance, lensStore } = await mountWith({}); - component.update(); - expect(getButton(component).disableButton).toEqual(true); + await act(async () => { + lensStore.dispatch( + setState({ + lastKnownDoc: ({} as unknown) as Document, + isSaveable: false, + activeData: { layer1: { type: 'datatable', columns: [], rows: [] } }, + }) + ); + }); + + instance.update(); + expect(getButton(instance).disableButton).toEqual(true); }); it('should still be enabled even if the user is missing save permissions', async () => { - const services = makeDefaultServices(); + const services = makeDefaultServices(sessionIdSubject); services.application = { ...services.application, capabilities: { @@ -1000,59 +784,63 @@ describe('Lens App', () => { }, }; - const { component, frame } = mountWith({ services }); - const onChange = frame.EditorFrameContainer.mock.calls[0][0].onChange; - await act(async () => - onChange({ - filterableIndexPatterns: [], - doc: ({} as unknown) as Document, - isSaveable: true, - activeData: { layer1: { type: 'datatable', columns: [], rows: [] } }, - }) - ); - component.update(); - expect(getButton(component).disableButton).toEqual(false); + const { instance, lensStore } = await mountWith({ services }); + await act(async () => { + lensStore.dispatch( + setState({ + lastKnownDoc: ({} as unknown) as Document, + isSaveable: true, + activeData: { layer1: { type: 'datatable', columns: [], rows: [] } }, + }) + ); + }); + instance.update(); + expect(getButton(instance).disableButton).toEqual(false); }); }); describe('query bar state management', () => { - it('uses the default time and query language settings', () => { - const { frame } = mountWith({}); - expect(TopNavMenu).toHaveBeenCalledWith( + it('uses the default time and query language settings', async () => { + const { lensStore, services } = await mountWith({}); + expect(services.navigation.ui.TopNavMenu).toHaveBeenCalledWith( expect.objectContaining({ - query: { query: '', language: 'kuery' }, + query: { query: '', language: 'lucene' }, dateRangeFrom: 'now-7d', dateRangeTo: 'now', }), {} ); - expect(frame.EditorFrameContainer).toHaveBeenCalledWith( - expect.objectContaining({ - dateRange: { fromDate: '2021-01-10T04:00:00.000Z', toDate: '2021-01-10T08:00:00.000Z' }, - query: { query: '', language: 'kuery' }, + + expect(lensStore.getState()).toEqual({ + app: expect.objectContaining({ + query: { query: '', language: 'lucene' }, + resolvedDateRange: { + fromDate: '2021-01-10T04:00:00.000Z', + toDate: '2021-01-10T08:00:00.000Z', + }, }), - {} - ); + }); }); it('updates the index patterns when the editor frame is changed', async () => { - const { component, frame } = mountWith({}); - expect(TopNavMenu).toHaveBeenCalledWith( + const { instance, lensStore, services } = await mountWith({}); + expect(services.navigation.ui.TopNavMenu).toHaveBeenCalledWith( expect.objectContaining({ indexPatterns: [], }), {} ); - const onChange = frame.EditorFrameContainer.mock.calls[0][0].onChange; await act(async () => { - onChange({ - filterableIndexPatterns: ['1'], - doc: ({ id: undefined } as unknown) as Document, - isSaveable: true, - }); + lensStore.dispatch( + setState({ + indexPatternsForTopNav: [{ id: '1' }] as IndexPattern[], + lastKnownDoc: ({} as unknown) as Document, + isSaveable: true, + }) + ); }); - component.update(); - expect(TopNavMenu).toHaveBeenCalledWith( + instance.update(); + expect(services.navigation.ui.TopNavMenu).toHaveBeenCalledWith( expect.objectContaining({ indexPatterns: [{ id: '1' }], }), @@ -1060,14 +848,16 @@ describe('Lens App', () => { ); // Do it again to verify that the dirty checking is done right await act(async () => { - onChange({ - filterableIndexPatterns: ['2'], - doc: ({ id: undefined } as unknown) as Document, - isSaveable: true, - }); + lensStore.dispatch( + setState({ + indexPatternsForTopNav: [{ id: '2' }] as IndexPattern[], + lastKnownDoc: ({} as unknown) as Document, + isSaveable: true, + }) + ); }); - component.update(); - expect(TopNavMenu).toHaveBeenLastCalledWith( + instance.update(); + expect(services.navigation.ui.TopNavMenu).toHaveBeenLastCalledWith( expect.objectContaining({ indexPatterns: [{ id: '2' }], }), @@ -1075,20 +865,20 @@ describe('Lens App', () => { ); }); - it('updates the editor frame when the user changes query or time in the search bar', () => { - const { component, frame, services } = mountWith({}); + it('updates the editor frame when the user changes query or time in the search bar', async () => { + const { instance, services, lensStore } = await mountWith({}); (services.data.query.timefilter.timefilter.calculateBounds as jest.Mock).mockReturnValue({ min: moment('2021-01-09T04:00:00.000Z'), max: moment('2021-01-09T08:00:00.000Z'), }); act(() => - component.find(TopNavMenu).prop('onQuerySubmit')!({ + instance.find(services.navigation.ui.TopNavMenu).prop('onQuerySubmit')!({ dateRange: { from: 'now-14d', to: 'now-7d' }, query: { query: 'new', language: 'lucene' }, }) ); - component.update(); - expect(TopNavMenu).toHaveBeenCalledWith( + instance.update(); + expect(services.navigation.ui.TopNavMenu).toHaveBeenCalledWith( expect.objectContaining({ query: { query: 'new', language: 'lucene' }, dateRangeFrom: 'now-14d', @@ -1100,64 +890,75 @@ describe('Lens App', () => { from: 'now-14d', to: 'now-7d', }); - expect(frame.EditorFrameContainer).toHaveBeenCalledWith( - expect.objectContaining({ - dateRange: { fromDate: '2021-01-09T04:00:00.000Z', toDate: '2021-01-09T08:00:00.000Z' }, + + expect(lensStore.getState()).toEqual({ + app: expect.objectContaining({ query: { query: 'new', language: 'lucene' }, + resolvedDateRange: { + fromDate: '2021-01-09T04:00:00.000Z', + toDate: '2021-01-09T08:00:00.000Z', + }, }), - {} - ); + }); }); - it('updates the filters when the user changes them', () => { - const { component, frame, services } = mountWith({}); + it('updates the filters when the user changes them', async () => { + const { instance, services, lensStore } = await mountWith({}); const indexPattern = ({ id: 'index1' } as unknown) as IIndexPattern; const field = ({ name: 'myfield' } as unknown) as IFieldType; + expect(lensStore.getState()).toEqual({ + app: expect.objectContaining({ + filters: [], + }), + }); act(() => services.data.query.filterManager.setFilters([ esFilters.buildExistsFilter(field, indexPattern), ]) ); - component.update(); - expect(frame.EditorFrameContainer).toHaveBeenCalledWith( - expect.objectContaining({ + instance.update(); + expect(lensStore.getState()).toEqual({ + app: expect.objectContaining({ filters: [esFilters.buildExistsFilter(field, indexPattern)], }), - {} - ); + }); }); - it('updates the searchSessionId when the user changes query or time in the search bar', () => { - const { component, frame, services } = mountWith({}); + it('updates the searchSessionId when the user changes query or time in the search bar', async () => { + const { instance, services, lensStore } = await mountWith({}); + + expect(lensStore.getState()).toEqual({ + app: expect.objectContaining({ + searchSessionId: `sessionId-1`, + }), + }); + act(() => - component.find(TopNavMenu).prop('onQuerySubmit')!({ + instance.find(services.navigation.ui.TopNavMenu).prop('onQuerySubmit')!({ dateRange: { from: 'now-14d', to: 'now-7d' }, query: { query: '', language: 'lucene' }, }) ); - component.update(); - expect(frame.EditorFrameContainer).toHaveBeenCalledWith( - expect.objectContaining({ - searchSessionId: `sessionId-1`, - }), - {} - ); + instance.update(); + expect(lensStore.getState()).toEqual({ + app: expect.objectContaining({ + searchSessionId: `sessionId-2`, + }), + }); // trigger again, this time changing just the query act(() => - component.find(TopNavMenu).prop('onQuerySubmit')!({ + instance.find(services.navigation.ui.TopNavMenu).prop('onQuerySubmit')!({ dateRange: { from: 'now-14d', to: 'now-7d' }, query: { query: 'new', language: 'lucene' }, }) ); - component.update(); - expect(frame.EditorFrameContainer).toHaveBeenCalledWith( - expect.objectContaining({ - searchSessionId: `sessionId-2`, + instance.update(); + expect(lensStore.getState()).toEqual({ + app: expect.objectContaining({ + searchSessionId: `sessionId-3`, }), - {} - ); - + }); const indexPattern = ({ id: 'index1' } as unknown) as IIndexPattern; const field = ({ name: 'myfield' } as unknown) as IFieldType; act(() => @@ -1165,19 +966,18 @@ describe('Lens App', () => { esFilters.buildExistsFilter(field, indexPattern), ]) ); - component.update(); - expect(frame.EditorFrameContainer).toHaveBeenCalledWith( - expect.objectContaining({ - searchSessionId: `sessionId-3`, + instance.update(); + expect(lensStore.getState()).toEqual({ + app: expect.objectContaining({ + searchSessionId: `sessionId-4`, }), - {} - ); + }); }); }); describe('saved query handling', () => { - it('does not allow saving when the user is missing the saveQuery permission', () => { - const services = makeDefaultServices(); + it('does not allow saving when the user is missing the saveQuery permission', async () => { + const services = makeDefaultServices(sessionIdSubject); services.application = { ...services.application, capabilities: { @@ -1185,16 +985,16 @@ describe('Lens App', () => { visualize: { save: false, saveQuery: false, show: true }, }, }; - mountWith({ services }); - expect(TopNavMenu).toHaveBeenCalledWith( + await mountWith({ services }); + expect(services.navigation.ui.TopNavMenu).toHaveBeenCalledWith( expect.objectContaining({ showSaveQuery: false }), {} ); }); - it('persists the saved query ID when the query is saved', () => { - const { component } = mountWith({}); - expect(TopNavMenu).toHaveBeenCalledWith( + it('persists the saved query ID when the query is saved', async () => { + const { instance, services } = await mountWith({}); + expect(services.navigation.ui.TopNavMenu).toHaveBeenCalledWith( expect.objectContaining({ showSaveQuery: true, savedQuery: undefined, @@ -1205,7 +1005,7 @@ describe('Lens App', () => { {} ); act(() => { - component.find(TopNavMenu).prop('onSaved')!({ + instance.find(services.navigation.ui.TopNavMenu).prop('onSaved')!({ id: '1', attributes: { title: '', @@ -1214,7 +1014,7 @@ describe('Lens App', () => { }, }); }); - expect(TopNavMenu).toHaveBeenCalledWith( + expect(services.navigation.ui.TopNavMenu).toHaveBeenCalledWith( expect.objectContaining({ savedQuery: { id: '1', @@ -1229,10 +1029,10 @@ describe('Lens App', () => { ); }); - it('changes the saved query ID when the query is updated', () => { - const { component } = mountWith({}); + it('changes the saved query ID when the query is updated', async () => { + const { instance, services } = await mountWith({}); act(() => { - component.find(TopNavMenu).prop('onSaved')!({ + instance.find(services.navigation.ui.TopNavMenu).prop('onSaved')!({ id: '1', attributes: { title: '', @@ -1242,7 +1042,7 @@ describe('Lens App', () => { }); }); act(() => { - component.find(TopNavMenu).prop('onSavedQueryUpdated')!({ + instance.find(services.navigation.ui.TopNavMenu).prop('onSavedQueryUpdated')!({ id: '2', attributes: { title: 'new title', @@ -1251,7 +1051,7 @@ describe('Lens App', () => { }, }); }); - expect(TopNavMenu).toHaveBeenCalledWith( + expect(services.navigation.ui.TopNavMenu).toHaveBeenCalledWith( expect.objectContaining({ savedQuery: { id: '2', @@ -1266,10 +1066,10 @@ describe('Lens App', () => { ); }); - it('updates the query if saved query is selected', () => { - const { component } = mountWith({}); + it('updates the query if saved query is selected', async () => { + const { instance, services } = await mountWith({}); act(() => { - component.find(TopNavMenu).prop('onSavedQueryUpdated')!({ + instance.find(services.navigation.ui.TopNavMenu).prop('onSavedQueryUpdated')!({ id: '2', attributes: { title: 'new title', @@ -1278,7 +1078,7 @@ describe('Lens App', () => { }, }); }); - expect(TopNavMenu).toHaveBeenCalledWith( + expect(services.navigation.ui.TopNavMenu).toHaveBeenCalledWith( expect.objectContaining({ query: { query: 'abc:def', language: 'lucene' }, }), @@ -1286,10 +1086,10 @@ describe('Lens App', () => { ); }); - it('clears all existing unpinned filters when the active saved query is cleared', () => { - const { component, frame, services } = mountWith({}); + it('clears all existing unpinned filters when the active saved query is cleared', async () => { + const { instance, services, lensStore } = await mountWith({}); act(() => - component.find(TopNavMenu).prop('onQuerySubmit')!({ + instance.find(services.navigation.ui.TopNavMenu).prop('onQuerySubmit')!({ dateRange: { from: 'now-14d', to: 'now-7d' }, query: { query: 'new', language: 'lucene' }, }) @@ -1301,23 +1101,22 @@ describe('Lens App', () => { const pinned = esFilters.buildExistsFilter(pinnedField, indexPattern); FilterManager.setFiltersStore([pinned], esFilters.FilterStateStore.GLOBAL_STATE); act(() => services.data.query.filterManager.setFilters([pinned, unpinned])); - component.update(); - act(() => component.find(TopNavMenu).prop('onClearSavedQuery')!()); - component.update(); - expect(frame.EditorFrameContainer).toHaveBeenLastCalledWith( - expect.objectContaining({ + instance.update(); + act(() => instance.find(services.navigation.ui.TopNavMenu).prop('onClearSavedQuery')!()); + instance.update(); + expect(lensStore.getState()).toEqual({ + app: expect.objectContaining({ filters: [pinned], }), - {} - ); + }); }); }); describe('search session id management', () => { - it('updates the searchSessionId when the query is updated', () => { - const { component, frame } = mountWith({}); + it('updates the searchSessionId when the query is updated', async () => { + const { instance, lensStore, services } = await mountWith({}); act(() => { - component.find(TopNavMenu).prop('onSaved')!({ + instance.find(services.navigation.ui.TopNavMenu).prop('onSaved')!({ id: '1', attributes: { title: '', @@ -1327,7 +1126,7 @@ describe('Lens App', () => { }); }); act(() => { - component.find(TopNavMenu).prop('onSavedQueryUpdated')!({ + instance.find(services.navigation.ui.TopNavMenu).prop('onSavedQueryUpdated')!({ id: '2', attributes: { title: 'new title', @@ -1336,37 +1135,18 @@ describe('Lens App', () => { }, }); }); - component.update(); - expect(frame.EditorFrameContainer).toHaveBeenCalledWith( - expect.objectContaining({ + instance.update(); + expect(lensStore.getState()).toEqual({ + app: expect.objectContaining({ searchSessionId: `sessionId-2`, }), - {} - ); - }); - - it('re-renders the frame if session id changes from the outside', async () => { - const services = makeDefaultServices(); - const { frame } = mountWith({ props: undefined, services }); - - act(() => { - sessionIdSubject.next('new-session-id'); - }); - await act(async () => { - await new Promise((r) => setTimeout(r, 0)); }); - expect(frame.EditorFrameContainer).toHaveBeenCalledWith( - expect.objectContaining({ - searchSessionId: `new-session-id`, - }), - {} - ); }); - it('updates the searchSessionId when the active saved query is cleared', () => { - const { component, frame, services } = mountWith({}); + it('updates the searchSessionId when the active saved query is cleared', async () => { + const { instance, services, lensStore } = await mountWith({}); act(() => - component.find(TopNavMenu).prop('onQuerySubmit')!({ + instance.find(services.navigation.ui.TopNavMenu).prop('onQuerySubmit')!({ dateRange: { from: 'now-14d', to: 'now-7d' }, query: { query: 'new', language: 'lucene' }, }) @@ -1378,15 +1158,14 @@ describe('Lens App', () => { const pinned = esFilters.buildExistsFilter(pinnedField, indexPattern); FilterManager.setFiltersStore([pinned], esFilters.FilterStateStore.GLOBAL_STATE); act(() => services.data.query.filterManager.setFilters([pinned, unpinned])); - component.update(); - act(() => component.find(TopNavMenu).prop('onClearSavedQuery')!()); - component.update(); - expect(frame.EditorFrameContainer).toHaveBeenCalledWith( - expect.objectContaining({ - searchSessionId: `sessionId-2`, + instance.update(); + act(() => instance.find(services.navigation.ui.TopNavMenu).prop('onClearSavedQuery')!()); + instance.update(); + expect(lensStore.getState()).toEqual({ + app: expect.objectContaining({ + searchSessionId: `sessionId-4`, }), - {} - ); + }); }); const mockUpdate = { @@ -1407,70 +1186,39 @@ describe('Lens App', () => { activeData: undefined, }; - it('does not update the searchSessionId when the state changes', () => { - const { component, frame } = mountWith({}); - act(() => { - component.find(frame.EditorFrameContainer).prop('onChange')(mockUpdate); - }); - component.update(); - expect(frame.EditorFrameContainer).not.toHaveBeenCalledWith( - expect.objectContaining({ - searchSessionId: `sessionId-2`, - }), - {} - ); - }); - - it('does update the searchSessionId when the state changes and too much time passed', () => { - const { component, frame, services } = mountWith({}); - - // time range is 100,000ms ago to 30,000ms ago (that's a lag of 30 percent) - (services.data.nowProvider.get as jest.Mock).mockReturnValue(new Date(Date.now() - 30000)); - (services.data.query.timefilter.timefilter.getTime as jest.Mock).mockReturnValue({ - from: 'now-2m', - to: 'now', - }); - (services.data.query.timefilter.timefilter.getBounds as jest.Mock).mockReturnValue({ - min: moment(Date.now() - 100000), - max: moment(Date.now() - 30000), - }); + it('updates the state if session id changes from the outside', async () => { + const services = makeDefaultServices(sessionIdSubject); + const { lensStore } = await mountWith({ props: undefined, services }); act(() => { - component.find(frame.EditorFrameContainer).prop('onChange')(mockUpdate); + sessionIdSubject.next('new-session-id'); }); - component.update(); - expect(frame.EditorFrameContainer).toHaveBeenCalledWith( - expect.objectContaining({ - searchSessionId: `sessionId-2`, - }), - {} - ); - }); - - it('does not update the searchSessionId when the state changes and too little time has passed', () => { - const { component, frame, services } = mountWith({}); - - // time range is 100,000ms ago to 300ms ago (that's a lag of .3 percent, not enough to trigger a session update) - (services.data.nowProvider.get as jest.Mock).mockReturnValue(new Date(Date.now() - 300)); - (services.data.query.timefilter.timefilter.getTime as jest.Mock).mockReturnValue({ - from: 'now-2m', - to: 'now', + await act(async () => { + await new Promise((r) => setTimeout(r, 0)); }); - (services.data.query.timefilter.timefilter.getBounds as jest.Mock).mockReturnValue({ - min: moment(Date.now() - 100000), - max: moment(Date.now() - 300), + expect(lensStore.getState()).toEqual({ + app: expect.objectContaining({ + searchSessionId: `new-session-id`, + }), }); + }); + it('does not update the searchSessionId when the state changes', async () => { + const { lensStore } = await mountWith({}); act(() => { - component.find(frame.EditorFrameContainer).prop('onChange')(mockUpdate); + lensStore.dispatch( + setState({ + indexPatternsForTopNav: [], + lastKnownDoc: mockUpdate.doc, + isSaveable: true, + }) + ); }); - component.update(); - expect(frame.EditorFrameContainer).not.toHaveBeenCalledWith( - expect.objectContaining({ - searchSessionId: `sessionId-2`, + expect(lensStore.getState()).toEqual({ + app: expect.objectContaining({ + searchSessionId: `sessionId-1`, }), - {} - ); + }); }); }); @@ -1483,16 +1231,16 @@ describe('Lens App', () => { confirmLeave = jest.fn(); }); - it('should not show a confirm message if there is no expression to save', () => { - const { props } = mountWith({}); + it('should not show a confirm message if there is no expression to save', async () => { + const { props } = await mountWith({}); const lastCall = props.onAppLeave.mock.calls[props.onAppLeave.mock.calls.length - 1][0]; lastCall({ default: defaultLeave, confirm: confirmLeave }); expect(defaultLeave).toHaveBeenCalled(); expect(confirmLeave).not.toHaveBeenCalled(); }); - it('does not confirm if the user is missing save permissions', () => { - const services = makeDefaultServices(); + it('does not confirm if the user is missing save permissions', async () => { + const services = makeDefaultServices(sessionIdSubject); services.application = { ...services.application, capabilities: { @@ -1500,36 +1248,36 @@ describe('Lens App', () => { visualize: { save: false, saveQuery: false, show: true }, }, }; - const { component, frame, props } = mountWith({ services }); - const onChange = frame.EditorFrameContainer.mock.calls[0][0].onChange; - act(() => - onChange({ - filterableIndexPatterns: [], - doc: ({ - savedObjectId: undefined, - references: [], - } as unknown) as Document, - isSaveable: true, - }) - ); - component.update(); + const { instance, props, lensStore } = await mountWith({ services }); + act(() => { + lensStore.dispatch( + setState({ + indexPatternsForTopNav: [] as IndexPattern[], + lastKnownDoc: ({ + savedObjectId: undefined, + references: [], + } as unknown) as Document, + isSaveable: true, + }) + ); + }); + instance.update(); const lastCall = props.onAppLeave.mock.calls[props.onAppLeave.mock.calls.length - 1][0]; lastCall({ default: defaultLeave, confirm: confirmLeave }); expect(defaultLeave).toHaveBeenCalled(); expect(confirmLeave).not.toHaveBeenCalled(); }); - it('should confirm when leaving with an unsaved doc', () => { - const { component, frame, props } = mountWith({}); - const onChange = frame.EditorFrameContainer.mock.calls[0][0].onChange; - act(() => - onChange({ - filterableIndexPatterns: [], - doc: ({ savedObjectId: undefined, state: {} } as unknown) as Document, - isSaveable: true, - }) - ); - component.update(); + it('should confirm when leaving with an unsaved doc', async () => { + const { lensStore, props } = await mountWith({}); + act(() => { + lensStore.dispatch( + setState({ + lastKnownDoc: ({ savedObjectId: undefined, state: {} } as unknown) as Document, + isSaveable: true, + }) + ); + }); const lastCall = props.onAppLeave.mock.calls[props.onAppLeave.mock.calls.length - 1][0]; lastCall({ default: defaultLeave, confirm: confirmLeave }); expect(confirmLeave).toHaveBeenCalled(); @@ -1537,22 +1285,19 @@ describe('Lens App', () => { }); it('should confirm when leaving with unsaved changes to an existing doc', async () => { - const { component, frame, props } = mountWith({}); - await act(async () => { - component.setProps({ initialInput: { savedObjectId: defaultSavedObjectId } }); + const { lensStore, props } = await mountWith({}); + act(() => { + lensStore.dispatch( + setState({ + persistedDoc: defaultDoc, + lastKnownDoc: ({ + savedObjectId: defaultSavedObjectId, + references: [], + } as unknown) as Document, + isSaveable: true, + }) + ); }); - const onChange = frame.EditorFrameContainer.mock.calls[0][0].onChange; - act(() => - onChange({ - filterableIndexPatterns: [], - doc: ({ - savedObjectId: defaultSavedObjectId, - references: [], - } as unknown) as Document, - isSaveable: true, - }) - ); - component.update(); const lastCall = props.onAppLeave.mock.calls[props.onAppLeave.mock.calls.length - 1][0]; lastCall({ default: defaultLeave, confirm: confirmLeave }); expect(confirmLeave).toHaveBeenCalled(); @@ -1560,19 +1305,16 @@ describe('Lens App', () => { }); it('should not confirm when changes are saved', async () => { - const { component, frame, props } = mountWith({}); - await act(async () => { - component.setProps({ initialInput: { savedObjectId: defaultSavedObjectId } }); + const { lensStore, props } = await mountWith({}); + act(() => { + lensStore.dispatch( + setState({ + lastKnownDoc: defaultDoc, + persistedDoc: defaultDoc, + isSaveable: true, + }) + ); }); - const onChange = frame.EditorFrameContainer.mock.calls[0][0].onChange; - act(() => - onChange({ - filterableIndexPatterns: [], - doc: defaultDoc, - isSaveable: true, - }) - ); - component.update(); const lastCall = props.onAppLeave.mock.calls[props.onAppLeave.mock.calls.length - 1][0]; lastCall({ default: defaultLeave, confirm: confirmLeave }); expect(defaultLeave).toHaveBeenCalled(); @@ -1580,19 +1322,19 @@ describe('Lens App', () => { }); it('should confirm when the latest doc is invalid', async () => { - const { component, frame, props } = mountWith({}); - await act(async () => { - component.setProps({ initialInput: { savedObjectId: defaultSavedObjectId } }); + const { lensStore, props } = await mountWith({}); + act(() => { + lensStore.dispatch( + setState({ + persistedDoc: defaultDoc, + lastKnownDoc: ({ + savedObjectId: defaultSavedObjectId, + references: [], + } as unknown) as Document, + isSaveable: true, + }) + ); }); - const onChange = frame.EditorFrameContainer.mock.calls[0][0].onChange; - act(() => - onChange({ - filterableIndexPatterns: [], - doc: ({ savedObjectId: defaultSavedObjectId, references: [] } as unknown) as Document, - isSaveable: true, - }) - ); - component.update(); const lastCall = props.onAppLeave.mock.calls[props.onAppLeave.mock.calls.length - 1][0]; lastCall({ default: defaultLeave, confirm: confirmLeave }); expect(confirmLeave).toHaveBeenCalled(); diff --git a/x-pack/plugins/lens/public/app_plugin/app.tsx b/x-pack/plugins/lens/public/app_plugin/app.tsx index c172f36913c21..61ed2934a4001 100644 --- a/x-pack/plugins/lens/public/app_plugin/app.tsx +++ b/x-pack/plugins/lens/public/app_plugin/app.tsx @@ -7,49 +7,38 @@ import './app.scss'; -import _ from 'lodash'; -import React, { useState, useEffect, useCallback, useRef } from 'react'; +import { isEqual, partition } from 'lodash'; +import React, { useState, useEffect, useCallback } from 'react'; import { i18n } from '@kbn/i18n'; import { Toast } from 'kibana/public'; import { VisualizeFieldContext } from 'src/plugins/ui_actions/public'; -import { Datatable } from 'src/plugins/expressions/public'; import { EuiBreadcrumb } from '@elastic/eui'; -import { delay, finalize, switchMap, tap } from 'rxjs/operators'; -import { downloadMultipleAs } from '../../../../../src/plugins/share/public'; import { createKbnUrlStateStorage, withNotifyOnErrors, } from '../../../../../src/plugins/kibana_utils/public'; import { useKibana } from '../../../../../src/plugins/kibana_react/public'; -import { - OnSaveProps, - checkForDuplicateTitle, -} from '../../../../../src/plugins/saved_objects/public'; +import { checkForDuplicateTitle } from '../../../../../src/plugins/saved_objects/public'; import { injectFilterReferences } from '../persistence'; import { trackUiEvent } from '../lens_ui_telemetry'; -import { - DataPublicPluginStart, - esFilters, - exporters, - Filter, - IndexPattern as IndexPatternInstance, - IndexPatternsContract, - Query, - SavedQuery, - syncQueryStateWithUrl, - waitUntilNextSessionCompletes$, -} from '../../../../../src/plugins/data/public'; -import { LENS_EMBEDDABLE_TYPE, getFullPath, APP_ID } from '../../common'; -import { LensAppProps, LensAppServices, LensAppState } from './types'; -import { getLensTopNavConfig } from './lens_top_nav'; +import { esFilters, syncQueryStateWithUrl } from '../../../../../src/plugins/data/public'; +import { getFullPath, APP_ID } from '../../common'; +import { LensAppProps, LensAppServices, RunSave } from './types'; +import { LensTopNavMenu } from './lens_top_nav'; import { Document } from '../persistence'; import { SaveModal } from './save_modal'; import { LensByReferenceInput, LensEmbeddableInput, } from '../editor_frame_service/embeddable/embeddable'; -import { useTimeRange } from './time_range'; import { EditorFrameInstance } from '../types'; +import { + setState as setAppState, + useLensSelector, + useLensDispatch, + LensAppState, + DispatchSetState, +} from '../state_management'; export function App({ history, @@ -67,7 +56,6 @@ export function App({ data, chrome, overlays, - navigation, uiSettings, application, stateTransfer, @@ -81,29 +69,18 @@ export function App({ dashboardFeatureFlag, } = useKibana().services; - const startSession = useCallback(() => data.search.session.start(), [data.search.session]); - - const [state, setState] = useState(() => { - return { - query: data.query.queryString.getQuery(), - // Do not use app-specific filters from previous app, - // only if Lens was opened with the intention to visualize a field (e.g. coming from Discover) - filters: !initialContext - ? data.query.filterManager.getGlobalFilters() - : data.query.filterManager.getFilters(), - isLoading: Boolean(initialInput), - indexPatternsForTopNav: [], - isLinkedToOriginatingApp: Boolean(incomingState?.originatingApp), - isSaveable: false, - searchSessionId: startSession(), - }; - }); + const dispatch = useLensDispatch(); + const dispatchSetState: DispatchSetState = useCallback( + (state: Partial) => dispatch(setAppState(state)), + [dispatch] + ); + + const appState = useLensSelector((state) => state.app); // Used to show a popover that guides the user towards changing the date range when no data is available. const [indicateNoData, setIndicateNoData] = useState(false); const [isSaveModalVisible, setIsSaveModalVisible] = useState(false); - - const { lastKnownDoc } = state; + const { lastKnownDoc } = appState; const showNoDataPopover = useCallback(() => { setIndicateNoData(true); @@ -116,19 +93,10 @@ export function App({ }, [ setIndicateNoData, indicateNoData, - state.query, - state.filters, - state.indexPatternsForTopNav, - state.searchSessionId, + appState.indexPatternsForTopNav, + appState.searchSessionId, ]); - const { resolvedDateRange, from: fromDate, to: toDate } = useTimeRange( - data, - state.lastKnownDoc, - setState, - state.searchSessionId - ); - const onError = useCallback( (e: { message: string }) => notifications.toasts.addDanger({ @@ -142,56 +110,13 @@ export function App({ Boolean( // Temporarily required until the 'by value' paradigm is default. dashboardFeatureFlag.allowByValueEmbeddables && - state.isLinkedToOriginatingApp && + appState.isLinkedToOriginatingApp && !(initialInput as LensByReferenceInput)?.savedObjectId ), - [dashboardFeatureFlag.allowByValueEmbeddables, state.isLinkedToOriginatingApp, initialInput] + [dashboardFeatureFlag.allowByValueEmbeddables, appState.isLinkedToOriginatingApp, initialInput] ); useEffect(() => { - // Clear app-specific filters when navigating to Lens. Necessary because Lens - // can be loaded without a full page refresh. If the user navigates to Lens from Discover - // we keep the filters - if (!initialContext) { - data.query.filterManager.setAppFilters([]); - } - - const filterSubscription = data.query.filterManager.getUpdates$().subscribe({ - next: () => { - setState((s) => ({ - ...s, - filters: data.query.filterManager.getFilters(), - searchSessionId: startSession(), - })); - trackUiEvent('app_filters_updated'); - }, - }); - - const timeSubscription = data.query.timefilter.timefilter.getTimeUpdate$().subscribe({ - next: () => { - setState((s) => ({ - ...s, - searchSessionId: startSession(), - })); - }, - }); - - const autoRefreshSubscription = data.query.timefilter.timefilter - .getAutoRefreshFetch$() - .pipe( - tap(() => { - setState((s) => ({ - ...s, - searchSessionId: startSession(), - })); - }), - switchMap((done) => - // best way in lens to estimate that all panels are updated is to rely on search session service state - waitUntilNextSessionCompletes$(data.search.session).pipe(finalize(done)) - ) - ) - .subscribe(); - const kbnUrlStateStorage = createKbnUrlStateStorage({ history, useHash: uiSettings.get('state:storeInSessionStorage'), @@ -202,41 +127,10 @@ export function App({ kbnUrlStateStorage ); - const sessionSubscription = data.search.session - .getSession$() - // wait for a tick to filter/timerange subscribers the chance to update the session id in the state - .pipe(delay(0)) - // then update if it didn't get updated yet - .subscribe((newSessionId) => { - if (newSessionId) { - setState((prevState) => { - if (prevState.searchSessionId !== newSessionId) { - return { ...prevState, searchSessionId: newSessionId }; - } else { - return prevState; - } - }); - } - }); - return () => { stopSyncingQueryServiceStateWithUrl(); - filterSubscription.unsubscribe(); - timeSubscription.unsubscribe(); - autoRefreshSubscription.unsubscribe(); - sessionSubscription.unsubscribe(); }; - }, [ - data.query.filterManager, - data.query.timefilter.timefilter, - data.search.session, - notifications.toasts, - uiSettings, - data.query, - history, - initialContext, - startSession, - ]); + }, [data.search.session, notifications.toasts, uiSettings, data.query, history]); useEffect(() => { onAppLeave((actions) => { @@ -244,11 +138,11 @@ export function App({ // or when the user has configured something without saving if ( application.capabilities.visualize.save && - !_.isEqual( - state.persistedDoc?.state, + !isEqual( + appState.persistedDoc?.state, getLastKnownDocWithoutPinnedFilters(lastKnownDoc)?.state ) && - (state.isSaveable || state.persistedDoc) + (appState.isSaveable || appState.persistedDoc) ) { return actions.confirm( i18n.translate('xpack.lens.app.unsavedWorkMessage', { @@ -265,8 +159,8 @@ export function App({ }, [ onAppLeave, lastKnownDoc, - state.isSaveable, - state.persistedDoc, + appState.isSaveable, + appState.persistedDoc, application.capabilities.visualize.save, ]); @@ -274,7 +168,7 @@ export function App({ useEffect(() => { const isByValueMode = getIsByValueMode(); const breadcrumbs: EuiBreadcrumb[] = []; - if (state.isLinkedToOriginatingApp && getOriginatingAppName() && redirectToOrigin) { + if (appState.isLinkedToOriginatingApp && getOriginatingAppName() && redirectToOrigin) { breadcrumbs.push({ onClick: () => { redirectToOrigin(); @@ -297,113 +191,31 @@ export function App({ let currentDocTitle = i18n.translate('xpack.lens.breadcrumbsCreate', { defaultMessage: 'Create', }); - if (state.persistedDoc) { + if (appState.persistedDoc) { currentDocTitle = isByValueMode ? i18n.translate('xpack.lens.breadcrumbsByValue', { defaultMessage: 'Edit visualization' }) - : state.persistedDoc.title; + : appState.persistedDoc.title; } breadcrumbs.push({ text: currentDocTitle }); chrome.setBreadcrumbs(breadcrumbs); }, [ dashboardFeatureFlag.allowByValueEmbeddables, - state.isLinkedToOriginatingApp, getOriginatingAppName, - state.persistedDoc, redirectToOrigin, getIsByValueMode, - initialInput, application, chrome, - ]); - - useEffect(() => { - if ( - !initialInput || - (attributeService.inputIsRefType(initialInput) && - initialInput.savedObjectId === state.persistedDoc?.savedObjectId) - ) { - return; - } - - setState((s) => ({ ...s, isLoading: true })); - attributeService - .unwrapAttributes(initialInput) - .then((attributes) => { - if (!initialInput) { - return; - } - const doc = { - ...initialInput, - ...attributes, - type: LENS_EMBEDDABLE_TYPE, - }; - - if (attributeService.inputIsRefType(initialInput)) { - chrome.recentlyAccessed.add( - getFullPath(initialInput.savedObjectId), - attributes.title, - initialInput.savedObjectId - ); - } - const indexPatternIds = _.uniq( - doc.references.filter(({ type }) => type === 'index-pattern').map(({ id }) => id) - ); - getAllIndexPatterns(indexPatternIds, data.indexPatterns) - .then(({ indexPatterns }) => { - // Don't overwrite any pinned filters - data.query.filterManager.setAppFilters( - injectFilterReferences(doc.state.filters, doc.references) - ); - setState((s) => ({ - ...s, - isLoading: false, - ...(!_.isEqual(state.persistedDoc, doc) ? { persistedDoc: doc } : null), - lastKnownDoc: doc, - query: doc.state.query, - indexPatternsForTopNav: indexPatterns, - })); - }) - .catch((e) => { - setState((s) => ({ ...s, isLoading: false })); - redirectTo(); - }); - }) - .catch((e) => { - setState((s) => ({ ...s, isLoading: false })); - notifications.toasts.addDanger( - i18n.translate('xpack.lens.app.docLoadingError', { - defaultMessage: 'Error loading saved document', - }) - ); - - redirectTo(); - }); - }, [ - notifications, - data.indexPatterns, - data.query.filterManager, initialInput, - attributeService, - redirectTo, - chrome.recentlyAccessed, - state.persistedDoc, + appState.isLinkedToOriginatingApp, + appState.persistedDoc, ]); const tagsIds = - state.persistedDoc && savedObjectsTagging - ? savedObjectsTagging.ui.getTagIdsFromReferences(state.persistedDoc.references) + appState.persistedDoc && savedObjectsTagging + ? savedObjectsTagging.ui.getTagIdsFromReferences(appState.persistedDoc.references) : []; - const runSave = async ( - saveProps: Omit & { - returnToOrigin: boolean; - dashboardId?: string | null; - onTitleDuplicate?: OnSaveProps['onTitleDuplicate']; - newDescription?: string; - newTags?: string[]; - }, - options: { saveToLibrary: boolean } - ) => { + const runSave: RunSave = async (saveProps, options) => { if (!lastKnownDoc) { return; } @@ -502,10 +314,8 @@ export function App({ docToSave.title, newInput.savedObjectId ); - setState((s) => ({ - ...s, - isLinkedToOriginatingApp: false, - })); + + dispatchSetState({ isLinkedToOriginatingApp: false }); setIsSaveModalVisible(false); // remove editor state so the connection is still broken after reload @@ -519,12 +329,12 @@ export function App({ ...docToSave, ...newInput, }; - setState((s) => ({ - ...s, + + dispatchSetState({ + isLinkedToOriginatingApp: false, persistedDoc: newDoc, lastKnownDoc: newDoc, - isLinkedToOriginatingApp: false, - })); + }); setIsSaveModalVisible(false); } catch (e) { @@ -535,187 +345,37 @@ export function App({ } }; - const lastKnownDocRef = useRef(state.lastKnownDoc); - lastKnownDocRef.current = state.lastKnownDoc; - - const activeDataRef = useRef(state.activeData); - activeDataRef.current = state.activeData; - - const { TopNavMenu } = navigation.ui; - const savingToLibraryPermitted = Boolean( - state.isSaveable && application.capabilities.visualize.save - ); - const savingToDashboardPermitted = Boolean( - state.isSaveable && application.capabilities.dashboard?.showWriteControls + appState.isSaveable && application.capabilities.visualize.save ); - const unsavedTitle = i18n.translate('xpack.lens.app.unsavedFilename', { - defaultMessage: 'unsaved', - }); - const topNavConfig = getLensTopNavConfig({ - showSaveAndReturn: Boolean( - state.isLinkedToOriginatingApp && - // Temporarily required until the 'by value' paradigm is default. - (dashboardFeatureFlag.allowByValueEmbeddables || Boolean(initialInput)) - ), - enableExportToCSV: Boolean( - state.isSaveable && state.activeData && Object.keys(state.activeData).length - ), - isByValueMode: getIsByValueMode(), - allowByValue: dashboardFeatureFlag.allowByValueEmbeddables, - showCancel: Boolean(state.isLinkedToOriginatingApp), - savingToLibraryPermitted, - savingToDashboardPermitted, - actions: { - exportToCSV: () => { - if (!state.activeData) { - return; - } - const datatables = Object.values(state.activeData); - const content = datatables.reduce>( - (memo, datatable, i) => { - // skip empty datatables - if (datatable) { - const postFix = datatables.length > 1 ? `-${i + 1}` : ''; - - memo[`${lastKnownDoc?.title || unsavedTitle}${postFix}.csv`] = { - content: exporters.datatableToCSV(datatable, { - csvSeparator: uiSettings.get('csv:separator', ','), - quoteValues: uiSettings.get('csv:quoteValues', true), - formatFactory: data.fieldFormats.deserialize, - }), - type: exporters.CSV_MIME_TYPE, - }; - } - return memo; - }, - {} - ); - if (content) { - downloadMultipleAs(content); - } - }, - saveAndReturn: () => { - if (savingToDashboardPermitted && lastKnownDoc) { - // disabling the validation on app leave because the document has been saved. - onAppLeave((actions) => { - return actions.default(); - }); - runSave( - { - newTitle: lastKnownDoc.title, - newCopyOnSave: false, - isTitleDuplicateConfirmed: false, - returnToOrigin: true, - }, - { - saveToLibrary: - (initialInput && attributeService.inputIsRefType(initialInput)) ?? false, - } - ); - } - }, - showSaveModal: () => { - if (savingToDashboardPermitted || savingToLibraryPermitted) { - setIsSaveModalVisible(true); - } - }, - cancel: () => { - if (redirectToOrigin) { - redirectToOrigin(); - } - }, - }, - }); - return ( <>
    - { - const { dateRange, query } = payload; - const currentRange = data.query.timefilter.timefilter.getTime(); - if (dateRange.from !== currentRange.from || dateRange.to !== currentRange.to) { - data.query.timefilter.timefilter.setTime(dateRange); - trackUiEvent('app_date_change'); - } else { - // Query has changed, renew the session id. - // Time change will be picked up by the time subscription - setState((s) => ({ - ...s, - searchSessionId: startSession(), - })); - trackUiEvent('app_query_change'); - } - setState((s) => ({ - ...s, - query: query || s.query, - })); - }} - onSaved={(savedQuery) => { - setState((s) => ({ ...s, savedQuery })); - }} - onSavedQueryUpdated={(savedQuery) => { - const savedQueryFilters = savedQuery.attributes.filters || []; - const globalFilters = data.query.filterManager.getGlobalFilters(); - data.query.filterManager.setFilters([...globalFilters, ...savedQueryFilters]); - setState((s) => ({ - ...s, - savedQuery: { ...savedQuery }, // Shallow query for reference issues - query: savedQuery.attributes.query, - })); - }} - onClearSavedQuery={() => { - data.query.filterManager.setFilters(data.query.filterManager.getGlobalFilters()); - setState((s) => ({ - ...s, - savedQuery: undefined, - filters: data.query.filterManager.getGlobalFilters(), - query: data.query.queryString.getDefaultQuery(), - })); - }} - query={state.query} - dateRangeFrom={fromDate} - dateRangeTo={toDate} + - {(!state.isLoading || state.persistedDoc) && ( + {(!appState.isAppLoading || appState.persistedDoc) && ( )}
    Toast; showNoDataPopover: () => void; initialContext: VisualizeFieldContext | undefined; - setState: React.Dispatch>; - data: DataPublicPluginStart; - lastKnownDoc: React.MutableRefObject; - activeData: React.MutableRefObject | undefined>; }) { const { EditorFrameContainer } = editorFrame; return ( { - if (isSaveable !== oldIsSaveable) { - setState((s) => ({ ...s, isSaveable })); - } - if (!_.isEqual(persistedDoc, doc) && !_.isEqual(lastKnownDoc.current, doc)) { - setState((s) => ({ ...s, lastKnownDoc: doc })); - } - if (!_.isEqual(activeDataRef.current, activeData)) { - setState((s) => ({ ...s, activeData })); - } - - // Update the cached index patterns if the user made a change to any of them - if ( - indexPatternsForTopNav.length !== filterableIndexPatterns.length || - filterableIndexPatterns.some( - (id) => !indexPatternsForTopNav.find((indexPattern) => indexPattern.id === id) - ) - ) { - getAllIndexPatterns(filterableIndexPatterns, data.indexPatterns).then( - ({ indexPatterns }) => { - if (indexPatterns) { - setState((s) => ({ ...s, indexPatternsForTopNav: indexPatterns })); - } - } - ); - } - }} /> ); }); -export async function getAllIndexPatterns( - ids: string[], - indexPatternsService: IndexPatternsContract -): Promise<{ indexPatterns: IndexPatternInstance[]; rejectedIds: string[] }> { - const responses = await Promise.allSettled(ids.map((id) => indexPatternsService.get(id))); - const fullfilled = responses.filter( - (response): response is PromiseFulfilledResult => - response.status === 'fulfilled' - ); - const rejectedIds = responses - .map((_response, i) => ids[i]) - .filter((id, i) => responses[i].status === 'rejected'); - // return also the rejected ids in case we want to show something later on - return { indexPatterns: fullfilled.map((response) => response.value), rejectedIds }; -} - function getLastKnownDocWithoutPinnedFilters(doc?: Document) { if (!doc) return undefined; - const [pinnedFilters, appFilters] = _.partition( + const [pinnedFilters, appFilters] = partition( injectFilterReferences(doc.state?.filters || [], doc.references), esFilters.isFilterPinned ); diff --git a/x-pack/plugins/lens/public/app_plugin/lens_top_nav.tsx b/x-pack/plugins/lens/public/app_plugin/lens_top_nav.tsx index f90a21b2818d4..245e964bbd2e6 100644 --- a/x-pack/plugins/lens/public/app_plugin/lens_top_nav.tsx +++ b/x-pack/plugins/lens/public/app_plugin/lens_top_nav.tsx @@ -5,11 +5,25 @@ * 2.0. */ +import { isEqual } from 'lodash'; import { i18n } from '@kbn/i18n'; +import React from 'react'; import { TopNavMenuData } from '../../../../../src/plugins/navigation/public'; -import { LensTopNavActions } from './types'; +import { LensAppServices, LensTopNavActions, LensTopNavMenuProps } from './types'; +import { downloadMultipleAs } from '../../../../../src/plugins/share/public'; +import { trackUiEvent } from '../lens_ui_telemetry'; +import { exporters } from '../../../../../src/plugins/data/public'; -export function getLensTopNavConfig(options: { +import { useKibana } from '../../../../../src/plugins/kibana_react/public'; +import { + setState as setAppState, + useLensSelector, + useLensDispatch, + LensAppState, + DispatchSetState, +} from '../state_management'; + +function getLensTopNavConfig(options: { showSaveAndReturn: boolean; enableExportToCSV: boolean; showCancel: boolean; @@ -101,6 +115,185 @@ export function getLensTopNavConfig(options: { }), }); } - return topNavMenu; } + +export const LensTopNavMenu = ({ + setHeaderActionMenu, + initialInput, + indicateNoData, + setIsSaveModalVisible, + getIsByValueMode, + runSave, + onAppLeave, + redirectToOrigin, +}: LensTopNavMenuProps) => { + const { + data, + navigation, + uiSettings, + application, + attributeService, + dashboardFeatureFlag, + } = useKibana().services; + + const dispatch = useLensDispatch(); + const dispatchSetState: DispatchSetState = React.useCallback( + (state: Partial) => dispatch(setAppState(state)), + [dispatch] + ); + + const { + isSaveable, + isLinkedToOriginatingApp, + indexPatternsForTopNav, + query, + lastKnownDoc, + activeData, + savedQuery, + } = useLensSelector((state) => state.app); + + const { TopNavMenu } = navigation.ui; + const { from, to } = data.query.timefilter.timefilter.getTime(); + + const savingToLibraryPermitted = Boolean(isSaveable && application.capabilities.visualize.save); + const savingToDashboardPermitted = Boolean( + isSaveable && application.capabilities.dashboard?.showWriteControls + ); + + const unsavedTitle = i18n.translate('xpack.lens.app.unsavedFilename', { + defaultMessage: 'unsaved', + }); + const topNavConfig = getLensTopNavConfig({ + showSaveAndReturn: Boolean( + isLinkedToOriginatingApp && + // Temporarily required until the 'by value' paradigm is default. + (dashboardFeatureFlag.allowByValueEmbeddables || Boolean(initialInput)) + ), + enableExportToCSV: Boolean(isSaveable && activeData && Object.keys(activeData).length), + isByValueMode: getIsByValueMode(), + allowByValue: dashboardFeatureFlag.allowByValueEmbeddables, + showCancel: Boolean(isLinkedToOriginatingApp), + savingToLibraryPermitted, + savingToDashboardPermitted, + actions: { + exportToCSV: () => { + if (!activeData) { + return; + } + const datatables = Object.values(activeData); + const content = datatables.reduce>( + (memo, datatable, i) => { + // skip empty datatables + if (datatable) { + const postFix = datatables.length > 1 ? `-${i + 1}` : ''; + + memo[`${lastKnownDoc?.title || unsavedTitle}${postFix}.csv`] = { + content: exporters.datatableToCSV(datatable, { + csvSeparator: uiSettings.get('csv:separator', ','), + quoteValues: uiSettings.get('csv:quoteValues', true), + formatFactory: data.fieldFormats.deserialize, + }), + type: exporters.CSV_MIME_TYPE, + }; + } + return memo; + }, + {} + ); + if (content) { + downloadMultipleAs(content); + } + }, + saveAndReturn: () => { + if (savingToDashboardPermitted && lastKnownDoc) { + // disabling the validation on app leave because the document has been saved. + onAppLeave((actions) => { + return actions.default(); + }); + runSave( + { + newTitle: lastKnownDoc.title, + newCopyOnSave: false, + isTitleDuplicateConfirmed: false, + returnToOrigin: true, + }, + { + saveToLibrary: + (initialInput && attributeService.inputIsRefType(initialInput)) ?? false, + } + ); + } + }, + showSaveModal: () => { + if (savingToDashboardPermitted || savingToLibraryPermitted) { + setIsSaveModalVisible(true); + } + }, + cancel: () => { + if (redirectToOrigin) { + redirectToOrigin(); + } + }, + }, + }); + + return ( + { + const { dateRange, query: newQuery } = payload; + const currentRange = data.query.timefilter.timefilter.getTime(); + if (dateRange.from !== currentRange.from || dateRange.to !== currentRange.to) { + data.query.timefilter.timefilter.setTime(dateRange); + trackUiEvent('app_date_change'); + } else { + // Query has changed, renew the session id. + // Time change will be picked up by the time subscription + dispatchSetState({ searchSessionId: data.search.session.start() }); + trackUiEvent('app_query_change'); + } + if (newQuery) { + if (!isEqual(newQuery, query)) { + dispatchSetState({ query: newQuery }); + } + } + }} + onSaved={(newSavedQuery) => { + dispatchSetState({ savedQuery: newSavedQuery }); + }} + onSavedQueryUpdated={(newSavedQuery) => { + const savedQueryFilters = newSavedQuery.attributes.filters || []; + const globalFilters = data.query.filterManager.getGlobalFilters(); + data.query.filterManager.setFilters([...globalFilters, ...savedQueryFilters]); + dispatchSetState({ + query: newSavedQuery.attributes.query, + savedQuery: { ...newSavedQuery }, + }); // Shallow query for reference issues + }} + onClearSavedQuery={() => { + data.query.filterManager.setFilters(data.query.filterManager.getGlobalFilters()); + dispatchSetState({ + filters: data.query.filterManager.getGlobalFilters(), + query: data.query.queryString.getDefaultQuery(), + savedQuery: undefined, + }); + }} + indexPatterns={indexPatternsForTopNav} + query={query} + dateRangeFrom={from} + dateRangeTo={to} + indicateNoData={indicateNoData} + showSearchBar={true} + showDatePicker={true} + showQueryBar={true} + showFilterBar={true} + data-test-subj="lnsApp_topNav" + screenTitle={'lens'} + appName={'lens'} + /> + ); +}; diff --git a/x-pack/plugins/lens/public/app_plugin/mounter.test.tsx b/x-pack/plugins/lens/public/app_plugin/mounter.test.tsx new file mode 100644 index 0000000000000..f2640c5c32acf --- /dev/null +++ b/x-pack/plugins/lens/public/app_plugin/mounter.test.tsx @@ -0,0 +1,150 @@ +/* + * 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 { makeDefaultServices, mockLensStore } from '../mocks'; +import { act } from 'react-dom/test-utils'; +import { loadDocument } from './mounter'; +import { LensEmbeddableInput } from '../editor_frame_service/embeddable/embeddable'; + +const defaultSavedObjectId = '1234'; + +describe('Mounter', () => { + describe('loadDocument', () => { + it('does not load a document if there is no initial input', async () => { + const services = makeDefaultServices(); + const redirectCallback = jest.fn(); + const lensStore = mockLensStore({ data: services.data }); + await loadDocument(redirectCallback, undefined, services, lensStore); + expect(services.attributeService.unwrapAttributes).not.toHaveBeenCalled(); + }); + + it('loads a document and uses query and filters if initial input is provided', async () => { + const services = makeDefaultServices(); + const redirectCallback = jest.fn(); + services.attributeService.unwrapAttributes = jest.fn().mockResolvedValue({ + savedObjectId: defaultSavedObjectId, + state: { + query: 'fake query', + filters: [{ query: { match_phrase: { src: 'test' } } }], + }, + references: [{ type: 'index-pattern', id: '1', name: 'index-pattern-0' }], + }); + + const lensStore = await mockLensStore({ data: services.data }); + await act(async () => { + await loadDocument( + redirectCallback, + { savedObjectId: defaultSavedObjectId } as LensEmbeddableInput, + services, + lensStore + ); + }); + + expect(services.attributeService.unwrapAttributes).toHaveBeenCalledWith({ + savedObjectId: defaultSavedObjectId, + }); + + expect(services.data.indexPatterns.get).toHaveBeenCalledWith('1'); + + expect(services.data.query.filterManager.setAppFilters).toHaveBeenCalledWith([ + { query: { match_phrase: { src: 'test' } } }, + ]); + + expect(lensStore.getState()).toEqual({ + app: expect.objectContaining({ + persistedDoc: expect.objectContaining({ + savedObjectId: defaultSavedObjectId, + state: expect.objectContaining({ + query: 'fake query', + filters: [{ query: { match_phrase: { src: 'test' } } }], + }), + }), + }), + }); + }); + + it('does not load documents on sequential renders unless the id changes', async () => { + const redirectCallback = jest.fn(); + const services = makeDefaultServices(); + const lensStore = mockLensStore({ data: services.data }); + + await act(async () => { + await loadDocument( + redirectCallback, + { savedObjectId: defaultSavedObjectId } as LensEmbeddableInput, + services, + lensStore + ); + }); + + await act(async () => { + await loadDocument( + redirectCallback, + { savedObjectId: defaultSavedObjectId } as LensEmbeddableInput, + services, + lensStore + ); + }); + + expect(services.attributeService.unwrapAttributes).toHaveBeenCalledTimes(1); + + await act(async () => { + await loadDocument( + redirectCallback, + { savedObjectId: '5678' } as LensEmbeddableInput, + services, + lensStore + ); + }); + + expect(services.attributeService.unwrapAttributes).toHaveBeenCalledTimes(2); + }); + + it('handles document load errors', async () => { + const services = makeDefaultServices(); + const redirectCallback = jest.fn(); + + const lensStore = mockLensStore({ data: services.data }); + + services.attributeService.unwrapAttributes = jest.fn().mockRejectedValue('failed to load'); + + await act(async () => { + await loadDocument( + redirectCallback, + { savedObjectId: defaultSavedObjectId } as LensEmbeddableInput, + services, + lensStore + ); + }); + expect(services.attributeService.unwrapAttributes).toHaveBeenCalledWith({ + savedObjectId: defaultSavedObjectId, + }); + expect(services.notifications.toasts.addDanger).toHaveBeenCalled(); + expect(redirectCallback).toHaveBeenCalled(); + }); + + it('adds to the recently accessed list on load', async () => { + const redirectCallback = jest.fn(); + + const services = makeDefaultServices(); + const lensStore = mockLensStore({ data: services.data }); + await act(async () => { + await loadDocument( + redirectCallback, + ({ savedObjectId: defaultSavedObjectId } as unknown) as LensEmbeddableInput, + services, + lensStore + ); + }); + + expect(services.chrome.recentlyAccessed.add).toHaveBeenCalledWith( + '/app/lens#/edit/1234', + 'An extremely cool default document!', + '1234' + ); + }); + }); +}); diff --git a/x-pack/plugins/lens/public/app_plugin/mounter.tsx b/x-pack/plugins/lens/public/app_plugin/mounter.tsx index e6eb115562d37..708573e843fcf 100644 --- a/x-pack/plugins/lens/public/app_plugin/mounter.tsx +++ b/x-pack/plugins/lens/public/app_plugin/mounter.tsx @@ -15,6 +15,8 @@ import { render, unmountComponentAtNode } from 'react-dom'; import { i18n } from '@kbn/i18n'; import { DashboardFeatureFlagConfig } from 'src/plugins/dashboard/public'; +import { Provider } from 'react-redux'; +import { uniq, isEqual } from 'lodash'; import { Storage } from '../../../../../src/plugins/kibana_utils/public'; import { LensReportManager, setReportManager, trackUiEvent } from '../lens_ui_telemetry'; @@ -23,7 +25,7 @@ import { App } from './app'; import { EditorFrameStart } from '../types'; import { addHelpMenuToAppChrome } from '../help_menu_util'; import { LensPluginStartDependencies } from '../plugin'; -import { LENS_EMBEDDABLE_TYPE, LENS_EDIT_BY_VALUE, APP_ID } from '../../common'; +import { LENS_EMBEDDABLE_TYPE, LENS_EDIT_BY_VALUE, APP_ID, getFullPath } from '../../common'; import { LensEmbeddableInput, LensByReferenceInput, @@ -34,6 +36,16 @@ import { LensAttributeService } from '../lens_attribute_service'; import { LensAppServices, RedirectToOriginProps, HistoryLocationState } from './types'; import { KibanaContextProvider } from '../../../../../src/plugins/kibana_react/public'; +import { + makeConfigureStore, + navigateAway, + getPreloadedState, + LensRootStore, + setState, +} from '../state_management'; +import { getAllIndexPatterns, getResolvedDateRange } from '../utils'; +import { injectFilterReferences } from '../persistence'; + export async function mountApp( core: CoreSetup, params: AppMountParameters, @@ -149,8 +161,32 @@ export async function mountApp( coreStart.application.navigateToApp(embeddableEditorIncomingState?.originatingApp); } }; + const initialContext = + historyLocationState && historyLocationState.type === ACTION_VISUALIZE_LENS_FIELD + ? historyLocationState.payload + : undefined; + + // Clear app-specific filters when navigating to Lens. Necessary because Lens + // can be loaded without a full page refresh. If the user navigates to Lens from Discover + // we keep the filters + if (!initialContext) { + data.query.filterManager.setAppFilters([]); + } + + const preloadedState = getPreloadedState({ + query: data.query.queryString.getQuery(), + // Do not use app-specific filters from previous app, + // only if Lens was opened with the intention to visualize a field (e.g. coming from Discover) + filters: !initialContext + ? data.query.filterManager.getGlobalFilters() + : data.query.filterManager.getFilters(), + searchSessionId: data.search.session.start(), + resolvedDateRange: getResolvedDateRange(data.query.timefilter.timefilter), + isLinkedToOriginatingApp: Boolean(embeddableEditorIncomingState?.originatingApp), + }); + + const lensStore: LensRootStore = makeConfigureStore(preloadedState, { data }); - // const featureFlagConfig = await getByValueFeatureFlag(); const EditorRenderer = React.memo( (props: { id?: string; history: History; editByValue?: boolean }) => { const redirectCallback = useCallback( @@ -160,23 +196,23 @@ export async function mountApp( [props.history] ); trackUiEvent('loaded'); + const initialInput = getInitialInput(props.id, props.editByValue); + loadDocument(redirectCallback, initialInput, lensServices, lensStore); return ( - + + + ); } ); @@ -232,5 +268,86 @@ export async function mountApp( data.search.session.clear(); unmountComponentAtNode(params.element); unlistenParentHistory(); + lensStore.dispatch(navigateAway()); }; } + +export function loadDocument( + redirectCallback: (savedObjectId?: string) => void, + initialInput: LensEmbeddableInput | undefined, + lensServices: LensAppServices, + lensStore: LensRootStore +) { + const { attributeService, chrome, notifications, data } = lensServices; + const { persistedDoc } = lensStore.getState().app; + if ( + !initialInput || + (attributeService.inputIsRefType(initialInput) && + initialInput.savedObjectId === persistedDoc?.savedObjectId) + ) { + return; + } + lensStore.dispatch(setState({ isAppLoading: true })); + + attributeService + .unwrapAttributes(initialInput) + .then((attributes) => { + if (!initialInput) { + return; + } + const doc = { + ...initialInput, + ...attributes, + type: LENS_EMBEDDABLE_TYPE, + }; + + if (attributeService.inputIsRefType(initialInput)) { + chrome.recentlyAccessed.add( + getFullPath(initialInput.savedObjectId), + attributes.title, + initialInput.savedObjectId + ); + } + const indexPatternIds = uniq( + doc.references.filter(({ type }) => type === 'index-pattern').map(({ id }) => id) + ); + getAllIndexPatterns(indexPatternIds, data.indexPatterns) + .then(({ indexPatterns }) => { + // Don't overwrite any pinned filters + data.query.filterManager.setAppFilters( + injectFilterReferences(doc.state.filters, doc.references) + ); + lensStore.dispatch( + setState({ + query: doc.state.query, + isAppLoading: false, + indexPatternsForTopNav: indexPatterns, + lastKnownDoc: doc, + ...(!isEqual(persistedDoc, doc) ? { persistedDoc: doc } : null), + }) + ); + }) + .catch((e) => { + lensStore.dispatch( + setState({ + isAppLoading: false, + }) + ); + redirectCallback(); + }); + }) + .catch((e) => { + lensStore.dispatch( + setState({ + isAppLoading: false, + }) + ); + notifications.toasts.addDanger( + i18n.translate('xpack.lens.app.docLoadingError', { + defaultMessage: 'Error loading saved document', + }) + ); + + redirectCallback(); + }); +} diff --git a/x-pack/plugins/lens/public/app_plugin/time_range.ts b/x-pack/plugins/lens/public/app_plugin/time_range.ts deleted file mode 100644 index c9e507f3e6f13..0000000000000 --- a/x-pack/plugins/lens/public/app_plugin/time_range.ts +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import './app.scss'; - -import _ from 'lodash'; -import moment from 'moment'; -import { useEffect, useMemo } from 'react'; -import { DataPublicPluginStart } from '../../../../../src/plugins/data/public'; -import { LensAppState } from './types'; -import { Document } from '../persistence'; - -function containsDynamicMath(dateMathString: string) { - return dateMathString.includes('now'); -} - -const TIME_LAG_PERCENTAGE_LIMIT = 0.02; - -/** - * Fetches the current global time range from data plugin and restarts session - * if the fixed "now" parameter is diverging too much from the actual current time. - * @param data data plugin contract to manage current now value, time range and session - * @param lastKnownDoc Current state of the editor - * @param setState state setter for Lens app state - * @param searchSessionId current session id - */ -export function useTimeRange( - data: DataPublicPluginStart, - lastKnownDoc: Document | undefined, - setState: React.Dispatch>, - searchSessionId: string -) { - const timefilter = data.query.timefilter.timefilter; - const { from, to } = data.query.timefilter.timefilter.getTime(); - - // Need a stable reference for the frame component of the dateRange - const resolvedDateRange = useMemo(() => { - const { min, max } = timefilter.calculateBounds({ - from, - to, - }); - return { fromDate: min?.toISOString() || from, toDate: max?.toISOString() || to }; - // recalculate current date range if the session gets updated because it - // might change "now" and calculateBounds depends on it internally - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [timefilter, searchSessionId, from, to]); - - useEffect(() => { - const unresolvedTimeRange = timefilter.getTime(); - if ( - !containsDynamicMath(unresolvedTimeRange.from) && - !containsDynamicMath(unresolvedTimeRange.to) - ) { - return; - } - - const { min, max } = timefilter.getBounds(); - - if (!min || !max) { - // bounds not fully specified, bailing out - return; - } - - // calculate length of currently configured range in ms - const timeRangeLength = moment.duration(max.diff(min)).asMilliseconds(); - - // calculate lag of managed "now" for date math - const nowDiff = Date.now() - data.nowProvider.get().valueOf(); - - // if the lag is signifcant, start a new session to clear the cache - if (nowDiff > timeRangeLength * TIME_LAG_PERCENTAGE_LIMIT) { - setState((s) => ({ - ...s, - searchSessionId: data.search.session.start(), - })); - } - }, [data.nowProvider, data.search.session, timefilter, lastKnownDoc, setState]); - - return { resolvedDateRange, from, to }; -} diff --git a/x-pack/plugins/lens/public/app_plugin/types.ts b/x-pack/plugins/lens/public/app_plugin/types.ts index c9143542e67bf..72850552723f3 100644 --- a/x-pack/plugins/lens/public/app_plugin/types.ts +++ b/x-pack/plugins/lens/public/app_plugin/types.ts @@ -6,6 +6,7 @@ */ import { History } from 'history'; +import { OnSaveProps } from 'src/plugins/saved_objects/public'; import { ApplicationStart, AppMountParameters, @@ -16,14 +17,7 @@ import { OverlayStart, SavedObjectsStart, } from '../../../../../src/core/public'; -import { - DataPublicPluginStart, - Filter, - IndexPattern, - Query, - SavedQuery, -} from '../../../../../src/plugins/data/public'; -import { Document } from '../persistence'; +import { DataPublicPluginStart } from '../../../../../src/plugins/data/public'; import { LensEmbeddableInput } from '../editor_frame_service/embeddable/embeddable'; import { NavigationPublicPluginStart } from '../../../../../src/plugins/navigation/public'; import { LensAttributeService } from '../lens_attribute_service'; @@ -38,28 +32,7 @@ import { EmbeddableEditorState, EmbeddableStateTransfer, } from '../../../../../src/plugins/embeddable/public'; -import { TableInspectorAdapter } from '../editor_frame_service/types'; import { EditorFrameInstance } from '../types'; - -export interface LensAppState { - isLoading: boolean; - persistedDoc?: Document; - lastKnownDoc?: Document; - - // index patterns used to determine which filters are available in the top nav. - indexPatternsForTopNav: IndexPattern[]; - - // Determines whether the lens editor shows the 'save and return' button, and the originating app breadcrumb. - isLinkedToOriginatingApp?: boolean; - - query: Query; - filters: Filter[]; - savedQuery?: SavedQuery; - isSaveable: boolean; - activeData?: TableInspectorAdapter; - searchSessionId: string; -} - export interface RedirectToOriginProps { input?: LensEmbeddableInput; isCopied?: boolean; @@ -82,6 +55,32 @@ export interface LensAppProps { initialContext?: VisualizeFieldContext; } +export type RunSave = ( + saveProps: Omit & { + returnToOrigin: boolean; + dashboardId?: string | null; + onTitleDuplicate?: OnSaveProps['onTitleDuplicate']; + newDescription?: string; + newTags?: string[]; + }, + options: { + saveToLibrary: boolean; + } +) => Promise; + +export interface LensTopNavMenuProps { + onAppLeave: AppMountParameters['onAppLeave']; + setHeaderActionMenu: AppMountParameters['setHeaderActionMenu']; + + redirectToOrigin?: (props?: RedirectToOriginProps) => void; + // The initial input passed in by the container when editing. Can be either by reference or by value. + initialInput?: LensEmbeddableInput; + getIsByValueMode: () => boolean; + indicateNoData: boolean; + setIsSaveModalVisible: React.Dispatch>; + runSave: RunSave; +} + export interface HistoryLocationState { type: typeof ACTION_VISUALIZE_LENS_FIELD; payload: VisualizeFieldContext; diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/editor_frame.test.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/editor_frame.test.tsx index f23e4c74e1a8b..351b4009240eb 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/editor_frame.test.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/editor_frame.test.tsx @@ -7,6 +7,7 @@ import React, { ReactElement } from 'react'; import { ReactWrapper } from 'enzyme'; +import { setState, LensRootStore } from '../../state_management/index'; // Tests are executed in a jsdom environment who does not have sizing methods, // thus the AutoSizer will always compute a 0x0 size space @@ -28,8 +29,7 @@ jest.mock('react-virtualized-auto-sizer', () => { }); import { EuiPanel, EuiToolTip } from '@elastic/eui'; -import { mountWithIntl as mount } from '@kbn/test/jest'; -import { EditorFrame } from './editor_frame'; +import { EditorFrame, EditorFrameProps } from './editor_frame'; import { DatasourcePublicAPI, DatasourceSuggestion, Visualization } from '../../types'; import { act } from 'react-dom/test-utils'; import { coreMock } from 'src/core/public/mocks'; @@ -44,9 +44,9 @@ import { ReactExpressionRendererType } from 'src/plugins/expressions/public'; import { DragDrop } from '../../drag_drop'; import { FrameLayout } from './frame_layout'; import { uiActionsPluginMock } from '../../../../../../src/plugins/ui_actions/public/mocks'; -import { dataPluginMock } from '../../../../../../src/plugins/data/public/mocks'; import { chartPluginMock } from '../../../../../../src/plugins/charts/public/mocks'; import { expressionsPluginMock } from '../../../../../../src/plugins/expressions/public/mocks'; +import { mockDataPlugin, mountWithProvider } from '../../mocks'; function generateSuggestion(state = {}): DatasourceSuggestion { return { @@ -62,7 +62,7 @@ function generateSuggestion(state = {}): DatasourceSuggestion { } function getDefaultProps() { - return { + const defaultProps = { store: { save: jest.fn(), load: jest.fn(), @@ -72,18 +72,17 @@ function getDefaultProps() { onChange: jest.fn(), dateRange: { fromDate: '', toDate: '' }, query: { query: '', language: 'lucene' }, - filters: [], core: coreMock.createStart(), plugins: { uiActions: uiActionsPluginMock.createStartContract(), - data: dataPluginMock.createStartContract(), + data: mockDataPlugin(), expressions: expressionsPluginMock.createStartContract(), charts: chartPluginMock.createStartContract(), }, palettes: chartPluginMock.createPaletteRegistry(), showNoDataPopover: jest.fn(), - searchSessionId: 'sessionId', }; + return defaultProps; } describe('editor_frame', () => { @@ -133,85 +132,57 @@ describe('editor_frame', () => { describe('initialization', () => { it('should initialize initial datasource', async () => { mockVisualization.getLayerIds.mockReturnValue([]); - await act(async () => { - mount( - - ); - }); - - expect(mockDatasource.initialize).toHaveBeenCalled(); - }); + const props = { + ...getDefaultProps(), + visualizationMap: { + testVis: mockVisualization, + }, + datasourceMap: { + testDatasource: mockDatasource, + }, - it('should not initialize datasource and visualization if no initial one is specificed', () => { - act(() => { - mount( - - ); - }); + ExpressionRenderer: expressionRendererMock, + }; - expect(mockVisualization.initialize).not.toHaveBeenCalled(); - expect(mockDatasource.initialize).not.toHaveBeenCalled(); + await mountWithProvider(, props.plugins.data); + expect(mockDatasource.initialize).toHaveBeenCalled(); }); it('should initialize all datasources with state from doc', async () => { const mockDatasource3 = createMockDatasource('testDatasource3'); const datasource1State = { datasource1: '' }; const datasource2State = { datasource2: '' }; + const props = { + ...getDefaultProps(), + visualizationMap: { + testVis: mockVisualization, + }, + datasourceMap: { + testDatasource: mockDatasource, + testDatasource2: mockDatasource2, + testDatasource3: mockDatasource3, + }, - await act(async () => { - mount( - - ); + ExpressionRenderer: expressionRendererMock, + }; + + await mountWithProvider(, props.plugins.data, { + persistedDoc: { + visualizationType: 'testVis', + title: '', + state: { + datasourceStates: { + testDatasource: datasource1State, + testDatasource2: datasource2State, + }, + visualization: {}, + query: { query: '', language: 'lucene' }, + filters: [], + }, + references: [], + }, }); + expect(mockDatasource.initialize).toHaveBeenCalledWith(datasource1State, [], undefined, { isFullEditor: true, }); @@ -222,42 +193,40 @@ describe('editor_frame', () => { }); it('should not render something before all datasources are initialized', async () => { + const props = { + ...getDefaultProps(), + visualizationMap: { + testVis: mockVisualization, + }, + datasourceMap: { + testDatasource: mockDatasource, + }, + + ExpressionRenderer: expressionRendererMock, + }; + await act(async () => { - mount( - - ); + mountWithProvider(, props.plugins.data); expect(mockDatasource.renderDataPanel).not.toHaveBeenCalled(); }); expect(mockDatasource.renderDataPanel).toHaveBeenCalled(); }); it('should not initialize visualization before datasource is initialized', async () => { + const props = { + ...getDefaultProps(), + visualizationMap: { + testVis: mockVisualization, + }, + datasourceMap: { + testDatasource: mockDatasource, + }, + + ExpressionRenderer: expressionRendererMock, + }; + await act(async () => { - mount( - - ); + mountWithProvider(, props.plugins.data); expect(mockVisualization.initialize).not.toHaveBeenCalled(); }); @@ -265,23 +234,19 @@ describe('editor_frame', () => { }); it('should pass the public frame api into visualization initialize', async () => { - const defaultProps = getDefaultProps(); + const props = { + ...getDefaultProps(), + visualizationMap: { + testVis: mockVisualization, + }, + datasourceMap: { + testDatasource: mockDatasource, + }, + + ExpressionRenderer: expressionRendererMock, + }; await act(async () => { - mount( - - ); + mountWithProvider(, props.plugins.data); expect(mockVisualization.initialize).not.toHaveBeenCalled(); }); @@ -291,33 +256,43 @@ describe('editor_frame', () => { removeLayers: expect.any(Function), query: { query: '', language: 'lucene' }, filters: [], - dateRange: { fromDate: 'now-7d', toDate: 'now' }, - availablePalettes: defaultProps.palettes, - searchSessionId: 'sessionId', + dateRange: { fromDate: '2021-01-10T04:00:00.000Z', toDate: '2021-01-10T08:00:00.000Z' }, + availablePalettes: props.palettes, + searchSessionId: 'sessionId-1', }); }); it('should add new layer on active datasource on frame api call', async () => { const initialState = { datasource2: '' }; mockDatasource2.initialize.mockReturnValue(Promise.resolve(initialState)); - await act(async () => { - mount( - , props.plugins.data, { + persistedDoc: { + visualizationType: 'testVis', + title: '', + state: { + datasourceStates: { testDatasource2: mockDatasource2, - }} - initialDatasourceId="testDatasource2" - initialVisualizationId="testVis" - ExpressionRenderer={expressionRendererMock} - /> - ); + }, + visualization: {}, + query: { query: '', language: 'lucene' }, + filters: [], + }, + references: [], + }, }); - act(() => { mockVisualization.initialize.mock.calls[0][0].addNewLayer(); }); @@ -332,22 +307,33 @@ describe('editor_frame', () => { mockDatasource2.getLayers.mockReturnValue(['abc', 'def']); mockDatasource2.removeLayer.mockReturnValue({ removed: true }); mockVisualization.getLayerIds.mockReturnValue(['first', 'abc', 'def']); - await act(async () => { - mount( - , props.plugins.data, { + persistedDoc: { + visualizationType: 'testVis', + title: '', + state: { + datasourceStates: { testDatasource2: mockDatasource2, - }} - initialDatasourceId="testDatasource2" - initialVisualizationId="testVis" - ExpressionRenderer={expressionRendererMock} - /> - ); + }, + visualization: {}, + query: { query: '', language: 'lucene' }, + filters: [], + }, + references: [], + }, }); act(() => { @@ -362,28 +348,26 @@ describe('editor_frame', () => { const initialState = {}; let databaseInitialized: ({}) => void; - await act(async () => { - mount( - - new Promise((resolve) => { - databaseInitialized = resolve; - }), - }, - }} - initialDatasourceId="testDatasource" - initialVisualizationId="testVis" - ExpressionRenderer={expressionRendererMock} - /> - ); - }); + const props = { + ...getDefaultProps(), + visualizationMap: { + testVis: mockVisualization, + }, + datasourceMap: { + testDatasource: { + ...mockDatasource, + initialize: () => + new Promise((resolve) => { + databaseInitialized = resolve; + }), + }, + }, + + ExpressionRenderer: expressionRendererMock, + }; + + await mountWithProvider(, props.plugins.data); + await act(async () => { databaseInitialized!(initialState); }); @@ -397,25 +381,22 @@ describe('editor_frame', () => { const initialState = {}; mockDatasource.getLayers.mockReturnValue(['first']); - await act(async () => { - mount( - initialState }, - }} - datasourceMap={{ - testDatasource: { - ...mockDatasource, - initialize: () => Promise.resolve(), - }, - }} - initialDatasourceId="testDatasource" - initialVisualizationId="testVis" - ExpressionRenderer={expressionRendererMock} - /> - ); - }); + const props = { + ...getDefaultProps(), + visualizationMap: { + testVis: { ...mockVisualization, initialize: () => initialState }, + }, + datasourceMap: { + testDatasource: { + ...mockDatasource, + initialize: () => Promise.resolve(), + }, + }, + + ExpressionRenderer: expressionRendererMock, + }; + + await mountWithProvider(, props.plugins.data); expect(mockVisualization.getConfiguration).toHaveBeenCalledWith( expect.objectContaining({ state: initialState }) @@ -427,25 +408,21 @@ describe('editor_frame', () => { it('should render the resulting expression using the expression renderer', async () => { mockDatasource.getLayers.mockReturnValue(['first']); - await act(async () => { - instance = mount( - 'vis' }, - }} - datasourceMap={{ - testDatasource: { - ...mockDatasource, - toExpression: () => 'datasource', - }, - }} - initialDatasourceId="testDatasource" - initialVisualizationId="testVis" - ExpressionRenderer={expressionRendererMock} - /> - ); - }); + const props = { + ...getDefaultProps(), + visualizationMap: { + testVis: { ...mockVisualization, toExpression: () => 'vis' }, + }, + datasourceMap: { + testDatasource: { + ...mockDatasource, + toExpression: () => 'datasource', + }, + }, + + ExpressionRenderer: expressionRendererMock, + }; + instance = (await mountWithProvider(, props.plugins.data)).instance; instance.update(); @@ -466,37 +443,34 @@ describe('editor_frame', () => { ); mockDatasource2.getLayers.mockReturnValue(['second', 'third']); - await act(async () => { - instance = mount( - 'vis' }, - }} - datasourceMap={{ - testDatasource: mockDatasource, - testDatasource2: mockDatasource2, - }} - initialDatasourceId="testDatasource" - initialVisualizationId="testVis" - ExpressionRenderer={expressionRendererMock} - doc={{ - visualizationType: 'testVis', - title: '', - state: { - datasourceStates: { - testDatasource: {}, - testDatasource2: {}, - }, - visualization: {}, - query: { query: '', language: 'lucene' }, - filters: [], + const props = { + ...getDefaultProps(), + visualizationMap: { + testVis: { ...mockVisualization, toExpression: () => 'vis' }, + }, + datasourceMap: { testDatasource: mockDatasource, testDatasource2: mockDatasource2 }, + + ExpressionRenderer: expressionRendererMock, + }; + + instance = ( + await mountWithProvider(, props.plugins.data, { + persistedDoc: { + visualizationType: 'testVis', + title: '', + state: { + datasourceStates: { + testDatasource: {}, + testDatasource2: {}, }, - references: [], - }} - /> - ); - }); + visualization: {}, + query: { query: '', language: 'lucene' }, + filters: [], + }, + references: [], + }, + }) + ).instance; instance.update(); @@ -577,23 +551,18 @@ describe('editor_frame', () => { describe('state update', () => { it('should re-render config panel after state update', async () => { mockDatasource.getLayers.mockReturnValue(['first']); + const props = { + ...getDefaultProps(), + visualizationMap: { + testVis: mockVisualization, + }, + datasourceMap: { + testDatasource: mockDatasource, + }, - await act(async () => { - mount( - - ); - }); + ExpressionRenderer: expressionRendererMock, + }; + await mountWithProvider(, props.plugins.data); const updatedState = {}; const setDatasourceState = (mockDatasource.renderDataPanel as jest.Mock).mock.calls[0][1] .setState; @@ -601,8 +570,9 @@ describe('editor_frame', () => { setDatasourceState(updatedState); }); + // TODO: temporary regression // validation requires to calls this getConfiguration API - expect(mockVisualization.getConfiguration).toHaveBeenCalledTimes(7); + expect(mockVisualization.getConfiguration).toHaveBeenCalledTimes(9); expect(mockVisualization.getConfiguration).toHaveBeenLastCalledWith( expect.objectContaining({ state: updatedState, @@ -613,22 +583,18 @@ describe('editor_frame', () => { it('should re-render data panel after state update', async () => { mockDatasource.getLayers.mockReturnValue(['first']); - await act(async () => { - mount( - - ); - }); + const props = { + ...getDefaultProps(), + visualizationMap: { + testVis: mockVisualization, + }, + datasourceMap: { + testDatasource: mockDatasource, + }, + + ExpressionRenderer: expressionRendererMock, + }; + await mountWithProvider(, props.plugins.data); const setDatasourceState = (mockDatasource.renderDataPanel as jest.Mock).mock.calls[0][1] .setState; @@ -653,23 +619,18 @@ describe('editor_frame', () => { it('should re-render config panel with updated datasource api after datasource state update', async () => { mockDatasource.getLayers.mockReturnValue(['first']); + const props = { + ...getDefaultProps(), + visualizationMap: { + testVis: mockVisualization, + }, + datasourceMap: { + testDatasource: mockDatasource, + }, - await act(async () => { - mount( - - ); - }); + ExpressionRenderer: expressionRendererMock, + }; + await mountWithProvider(, props.plugins.data); const updatedPublicAPI: DatasourcePublicAPI = { datasourceId: 'testDatasource', @@ -684,8 +645,9 @@ describe('editor_frame', () => { setDatasourceState({}); }); + // TODO: temporary regression, selectors will help // validation requires to calls this getConfiguration API - expect(mockVisualization.getConfiguration).toHaveBeenCalledTimes(7); + expect(mockVisualization.getConfiguration).toHaveBeenCalledTimes(9); expect(mockVisualization.getConfiguration).toHaveBeenLastCalledWith( expect.objectContaining({ frame: expect.objectContaining({ @@ -703,37 +665,33 @@ describe('editor_frame', () => { mockDatasource.getLayers.mockReturnValue(['first']); mockDatasource2.getLayers.mockReturnValue(['second', 'third']); mockVisualization.getLayerIds.mockReturnValue(['first', 'second', 'third']); + const props = { + ...getDefaultProps(), + visualizationMap: { + testVis: mockVisualization, + }, + datasourceMap: { + testDatasource: mockDatasource, + testDatasource2: mockDatasource2, + }, - await act(async () => { - mount( - - ); + ExpressionRenderer: expressionRendererMock, + }; + await mountWithProvider(, props.plugins.data, { + persistedDoc: { + visualizationType: 'testVis', + title: '', + state: { + datasourceStates: { + testDatasource: {}, + testDatasource2: {}, + }, + visualization: {}, + query: { query: '', language: 'lucene' }, + filters: [], + }, + references: [], + }, }); expect(mockVisualization.getConfiguration).toHaveBeenCalled(); @@ -756,36 +714,33 @@ describe('editor_frame', () => { const datasource1State = { datasource1: '' }; const datasource2State = { datasource2: '' }; - await act(async () => { - mount( - - ); + const props = { + ...getDefaultProps(), + visualizationMap: { + testVis: mockVisualization, + }, + datasourceMap: { + testDatasource: mockDatasource, + testDatasource2: mockDatasource2, + }, + + ExpressionRenderer: expressionRendererMock, + }; + await mountWithProvider(, props.plugins.data, { + persistedDoc: { + visualizationType: 'testVis', + title: '', + state: { + datasourceStates: { + testDatasource: datasource1State, + testDatasource2: datasource2State, + }, + visualization: {}, + query: { query: '', language: 'lucene' }, + filters: [], + }, + references: [], + }, }); expect(mockDatasource.getPublicAPI).toHaveBeenCalledWith( @@ -813,22 +768,18 @@ describe('editor_frame', () => { mockDatasource.initialize.mockResolvedValue(datasourceState); mockDatasource.getLayers.mockReturnValue(['first']); - await act(async () => { - mount( - - ); - }); + const props = { + ...getDefaultProps(), + visualizationMap: { + testVis: mockVisualization, + }, + datasourceMap: { + testDatasource: mockDatasource, + }, + + ExpressionRenderer: expressionRendererMock, + }; + await mountWithProvider(, props.plugins.data); expect(mockDatasource.getPublicAPI).toHaveBeenCalledWith({ state: datasourceState, @@ -870,24 +821,20 @@ describe('editor_frame', () => { }, ]); - await act(async () => { - instance = mount( - - ); - }); + const props = { + ...getDefaultProps(), + visualizationMap: { + testVis: mockVisualization, + testVis2: mockVisualization2, + }, + datasourceMap: { + testDatasource: mockDatasource, + testDatasource2: mockDatasource2, + }, + + ExpressionRenderer: expressionRendererMock, + }; + instance = (await mountWithProvider(, props.plugins.data)).instance; // necessary to flush elements to dom synchronously instance.update(); @@ -984,49 +931,41 @@ describe('editor_frame', () => { describe('suggestions', () => { it('should fetch suggestions of currently active datasource when initializes from visualization trigger', async () => { - await act(async () => { - mount( - - ); - }); + const props = { + ...getDefaultProps(), + initialContext: { + indexPatternId: '1', + fieldName: 'test', + }, + visualizationMap: { + testVis: mockVisualization, + }, + datasourceMap: { + testDatasource: mockDatasource, + testDatasource2: mockDatasource2, + }, + + ExpressionRenderer: expressionRendererMock, + }; + await mountWithProvider(, props.plugins.data); expect(mockDatasource.getDatasourceSuggestionsForVisualizeField).toHaveBeenCalled(); }); it('should fetch suggestions of currently active datasource', async () => { - await act(async () => { - mount( - - ); - }); + const props = { + ...getDefaultProps(), + visualizationMap: { + testVis: mockVisualization, + }, + datasourceMap: { + testDatasource: mockDatasource, + testDatasource2: mockDatasource2, + }, + + ExpressionRenderer: expressionRendererMock, + }; + await mountWithProvider(, props.plugins.data); expect(mockDatasource.getDatasourceSuggestionsFromCurrentState).toHaveBeenCalled(); expect(mockDatasource2.getDatasourceSuggestionsFromCurrentState).not.toHaveBeenCalled(); @@ -1046,24 +985,20 @@ describe('editor_frame', () => { }, ]); - await act(async () => { - mount( - - ); - }); + const props = { + ...getDefaultProps(), + visualizationMap: { + testVis: mockVisualization, + testVis2: mockVisualization2, + }, + datasourceMap: { + testDatasource: mockDatasource, + testDatasource2: mockDatasource2, + }, + + ExpressionRenderer: expressionRendererMock, + }; + await mountWithProvider(, props.plugins.data); expect(mockVisualization.getSuggestions).toHaveBeenCalled(); expect(mockVisualization2.getSuggestions).toHaveBeenCalled(); @@ -1072,71 +1007,66 @@ describe('editor_frame', () => { let instance: ReactWrapper; it('should display top 5 suggestions in descending order', async () => { mockDatasource.getLayers.mockReturnValue(['first']); - - await act(async () => { - instance = mount( - [ - { - score: 0.1, - state: {}, - title: 'Suggestion6', - previewIcon: 'empty', - }, - { - score: 0.5, - state: {}, - title: 'Suggestion3', - previewIcon: 'empty', - }, - { - score: 0.7, - state: {}, - title: 'Suggestion2', - previewIcon: 'empty', - }, - { - score: 0.8, - state: {}, - title: 'Suggestion1', - previewIcon: 'empty', - }, - ], + const props = { + ...getDefaultProps(), + visualizationMap: { + testVis: { + ...mockVisualization, + getSuggestions: () => [ + { + score: 0.1, + state: {}, + title: 'Suggestion6', + previewIcon: 'empty', }, - testVis2: { - ...mockVisualization, - getSuggestions: () => [ - { - score: 0.4, - state: {}, - title: 'Suggestion5', - previewIcon: 'empty', - }, - { - score: 0.45, - state: {}, - title: 'Suggestion4', - previewIcon: 'empty', - }, - ], + { + score: 0.5, + state: {}, + title: 'Suggestion3', + previewIcon: 'empty', }, - }} - datasourceMap={{ - testDatasource: { - ...mockDatasource, - getDatasourceSuggestionsFromCurrentState: () => [generateSuggestion()], + { + score: 0.7, + state: {}, + title: 'Suggestion2', + previewIcon: 'empty', }, - }} - initialDatasourceId="testDatasource" - initialVisualizationId="testVis" - ExpressionRenderer={expressionRendererMock} - /> - ); - }); + { + score: 0.8, + state: {}, + title: 'Suggestion1', + previewIcon: 'empty', + }, + ], + }, + testVis2: { + ...mockVisualization, + getSuggestions: () => [ + { + score: 0.4, + state: {}, + title: 'Suggestion5', + previewIcon: 'empty', + }, + { + score: 0.45, + state: {}, + title: 'Suggestion4', + previewIcon: 'empty', + }, + ], + }, + }, + datasourceMap: { + testDatasource: { + ...mockDatasource, + getDatasourceSuggestionsFromCurrentState: () => [generateSuggestion()], + }, + }, + + ExpressionRenderer: expressionRendererMock, + }; + instance = (await mountWithProvider(, props.plugins.data)).instance; // TODO why is this necessary? instance.update(); @@ -1159,37 +1089,32 @@ describe('editor_frame', () => { mockDatasource.getLayers.mockReturnValue(['first', 'second', 'third']); const newDatasourceState = {}; const suggestionVisState = {}; - - await act(async () => { - instance = mount( - [ - { - score: 0.8, - state: suggestionVisState, - title: 'Suggestion1', - previewIcon: 'empty', - }, - ], - }, - testVis2: mockVisualization2, - }} - datasourceMap={{ - testDatasource: { - ...mockDatasource, - getDatasourceSuggestionsFromCurrentState: () => [generateSuggestion()], + const props = { + ...getDefaultProps(), + visualizationMap: { + testVis: { + ...mockVisualization, + getSuggestions: () => [ + { + score: 0.8, + state: suggestionVisState, + title: 'Suggestion1', + previewIcon: 'empty', }, - }} - initialDatasourceId="testDatasource" - initialVisualizationId="testVis2" - ExpressionRenderer={expressionRendererMock} - /> - ); - }); + ], + }, + testVis2: mockVisualization2, + }, + datasourceMap: { + testDatasource: { + ...mockDatasource, + getDatasourceSuggestionsFromCurrentState: () => [generateSuggestion()], + }, + }, + + ExpressionRenderer: expressionRendererMock, + }; + instance = (await mountWithProvider(, props.plugins.data)).instance; // TODO why is this necessary? instance.update(); @@ -1199,7 +1124,8 @@ describe('editor_frame', () => { }); // validation requires to calls this getConfiguration API - expect(mockVisualization.getConfiguration).toHaveBeenCalledTimes(5); + // TODO: why so many times? + expect(mockVisualization.getConfiguration).toHaveBeenCalledTimes(10); expect(mockVisualization.getConfiguration).toHaveBeenCalledWith( expect.objectContaining({ state: suggestionVisState, @@ -1216,45 +1142,40 @@ describe('editor_frame', () => { it('should switch to best suggested visualization on field drop', async () => { mockDatasource.getLayers.mockReturnValue(['first']); const suggestionVisState = {}; - - await act(async () => { - instance = mount( - [ - { - score: 0.2, - state: {}, - title: 'Suggestion1', - previewIcon: 'empty', - }, - { - score: 0.8, - state: suggestionVisState, - title: 'Suggestion2', - previewIcon: 'empty', - }, - ], + const props = { + ...getDefaultProps(), + visualizationMap: { + testVis: { + ...mockVisualization, + getSuggestions: () => [ + { + score: 0.2, + state: {}, + title: 'Suggestion1', + previewIcon: 'empty', }, - testVis2: mockVisualization2, - }} - datasourceMap={{ - testDatasource: { - ...mockDatasource, - getDatasourceSuggestionsForField: () => [generateSuggestion()], - getDatasourceSuggestionsFromCurrentState: () => [generateSuggestion()], - getDatasourceSuggestionsForVisualizeField: () => [generateSuggestion()], + { + score: 0.8, + state: suggestionVisState, + title: 'Suggestion2', + previewIcon: 'empty', }, - }} - initialDatasourceId="testDatasource" - initialVisualizationId="testVis" - ExpressionRenderer={expressionRendererMock} - /> - ); - }); + ], + }, + testVis2: mockVisualization2, + }, + datasourceMap: { + testDatasource: { + ...mockDatasource, + getDatasourceSuggestionsForField: () => [generateSuggestion()], + getDatasourceSuggestionsFromCurrentState: () => [generateSuggestion()], + getDatasourceSuggestionsForVisualizeField: () => [generateSuggestion()], + }, + }, + + ExpressionRenderer: expressionRendererMock, + }; + instance = (await mountWithProvider(, props.plugins.data)).instance; // TODO why is this necessary? instance.update(); @@ -1274,63 +1195,58 @@ describe('editor_frame', () => { mockDatasource.getLayers.mockReturnValue(['first', 'second', 'third']); const suggestionVisState = {}; - await act(async () => { - instance = mount( - [ - { - score: 0.2, - state: {}, - title: 'Suggestion1', - previewIcon: 'empty', - }, - { - score: 0.6, - state: {}, - title: 'Suggestion2', - previewIcon: 'empty', - }, - ], + const props = { + ...getDefaultProps(), + visualizationMap: { + testVis: { + ...mockVisualization, + getSuggestions: () => [ + { + score: 0.2, + state: {}, + title: 'Suggestion1', + previewIcon: 'empty', }, - testVis2: { - ...mockVisualization2, - getSuggestions: () => [ - { - score: 0.8, - state: suggestionVisState, - title: 'Suggestion3', - previewIcon: 'empty', - }, - ], + { + score: 0.6, + state: {}, + title: 'Suggestion2', + previewIcon: 'empty', }, - }} - datasourceMap={{ - testDatasource: { - ...mockDatasource, - getDatasourceSuggestionsForField: () => [generateSuggestion()], - getDatasourceSuggestionsFromCurrentState: () => [generateSuggestion()], - getDatasourceSuggestionsForVisualizeField: () => [generateSuggestion()], - renderDataPanel: (_element, { dragDropContext: { setDragging, dragging } }) => { - if (!dragging || dragging.id !== 'draggedField') { - setDragging({ - id: 'draggedField', - humanData: { label: 'draggedField' }, - }); - } - }, + ], + }, + testVis2: { + ...mockVisualization2, + getSuggestions: () => [ + { + score: 0.8, + state: suggestionVisState, + title: 'Suggestion3', + previewIcon: 'empty', }, - }} - initialDatasourceId="testDatasource" - initialVisualizationId="testVis2" - ExpressionRenderer={expressionRendererMock} - /> - ); - }); + ], + }, + }, + datasourceMap: { + testDatasource: { + ...mockDatasource, + getDatasourceSuggestionsForField: () => [generateSuggestion()], + getDatasourceSuggestionsFromCurrentState: () => [generateSuggestion()], + getDatasourceSuggestionsForVisualizeField: () => [generateSuggestion()], + renderDataPanel: (_element, { dragDropContext: { setDragging, dragging } }) => { + if (!dragging || dragging.id !== 'draggedField') { + setDragging({ + id: 'draggedField', + humanData: { label: 'draggedField' }, + }); + } + }, + }, + }, + ExpressionRenderer: expressionRendererMock, + } as EditorFrameProps; + instance = (await mountWithProvider(, props.plugins.data)).instance; // TODO why is this necessary? instance.update(); @@ -1384,58 +1300,55 @@ describe('editor_frame', () => { ], }; - await act(async () => { - instance = mount( - [ - { - score: 0.2, - state: {}, - title: 'Suggestion1', - previewIcon: 'empty', - }, - { - score: 0.6, - state: {}, - title: 'Suggestion2', - previewIcon: 'empty', - }, - ], - }, - testVis2: { - ...mockVisualization2, - getSuggestions: () => [], + const props = { + ...getDefaultProps(), + visualizationMap: { + testVis: { + ...mockVisualization, + getSuggestions: () => [ + { + score: 0.2, + state: {}, + title: 'Suggestion1', + previewIcon: 'empty', }, - testVis3: { - ...mockVisualization3, + { + score: 0.6, + state: {}, + title: 'Suggestion2', + previewIcon: 'empty', }, - }} - datasourceMap={{ - testDatasource: { - ...mockDatasource, - getDatasourceSuggestionsForField: () => [generateSuggestion()], - getDatasourceSuggestionsFromCurrentState: () => [generateSuggestion()], - getDatasourceSuggestionsForVisualizeField: () => [generateSuggestion()], - renderDataPanel: (_element, { dragDropContext: { setDragging, dragging } }) => { - if (!dragging || dragging.id !== 'draggedField') { - setDragging({ - id: 'draggedField', - humanData: { label: '1' }, - }); - } - }, - }, - }} - initialDatasourceId="testDatasource" - initialVisualizationId="testVis2" - ExpressionRenderer={expressionRendererMock} - /> - ); - }); + ], + }, + testVis2: { + ...mockVisualization2, + getSuggestions: () => [], + }, + testVis3: { + ...mockVisualization3, + }, + }, + datasourceMap: { + testDatasource: { + ...mockDatasource, + getDatasourceSuggestionsForField: () => [generateSuggestion()], + getDatasourceSuggestionsFromCurrentState: () => [generateSuggestion()], + getDatasourceSuggestionsForVisualizeField: () => [generateSuggestion()], + renderDataPanel: (_element, { dragDropContext: { setDragging, dragging } }) => { + if (!dragging || dragging.id !== 'draggedField') { + setDragging({ + id: 'draggedField', + humanData: { label: '1' }, + }); + } + }, + }, + }, + + ExpressionRenderer: expressionRendererMock, + } as EditorFrameProps; + + instance = (await mountWithProvider(, props.plugins.data)).instance; // TODO why is this necessary? instance.update(); @@ -1481,74 +1394,79 @@ describe('editor_frame', () => { })); mockVisualization.initialize.mockReturnValue({ initialState: true }); + const props = { + ...getDefaultProps(), + visualizationMap: { + testVis: mockVisualization, + }, + datasourceMap: { + testDatasource: mockDatasource, + }, + + ExpressionRenderer: expressionRendererMock, + onChange, + }; + + let lensStore: LensRootStore = {} as LensRootStore; await act(async () => { - mount( - - ); - expect(onChange).toHaveBeenCalledTimes(0); + const mounted = await mountWithProvider(, props.plugins.data); + lensStore = mounted.lensStore; + expect(lensStore.dispatch).toHaveBeenCalledTimes(0); resolver({}); }); - expect(onChange).toHaveBeenCalledTimes(2); - expect(onChange).toHaveBeenNthCalledWith(1, { - filterableIndexPatterns: ['1'], - doc: { - id: undefined, - description: undefined, - references: [ - { - id: '1', - name: 'index-pattern-0', - type: 'index-pattern', + expect(lensStore.dispatch).toHaveBeenCalledTimes(2); + expect(lensStore.dispatch).toHaveBeenNthCalledWith(1, { + payload: { + indexPatternsForTopNav: [{ id: '1' }], + lastKnownDoc: { + savedObjectId: undefined, + description: undefined, + references: [ + { + id: '1', + name: 'index-pattern-0', + type: 'index-pattern', + }, + ], + state: { + visualization: null, // Not yet loaded + datasourceStates: { testDatasource: {} }, + query: { query: '', language: 'lucene' }, + filters: [], }, - ], - state: { - visualization: null, // Not yet loaded - datasourceStates: { testDatasource: {} }, - query: { query: '', language: 'lucene' }, - filters: [], + title: '', + type: 'lens', + visualizationType: 'testVis', }, - title: '', - type: 'lens', - visualizationType: 'testVis', }, - isSaveable: false, + type: 'app/onChangeFromEditorFrame', }); - expect(onChange).toHaveBeenLastCalledWith({ - filterableIndexPatterns: ['1'], - doc: { - references: [ - { - id: '1', - name: 'index-pattern-0', - type: 'index-pattern', + expect(lensStore.dispatch).toHaveBeenLastCalledWith({ + payload: { + indexPatternsForTopNav: [{ id: '1' }], + lastKnownDoc: { + references: [ + { + id: '1', + name: 'index-pattern-0', + type: 'index-pattern', + }, + ], + description: undefined, + savedObjectId: undefined, + state: { + visualization: { initialState: true }, // Now loaded + datasourceStates: { testDatasource: {} }, + query: { query: '', language: 'lucene' }, + filters: [], }, - ], - description: undefined, - id: undefined, - state: { - visualization: { initialState: true }, // Now loaded - datasourceStates: { testDatasource: {} }, - query: { query: '', language: 'lucene' }, - filters: [], + title: '', + type: 'lens', + visualizationType: 'testVis', }, - title: '', - type: 'lens', - visualizationType: 'testVis', }, - isSaveable: false, + type: 'app/onChangeFromEditorFrame', }); }); @@ -1561,48 +1479,63 @@ describe('editor_frame', () => { mockDatasource.getLayers.mockReturnValue(['first']); mockVisualization.initialize.mockReturnValue({ initialState: true }); - await act(async () => { - instance = mount( - - ); - }); + const props = { + ...getDefaultProps(), + visualizationMap: { + testVis: mockVisualization, + }, + datasourceMap: { + testDatasource: mockDatasource, + }, + + ExpressionRenderer: expressionRendererMock, + onChange, + }; - expect(onChange).toHaveBeenCalledTimes(2); + const { instance: el, lensStore } = await mountWithProvider( + , + props.plugins.data + ); + instance = el; + + expect(lensStore.dispatch).toHaveBeenCalledTimes(2); mockDatasource.toExpression.mockReturnValue('data expression'); mockVisualization.toExpression.mockReturnValue('vis expression'); - instance.setProps({ query: { query: 'new query', language: 'lucene' } }); + await act(async () => { + lensStore.dispatch(setState({ query: { query: 'new query', language: 'lucene' } })); + }); + instance.update(); - expect(onChange).toHaveBeenCalledTimes(3); - expect(onChange).toHaveBeenNthCalledWith(3, { - filterableIndexPatterns: [], - doc: { - id: undefined, - references: [], - state: { - datasourceStates: { testDatasource: { datasource: '' } }, - visualization: { initialState: true }, - query: { query: 'new query', language: 'lucene' }, - filters: [], + expect(lensStore.dispatch).toHaveBeenCalledTimes(4); + expect(lensStore.dispatch).toHaveBeenNthCalledWith(3, { + payload: { + query: { + language: 'lucene', + query: 'new query', }, - title: '', - type: 'lens', - visualizationType: 'testVis', }, - isSaveable: true, + type: 'app/setState', + }); + expect(lensStore.dispatch).toHaveBeenNthCalledWith(4, { + payload: { + lastKnownDoc: { + savedObjectId: undefined, + references: [], + state: { + datasourceStates: { testDatasource: { datasource: '' } }, + visualization: { initialState: true }, + query: { query: 'new query', language: 'lucene' }, + filters: [], + }, + title: '', + type: 'lens', + visualizationType: 'testVis', + }, + isSaveable: true, + }, + type: 'app/onChangeFromEditorFrame', }); }); @@ -1617,21 +1550,23 @@ describe('editor_frame', () => { })); mockVisualization.initialize.mockReturnValue({ initialState: true }); - await act(async () => { - instance = mount( - - ); - }); + const props = { + ...getDefaultProps(), + visualizationMap: { + testVis: mockVisualization, + }, + datasourceMap: { + testDatasource: mockDatasource, + }, + + ExpressionRenderer: expressionRendererMock, + onChange, + }; + const mounted = await mountWithProvider(, props.plugins.data); + instance = mounted.instance; + const { lensStore } = mounted; - expect(onChange).toHaveBeenCalledTimes(2); + expect(lensStore.dispatch).toHaveBeenCalledTimes(2); await act(async () => { (instance.find(FrameLayout).prop('dataPanel') as ReactElement)!.props.dispatch({ @@ -1643,7 +1578,7 @@ describe('editor_frame', () => { }); }); - expect(onChange).toHaveBeenCalledTimes(3); + expect(lensStore.dispatch).toHaveBeenCalledTimes(3); }); }); }); diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/editor_frame.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/editor_frame.tsx index 91b59664ada83..4710e03d336bc 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/editor_frame.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/editor_frame.tsx @@ -7,7 +7,10 @@ import React, { useEffect, useReducer, useState, useCallback } from 'react'; import { CoreStart } from 'kibana/public'; +import { isEqual } from 'lodash'; import { PaletteRegistry } from 'src/plugins/charts/public'; +import { IndexPattern } from '../../../../../../src/plugins/data/public'; +import { getAllIndexPatterns } from '../../utils'; import { ReactExpressionRendererType } from '../../../../../../src/plugins/expressions/public'; import { Datasource, FramePublicAPI, Visualization } from '../../types'; import { reducer, getInitialState } from './state_management'; @@ -20,7 +23,6 @@ import { Document } from '../../persistence/saved_object_store'; import { DragDropIdentifier, RootDragDropProvider } from '../../drag_drop'; import { getSavedObjectFormat } from './save'; import { generateId } from '../../id_generator'; -import { Filter, Query, SavedQuery } from '../../../../../../src/plugins/data/public'; import { VisualizeFieldContext } from '../../../../../../src/plugins/ui_actions/public'; import { EditorFrameStartPlugins } from '../service'; import { initializeDatasources, createDatasourceLayers } from './state_helpers'; @@ -30,37 +32,45 @@ import { switchToSuggestion, } from './suggestion_helpers'; import { trackUiEvent } from '../../lens_ui_telemetry'; +import { + useLensSelector, + useLensDispatch, + LensAppState, + DispatchSetState, + onChangeFromEditorFrame, +} from '../../state_management'; export interface EditorFrameProps { - doc?: Document; datasourceMap: Record; visualizationMap: Record; - initialDatasourceId: string | null; - initialVisualizationId: string | null; ExpressionRenderer: ReactExpressionRendererType; palettes: PaletteRegistry; onError: (e: { message: string }) => void; core: CoreStart; plugins: EditorFrameStartPlugins; - dateRange: { - fromDate: string; - toDate: string; - }; - query: Query; - filters: Filter[]; - savedQuery?: SavedQuery; - searchSessionId: string; - onChange: (arg: { - filterableIndexPatterns: string[]; - doc: Document; - isSaveable: boolean; - }) => void; showNoDataPopover: () => void; initialContext?: VisualizeFieldContext; } export function EditorFrame(props: EditorFrameProps) { - const [state, dispatch] = useReducer(reducer, props, getInitialState); + const { + filters, + searchSessionId, + savedQuery, + query, + persistedDoc, + indexPatternsForTopNav, + lastKnownDoc, + activeData, + isSaveable, + resolvedDateRange: dateRange, + } = useLensSelector((state) => state.app); + const [state, dispatch] = useReducer(reducer, { ...props, doc: persistedDoc }, getInitialState); + const dispatchLens = useLensDispatch(); + const dispatchChange: DispatchSetState = useCallback( + (s: Partial) => dispatchLens(onChangeFromEditorFrame(s)), + [dispatchLens] + ); const [visualizeTriggerFieldContext, setVisualizeTriggerFieldContext] = useState( props.initialContext ); @@ -81,7 +91,7 @@ export function EditorFrame(props: EditorFrameProps) { initializeDatasources( props.datasourceMap, state.datasourceStates, - props.doc?.references, + persistedDoc?.references, visualizeTriggerFieldContext, { isFullEditor: true } ) @@ -109,11 +119,11 @@ export function EditorFrame(props: EditorFrameProps) { const framePublicAPI: FramePublicAPI = { datasourceLayers, - activeData: state.activeData, - dateRange: props.dateRange, - query: props.query, - filters: props.filters, - searchSessionId: props.searchSessionId, + activeData, + dateRange, + query, + filters, + searchSessionId, availablePalettes: props.palettes, addNewLayer() { @@ -160,19 +170,19 @@ export function EditorFrame(props: EditorFrameProps) { useEffect( () => { - if (props.doc) { + if (persistedDoc) { dispatch({ type: 'VISUALIZATION_LOADED', doc: { - ...props.doc, + ...persistedDoc, state: { - ...props.doc.state, - visualization: props.doc.visualizationType - ? props.visualizationMap[props.doc.visualizationType].initialize( + ...persistedDoc.state, + visualization: persistedDoc.visualizationType + ? props.visualizationMap[persistedDoc.visualizationType].initialize( framePublicAPI, - props.doc.state.visualization + persistedDoc.state.visualization ) - : props.doc.state.visualization, + : persistedDoc.state.visualization, }, }, }); @@ -184,7 +194,7 @@ export function EditorFrame(props: EditorFrameProps) { } }, // eslint-disable-next-line react-hooks/exhaustive-deps - [props.doc] + [persistedDoc] ); // Initialize visualization as soon as all datasources are ready @@ -205,7 +215,7 @@ export function EditorFrame(props: EditorFrameProps) { // Get suggestions for visualize field when all datasources are ready useEffect(() => { - if (allLoaded && visualizeTriggerFieldContext && !props.doc) { + if (allLoaded && visualizeTriggerFieldContext && !persistedDoc) { applyVisualizeFieldSuggestions({ datasourceMap: props.datasourceMap, datasourceStates: state.datasourceStates, @@ -220,6 +230,51 @@ export function EditorFrame(props: EditorFrameProps) { // eslint-disable-next-line react-hooks/exhaustive-deps }, [allLoaded]); + const getStateToUpdate: ( + arg: { + filterableIndexPatterns: string[]; + doc: Document; + isSaveable: boolean; + }, + oldState: { + isSaveable: boolean; + indexPatternsForTopNav: IndexPattern[]; + persistedDoc?: Document; + lastKnownDoc?: Document; + } + ) => Promise | undefined> = async ( + { filterableIndexPatterns, doc, isSaveable: incomingIsSaveable }, + prevState + ) => { + const batchedStateToUpdate: Partial = {}; + + if (incomingIsSaveable !== prevState.isSaveable) { + batchedStateToUpdate.isSaveable = incomingIsSaveable; + } + + if (!isEqual(prevState.persistedDoc, doc) && !isEqual(prevState.lastKnownDoc, doc)) { + batchedStateToUpdate.lastKnownDoc = doc; + } + const hasIndexPatternsChanged = + prevState.indexPatternsForTopNav.length !== filterableIndexPatterns.length || + filterableIndexPatterns.some( + (id) => !prevState.indexPatternsForTopNav.find((indexPattern) => indexPattern.id === id) + ); + // Update the cached index patterns if the user made a change to any of them + if (hasIndexPatternsChanged) { + const { indexPatterns } = await getAllIndexPatterns( + filterableIndexPatterns, + props.plugins.data.indexPatterns + ); + if (indexPatterns) { + batchedStateToUpdate.indexPatternsForTopNav = indexPatterns; + } + } + if (Object.keys(batchedStateToUpdate).length) { + return batchedStateToUpdate; + } + }; + // The frame needs to call onChange every time its internal state changes useEffect( () => { @@ -232,31 +287,43 @@ export function EditorFrame(props: EditorFrameProps) { return; } - props.onChange( - getSavedObjectFormat({ - activeDatasources: Object.keys(state.datasourceStates).reduce( - (datasourceMap, datasourceId) => ({ - ...datasourceMap, - [datasourceId]: props.datasourceMap[datasourceId], - }), - {} - ), - visualization: activeVisualization, - state, - framePublicAPI, - }) - ); + const savedObjectFormat = getSavedObjectFormat({ + activeDatasources: Object.keys(state.datasourceStates).reduce( + (datasourceMap, datasourceId) => ({ + ...datasourceMap, + [datasourceId]: props.datasourceMap[datasourceId], + }), + {} + ), + visualization: activeVisualization, + state, + framePublicAPI, + }); + + // Frame loader (app or embeddable) is expected to call this when it loads and updates + // This should be replaced with a top-down state + getStateToUpdate(savedObjectFormat, { + isSaveable, + persistedDoc, + indexPatternsForTopNav, + lastKnownDoc, + }).then((batchedStateToUpdate) => { + if (batchedStateToUpdate) { + dispatchChange(batchedStateToUpdate); + } + }); }, // eslint-disable-next-line react-hooks/exhaustive-deps [ activeVisualization, state.datasourceStates, state.visualization, - state.activeData, - props.query, - props.filters, - props.savedQuery, + activeData, + query, + filters, + savedQuery, state.title, + dispatchChange, ] ); @@ -326,9 +393,9 @@ export function EditorFrame(props: EditorFrameProps) { } dispatch={dispatch} core={props.core} - query={props.query} - dateRange={props.dateRange} - filters={props.filters} + query={query} + dateRange={dateRange} + filters={filters} showNoDataPopover={props.showNoDataPopover} dropOntoWorkspace={dropOntoWorkspace} hasSuggestionForField={hasSuggestionForField} diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/save.ts b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/save.ts index 6eec13dd9d7ce..86a28be65d2b9 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/save.ts +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/save.ts @@ -5,9 +5,8 @@ * 2.0. */ -import _ from 'lodash'; +import { uniq } from 'lodash'; import { SavedObjectReference } from 'kibana/public'; -import { Datatable } from 'src/plugins/expressions'; import { EditorFrameState } from './state_management'; import { Document } from '../../persistence/saved_object_store'; import { Datasource, Visualization, FramePublicAPI } from '../../types'; @@ -30,7 +29,6 @@ export function getSavedObjectFormat({ doc: Document; filterableIndexPatterns: string[]; isSaveable: boolean; - activeData: Record | undefined; } { const datasourceStates: Record = {}; const references: SavedObjectReference[] = []; @@ -42,7 +40,7 @@ export function getSavedObjectFormat({ references.push(...savedObjectReferences); }); - const uniqueFilterableIndexPatternIds = _.uniq( + const uniqueFilterableIndexPatternIds = uniq( references.filter(({ type }) => type === 'index-pattern').map(({ id }) => id) ); @@ -77,6 +75,5 @@ export function getSavedObjectFormat({ }, filterableIndexPatterns: uniqueFilterableIndexPatternIds, isSaveable: expression !== null, - activeData: state.activeData, }; } diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/state_management.test.ts b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/state_management.test.ts index 5d6dae557dbb8..af8a9c0a85558 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/state_management.test.ts +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/state_management.test.ts @@ -24,10 +24,7 @@ describe('editor_frame state management', () => { onError: jest.fn(), datasourceMap: { testDatasource: ({} as unknown) as Datasource }, visualizationMap: { testVis: ({ initialize: jest.fn() } as unknown) as Visualization }, - initialDatasourceId: 'testDatasource', - initialVisualizationId: 'testVis', ExpressionRenderer: createExpressionRendererMock(), - onChange: jest.fn(), core: coreMock.createStart(), plugins: { uiActions: uiActionsPluginMock.createStartContract(), @@ -36,11 +33,7 @@ describe('editor_frame state management', () => { charts: chartPluginMock.createStartContract(), }, palettes: chartPluginMock.createPaletteRegistry(), - dateRange: { fromDate: 'now-7d', toDate: 'now' }, - query: { query: '', language: 'lucene' }, - filters: [], showNoDataPopover: jest.fn(), - searchSessionId: 'sessionId', }; }); @@ -101,8 +94,8 @@ describe('editor_frame state management', () => { `); }); - it('should not set active id if no initial visualization is passed in', () => { - const initialState = getInitialState({ ...props, initialVisualizationId: null }); + it('should not set active id if initiated with empty document and visualizationMap is empty', () => { + const initialState = getInitialState({ ...props, visualizationMap: {} }); expect(initialState.visualization.state).toEqual(null); expect(initialState.visualization.activeId).toEqual(null); diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/state_management.ts b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/state_management.ts index 53aba0d6f3f6c..aa365d1e66d6c 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/state_management.ts +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/state_management.ts @@ -7,7 +7,6 @@ import { EditorFrameProps } from './index'; import { Document } from '../../persistence/saved_object_store'; -import { TableInspectorAdapter } from '../types'; export interface PreviewState { visualization: { @@ -23,7 +22,6 @@ export interface EditorFrameState extends PreviewState { description?: string; stagedPreview?: PreviewState; activeDatasourceId: string | null; - activeData?: TableInspectorAdapter; } export type Action = @@ -35,10 +33,6 @@ export type Action = type: 'UPDATE_TITLE'; title: string; } - | { - type: 'UPDATE_ACTIVE_DATA'; - tables: TableInspectorAdapter; - } | { type: 'UPDATE_STATE'; // Just for diagnostics, so we can determine what action @@ -103,25 +97,27 @@ export function getActiveDatasourceIdFromDoc(doc?: Document) { return null; } - const [initialDatasourceId] = Object.keys(doc.state.datasourceStates); - return initialDatasourceId || null; + const [firstDatasourceFromDoc] = Object.keys(doc.state.datasourceStates); + return firstDatasourceFromDoc || null; } -function getInitialDatasourceId(props: EditorFrameProps) { - return props.initialDatasourceId - ? props.initialDatasourceId - : getActiveDatasourceIdFromDoc(props.doc); -} - -export const getInitialState = (props: EditorFrameProps): EditorFrameState => { +export const getInitialState = ( + params: EditorFrameProps & { doc?: Document } +): EditorFrameState => { const datasourceStates: EditorFrameState['datasourceStates'] = {}; - if (props.doc) { - Object.entries(props.doc.state.datasourceStates).forEach(([datasourceId, state]) => { + const initialDatasourceId = + getActiveDatasourceIdFromDoc(params.doc) || Object.keys(params.datasourceMap)[0] || null; + + const initialVisualizationId = + (params.doc && params.doc.visualizationType) || Object.keys(params.visualizationMap)[0] || null; + + if (params.doc) { + Object.entries(params.doc.state.datasourceStates).forEach(([datasourceId, state]) => { datasourceStates[datasourceId] = { isLoading: true, state }; }); - } else if (props.initialDatasourceId) { - datasourceStates[props.initialDatasourceId] = { + } else if (initialDatasourceId) { + datasourceStates[initialDatasourceId] = { state: null, isLoading: true, }; @@ -130,10 +126,10 @@ export const getInitialState = (props: EditorFrameProps): EditorFrameState => { return { title: '', datasourceStates, - activeDatasourceId: getInitialDatasourceId(props), + activeDatasourceId: initialDatasourceId, visualization: { state: null, - activeId: props.initialVisualizationId, + activeId: initialVisualizationId, }, }; }; @@ -146,11 +142,6 @@ export const reducer = (state: EditorFrameState, action: Action): EditorFrameSta return { ...state, title: action.title }; case 'UPDATE_STATE': return action.updater(state); - case 'UPDATE_ACTIVE_DATA': - return { - ...state, - activeData: { ...action.tables }, - }; case 'UPDATE_LAYER': return { ...state, diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_helpers.ts b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_helpers.ts index 83b0922626542..bd8f134f59fbb 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_helpers.ts +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_helpers.ts @@ -5,7 +5,7 @@ * 2.0. */ -import _ from 'lodash'; +import { flatten } from 'lodash'; import { Ast } from '@kbn/interpreter/common'; import { IconType } from '@elastic/eui/src/components/icon/icon'; import { Datatable } from 'src/plugins/expressions'; @@ -79,7 +79,7 @@ export function getSuggestions({ ); // Collect all table suggestions from available datasources - const datasourceTableSuggestions = _.flatten( + const datasourceTableSuggestions = flatten( datasources.map(([datasourceId, datasource]) => { const datasourceState = datasourceStates[datasourceId].state; let dataSourceSuggestions; @@ -103,9 +103,9 @@ export function getSuggestions({ // Pass all table suggestions to all visualization extensions to get visualization suggestions // and rank them by score - return _.flatten( + return flatten( Object.entries(visualizationMap).map(([visualizationId, visualization]) => - _.flatten( + flatten( datasourceTableSuggestions.map((datasourceSuggestion) => { const table = datasourceSuggestion.table; const currentVisualizationState = diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.test.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.test.tsx index baa9d45a431ea..1d248c4411023 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.test.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.test.tsx @@ -16,14 +16,14 @@ import { DatasourceMock, createMockFramePublicAPI, } from '../../mocks'; - +import { mockDataPlugin, mountWithProvider } from '../../../mocks'; jest.mock('../../../debounced_component', () => { return { debouncedComponent: (fn: unknown) => fn, }; }); -import { WorkspacePanel, WorkspacePanelProps } from './workspace_panel'; +import { WorkspacePanel } from './workspace_panel'; import { mountWithIntl as mount } from '@kbn/test/jest'; import { ReactWrapper } from 'enzyme'; import { DragDrop, ChildDragDropProvider } from '../../../drag_drop'; @@ -34,7 +34,6 @@ import { UiActionsStart } from '../../../../../../../src/plugins/ui_actions/publ import { uiActionsPluginMock } from '../../../../../../../src/plugins/ui_actions/public/mocks'; import { TriggerContract } from '../../../../../../../src/plugins/ui_actions/public/triggers'; import { VIS_EVENT_TO_TRIGGER } from '../../../../../../../src/plugins/visualizations/public/embeddable'; -import { dataPluginMock } from '../../../../../../../src/plugins/data/public/mocks'; const defaultPermissions: Record>> = { navLinks: { management: true }, @@ -50,24 +49,22 @@ function createCoreStartWithPermissions(newCapabilities = defaultPermissions) { return core; } -function getDefaultProps() { - return { - activeDatasourceId: 'mock', - datasourceStates: {}, - datasourceMap: {}, - framePublicAPI: createMockFramePublicAPI(), - activeVisualizationId: 'vis', - visualizationState: {}, - dispatch: () => {}, - ExpressionRenderer: createExpressionRendererMock(), - core: createCoreStartWithPermissions(), - plugins: { - uiActions: uiActionsPluginMock.createStartContract(), - data: dataPluginMock.createStartContract(), - }, - getSuggestionForField: () => undefined, - }; -} +const defaultProps = { + activeDatasourceId: 'mock', + datasourceStates: {}, + datasourceMap: {}, + framePublicAPI: createMockFramePublicAPI(), + activeVisualizationId: 'vis', + visualizationState: {}, + dispatch: () => {}, + ExpressionRenderer: createExpressionRendererMock(), + core: createCoreStartWithPermissions(), + plugins: { + uiActions: uiActionsPluginMock.createStartContract(), + data: mockDataPlugin(), + }, + getSuggestionForField: () => undefined, +}; describe('workspace_panel', () => { let mockVisualization: jest.Mocked; @@ -78,7 +75,7 @@ describe('workspace_panel', () => { let uiActionsMock: jest.Mocked; let trigger: jest.Mocked; - let instance: ReactWrapper; + let instance: ReactWrapper; beforeEach(() => { // These are used in specific tests to assert function calls @@ -95,50 +92,56 @@ describe('workspace_panel', () => { instance.unmount(); }); - it('should render an explanatory text if no visualization is active', () => { - instance = mount( + it('should render an explanatory text if no visualization is active', async () => { + const mounted = await mountWithProvider( + />, + defaultProps.plugins.data ); + instance = mounted.instance; expect(instance.find('[data-test-subj="empty-workspace"]')).toHaveLength(2); expect(instance.find(expressionRendererMock)).toHaveLength(0); }); - it('should render an explanatory text if the visualization does not produce an expression', () => { - instance = mount( + it('should render an explanatory text if the visualization does not produce an expression', async () => { + const mounted = await mountWithProvider( null }, }} - /> + />, + defaultProps.plugins.data ); + instance = mounted.instance; expect(instance.find('[data-test-subj="empty-workspace"]')).toHaveLength(2); expect(instance.find(expressionRendererMock)).toHaveLength(0); }); - it('should render an explanatory text if the datasource does not produce an expression', () => { - instance = mount( + it('should render an explanatory text if the datasource does not produce an expression', async () => { + const mounted = await mountWithProvider( 'vis' }, }} - /> + />, + defaultProps.plugins.data ); + instance = mounted.instance; expect(instance.find('[data-test-subj="empty-workspace"]')).toHaveLength(2); expect(instance.find(expressionRendererMock)).toHaveLength(0); }); - it('should render the resulting expression using the expression renderer', () => { + it('should render the resulting expression using the expression renderer', async () => { const framePublicAPI = createMockFramePublicAPI(); framePublicAPI.datasourceLayers = { first: mockDatasource.publicAPIMock, @@ -146,9 +149,9 @@ describe('workspace_panel', () => { mockDatasource.toExpression.mockReturnValue('datasource'); mockDatasource.getLayers.mockReturnValue(['first']); - instance = mount( + const mounted = await mountWithProvider( { vis: { ...mockVisualization, toExpression: () => 'vis' }, }} ExpressionRenderer={expressionRendererMock} - /> + />, + defaultProps.plugins.data ); + instance = mounted.instance; + expect(instance.find(expressionRendererMock).prop('expression')).toMatchInlineSnapshot(` "kibana | lens_merge_tables layerIds=\\"first\\" tables={datasource} @@ -173,16 +179,16 @@ describe('workspace_panel', () => { `); }); - it('should execute a trigger on expression event', () => { + it('should execute a trigger on expression event', async () => { const framePublicAPI = createMockFramePublicAPI(); framePublicAPI.datasourceLayers = { first: mockDatasource.publicAPIMock, }; mockDatasource.toExpression.mockReturnValue('datasource'); mockDatasource.getLayers.mockReturnValue(['first']); - const props = getDefaultProps(); + const props = defaultProps; - instance = mount( + const mounted = await mountWithProvider( { }} ExpressionRenderer={expressionRendererMock} plugins={{ ...props.plugins, uiActions: uiActionsMock }} - /> + />, + defaultProps.plugins.data ); + instance = mounted.instance; const onEvent = expressionRendererMock.mock.calls[0][0].onEvent!; @@ -212,7 +220,7 @@ describe('workspace_panel', () => { expect(trigger.exec).toHaveBeenCalledWith({ data: eventData }); }); - it('should push add current data table to state on data$ emitting value', () => { + it('should push add current data table to state on data$ emitting value', async () => { const framePublicAPI = createMockFramePublicAPI(); framePublicAPI.datasourceLayers = { first: mockDatasource.publicAPIMock, @@ -221,9 +229,9 @@ describe('workspace_panel', () => { mockDatasource.getLayers.mockReturnValue(['first']); const dispatch = jest.fn(); - instance = mount( + const mounted = await mountWithProvider( { }} dispatch={dispatch} ExpressionRenderer={expressionRendererMock} - /> + />, + defaultProps.plugins.data ); + instance = mounted.instance; + const onData = expressionRendererMock.mock.calls[0][0].onData$!; const tableData = { table1: { columns: [], rows: [] } }; onData(undefined, { tables: { tables: tableData } }); - expect(dispatch).toHaveBeenCalledWith({ type: 'UPDATE_ACTIVE_DATA', tables: tableData }); + expect(mounted.lensStore.dispatch).toHaveBeenCalledWith({ + type: 'app/onActiveDataChange', + payload: { activeData: tableData }, + }); }); - it('should include data fetching for each layer in the expression', () => { + it('should include data fetching for each layer in the expression', async () => { const mockDatasource2 = createMockDatasource('a'); const framePublicAPI = createMockFramePublicAPI(); framePublicAPI.datasourceLayers = { @@ -263,9 +277,9 @@ describe('workspace_panel', () => { mockDatasource2.toExpression.mockReturnValue('datasource2'); mockDatasource2.getLayers.mockReturnValue(['second', 'third']); - instance = mount( + const mounted = await mountWithProvider( { vis: { ...mockVisualization, toExpression: () => 'vis' }, }} ExpressionRenderer={expressionRendererMock} - /> + />, + defaultProps.plugins.data ); + instance = mounted.instance; const ast = fromExpression(instance.find(expressionRendererMock).prop('expression') as string); @@ -341,9 +357,9 @@ describe('workspace_panel', () => { expressionRendererMock = jest.fn((_arg) => ); await act(async () => { - instance = mount( + const mounted = await mountWithProvider( { vis: { ...mockVisualization, toExpression: () => 'vis' }, }} ExpressionRenderer={expressionRendererMock} - /> + />, + defaultProps.plugins.data ); + instance = mounted.instance; }); instance.update(); @@ -392,9 +410,9 @@ describe('workspace_panel', () => { expressionRendererMock = jest.fn((_arg) => ); await act(async () => { - instance = mount( + const mounted = await mountWithProvider( { vis: { ...mockVisualization, toExpression: () => 'vis' }, }} ExpressionRenderer={expressionRendererMock} - /> + />, + defaultProps.plugins.data ); + instance = mounted.instance; }); instance.update(); @@ -434,16 +454,16 @@ describe('workspace_panel', () => { expect(expressionRendererMock).toHaveBeenCalledTimes(2); }); - it('should show an error message if there are missing indexpatterns in the visualization', () => { + it('should show an error message if there are missing indexpatterns in the visualization', async () => { mockDatasource.getLayers.mockReturnValue(['first']); mockDatasource.checkIntegrity.mockReturnValue(['a']); const framePublicAPI = createMockFramePublicAPI(); framePublicAPI.datasourceLayers = { first: mockDatasource.publicAPIMock, }; - instance = mount( + const mounted = await mountWithProvider( { visualizationMap={{ vis: { ...mockVisualization, toExpression: () => 'vis' }, }} - /> + />, + defaultProps.plugins.data ); + instance = mounted.instance; expect(instance.find('[data-test-subj="missing-refs-failure"]').exists()).toBeTruthy(); expect(instance.find(expressionRendererMock)).toHaveLength(0); }); - it('should not show the management action in case of missing indexpattern and no navigation permissions', () => { + it('should not show the management action in case of missing indexpattern and no navigation permissions', async () => { mockDatasource.getLayers.mockReturnValue(['first']); const framePublicAPI = createMockFramePublicAPI(); framePublicAPI.datasourceLayers = { first: mockDatasource.publicAPIMock, }; - instance = mount( + const mounted = await mountWithProvider( { navLinks: { management: false }, management: { kibana: { indexPatterns: true } }, })} - /> + />, + defaultProps.plugins.data ); + instance = mounted.instance; expect( instance.find('[data-test-subj="configuration-failure-reconfigure-indexpatterns"]').exists() ).toBeFalsy(); }); - it('should not show the management action in case of missing indexpattern and no indexPattern specific permissions', () => { + it('should not show the management action in case of missing indexpattern and no indexPattern specific permissions', async () => { mockDatasource.getLayers.mockReturnValue(['first']); const framePublicAPI = createMockFramePublicAPI(); framePublicAPI.datasourceLayers = { first: mockDatasource.publicAPIMock, }; - instance = mount( + const mounted = await mountWithProvider( { navLinks: { management: true }, management: { kibana: { indexPatterns: false } }, })} - /> + />, + defaultProps.plugins.data ); + instance = mounted.instance; expect( instance.find('[data-test-subj="configuration-failure-reconfigure-indexpatterns"]').exists() ).toBeFalsy(); }); - it('should show an error message if validation on datasource does not pass', () => { + it('should show an error message if validation on datasource does not pass', async () => { mockDatasource.getErrorMessages.mockReturnValue([ { shortMessage: 'An error occurred', longMessage: 'An long description here' }, ]); @@ -550,9 +576,9 @@ describe('workspace_panel', () => { first: mockDatasource.publicAPIMock, }; - instance = mount( + const mounted = await mountWithProvider( { visualizationMap={{ vis: { ...mockVisualization, toExpression: () => 'vis' }, }} - /> + />, + defaultProps.plugins.data ); + instance = mounted.instance; expect(instance.find('[data-test-subj="configuration-failure"]').exists()).toBeTruthy(); expect(instance.find(expressionRendererMock)).toHaveLength(0); }); - it('should show an error message if validation on visualization does not pass', () => { + it('should show an error message if validation on visualization does not pass', async () => { mockDatasource.getErrorMessages.mockReturnValue(undefined); mockDatasource.getLayers.mockReturnValue(['first']); mockVisualization.getErrorMessages.mockReturnValue([ @@ -585,9 +613,9 @@ describe('workspace_panel', () => { first: mockDatasource.publicAPIMock, }; - instance = mount( + const mounted = await mountWithProvider( { visualizationMap={{ vis: mockVisualization, }} - /> + />, + defaultProps.plugins.data ); + instance = mounted.instance; expect(instance.find('[data-test-subj="configuration-failure"]').exists()).toBeTruthy(); expect(instance.find(expressionRendererMock)).toHaveLength(0); }); - it('should show an error message if validation on both datasource and visualization do not pass', () => { + it('should show an error message if validation on both datasource and visualization do not pass', async () => { mockDatasource.getErrorMessages.mockReturnValue([ { shortMessage: 'An error occurred', longMessage: 'An long description here' }, ]); @@ -622,9 +652,9 @@ describe('workspace_panel', () => { first: mockDatasource.publicAPIMock, }; - instance = mount( + const mounted = await mountWithProvider( { visualizationMap={{ vis: mockVisualization, }} - /> + />, + defaultProps.plugins.data ); + instance = mounted.instance; // EuiFlexItem duplicates internally the attribute, so we need to filter only the most inner one here expect( @@ -648,7 +680,7 @@ describe('workspace_panel', () => { expect(instance.find(expressionRendererMock)).toHaveLength(0); }); - it('should show an error message if the expression fails to parse', () => { + it('should show an error message if the expression fails to parse', async () => { mockDatasource.toExpression.mockReturnValue('|||'); mockDatasource.getLayers.mockReturnValue(['first']); const framePublicAPI = createMockFramePublicAPI(); @@ -656,9 +688,9 @@ describe('workspace_panel', () => { first: mockDatasource.publicAPIMock, }; - instance = mount( + const mounted = await mountWithProvider( { visualizationMap={{ vis: { ...mockVisualization, toExpression: () => 'vis' }, }} - /> + />, + defaultProps.plugins.data ); + instance = mounted.instance; expect(instance.find('[data-test-subj="expression-failure"]').exists()).toBeTruthy(); expect(instance.find(expressionRendererMock)).toHaveLength(0); @@ -688,9 +722,9 @@ describe('workspace_panel', () => { }; await act(async () => { - instance = mount( + const mounted = await mountWithProvider( { vis: { ...mockVisualization, toExpression: () => 'vis' }, }} ExpressionRenderer={expressionRendererMock} - /> + />, + defaultProps.plugins.data ); + instance = mounted.instance; }); instance.update(); @@ -727,9 +763,9 @@ describe('workspace_panel', () => { }; await act(async () => { - instance = mount( + const mounted = await mountWithProvider( { vis: { ...mockVisualization, toExpression: () => 'vis' }, }} ExpressionRenderer={expressionRendererMock} - /> + />, + defaultProps.plugins.data ); + instance = mounted.instance; }); instance.update(); @@ -791,7 +829,7 @@ describe('workspace_panel', () => { dropTargetsByOrder={undefined} > { ); } - it('should immediately transition if exactly one suggestion is returned', () => { + it('should immediately transition if exactly one suggestion is returned', async () => { mockGetSuggestionForField.mockReturnValue({ visualizationId: 'vis', datasourceState: {}, diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx index 3d5d9a6d84d81..94065f316340c 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx @@ -54,6 +54,7 @@ import { DropIllustration } from '../../../assets/drop_illustration'; import { getOriginalRequestErrorMessages } from '../../error_helper'; import { getMissingIndexPattern, validateDatasourceAndVisualization } from '../state_helpers'; import { DefaultInspectorAdapters } from '../../../../../../../src/plugins/expressions/common'; +import { onActiveDataChange, useLensDispatch } from '../../../state_management'; export interface WorkspacePanelProps { activeVisualizationId: string | null; @@ -428,16 +429,15 @@ export const VisualizationWrapper = ({ ] ); + const dispatchLens = useLensDispatch(); + const onData$ = useCallback( (data: unknown, inspectorAdapters?: Partial) => { if (inspectorAdapters && inspectorAdapters.tables) { - dispatch({ - type: 'UPDATE_ACTIVE_DATA', - tables: inspectorAdapters.tables.tables, - }); + dispatchLens(onActiveDataChange({ activeData: { ...inspectorAdapters.tables.tables } })); } }, - [dispatch] + [dispatchLens] ); if (localState.configurationValidationError?.length) { diff --git a/x-pack/plugins/lens/public/editor_frame_service/service.tsx b/x-pack/plugins/lens/public/editor_frame_service/service.tsx index f6500596ce5a0..62274df23e837 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/service.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/service.tsx @@ -126,26 +126,11 @@ export class EditorFrameService { collectAsyncDefinitions(this.visualizations), ]); - const firstDatasourceId = Object.keys(resolvedDatasources)[0]; - const firstVisualizationId = Object.keys(resolvedVisualizations)[0]; - - const { EditorFrame, getActiveDatasourceIdFromDoc } = await import('../async_services'); - + const { EditorFrame } = await import('../async_services'); const palettes = await plugins.charts.palettes.getPalettes(); return { - EditorFrameContainer: ({ - doc, - onError, - dateRange, - query, - filters, - savedQuery, - onChange, - showNoDataPopover, - initialContext, - searchSessionId, - }) => { + EditorFrameContainer: ({ onError, showNoDataPopover, initialContext }) => { return (
    ); diff --git a/x-pack/plugins/lens/public/mocks.tsx b/x-pack/plugins/lens/public/mocks.tsx index c1f885d167659..473c170aef294 100644 --- a/x-pack/plugins/lens/public/mocks.tsx +++ b/x-pack/plugins/lens/public/mocks.tsx @@ -6,8 +6,35 @@ */ import React from 'react'; +// eslint-disable-next-line import/no-extraneous-dependencies +import { ReactWrapper } from 'enzyme'; +// eslint-disable-next-line import/no-extraneous-dependencies +import { mountWithIntl as mount } from '@kbn/test/jest'; +import { Observable, Subject } from 'rxjs'; +import { coreMock } from 'src/core/public/mocks'; +import moment from 'moment'; +import { Provider } from 'react-redux'; +import { act } from 'react-dom/test-utils'; import { LensPublicStart } from '.'; import { visualizationTypes } from './xy_visualization/types'; +import { navigationPluginMock } from '../../../../src/plugins/navigation/public/mocks'; +import { LensAppServices } from './app_plugin/types'; +import { DOC_TYPE } from '../common'; +import { DataPublicPluginStart, esFilters, UI_SETTINGS } from '../../../../src/plugins/data/public'; +import { + LensByValueInput, + LensSavedObjectAttributes, + LensByReferenceInput, +} from './editor_frame_service/embeddable/embeddable'; +import { + mockAttributeService, + createEmbeddableStateTransferMock, +} from '../../../../src/plugins/embeddable/public/mocks'; +import { LensAttributeService } from './lens_attribute_service'; +import { EmbeddableStateTransfer } from '../../../../src/plugins/embeddable/public'; + +import { makeConfigureStore, getPreloadedState, LensAppState } from './state_management/index'; +import { getResolvedDateRange } from './utils'; export type Start = jest.Mocked; @@ -26,3 +53,252 @@ const createStartContract = (): Start => { export const lensPluginMock = { createStartContract, }; + +export const defaultDoc = ({ + savedObjectId: '1234', + title: 'An extremely cool default document!', + expression: 'definitely a valid expression', + state: { + query: 'kuery', + filters: [{ query: { match_phrase: { src: 'test' } } }], + }, + references: [{ type: 'index-pattern', id: '1', name: 'index-pattern-0' }], +} as unknown) as Document; + +export function createMockTimefilter() { + const unsubscribe = jest.fn(); + + let timeFilter = { from: 'now-7d', to: 'now' }; + let subscriber: () => void; + return { + getTime: jest.fn(() => timeFilter), + setTime: jest.fn((newTimeFilter) => { + timeFilter = newTimeFilter; + if (subscriber) { + subscriber(); + } + }), + getTimeUpdate$: () => ({ + subscribe: ({ next }: { next: () => void }) => { + subscriber = next; + return unsubscribe; + }, + }), + calculateBounds: jest.fn(() => ({ + min: moment('2021-01-10T04:00:00.000Z'), + max: moment('2021-01-10T08:00:00.000Z'), + })), + getBounds: jest.fn(() => timeFilter), + getRefreshInterval: () => {}, + getRefreshIntervalDefaults: () => {}, + getAutoRefreshFetch$: () => new Observable(), + }; +} + +export function mockDataPlugin(sessionIdSubject = new Subject()) { + function createMockSearchService() { + let sessionIdCounter = 1; + return { + session: { + start: jest.fn(() => `sessionId-${sessionIdCounter++}`), + clear: jest.fn(), + getSessionId: jest.fn(() => `sessionId-${sessionIdCounter}`), + getSession$: jest.fn(() => sessionIdSubject.asObservable()), + }, + }; + } + + function createMockFilterManager() { + const unsubscribe = jest.fn(); + + let subscriber: () => void; + let filters: unknown = []; + + return { + getUpdates$: () => ({ + subscribe: ({ next }: { next: () => void }) => { + subscriber = next; + return unsubscribe; + }, + }), + setFilters: jest.fn((newFilters: unknown[]) => { + filters = newFilters; + if (subscriber) subscriber(); + }), + setAppFilters: jest.fn((newFilters: unknown[]) => { + filters = newFilters; + if (subscriber) subscriber(); + }), + getFilters: () => filters, + getGlobalFilters: () => { + // @ts-ignore + return filters.filter(esFilters.isFilterPinned); + }, + removeAll: () => { + filters = []; + subscriber(); + }, + }; + } + + function createMockQueryString() { + return { + getQuery: jest.fn(() => ({ query: '', language: 'lucene' })), + setQuery: jest.fn(), + getDefaultQuery: jest.fn(() => ({ query: '', language: 'lucene' })), + }; + } + return ({ + query: { + filterManager: createMockFilterManager(), + timefilter: { + timefilter: createMockTimefilter(), + }, + queryString: createMockQueryString(), + state$: new Observable(), + }, + indexPatterns: { + get: jest.fn((id) => { + return new Promise((resolve) => resolve({ id })); + }), + }, + search: createMockSearchService(), + nowProvider: { + get: jest.fn(), + }, + } as unknown) as DataPublicPluginStart; +} + +export function makeDefaultServices( + sessionIdSubject = new Subject(), + doc = defaultDoc +): jest.Mocked { + const core = coreMock.createStart({ basePath: '/testbasepath' }); + core.uiSettings.get.mockImplementation( + jest.fn((type) => { + if (type === UI_SETTINGS.TIMEPICKER_TIME_DEFAULTS) { + return { from: 'now-7d', to: 'now' }; + } else if (type === UI_SETTINGS.SEARCH_QUERY_LANGUAGE) { + return 'kuery'; + } else if (type === 'state:storeInSessionStorage') { + return false; + } else { + return []; + } + }) + ); + + const navigationStartMock = navigationPluginMock.createStartContract(); + + jest.spyOn(navigationStartMock.ui.TopNavMenu.prototype, 'constructor').mockImplementation(() => { + return
    ; + }); + + function makeAttributeService(): LensAttributeService { + const attributeServiceMock = mockAttributeService< + LensSavedObjectAttributes, + LensByValueInput, + LensByReferenceInput + >( + DOC_TYPE, + { + saveMethod: jest.fn(), + unwrapMethod: jest.fn(), + checkForDuplicateTitle: jest.fn(), + }, + core + ); + + attributeServiceMock.unwrapAttributes = jest.fn().mockResolvedValue(doc); + attributeServiceMock.wrapAttributes = jest.fn().mockResolvedValue({ + savedObjectId: ((doc as unknown) as LensByReferenceInput).savedObjectId, + }); + + return attributeServiceMock; + } + + return { + http: core.http, + chrome: core.chrome, + overlays: core.overlays, + uiSettings: core.uiSettings, + navigation: navigationStartMock, + notifications: core.notifications, + attributeService: makeAttributeService(), + savedObjectsClient: core.savedObjects.client, + dashboardFeatureFlag: { allowByValueEmbeddables: false }, + stateTransfer: createEmbeddableStateTransferMock() as EmbeddableStateTransfer, + getOriginatingAppName: jest.fn(() => 'defaultOriginatingApp'), + application: { + ...core.application, + capabilities: { + ...core.application.capabilities, + visualize: { save: true, saveQuery: true, show: true }, + }, + getUrlForApp: jest.fn((appId: string) => `/testbasepath/app/${appId}#/`), + }, + data: mockDataPlugin(sessionIdSubject), + storage: { + get: jest.fn(), + set: jest.fn(), + remove: jest.fn(), + clear: jest.fn(), + }, + }; +} + +export function mockLensStore({ + data, + storePreloadedState, +}: { + data: DataPublicPluginStart; + storePreloadedState?: Partial; +}) { + const lensStore = makeConfigureStore( + getPreloadedState({ + query: data.query.queryString.getQuery(), + filters: data.query.filterManager.getGlobalFilters(), + searchSessionId: data.search.session.start(), + resolvedDateRange: getResolvedDateRange(data.query.timefilter.timefilter), + ...storePreloadedState, + }), + { + data, + } + ); + + const origDispatch = lensStore.dispatch; + lensStore.dispatch = jest.fn(origDispatch); + return lensStore; +} + +export const mountWithProvider = async ( + component: React.ReactElement, + data: DataPublicPluginStart, + storePreloadedState?: Partial, + extraWrappingComponent?: React.FC<{ + children: React.ReactNode; + }> +) => { + const lensStore = mockLensStore({ data, storePreloadedState }); + + const wrappingComponent: React.FC<{ + children: React.ReactNode; + }> = ({ children }) => { + if (extraWrappingComponent) { + return extraWrappingComponent({ + children: {children}, + }); + } + return {children}; + }; + + let instance: ReactWrapper = {} as ReactWrapper; + + await act(async () => { + instance = mount(component, ({ + wrappingComponent, + } as unknown) as ReactWrapper); + }); + return { instance, lensStore }; +}; diff --git a/x-pack/plugins/lens/public/shared_components/debounced_value.ts b/x-pack/plugins/lens/public/shared_components/debounced_value.ts index 5447384ce38ea..1f8ba0fa765b2 100644 --- a/x-pack/plugins/lens/public/shared_components/debounced_value.ts +++ b/x-pack/plugins/lens/public/shared_components/debounced_value.ts @@ -6,7 +6,7 @@ */ import { useState, useMemo, useEffect, useRef } from 'react'; -import _ from 'lodash'; +import { debounce } from 'lodash'; /** * Debounces value changes and updates inputValue on root state changes if no debounced changes @@ -27,7 +27,7 @@ export const useDebouncedValue = ({ const initialValue = useRef(value); const onChangeDebounced = useMemo(() => { - const callback = _.debounce((val: T) => { + const callback = debounce((val: T) => { onChange(val); unflushedChanges.current = false; }, 256); diff --git a/x-pack/plugins/lens/public/state_management/app_slice.ts b/x-pack/plugins/lens/public/state_management/app_slice.ts new file mode 100644 index 0000000000000..29d5b0bee843f --- /dev/null +++ b/x-pack/plugins/lens/public/state_management/app_slice.ts @@ -0,0 +1,55 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { createSlice, PayloadAction } from '@reduxjs/toolkit'; +import { isEqual } from 'lodash'; +import { LensAppState } from './types'; + +export const initialState: LensAppState = { + searchSessionId: '', + filters: [], + query: { language: 'kuery', query: '' }, + resolvedDateRange: { fromDate: '', toDate: '' }, + + indexPatternsForTopNav: [], + isSaveable: false, + isAppLoading: false, + isLinkedToOriginatingApp: false, +}; + +export const appSlice = createSlice({ + name: 'app', + initialState, + reducers: { + setState: (state, { payload }: PayloadAction>) => { + return { + ...state, + ...payload, + }; + }, + onChangeFromEditorFrame: (state, { payload }: PayloadAction>) => { + return { + ...state, + ...payload, + }; + }, + onActiveDataChange: (state, { payload }: PayloadAction>) => { + if (!isEqual(state.activeData, payload?.activeData)) { + return { + ...state, + ...payload, + }; + } + return state; + }, + navigateAway: (state) => state, + }, +}); + +export const reducer = { + app: appSlice.reducer, +}; diff --git a/x-pack/plugins/lens/public/state_management/external_context_middleware.ts b/x-pack/plugins/lens/public/state_management/external_context_middleware.ts new file mode 100644 index 0000000000000..35d0f7cf197ed --- /dev/null +++ b/x-pack/plugins/lens/public/state_management/external_context_middleware.ts @@ -0,0 +1,103 @@ +/* + * 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 { delay, finalize, switchMap, tap } from 'rxjs/operators'; +import _, { debounce } from 'lodash'; +import { Dispatch, MiddlewareAPI, PayloadAction } from '@reduxjs/toolkit'; +import { trackUiEvent } from '../lens_ui_telemetry'; + +import { + waitUntilNextSessionCompletes$, + DataPublicPluginStart, +} from '../../../../../src/plugins/data/public'; +import { setState, LensGetState, LensDispatch } from '.'; +import { LensAppState } from './types'; +import { getResolvedDateRange } from '../utils'; + +export const externalContextMiddleware = (data: DataPublicPluginStart) => ( + store: MiddlewareAPI +) => { + const unsubscribeFromExternalContext = subscribeToExternalContext( + data, + store.getState, + store.dispatch + ); + return (next: Dispatch) => (action: PayloadAction>) => { + if (action.type === 'app/navigateAway') { + unsubscribeFromExternalContext(); + } + next(action); + }; +}; + +function subscribeToExternalContext( + data: DataPublicPluginStart, + getState: LensGetState, + dispatch: LensDispatch +) { + const { query: queryService, search } = data; + const { filterManager } = queryService; + + const dispatchFromExternal = (searchSessionId = search.session.start()) => { + const globalFilters = filterManager.getFilters(); + const filters = _.isEqual(getState().app.filters, globalFilters) + ? null + : { filters: globalFilters }; + dispatch( + setState({ + searchSessionId, + ...filters, + resolvedDateRange: getResolvedDateRange(queryService.timefilter.timefilter), + }) + ); + }; + + const debounceDispatchFromExternal = debounce(dispatchFromExternal, 100); + + const sessionSubscription = search.session + .getSession$() + // wait for a tick to filter/timerange subscribers the chance to update the session id in the state + .pipe(delay(0)) + // then update if it didn't get updated yet + .subscribe((newSessionId?: string) => { + if (newSessionId && getState().app.searchSessionId !== newSessionId) { + debounceDispatchFromExternal(newSessionId); + } + }); + + const filterSubscription = filterManager.getUpdates$().subscribe({ + next: () => { + debounceDispatchFromExternal(); + trackUiEvent('app_filters_updated'); + }, + }); + + const timeSubscription = data.query.timefilter.timefilter.getTimeUpdate$().subscribe({ + next: () => { + debounceDispatchFromExternal(); + }, + }); + + const autoRefreshSubscription = data.query.timefilter.timefilter + .getAutoRefreshFetch$() + .pipe( + tap(() => { + debounceDispatchFromExternal(); + }), + switchMap((done) => + // best way in lens to estimate that all panels are updated is to rely on search session service state + waitUntilNextSessionCompletes$(search.session).pipe(finalize(done)) + ) + ) + .subscribe(); + return () => { + filterSubscription.unsubscribe(); + timeSubscription.unsubscribe(); + autoRefreshSubscription.unsubscribe(); + sessionSubscription.unsubscribe(); + }; +} diff --git a/x-pack/plugins/lens/public/state_management/index.ts b/x-pack/plugins/lens/public/state_management/index.ts new file mode 100644 index 0000000000000..429978e60756b --- /dev/null +++ b/x-pack/plugins/lens/public/state_management/index.ts @@ -0,0 +1,76 @@ +/* + * 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 { configureStore, DeepPartial, getDefaultMiddleware } from '@reduxjs/toolkit'; +import logger from 'redux-logger'; +import { useDispatch, useSelector, TypedUseSelectorHook } from 'react-redux'; +import { appSlice, initialState } from './app_slice'; +import { timeRangeMiddleware } from './time_range_middleware'; +import { externalContextMiddleware } from './external_context_middleware'; + +import { DataPublicPluginStart } from '../../../../../src/plugins/data/public'; +import { LensAppState, LensState } from './types'; +export * from './types'; + +export const reducer = { + app: appSlice.reducer, +}; + +export const { + setState, + navigateAway, + onChangeFromEditorFrame, + onActiveDataChange, +} = appSlice.actions; + +export const getPreloadedState = (initializedState: Partial) => { + const state = { + app: { + ...initialState, + ...initializedState, + }, + } as DeepPartial; + return state; +}; + +type PreloadedState = ReturnType; + +export const makeConfigureStore = ( + preloadedState: PreloadedState, + { data }: { data: DataPublicPluginStart } +) => { + const middleware = [ + ...getDefaultMiddleware({ + serializableCheck: { + ignoredActions: [ + 'app/setState', + 'app/onChangeFromEditorFrame', + 'app/onActiveDataChange', + 'app/navigateAway', + ], + }, + }), + timeRangeMiddleware(data), + externalContextMiddleware(data), + ]; + if (process.env.NODE_ENV === 'development') middleware.push(logger); + + return configureStore({ + reducer, + middleware, + preloadedState, + }); +}; + +export type LensRootStore = ReturnType; + +export type LensDispatch = LensRootStore['dispatch']; +export type LensGetState = LensRootStore['getState']; +export type LensRootState = ReturnType; + +export const useLensDispatch = () => useDispatch(); +export const useLensSelector: TypedUseSelectorHook = useSelector; diff --git a/x-pack/plugins/lens/public/state_management/time_range_middleware.test.ts b/x-pack/plugins/lens/public/state_management/time_range_middleware.test.ts new file mode 100644 index 0000000000000..4145f8ed5e52c --- /dev/null +++ b/x-pack/plugins/lens/public/state_management/time_range_middleware.test.ts @@ -0,0 +1,198 @@ +/* + * 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. + */ + +// /* +// * 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 { timeRangeMiddleware } from './time_range_middleware'; + +import { Observable, Subject } from 'rxjs'; +import { DataPublicPluginStart, esFilters } from '../../../../../src/plugins/data/public'; +import moment from 'moment'; +import { initialState } from './app_slice'; +import { LensAppState } from './types'; +import { PayloadAction } from '@reduxjs/toolkit'; +import { Document } from '../persistence'; + +const sessionIdSubject = new Subject(); + +function createMockSearchService() { + let sessionIdCounter = 1; + return { + session: { + start: jest.fn(() => `sessionId-${sessionIdCounter++}`), + clear: jest.fn(), + getSessionId: jest.fn(() => `sessionId-${sessionIdCounter}`), + getSession$: jest.fn(() => sessionIdSubject.asObservable()), + }, + }; +} + +function createMockFilterManager() { + const unsubscribe = jest.fn(); + + let subscriber: () => void; + let filters: unknown = []; + + return { + getUpdates$: () => ({ + subscribe: ({ next }: { next: () => void }) => { + subscriber = next; + return unsubscribe; + }, + }), + setFilters: jest.fn((newFilters: unknown[]) => { + filters = newFilters; + if (subscriber) subscriber(); + }), + setAppFilters: jest.fn((newFilters: unknown[]) => { + filters = newFilters; + if (subscriber) subscriber(); + }), + getFilters: () => filters, + getGlobalFilters: () => { + // @ts-ignore + return filters.filter(esFilters.isFilterPinned); + }, + removeAll: () => { + filters = []; + subscriber(); + }, + }; +} + +function createMockQueryString() { + return { + getQuery: jest.fn(() => ({ query: '', language: 'kuery' })), + setQuery: jest.fn(), + getDefaultQuery: jest.fn(() => ({ query: '', language: 'kuery' })), + }; +} + +function createMockTimefilter() { + const unsubscribe = jest.fn(); + + let timeFilter = { from: 'now-7d', to: 'now' }; + let subscriber: () => void; + return { + getTime: jest.fn(() => timeFilter), + setTime: jest.fn((newTimeFilter) => { + timeFilter = newTimeFilter; + if (subscriber) { + subscriber(); + } + }), + getTimeUpdate$: () => ({ + subscribe: ({ next }: { next: () => void }) => { + subscriber = next; + return unsubscribe; + }, + }), + calculateBounds: jest.fn(() => ({ + min: moment('2021-01-10T04:00:00.000Z'), + max: moment('2021-01-10T08:00:00.000Z'), + })), + getBounds: jest.fn(() => timeFilter), + getRefreshInterval: () => {}, + getRefreshIntervalDefaults: () => {}, + getAutoRefreshFetch$: () => new Observable(), + }; +} + +function makeDefaultData(): jest.Mocked { + return ({ + query: { + filterManager: createMockFilterManager(), + timefilter: { + timefilter: createMockTimefilter(), + }, + queryString: createMockQueryString(), + state$: new Observable(), + }, + indexPatterns: { + get: jest.fn((id) => { + return new Promise((resolve) => resolve({ id })); + }), + }, + search: createMockSearchService(), + nowProvider: { + get: jest.fn(), + }, + } as unknown) as DataPublicPluginStart; +} + +const createMiddleware = (data: DataPublicPluginStart) => { + const middleware = timeRangeMiddleware(data); + const store = { + getState: jest.fn(() => ({ app: initialState })), + dispatch: jest.fn(), + }; + const next = jest.fn(); + + const invoke = (action: PayloadAction>) => middleware(store)(next)(action); + + return { store, next, invoke }; +}; + +describe('timeRangeMiddleware', () => { + describe('time update', () => { + it('does update the searchSessionId when the state changes and too much time passed', () => { + const data = makeDefaultData(); + (data.nowProvider.get as jest.Mock).mockReturnValue(new Date(Date.now() - 30000)); + (data.query.timefilter.timefilter.getTime as jest.Mock).mockReturnValue({ + from: 'now-2m', + to: 'now', + }); + (data.query.timefilter.timefilter.getBounds as jest.Mock).mockReturnValue({ + min: moment(Date.now() - 100000), + max: moment(Date.now() - 30000), + }); + const { next, invoke, store } = createMiddleware(data); + const action = { + type: 'app/setState', + payload: { lastKnownDoc: ('new' as unknown) as Document }, + }; + invoke(action); + expect(store.dispatch).toHaveBeenCalledWith({ + payload: { + resolvedDateRange: { + fromDate: '2021-01-10T04:00:00.000Z', + toDate: '2021-01-10T08:00:00.000Z', + }, + searchSessionId: 'sessionId-1', + }, + type: 'app/setState', + }); + expect(next).toHaveBeenCalledWith(action); + }); + it('does not update the searchSessionId when the state changes and too little time has passed', () => { + const data = makeDefaultData(); + // time range is 100,000ms ago to 300ms ago (that's a lag of .3 percent, not enough to trigger a session update) + (data.nowProvider.get as jest.Mock).mockReturnValue(new Date(Date.now() - 300)); + (data.query.timefilter.timefilter.getTime as jest.Mock).mockReturnValue({ + from: 'now-2m', + to: 'now', + }); + (data.query.timefilter.timefilter.getBounds as jest.Mock).mockReturnValue({ + min: moment(Date.now() - 100000), + max: moment(Date.now() - 300), + }); + const { next, invoke, store } = createMiddleware(data); + const action = { + type: 'app/setState', + payload: { lastKnownDoc: ('new' as unknown) as Document }, + }; + invoke(action); + expect(store.dispatch).not.toHaveBeenCalled(); + expect(next).toHaveBeenCalledWith(action); + }); + }); +}); diff --git a/x-pack/plugins/lens/public/state_management/time_range_middleware.ts b/x-pack/plugins/lens/public/state_management/time_range_middleware.ts new file mode 100644 index 0000000000000..a6c868be60565 --- /dev/null +++ b/x-pack/plugins/lens/public/state_management/time_range_middleware.ts @@ -0,0 +1,61 @@ +/* + * 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 { isEqual } from 'lodash'; +import { Dispatch, MiddlewareAPI, PayloadAction } from '@reduxjs/toolkit'; +import moment from 'moment'; + +import { DataPublicPluginStart } from '../../../../../src/plugins/data/public'; +import { setState, LensDispatch } from '.'; +import { LensAppState } from './types'; +import { getResolvedDateRange, containsDynamicMath, TIME_LAG_PERCENTAGE_LIMIT } from '../utils'; + +export const timeRangeMiddleware = (data: DataPublicPluginStart) => (store: MiddlewareAPI) => { + return (next: Dispatch) => (action: PayloadAction>) => { + // if document was modified or sessionId check if too much time passed to update searchSessionId + if ( + action.payload?.lastKnownDoc && + !isEqual(action.payload?.lastKnownDoc, store.getState().app.lastKnownDoc) + ) { + updateTimeRange(data, store.dispatch); + } + next(action); + }; +}; +function updateTimeRange(data: DataPublicPluginStart, dispatch: LensDispatch) { + const timefilter = data.query.timefilter.timefilter; + const unresolvedTimeRange = timefilter.getTime(); + if ( + !containsDynamicMath(unresolvedTimeRange.from) && + !containsDynamicMath(unresolvedTimeRange.to) + ) { + return; + } + + const { min, max } = timefilter.getBounds(); + + if (!min || !max) { + // bounds not fully specified, bailing out + return; + } + + // calculate length of currently configured range in ms + const timeRangeLength = moment.duration(max.diff(min)).asMilliseconds(); + + // calculate lag of managed "now" for date math + const nowDiff = Date.now() - data.nowProvider.get().valueOf(); + + // if the lag is signifcant, start a new session to clear the cache + if (nowDiff > timeRangeLength * TIME_LAG_PERCENTAGE_LIMIT) { + dispatch( + setState({ + searchSessionId: data.search.session.start(), + resolvedDateRange: getResolvedDateRange(timefilter), + }) + ); + } +} diff --git a/x-pack/plugins/lens/public/state_management/types.ts b/x-pack/plugins/lens/public/state_management/types.ts new file mode 100644 index 0000000000000..87045d15cc994 --- /dev/null +++ b/x-pack/plugins/lens/public/state_management/types.ts @@ -0,0 +1,42 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { Filter, IndexPattern, Query, SavedQuery } from '../../../../../src/plugins/data/public'; +import { Document } from '../persistence'; + +import { TableInspectorAdapter } from '../editor_frame_service/types'; +import { DateRange } from '../../common'; + +export interface LensAppState { + persistedDoc?: Document; + lastKnownDoc?: Document; + + // index patterns used to determine which filters are available in the top nav. + indexPatternsForTopNav: IndexPattern[]; + // Determines whether the lens editor shows the 'save and return' button, and the originating app breadcrumb. + isLinkedToOriginatingApp?: boolean; + isSaveable: boolean; + activeData?: TableInspectorAdapter; + + isAppLoading: boolean; + query: Query; + filters: Filter[]; + savedQuery?: SavedQuery; + searchSessionId: string; + resolvedDateRange: DateRange; +} + +export type DispatchSetState = ( + state: Partial +) => { + payload: Partial; + type: string; +}; + +export interface LensState { + app: LensAppState; +} diff --git a/x-pack/plugins/lens/public/types.ts b/x-pack/plugins/lens/public/types.ts index 9cde4eb8a1561..5a632e03f8f36 100644 --- a/x-pack/plugins/lens/public/types.ts +++ b/x-pack/plugins/lens/public/types.ts @@ -18,9 +18,8 @@ import { SerializedFieldFormat, } from '../../../../src/plugins/expressions/public'; import { DraggingIdentifier, DragDropIdentifier, DragContextState } from './drag_drop'; -import { Document } from './persistence'; import { DateRange } from '../common'; -import { Query, Filter, SavedQuery, IFieldFormat } from '../../../../src/plugins/data/public'; +import { Query, Filter, IFieldFormat } from '../../../../src/plugins/data/public'; import { VisualizeFieldContext } from '../../../../src/plugins/ui_actions/public'; import { RangeSelectContext, ValueClickContext } from '../../../../src/plugins/embeddable/public'; import { @@ -46,22 +45,7 @@ export interface PublicAPIProps { export interface EditorFrameProps { onError: ErrorCallback; - doc?: Document; - dateRange: DateRange; - query: Query; - filters: Filter[]; - savedQuery?: SavedQuery; - searchSessionId: string; initialContext?: VisualizeFieldContext; - - // Frame loader (app or embeddable) is expected to call this when it loads and updates - // This should be replaced with a top-down state - onChange: (newState: { - filterableIndexPatterns: string[]; - doc: Document; - isSaveable: boolean; - activeData?: Record; - }) => void; showNoDataPopover: () => void; } export interface EditorFrameInstance { diff --git a/x-pack/plugins/lens/public/utils.ts b/x-pack/plugins/lens/public/utils.ts index 2d8cfee2185fa..c1aab4c18f529 100644 --- a/x-pack/plugins/lens/public/utils.ts +++ b/x-pack/plugins/lens/public/utils.ts @@ -6,6 +6,7 @@ */ import { i18n } from '@kbn/i18n'; +import { IndexPattern, IndexPatternsContract, TimefilterContract } from 'src/plugins/data/public'; import { LensFilterEvent } from './types'; /** replaces the value `(empty) to empty string for proper filtering` */ @@ -49,3 +50,32 @@ export function getVisualizeGeoFieldMessage(fieldType: string) { values: { fieldType }, }); } + +export const getResolvedDateRange = function (timefilter: TimefilterContract) { + const { from, to } = timefilter.getTime(); + const { min, max } = timefilter.calculateBounds({ + from, + to, + }); + return { fromDate: min?.toISOString() || from, toDate: max?.toISOString() || to }; +}; + +export function containsDynamicMath(dateMathString: string) { + return dateMathString.includes('now'); +} +export const TIME_LAG_PERCENTAGE_LIMIT = 0.02; + +export async function getAllIndexPatterns( + ids: string[], + indexPatternsService: IndexPatternsContract +): Promise<{ indexPatterns: IndexPattern[]; rejectedIds: string[] }> { + const responses = await Promise.allSettled(ids.map((id) => indexPatternsService.get(id))); + const fullfilled = responses.filter( + (response): response is PromiseFulfilledResult => response.status === 'fulfilled' + ); + const rejectedIds = responses + .map((_response, i) => ids[i]) + .filter((id, i) => responses[i].status === 'rejected'); + // return also the rejected ids in case we want to show something later on + return { indexPatterns: fullfilled.map((response) => response.value), rejectedIds }; +} diff --git a/x-pack/plugins/lens/public/xy_visualization/visualization.tsx b/x-pack/plugins/lens/public/xy_visualization/visualization.tsx index dda1a444f4544..19cfcb1a60cc7 100644 --- a/x-pack/plugins/lens/public/xy_visualization/visualization.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/visualization.tsx @@ -6,7 +6,7 @@ */ import React from 'react'; -import _ from 'lodash'; +import { uniq } from 'lodash'; import { render } from 'react-dom'; import { Position } from '@elastic/charts'; import { I18nProvider } from '@kbn/i18n/react'; @@ -43,7 +43,7 @@ function getVisualizationType(state: State): VisualizationType | 'mixed' { ); } const visualizationType = visualizationTypes.find((t) => t.id === state.layers[0].seriesType); - const seriesTypes = _.uniq(state.layers.map((l) => l.seriesType)); + const seriesTypes = uniq(state.layers.map((l) => l.seriesType)); return visualizationType && seriesTypes.length === 1 ? visualizationType : 'mixed'; } @@ -111,7 +111,7 @@ export const getXyVisualization = ({ }, appendLayer(state, layerId) { - const usedSeriesTypes = _.uniq(state.layers.map((layer) => layer.seriesType)); + const usedSeriesTypes = uniq(state.layers.map((layer) => layer.seriesType)); return { ...state, layers: [ @@ -255,10 +255,11 @@ export const getXyVisualization = ({ }, setDimension({ prevState, layerId, columnId, groupId }) { - const newLayer = prevState.layers.find((l) => l.layerId === layerId); - if (!newLayer) { + const foundLayer = prevState.layers.find((l) => l.layerId === layerId); + if (!foundLayer) { return prevState; } + const newLayer = { ...foundLayer }; if (groupId === 'x') { newLayer.xAccessor = columnId; @@ -277,11 +278,11 @@ export const getXyVisualization = ({ }, removeDimension({ prevState, layerId, columnId }) { - const newLayer = prevState.layers.find((l) => l.layerId === layerId); - if (!newLayer) { + const foundLayer = prevState.layers.find((l) => l.layerId === layerId); + if (!foundLayer) { return prevState; } - + const newLayer = { ...foundLayer }; if (newLayer.xAccessor === columnId) { delete newLayer.xAccessor; } else if (newLayer.splitAccessor === columnId) { diff --git a/yarn.lock b/yarn.lock index 3add4843d0966..a92dadf08dde7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3587,6 +3587,16 @@ resolved "https://registry.yarnpkg.com/@redux-saga/types/-/types-1.1.0.tgz#0e81ce56b4883b4b2a3001ebe1ab298b84237204" integrity sha512-afmTuJrylUU/0OtqzaRkbyYFFNgCF73Bvel/sw90pvGrWIZ+vyoIJqA6eMSoA6+nb443kTmulmBtC9NerXboNg== +"@reduxjs/toolkit@^1.5.1": + version "1.5.1" + resolved "https://registry.yarnpkg.com/@reduxjs/toolkit/-/toolkit-1.5.1.tgz#05daa2f6eebc70dc18cd98a90421fab7fa565dc5" + integrity sha512-PngZKuwVZsd+mimnmhiOQzoD0FiMjqVks6ituO1//Ft5UEX5Ca9of13NEjo//pU22Jk7z/mdXVsmDfgsig1osA== + dependencies: + immer "^8.0.1" + redux "^4.0.0" + redux-thunk "^2.3.0" + reselect "^4.0.0" + "@samverschueren/stream-to-observable@^0.3.0": version "0.3.0" resolved "https://registry.yarnpkg.com/@samverschueren/stream-to-observable/-/stream-to-observable-0.3.0.tgz#ecdf48d532c58ea477acfcab80348424f8d0662f" @@ -5793,6 +5803,13 @@ resolved "https://registry.yarnpkg.com/@types/redux-actions/-/redux-actions-2.6.1.tgz#0940e97fa35ad3004316bddb391d8e01d2efa605" integrity sha512-zKgK+ATp3sswXs6sOYo1tk8xdXTy4CTaeeYrVQlClCjeOpag5vzPo0ASWiiBJ7vsiQRAdb3VkuFLnDoBimF67g== +"@types/redux-logger@^3.0.8": + version "3.0.8" + resolved "https://registry.yarnpkg.com/@types/redux-logger/-/redux-logger-3.0.8.tgz#1fb6d26917bb198792bb1cf57feb31cae1532c5d" + integrity sha512-zM+cxiSw6nZtRbxpVp9SE3x/X77Z7e7YAfHD1NkxJyJbAGSXJGF0E9aqajZfPOa/sTYnuwutmlCldveExuCeLw== + dependencies: + redux "^4.0.0" + "@types/request@^2.48.2": version "2.48.2" resolved "https://registry.yarnpkg.com/@types/request/-/request-2.48.2.tgz#936374cbe1179d7ed529fc02543deb4597450fed" @@ -11284,6 +11301,11 @@ dedent@^0.7.0: resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c" integrity sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw= +deep-diff@^0.3.5: + version "0.3.8" + resolved "https://registry.yarnpkg.com/deep-diff/-/deep-diff-0.3.8.tgz#c01de63efb0eec9798801d40c7e0dae25b582c84" + integrity sha1-wB3mPvsO7JeYgB1Ax+Da4ltYLIQ= + deep-eql@^0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-0.1.3.tgz#ef558acab8de25206cd713906d74e56930eb69f2" @@ -23625,6 +23647,13 @@ redux-devtools-extension@^2.13.8: resolved "https://registry.yarnpkg.com/redux-devtools-extension/-/redux-devtools-extension-2.13.8.tgz#37b982688626e5e4993ff87220c9bbb7cd2d96e1" integrity sha512-8qlpooP2QqPtZHQZRhx3x3OP5skEV1py/zUdMY28WNAocbafxdG2tRD1MWE7sp8obGMNYuLWanhhQ7EQvT1FBg== +redux-logger@^3.0.6: + version "3.0.6" + resolved "https://registry.yarnpkg.com/redux-logger/-/redux-logger-3.0.6.tgz#f7555966f3098f3c88604c449cf0baf5778274bf" + integrity sha1-91VZZvMJjzyIYExEnPC69XeCdL8= + dependencies: + deep-diff "^0.3.5" + redux-observable@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/redux-observable/-/redux-observable-1.2.0.tgz#ff51b6c6be2598e9b5e89fc36639186bb0e669c7" From 79945fe0275b2ec9c93747e26154110133ec51fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B8ren=20Louv-Jansen?= Date: Fri, 28 May 2021 14:41:42 +0200 Subject: [PATCH 56/77] [Observability] Fix typo in readme for new navigation (#100861) * [Observability] Fix typo in readme for new navigation * Add rxjs dep --- .../public/components/shared/page_template/README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/observability/public/components/shared/page_template/README.md b/x-pack/plugins/observability/public/components/shared/page_template/README.md index e360e6d95a9d8..fb2a603cc7a7f 100644 --- a/x-pack/plugins/observability/public/components/shared/page_template/README.md +++ b/x-pack/plugins/observability/public/components/shared/page_template/README.md @@ -17,6 +17,8 @@ Now within your solution's **public** plugin `setup` lifecycle method you can ca ```typescript // x-pack/plugins/example_plugin/public/plugin.ts +import { of } from 'rxjs'; + export class Plugin implements PluginClass { constructor(_context: PluginInitializerContext) {} @@ -64,7 +66,7 @@ This can be accessed like so: ``` const [coreStart, pluginsStart] = await core.getStartServices(); -const pageTemplateComponent = pluginsStart.observability.navigation.PageTemplate; +const ObservabilityPageTemplate = pluginsStart.observability.navigation.PageTemplate; ``` Now that you have access to the component you can render your solution's content using it. @@ -101,4 +103,4 @@ The `` component is a wrapper around the ` Date: Fri, 28 May 2021 08:42:44 -0400 Subject: [PATCH 57/77] [Infra] Update LogStream component docs (#100795) --- .../log_stream/log_stream.stories.mdx | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/x-pack/plugins/infra/public/components/log_stream/log_stream.stories.mdx b/x-pack/plugins/infra/public/components/log_stream/log_stream.stories.mdx index 901a4b6a8383e..7f1636b00d24e 100644 --- a/x-pack/plugins/infra/public/components/log_stream/log_stream.stories.mdx +++ b/x-pack/plugins/infra/public/components/log_stream/log_stream.stories.mdx @@ -113,7 +113,7 @@ export const Template = (args) => ; The purpose of this component is to allow you, the developer, to have your very own Log Stream in your plugin. -The component is exposed through `infra/public`. Since Kibana uses relative paths is up to you to find how to import it (sorry). +The component is exposed through `infra/public`. Since Kibana uses relative paths, it is up to you to find how to import it (sorry). ```tsx import { LogStream } from '../../../../../../infra/public'; @@ -124,8 +124,9 @@ import { LogStream } from '../../../../../../infra/public'; To use the component your plugin needs to follow certain criteria: -- Ensure `"infra"` is specified as a `requiredPlugins` in your plugin's `kibana.json`. -- Ensure the `` component is mounted inside the hiearchy of a [`kibana-react` provider](https://github.com/elastic/kibana/blob/b2d0aa7b7fae1c89c8f9e8854ae73e71be64e765/src/plugins/kibana_react/README.md#L45). +- Ensure `"infra"` and `"data"` are specified as a `requiredPlugins` in your plugin's `kibana.json`. +- Ensure the `` component is mounted inside the hierachy of a [`kibana-react` provider](https://github.com/elastic/kibana/blob/b2d0aa7b7fae1c89c8f9e8854ae73e71be64e765/src/plugins/kibana_react/README.md#L45). At a minimum, the kibana-react provider must pass `http` (from core start services) and `data` (from core plugin start dependencies). +- Ensure the `` component is mounted inside the hierachy of a [`EuiThemeProvider`](https://github.com/elastic/kibana/blob/master/src/plugins/kibana_react/common/eui_styled_components.tsx). ## Usage @@ -354,25 +355,30 @@ The infra plugin has the concept of a "source configuration", a collection of se The `` component will use the `"default"` source configuration. If you want to use your own configuration, you need to first create it when you initialize your plugin, and then specify it in the `` component with the `sourceId` prop. ```tsx -// Your `plugin/init.ts` +// Your `server/plugin.ts` class MyPlugin { // ... setup(core, plugins) { plugins.infra.defineInternalSourceConfiguration( 'my_source', // ID for your source configuration { - logAlias: 'some-index-*', // Optional. what ES index to query. + name: 'some-name', + description: 'some description', + logIndices: { // Also accepts an `index_pattern` type with `indexPatternId` + type: 'index_name', + indexName: 'some-index', + }, logColumns: [ - { timestampColumn: { id: '...uuid4' }, // The `@timestamp` column. - { fieldColumn: { id: '...uuid4', field: 'some_field' }}, // Any column(s) you want. - { messageColumn: { id: '...uuid' }} // The `message` column. + { timestampColumn: { id: '...uuid4' }, // The `@timestamp` column. `id` is an arbitrary string identifier. + { fieldColumn: { id: '...uuid4', field: 'some_field' }}, // Any column(s) you want. `id` is an arbitrary string identifier. + { messageColumn: { id: '...uuid' }} // The `message` column. `id` is an arbitrary string identifier. ] } ); } } -// Somewhere else on your code +// Somewhere else in your client-side code Date: Fri, 28 May 2021 15:19:15 +0200 Subject: [PATCH 58/77] [Security Solution][Endpoint] Do not display searchbar in security-trusted apps if there are no items (#100853) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../components/search_bar/index.tsx | 2 +- .../view/trusted_apps_page.test.tsx | 17 +++++- .../trusted_apps/view/trusted_apps_page.tsx | 54 ++++++++++--------- 3 files changed, 44 insertions(+), 29 deletions(-) diff --git a/x-pack/plugins/security_solution/public/management/components/search_bar/index.tsx b/x-pack/plugins/security_solution/public/management/components/search_bar/index.tsx index 3c92ab31680c2..5ace2b901da11 100644 --- a/x-pack/plugins/security_solution/public/management/components/search_bar/index.tsx +++ b/x-pack/plugins/security_solution/public/management/components/search_bar/index.tsx @@ -25,7 +25,7 @@ export const SearchBar = memo(({ defaultValue = '', onSearch, pl const handleOnSearch = useCallback(() => onSearch(query), [query, onSearch]); return ( - + { it('should display a Add Trusted App button', async () => { const { getByTestId } = await renderWithListData(); - const addButton = await getByTestId('trustedAppsListAddButton'); + const addButton = getByTestId('trustedAppsListAddButton'); expect(addButton.textContent).toBe('Add Trusted Application'); }); + it('should display the searchbar', async () => { + const renderResult = await renderWithListData(); + expect(await renderResult.findByTestId('searchBar')).not.toBeNull(); + }); + describe('and the Grid view is being displayed', () => { describe('and the edit trusted app button is clicked', () => { let renderResult: ReturnType; @@ -555,7 +560,7 @@ describe('When on the Trusted Apps Page', () => { // to test the UI behaviours while the API call is in flight coreStart.http.post.mockImplementation( // @ts-ignore - async (path: string, options: HttpFetchOptions) => { + async (_, options: HttpFetchOptions) => { return new Promise((resolve, reject) => { httpPostBody = options.body as string; resolveHttpPost = resolve; @@ -861,6 +866,14 @@ describe('When on the Trusted Apps Page', () => { expect(await renderResult.findByTestId('trustedAppEmptyState')).not.toBeNull(); }); + + it('should not display the searchbar', async () => { + const renderResult = render(); + await act(async () => { + await waitForAction('trustedAppsExistStateChanged'); + }); + expect(renderResult.queryByTestId('searchBar')).toBeNull(); + }); }); describe('and the search is dispatched', () => { diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/trusted_apps_page.tsx b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/trusted_apps_page.tsx index ac06254a53100..5603b8e2d61c9 100644 --- a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/trusted_apps_page.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/trusted_apps_page.tsx @@ -96,34 +96,36 @@ export const TrustedAppsPage = memo(() => { /> )} - {doEntriesExist ? ( - - - - - + <> + + - - - - - {location.view_type === 'grid' && } - {location.view_type === 'list' && } - - + + + + + + + + + {location.view_type === 'grid' && } + {location.view_type === 'list' && } + + + ) : ( )} From 51616e1b8d72d7186b2509339f629f8891ea85e3 Mon Sep 17 00:00:00 2001 From: Marco Liberati Date: Fri, 28 May 2021 15:24:28 +0200 Subject: [PATCH 59/77] [Lens] Adds dynamic table cell coloring (#95217) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Greg Thompson Co-authored-by: Michael Marcialis --- src/plugins/charts/common/palette.test.ts | 25 +- src/plugins/charts/common/palette.ts | 60 ++- .../public/services/palettes/helpers.test.ts | 307 ++++++++++++++ .../public/services/palettes/helpers.ts | 101 +++++ .../charts/public/services/palettes/mock.ts | 37 +- .../services/palettes/palettes.test.tsx | 111 +++-- .../public/services/palettes/palettes.tsx | 81 +++- .../charts/public/services/palettes/types.ts | 27 +- .../components/controls/palette_picker.tsx | 4 +- .../application/components/palette_picker.tsx | 8 +- .../lib/get_split_by_terms_color.ts | 2 +- .../vis_type_xy/public/vis_component.tsx | 2 +- .../canvas/public/functions/pie.test.js | 4 +- x-pack/plugins/canvas/public/functions/pie.ts | 2 +- .../canvas/public/functions/plot.test.js | 4 +- .../canvas/public/functions/plot/index.ts | 2 +- .../__snapshots__/table_basic.test.tsx.snap | 21 + .../components/cell_value.test.tsx | 117 ++++- .../components/cell_value.tsx | 82 +++- .../components/dimension_editor.scss | 7 + .../components/dimension_editor.test.tsx | 119 +++++- .../components/dimension_editor.tsx | 223 +++++++++- .../components/palette_panel_container.scss | 53 +++ .../components/palette_panel_container.tsx | 112 +++++ .../components/shared_utils.tsx | 36 ++ .../components/table_basic.test.tsx | 56 +++ .../components/table_basic.tsx | 37 +- .../components/types.ts | 10 + .../datatable_visualization/expression.tsx | 19 +- .../public/datatable_visualization/index.ts | 11 +- .../transpose_helpers.ts | 22 +- .../visualization.test.tsx | 45 +- .../datatable_visualization/visualization.tsx | 93 ++-- .../config_panel/dimension_container.tsx | 124 +++--- .../editor_frame/config_panel/layer_panel.tsx | 5 +- .../public/editor_frame_service/mocks.tsx | 5 +- .../calculations/moving_average.tsx | 8 +- .../operations/definitions/helpers.tsx | 24 -- .../operations/definitions/percentile.tsx | 2 +- .../definitions/ranges/advanced_editor.tsx | 3 +- .../definitions/ranges/range_editor.tsx | 2 +- .../definitions/terms/values_input.tsx | 2 +- .../render_function.test.tsx | 2 +- .../pie_visualization/render_function.tsx | 2 +- .../pie_visualization/visualization.tsx | 2 +- .../coloring/color_stops.test.tsx | 156 +++++++ .../coloring/color_stops.tsx | 294 +++++++++++++ .../shared_components/coloring/constants.ts | 29 ++ .../shared_components/coloring/index.ts | 12 + .../coloring/palette_configuration.scss | 7 + .../coloring/palette_configuration.test.tsx | 185 ++++++++ .../coloring/palette_configuration.tsx | 340 +++++++++++++++ .../coloring/palette_picker.tsx | 109 +++++ .../shared_components/coloring/types.ts | 25 ++ .../shared_components/coloring/utils.test.ts | 399 ++++++++++++++++++ .../shared_components/coloring/utils.ts | 308 ++++++++++++++ .../lens/public/shared_components/helpers.ts | 31 ++ .../lens/public/shared_components/index.ts | 3 + .../shared_components/palette_picker.tsx | 47 +-- .../tooltip_wrapper.tsx | 0 x-pack/plugins/lens/public/types.ts | 4 +- .../xy_visualization/color_assignment.ts | 2 +- .../public/xy_visualization/expression.tsx | 2 +- .../visual_options_popover.tsx | 3 +- .../xy_visualization/visualization.test.ts | 16 +- .../public/xy_visualization/visualization.tsx | 2 +- .../xy_visualization/xy_config_panel.test.tsx | 4 + .../xy_visualization/xy_config_panel.tsx | 3 +- x-pack/plugins/maps/public/kibana_services.ts | 2 +- x-pack/test/accessibility/apps/lens.ts | 23 + x-pack/test/functional/apps/lens/table.ts | 51 +++ .../test/functional/page_objects/lens_page.ts | 55 ++- 72 files changed, 3792 insertions(+), 341 deletions(-) create mode 100644 src/plugins/charts/public/services/palettes/helpers.test.ts create mode 100644 src/plugins/charts/public/services/palettes/helpers.ts create mode 100644 x-pack/plugins/lens/public/datatable_visualization/components/dimension_editor.scss create mode 100644 x-pack/plugins/lens/public/datatable_visualization/components/palette_panel_container.scss create mode 100644 x-pack/plugins/lens/public/datatable_visualization/components/palette_panel_container.tsx create mode 100644 x-pack/plugins/lens/public/datatable_visualization/components/shared_utils.tsx create mode 100644 x-pack/plugins/lens/public/shared_components/coloring/color_stops.test.tsx create mode 100644 x-pack/plugins/lens/public/shared_components/coloring/color_stops.tsx create mode 100644 x-pack/plugins/lens/public/shared_components/coloring/constants.ts create mode 100644 x-pack/plugins/lens/public/shared_components/coloring/index.ts create mode 100644 x-pack/plugins/lens/public/shared_components/coloring/palette_configuration.scss create mode 100644 x-pack/plugins/lens/public/shared_components/coloring/palette_configuration.test.tsx create mode 100644 x-pack/plugins/lens/public/shared_components/coloring/palette_configuration.tsx create mode 100644 x-pack/plugins/lens/public/shared_components/coloring/palette_picker.tsx create mode 100644 x-pack/plugins/lens/public/shared_components/coloring/types.ts create mode 100644 x-pack/plugins/lens/public/shared_components/coloring/utils.test.ts create mode 100644 x-pack/plugins/lens/public/shared_components/coloring/utils.ts create mode 100644 x-pack/plugins/lens/public/shared_components/helpers.ts rename x-pack/plugins/lens/public/{xy_visualization => shared_components}/tooltip_wrapper.tsx (100%) diff --git a/src/plugins/charts/common/palette.test.ts b/src/plugins/charts/common/palette.test.ts index 0a26d71a9b9d5..86ba74d409cc6 100644 --- a/src/plugins/charts/common/palette.test.ts +++ b/src/plugins/charts/common/palette.test.ts @@ -12,13 +12,14 @@ import { systemPalette, PaletteOutput, CustomPaletteState, + CustomPaletteArguments, } from './palette'; import { functionWrapper } from 'src/plugins/expressions/common/expression_functions/specs/tests/utils'; describe('palette', () => { const fn = functionWrapper(palette()) as ( context: null, - args?: { color?: string[]; gradient?: boolean; reverse?: boolean } + args?: Partial ) => PaletteOutput; it('results a palette', () => { @@ -39,6 +40,18 @@ describe('palette', () => { }); }); + describe('stop', () => { + it('sets stops', () => { + const result = fn(null, { color: ['red', 'green', 'blue'], stop: [1, 2, 3] }); + expect(result.params!.stops).toEqual([1, 2, 3]); + }); + + it('defaults to pault_tor_14 colors', () => { + const result = fn(null); + expect(result.params!.colors).toEqual(defaultCustomColors); + }); + }); + describe('gradient', () => { it('sets gradient', () => { let result = fn(null, { gradient: true }); @@ -69,6 +82,16 @@ describe('palette', () => { const result = fn(null); expect(result.params!.colors).toEqual(defaultCustomColors); }); + + it('keeps the stops order pristine when set', () => { + const stops = [1, 2, 3]; + const result = fn(null, { + color: ['red', 'green', 'blue'], + stop: [1, 2, 3], + reverse: true, + }); + expect(result.params!.stops).toEqual(stops); + }); }); }); }); diff --git a/src/plugins/charts/common/palette.ts b/src/plugins/charts/common/palette.ts index c9232b22cfae1..78c6fcc812028 100644 --- a/src/plugins/charts/common/palette.ts +++ b/src/plugins/charts/common/palette.ts @@ -14,11 +14,21 @@ export interface CustomPaletteArguments { color?: string[]; gradient: boolean; reverse?: boolean; + stop?: number[]; + range?: 'number' | 'percent'; + rangeMin?: number; + rangeMax?: number; + continuity?: 'above' | 'below' | 'all' | 'none'; } export interface CustomPaletteState { colors: string[]; gradient: boolean; + stops: number[]; + range: 'number' | 'percent'; + rangeMin: number; + rangeMax: number; + continuity?: 'above' | 'below' | 'all' | 'none'; } export interface SystemPaletteArguments { @@ -83,6 +93,35 @@ export function palette(): ExpressionFunctionDefinition< }), required: false, }, + stop: { + multi: true, + types: ['number'], + help: i18n.translate('charts.functions.palette.args.stopHelpText', { + defaultMessage: + 'The palette color stops. When used, it must be associated with each color.', + }), + required: false, + }, + continuity: { + types: ['string'], + options: ['above', 'below', 'all', 'none'], + default: 'above', + help: '', + }, + rangeMin: { + types: ['number'], + help: '', + }, + rangeMax: { + types: ['number'], + help: '', + }, + range: { + types: ['string'], + options: ['number', 'percent'], + default: 'percent', + help: '', + }, gradient: { types: ['boolean'], default: false, @@ -101,15 +140,32 @@ export function palette(): ExpressionFunctionDefinition< }, }, fn: (input, args) => { - const { color, reverse, gradient } = args; + const { + color, + continuity, + reverse, + gradient, + stop, + range, + rangeMin = 0, + rangeMax = 100, + } = args; const colors = ([] as string[]).concat(color || defaultCustomColors); - + const stops = ([] as number[]).concat(stop || []); + if (stops.length > 0 && colors.length !== stops.length) { + throw Error('When stop is used, each color must have an associated stop value.'); + } return { type: 'palette', name: 'custom', params: { colors: reverse ? colors.reverse() : colors, + stops, + range: range ?? 'percent', gradient, + continuity, + rangeMin, + rangeMax, }, }; }, diff --git a/src/plugins/charts/public/services/palettes/helpers.test.ts b/src/plugins/charts/public/services/palettes/helpers.test.ts new file mode 100644 index 0000000000000..90f5745570cc8 --- /dev/null +++ b/src/plugins/charts/public/services/palettes/helpers.test.ts @@ -0,0 +1,307 @@ +/* + * 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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { workoutColorForValue } from './helpers'; +import { CustomPaletteState } from '../..'; + +describe('workoutColorForValue', () => { + it('should return no color for empty value', () => { + expect( + workoutColorForValue( + undefined, + { + continuity: 'above', + colors: ['red', 'green', 'blue', 'yellow'], + range: 'number', + gradient: false, + rangeMin: 0, + rangeMax: 200, + stops: [], + }, + { min: 0, max: 200 } + ) + ).toBeUndefined(); + }); + + describe('range: "number"', () => { + const DEFAULT_PROPS: CustomPaletteState = { + continuity: 'above', + colors: ['red', 'green', 'blue', 'yellow'], + range: 'number', + gradient: false, + rangeMin: 0, + rangeMax: 200, + stops: [], + }; + it('find the right color for predefined palettes', () => { + expect(workoutColorForValue(123, DEFAULT_PROPS, { min: 0, max: 200 })).toBe('blue'); + }); + + it('find the right color for custom stops palettes', () => { + expect( + workoutColorForValue( + 50, + { + ...DEFAULT_PROPS, + stops: [20, 40, 60, 80], + }, + { min: 0, max: 200 } + ) + ).toBe('blue'); + }); + + it('find the right color for custom stops palettes when value is higher than rangeMax', () => { + expect( + workoutColorForValue( + 123, + { + ...DEFAULT_PROPS, + rangeMax: 100, + stops: [20, 40, 60, 80], + }, + { min: 0, max: 200 } + ) + ).toBe('yellow'); + expect( + workoutColorForValue( + 123, + { + ...DEFAULT_PROPS, + continuity: 'all', + rangeMax: 100, + stops: [20, 40, 60, 80], + }, + { min: 0, max: 200 } + ) + ).toBe('yellow'); + }); + + it('returns no color if the value if higher than rangeMax and continuity is nor "above" or "all"', () => { + expect( + workoutColorForValue( + 123, + { + ...DEFAULT_PROPS, + continuity: 'below', + rangeMax: 100, + stops: [20, 40, 60, 80], + }, + { min: 0, max: 200 } + ) + ).toBeUndefined(); + expect( + workoutColorForValue( + 123, + { + ...DEFAULT_PROPS, + continuity: 'none', + rangeMax: 100, + stops: [20, 40, 60, 80], + }, + { min: 0, max: 200 } + ) + ).toBeUndefined(); + }); + + it('find the right color for custom stops palettes when value is lower than rangeMin', () => { + expect( + workoutColorForValue( + 10, + { + ...DEFAULT_PROPS, + continuity: 'below', + rangeMin: 20, + rangeMax: 100, + stops: [20, 40, 60, 80], + }, + { min: 0, max: 200 } + ) + ).toBe('red'); + expect( + workoutColorForValue( + 10, + { + ...DEFAULT_PROPS, + continuity: 'all', + rangeMin: 20, + rangeMax: 100, + stops: [20, 40, 60, 80], + }, + { min: 0, max: 200 } + ) + ).toBe('red'); + }); + + it('returns no color if the value if lower than rangeMin and continuity is nor "below" or "all"', () => { + expect( + workoutColorForValue( + 0, + { + ...DEFAULT_PROPS, + rangeMin: 10, + rangeMax: 100, + stops: [20, 40, 60, 80], + }, + { min: 0, max: 200 } + ) + ).toBeUndefined(); + expect( + workoutColorForValue( + 0, + { + ...DEFAULT_PROPS, + continuity: 'none', + rangeMin: 10, + rangeMax: 100, + stops: [20, 40, 60, 80], + }, + { min: 0, max: 200 } + ) + ).toBeUndefined(); + }); + }); + + describe('range: "percent"', () => { + const DEFAULT_PROPS: CustomPaletteState = { + continuity: 'above', + colors: ['red', 'green', 'blue', 'yellow'], + range: 'percent', + gradient: false, + rangeMin: 0, + rangeMax: 100, + stops: [], + }; + it('find the right color for predefined palettes', () => { + expect(workoutColorForValue(123, DEFAULT_PROPS, { min: 0, max: 200 })).toBe('blue'); + }); + + it('find the right color for custom stops palettes', () => { + expect( + workoutColorForValue( + 113, + { + ...DEFAULT_PROPS, + stops: [20, 40, 60, 80], + }, + { min: 0, max: 200 } + ) + ).toBe('blue'); // 113/200 ~ 56% + }); + + it('find the right color for custom stops palettes when value is higher than rangeMax', () => { + expect( + workoutColorForValue( + 123, + { + ...DEFAULT_PROPS, + rangeMax: 90, + stops: [20, 40, 60, 80], + }, + { min: 0, max: 200 } + ) + ).toBe('yellow'); + expect( + workoutColorForValue( + 123, + { + ...DEFAULT_PROPS, + continuity: 'all', + rangeMax: 90, + stops: [20, 40, 60, 80], + }, + { min: 0, max: 200 } + ) + ).toBe('yellow'); + }); + + it('returns no color if the value if higher than rangeMax and continuity is nor "above" or "all"', () => { + expect( + workoutColorForValue( + 190, + { + ...DEFAULT_PROPS, + continuity: 'below', + rangeMax: 90, + stops: [20, 40, 60, 80], + }, + { min: 0, max: 200 } + ) + ).toBeUndefined(); + expect( + workoutColorForValue( + 190, + { + ...DEFAULT_PROPS, + continuity: 'none', + rangeMax: 90, + stops: [20, 40, 60, 80], + }, + { min: 0, max: 200 } + ) + ).toBeUndefined(); + }); + + it('find the right color for custom stops palettes when value is lower than rangeMin', () => { + expect( + workoutColorForValue( + 10, + { + ...DEFAULT_PROPS, + continuity: 'below', + rangeMin: 20, + rangeMax: 100, + stops: [20, 40, 60, 80], + }, + { min: 0, max: 200 } + ) + ).toBe('red'); + expect( + workoutColorForValue( + 10, + { + ...DEFAULT_PROPS, + continuity: 'all', + rangeMin: 20, + rangeMax: 100, + stops: [20, 40, 60, 80], + }, + { min: 0, max: 200 } + ) + ).toBe('red'); + }); + + it('returns no color if the value if lower than rangeMin and continuity is nor "below" or "all"', () => { + expect( + workoutColorForValue( + 0, + { + ...DEFAULT_PROPS, + continuity: 'above', + rangeMin: 10, + rangeMax: 100, + stops: [20, 40, 60, 80], + }, + { min: 0, max: 200 } + ) + ).toBeUndefined(); + expect( + workoutColorForValue( + 0, + { + ...DEFAULT_PROPS, + continuity: 'none', + rangeMin: 10, + rangeMax: 100, + stops: [20, 40, 60, 80], + }, + { min: 0, max: 200 } + ) + ).toBeUndefined(); + }); + }); +}); diff --git a/src/plugins/charts/public/services/palettes/helpers.ts b/src/plugins/charts/public/services/palettes/helpers.ts new file mode 100644 index 0000000000000..d4b1e98f94cc8 --- /dev/null +++ b/src/plugins/charts/public/services/palettes/helpers.ts @@ -0,0 +1,101 @@ +/* + * 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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { CustomPaletteState } from '../..'; + +function findColorSegment( + value: number, + comparison: (value: number, bucket: number) => number, + colors: string[], + rangeMin: number, + rangeMax: number +) { + // assume uniform distribution within the provided range, can ignore stops + const step = (rangeMax - rangeMin) / colors.length; + + // what about values in range + const index = colors.findIndex((c, i) => comparison(value, rangeMin + (1 + i) * step) <= 0); + return colors[index] || colors[0]; +} + +function findColorsByStops( + value: number, + comparison: (value: number, bucket: number) => number, + colors: string[], + stops: number[] +) { + const index = stops.findIndex((s) => comparison(value, s) < 0); + return colors[index] || colors[0]; +} + +function getNormalizedValueByRange( + value: number, + { range }: CustomPaletteState, + minMax: { min: number; max: number } +) { + let result = value; + if (range === 'percent') { + result = (100 * (value - minMax.min)) / (minMax.max - minMax.min); + } + // for a range of 1 value the formulas above will divide by 0, so here's a safety guard + if (Number.isNaN(result)) { + return 1; + } + return result; +} + +/** + * When stops are empty, it is assumed a predefined palette, so colors are distributed uniformly in the whole data range + * When stops are passed, then rangeMin/rangeMax are used as reference for user defined limits: + * continuity is defined over rangeMin/rangeMax, not these stops values (rangeMin/rangeMax are computed from user's stop inputs) + */ +export function workoutColorForValue( + value: number | undefined, + params: CustomPaletteState, + minMax: { min: number; max: number } +) { + if (value == null) { + return; + } + const { colors, stops, range = 'percent', continuity = 'above', rangeMax, rangeMin } = params; + // ranges can be absolute numbers or percentages + // normalized the incoming value to the same format as range to make easier comparisons + const normalizedValue = getNormalizedValueByRange(value, params, minMax); + const dataRangeArguments = range === 'percent' ? [0, 100] : [minMax.min, minMax.max]; + const comparisonFn = (v: number, threshold: number) => v - threshold; + + // if steps are defined consider the specific rangeMax/Min as data boundaries + const maxRange = stops.length ? rangeMax : dataRangeArguments[1]; + const minRange = stops.length ? rangeMin : dataRangeArguments[0]; + + // in case of shorter rangers, extends the steps on the sides to cover the whole set + if (comparisonFn(normalizedValue, maxRange) > 0) { + if (continuity === 'above' || continuity === 'all') { + return colors[colors.length - 1]; + } + return; + } + if (comparisonFn(normalizedValue, minRange) < 0) { + if (continuity === 'below' || continuity === 'all') { + return colors[0]; + } + return; + } + + if (stops.length) { + return findColorsByStops(normalizedValue, comparisonFn, colors, stops); + } + + return findColorSegment( + normalizedValue, + comparisonFn, + colors, + dataRangeArguments[0], + dataRangeArguments[1] + ); +} diff --git a/src/plugins/charts/public/services/palettes/mock.ts b/src/plugins/charts/public/services/palettes/mock.ts index 1c112ec800c92..e94f47477ab11 100644 --- a/src/plugins/charts/public/services/palettes/mock.ts +++ b/src/plugins/charts/public/services/palettes/mock.ts @@ -14,8 +14,8 @@ export const getPaletteRegistry = () => { const mockPalette1: jest.Mocked = { id: 'default', title: 'My Palette', - getColor: jest.fn((_: SeriesLayer[]) => 'black'), - getColors: jest.fn((num: number) => ['red', 'black']), + getCategoricalColor: jest.fn((_: SeriesLayer[]) => 'black'), + getCategoricalColors: jest.fn((num: number) => ['red', 'black']), toExpression: jest.fn(() => ({ type: 'expression', chain: [ @@ -33,8 +33,32 @@ export const getPaletteRegistry = () => { const mockPalette2: jest.Mocked = { id: 'mocked', title: 'Mocked Palette', - getColor: jest.fn((_: SeriesLayer[]) => 'blue'), - getColors: jest.fn((num: number) => ['blue', 'yellow']), + getCategoricalColor: jest.fn((_: SeriesLayer[]) => 'blue'), + getCategoricalColors: jest.fn((num: number) => ['blue', 'yellow']), + toExpression: jest.fn(() => ({ + type: 'expression', + chain: [ + { + type: 'function', + function: 'system_palette', + arguments: { + name: ['mocked'], + }, + }, + ], + })), + }; + + const mockPalette3: jest.Mocked = { + id: 'custom', + title: 'Custom Mocked Palette', + getCategoricalColor: jest.fn((_: SeriesLayer[]) => 'blue'), + getCategoricalColors: jest.fn((num: number) => ['blue', 'yellow']), + getColorForValue: jest.fn( + (num: number | undefined, state: unknown, minMax: { min: number; max: number }) => + num == null || num < 1 ? undefined : 'blue' + ), + canDynamicColoring: true, toExpression: jest.fn(() => ({ type: 'expression', chain: [ @@ -50,8 +74,9 @@ export const getPaletteRegistry = () => { }; return { - get: (name: string) => (name !== 'default' ? mockPalette2 : mockPalette1), - getAll: () => [mockPalette1, mockPalette2], + get: (name: string) => + name === 'custom' ? mockPalette3 : name !== 'default' ? mockPalette2 : mockPalette1, + getAll: () => [mockPalette1, mockPalette2, mockPalette3], }; }; diff --git a/src/plugins/charts/public/services/palettes/palettes.test.tsx b/src/plugins/charts/public/services/palettes/palettes.test.tsx index 8f495df7f882a..8cb477b0e0838 100644 --- a/src/plugins/charts/public/services/palettes/palettes.test.tsx +++ b/src/plugins/charts/public/services/palettes/palettes.test.tsx @@ -19,14 +19,14 @@ describe('palettes', () => { it('should return different colors based on behind text flag', () => { const palette = palettes.default; - const color1 = palette.getColor([ + const color1 = palette.getCategoricalColor([ { name: 'abc', rankAtDepth: 0, totalSeriesAtDepth: 5, }, ]); - const color2 = palette.getColor( + const color2 = palette.getCategoricalColor( [ { name: 'abc', @@ -44,14 +44,14 @@ describe('palettes', () => { it('should return different colors based on rank at current series', () => { const palette = palettes.default; - const color1 = palette.getColor([ + const color1 = palette.getCategoricalColor([ { name: 'abc', rankAtDepth: 0, totalSeriesAtDepth: 5, }, ]); - const color2 = palette.getColor([ + const color2 = palette.getCategoricalColor([ { name: 'abc', rankAtDepth: 1, @@ -64,7 +64,7 @@ describe('palettes', () => { it('should return the same color for different positions on outer series layers', () => { const palette = palettes.default; - const color1 = palette.getColor([ + const color1 = palette.getCategoricalColor([ { name: 'abc', rankAtDepth: 0, @@ -76,7 +76,7 @@ describe('palettes', () => { totalSeriesAtDepth: 2, }, ]); - const color2 = palette.getColor([ + const color2 = palette.getCategoricalColor([ { name: 'abc', rankAtDepth: 0, @@ -96,7 +96,7 @@ describe('palettes', () => { it('should return different colors based on behind text flag', () => { const palette = palettes.default; - const color1 = palette.getColor( + const color1 = palette.getCategoricalColor( [ { name: 'abc', @@ -108,7 +108,7 @@ describe('palettes', () => { syncColors: true, } ); - const color2 = palette.getColor( + const color2 = palette.getCategoricalColor( [ { name: 'abc', @@ -127,7 +127,7 @@ describe('palettes', () => { it('should return different colors for different keys', () => { const palette = palettes.default; - const color1 = palette.getColor( + const color1 = palette.getCategoricalColor( [ { name: 'abc', @@ -139,7 +139,7 @@ describe('palettes', () => { syncColors: true, } ); - const color2 = palette.getColor( + const color2 = palette.getCategoricalColor( [ { name: 'def', @@ -157,7 +157,7 @@ describe('palettes', () => { it('should return the same color for the same key, irregardless of rank', () => { const palette = palettes.default; - const color1 = palette.getColor( + const color1 = palette.getCategoricalColor( [ { name: 'hij', @@ -169,7 +169,7 @@ describe('palettes', () => { syncColors: true, } ); - const color2 = palette.getColor( + const color2 = palette.getCategoricalColor( [ { name: 'hij', @@ -187,7 +187,7 @@ describe('palettes', () => { it('should return the same color for different positions on outer series layers', () => { const palette = palettes.default; - const color1 = palette.getColor( + const color1 = palette.getCategoricalColor( [ { name: 'klm', @@ -204,7 +204,7 @@ describe('palettes', () => { syncColors: true, } ); - const color2 = palette.getColor( + const color2 = palette.getCategoricalColor( [ { name: 'klm', @@ -227,7 +227,7 @@ describe('palettes', () => { it('should return the same index of the behind text palette for same key', () => { const palette = palettes.default; - const color1 = palette.getColor( + const color1 = palette.getCategoricalColor( [ { name: 'klm', @@ -244,7 +244,7 @@ describe('palettes', () => { syncColors: true, } ); - const color2 = palette.getColor( + const color2 = palette.getCategoricalColor( [ { name: 'klm', @@ -273,15 +273,15 @@ describe('palettes', () => { const palette = palettes.warm; it('should use the whole gradient', () => { - const wholePalette = palette.getColors(10); - const color1 = palette.getColor([ + const wholePalette = palette.getCategoricalColors(10); + const color1 = palette.getCategoricalColor([ { name: 'abc', rankAtDepth: 0, totalSeriesAtDepth: 10, }, ]); - const color2 = palette.getColor([ + const color2 = palette.getCategoricalColor([ { name: 'def', rankAtDepth: 9, @@ -304,7 +304,7 @@ describe('palettes', () => { describe('syncColors: false', () => { it('should not query legacy color service', () => { - palette.getColor( + palette.getCategoricalColor( [ { name: 'abc', @@ -323,7 +323,7 @@ describe('palettes', () => { it('should respect the advanced settings color mapping', () => { const configColorGetter = colorsServiceMock.mappedColors.getColorFromConfig as jest.Mock; configColorGetter.mockImplementation(() => 'blue'); - const result = palette.getColor( + const result = palette.getCategoricalColor( [ { name: 'abc', @@ -345,7 +345,7 @@ describe('palettes', () => { }); it('should return a color from the legacy palette based on position of first series', () => { - const result = palette.getColor( + const result = palette.getCategoricalColor( [ { name: 'abc', @@ -368,7 +368,7 @@ describe('palettes', () => { describe('syncColors: true', () => { it('should query legacy color service', () => { - palette.getColor( + palette.getCategoricalColor( [ { name: 'abc', @@ -387,7 +387,7 @@ describe('palettes', () => { it('should respect the advanced settings color mapping', () => { const configColorGetter = colorsServiceMock.mappedColors.getColorFromConfig as jest.Mock; configColorGetter.mockImplementation(() => 'blue'); - const result = palette.getColor( + const result = palette.getCategoricalColor( [ { name: 'abc', @@ -409,7 +409,7 @@ describe('palettes', () => { }); it('should always use root series', () => { - palette.getColor( + palette.getCategoricalColor( [ { name: 'abc', @@ -437,7 +437,7 @@ describe('palettes', () => { describe('custom palette', () => { const palette = palettes.custom; it('should return different colors based on rank at current series', () => { - const color1 = palette.getColor( + const color1 = palette.getCategoricalColor( [ { name: 'abc', @@ -450,7 +450,7 @@ describe('palettes', () => { colors: ['#00ff00', '#000000'], } ); - const color2 = palette.getColor( + const color2 = palette.getCategoricalColor( [ { name: 'abc', @@ -467,7 +467,7 @@ describe('palettes', () => { }); it('should return the same color for different positions on outer series layers', () => { - const color1 = palette.getColor( + const color1 = palette.getCategoricalColor( [ { name: 'abc', @@ -485,7 +485,7 @@ describe('palettes', () => { colors: ['#00ff00', '#000000'], } ); - const color2 = palette.getColor( + const color2 = palette.getCategoricalColor( [ { name: 'abc', @@ -507,7 +507,7 @@ describe('palettes', () => { }); it('should use passed in colors', () => { - const color = palette.getColor( + const color = palette.getCategoricalColor( [ { name: 'abc', @@ -523,5 +523,56 @@ describe('palettes', () => { ); expect(color).toEqual('#00ff00'); }); + + // just an integration test here. More in depth tests on the subject can be found on the helper file + it('should return a color for the given value with its domain', () => { + expect( + palette.getColorForValue!( + 0, + { colors: ['red', 'green', 'blue'], stops: [], gradient: false }, + { min: 0, max: 100 } + ) + ).toBe('red'); + }); + + it('should return a color for the given value with its domain based on custom stops', () => { + expect( + palette.getColorForValue!( + 60, + { + colors: ['red', 'green', 'blue'], + stops: [10, 50, 100], + range: 'percent', + gradient: false, + rangeMin: 0, + rangeMax: 100, + }, + { min: 0, max: 100 } + ) + ).toBe('blue'); + }); + + // just make sure to not have broken anything + it('should work with only legacy arguments, filling with default values the new ones', () => { + expect(palette.toExpression({ colors: [], gradient: false })).toEqual({ + type: 'expression', + chain: [ + { + type: 'function', + function: 'palette', + arguments: { + color: [], + gradient: [false], + reverse: [false], + continuity: ['above'], + stop: [], + range: ['percent'], + rangeMax: [], + rangeMin: [], + }, + }, + ], + }); + }); }); }); diff --git a/src/plugins/charts/public/services/palettes/palettes.tsx b/src/plugins/charts/public/services/palettes/palettes.tsx index b11d598c1c1cb..65e3f9a84203d 100644 --- a/src/plugins/charts/public/services/palettes/palettes.tsx +++ b/src/plugins/charts/public/services/palettes/palettes.tsx @@ -30,6 +30,7 @@ import { lightenColor } from './lighten_color'; import { ChartColorConfiguration, PaletteDefinition, SeriesLayer } from './types'; import { LegacyColorsService } from '../legacy_colors'; import { MappedColors } from '../mapped_colors'; +import { workoutColorForValue } from './helpers'; function buildRoundRobinCategoricalWithMappedColors(): Omit { const colors = euiPaletteColorBlind({ rotations: 2 }); @@ -64,8 +65,8 @@ function buildRoundRobinCategoricalWithMappedColors(): Omit euiPaletteColorBlind(), + getCategoricalColor: getColor, + getCategoricalColors: () => euiPaletteColorBlind(), toExpression: () => ({ type: 'expression', chain: [ @@ -102,8 +103,9 @@ function buildGradient( } return { id, - getColor, - getColors: colors, + getCategoricalColor: getColor, + getCategoricalColors: colors, + canDynamicColoring: true, toExpression: () => ({ type: 'expression', chain: [ @@ -141,8 +143,8 @@ function buildSyncedKibanaPalette( } return { id: 'kibana_palette', - getColor, - getColors: () => colors.seedColors.slice(0, 10), + getCategoricalColor: getColor, + getCategoricalColors: () => colors.seedColors.slice(0, 10), toExpression: () => ({ type: 'expression', chain: [ @@ -161,7 +163,24 @@ function buildSyncedKibanaPalette( function buildCustomPalette(): PaletteDefinition { return { id: 'custom', - getColor: ( + getColorForValue: ( + value, + params: { + colors: string[]; + range: 'number' | 'percent'; + continuity: 'above' | 'below' | 'none' | 'all'; + gradient: boolean; + /** Stops values mark where colors end (non-inclusive value) */ + stops: number[]; + /** Important: specify rangeMin/rangeMax if custom stops are defined! */ + rangeMax: number; + rangeMin: number; + }, + dataBounds + ) => { + return workoutColorForValue(value, params, dataBounds); + }, + getCategoricalColor: ( series: SeriesLayer[], chartConfiguration: ChartColorConfiguration = { behindText: false }, { colors, gradient }: { colors: string[]; gradient: boolean } @@ -179,10 +198,48 @@ function buildCustomPalette(): PaletteDefinition { }, internal: true, title: i18n.translate('charts.palettes.customLabel', { defaultMessage: 'Custom' }), - getColors: (size: number, { colors, gradient }: { colors: string[]; gradient: boolean }) => { + getCategoricalColors: ( + size: number, + { + colors, + gradient, + stepped, + stops, + }: { colors: string[]; gradient: boolean; stepped: boolean; stops: number[] } = { + colors: [], + gradient: false, + stepped: false, + stops: [], + } + ) => { + if (stepped) { + const range = stops[stops.length - 1] - stops[0]; + const offset = stops[0]; + const finalStops = [...stops.map((stop) => (stop - offset) / range)]; + return chroma.scale(colors).domain(finalStops).colors(size); + } return gradient ? chroma.scale(colors).colors(size) : colors; }, - toExpression: ({ colors, gradient }: { colors: string[]; gradient: boolean }) => ({ + canDynamicColoring: false, + toExpression: ({ + colors, + gradient, + stops = [], + rangeMax, + rangeMin, + rangeType = 'percent', + continuity = 'above', + reverse = false, + }: { + colors: string[]; + gradient: boolean; + stops: number[]; + rangeMax?: number; + rangeMin?: number; + rangeType: 'percent' | 'number'; + continuity?: 'all' | 'none' | 'above' | 'below'; + reverse?: boolean; + }) => ({ type: 'expression', chain: [ { @@ -191,6 +248,12 @@ function buildCustomPalette(): PaletteDefinition { arguments: { color: colors, gradient: [gradient], + reverse: [reverse], + continuity: [continuity], + stop: stops, + range: [rangeType], + rangeMax: rangeMax == null ? [] : [rangeMax], + rangeMin: rangeMin == null ? [] : [rangeMin], }, }, ], diff --git a/src/plugins/charts/public/services/palettes/types.ts b/src/plugins/charts/public/services/palettes/types.ts index 3d2a6b032f63e..6f13f62178364 100644 --- a/src/plugins/charts/public/services/palettes/types.ts +++ b/src/plugins/charts/public/services/palettes/types.ts @@ -79,22 +79,12 @@ export interface PaletteDefinition { * @param state The internal state of the palette */ toExpression: (state?: T) => Ast; - /** - * Renders the UI for editing the internal state of the palette. - * Not each palette has to feature an internal state, so this is an optional property. - * @param domElement The dom element to the render the editor UI into - * @param props Current state and state setter to issue updates - */ - renderEditor?: ( - domElement: Element, - props: { state?: T; setState: (updater: (oldState: T) => T) => void } - ) => void; /** * Color a series according to the internal rules of the palette. * @param series The current series along with its ancestors. * @param state The internal state of the palette */ - getColor: ( + getCategoricalColor: ( series: SeriesLayer[], chartConfiguration?: ChartColorConfiguration, state?: T @@ -103,7 +93,20 @@ export interface PaletteDefinition { * Get a spectrum of colors of the current palette. * This can be used if the chart wants to control color assignment locally. */ - getColors: (size: number, state?: T) => string[]; + getCategoricalColors: (size: number, state?: T) => string[]; + /** + * Define whether a palette supports dynamic coloring (i.e. gradient colors mapped to number values) + */ + canDynamicColoring?: boolean; + /** + * Get the assigned color for the given value based on its data domain and state settings. + * This can be used for dynamic coloring based on uniform color distribution or custom stops. + */ + getColorForValue?: ( + value: number | undefined, + state: T, + { min, max }: { min: number; max: number } + ) => string | undefined; } export interface PaletteRegistry { diff --git a/src/plugins/vis_default_editor/public/components/controls/palette_picker.tsx b/src/plugins/vis_default_editor/public/components/controls/palette_picker.tsx index b09a806e8fc25..9249edef8af92 100644 --- a/src/plugins/vis_default_editor/public/components/controls/palette_picker.tsx +++ b/src/plugins/vis_default_editor/public/components/controls/palette_picker.tsx @@ -39,12 +39,12 @@ export function PalettePicker({ palettes={palettes .getAll() .filter(({ internal }) => !internal) - .map(({ id, title, getColors }) => { + .map(({ id, title, getCategoricalColors }) => { return { value: id, title, type: 'fixed', - palette: getColors( + palette: getCategoricalColors( 10, id === activePalette?.name ? activePalette?.params : undefined ), diff --git a/src/plugins/vis_type_timeseries/public/application/components/palette_picker.tsx b/src/plugins/vis_type_timeseries/public/application/components/palette_picker.tsx index 20c0b40bb2e54..749d6ca62bfa9 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/palette_picker.tsx +++ b/src/plugins/vis_type_timeseries/public/application/components/palette_picker.tsx @@ -33,12 +33,12 @@ export function PalettePicker({ activePalette, palettes, setPalette, color }: Pa ...palettes .getAll() .filter(({ internal }) => !internal) - .map(({ id, title, getColors }) => { + .map(({ id, title, getCategoricalColors }) => { return { value: id, title, type: 'fixed' as const, - palette: getColors(10), + palette: getCategoricalColors(10), }; }), { @@ -49,7 +49,7 @@ export function PalettePicker({ activePalette, palettes, setPalette, color }: Pa type: 'fixed', palette: palettes .get('custom') - .getColors(10, { colors: [color, finalGradientColor], gradient: true }), + .getCategoricalColors(10, { colors: [color, finalGradientColor], gradient: true }), }, { value: PALETTES.RAINBOW, @@ -59,7 +59,7 @@ export function PalettePicker({ activePalette, palettes, setPalette, color }: Pa type: 'fixed', palette: palettes .get('custom') - .getColors(10, { colors: rainbowColors.slice(0, 10), gradient: false }), + .getCategoricalColors(10, { colors: rainbowColors.slice(0, 10), gradient: false }), }, ]} onChange={(newPalette) => { diff --git a/src/plugins/vis_type_timeseries/public/application/lib/get_split_by_terms_color.ts b/src/plugins/vis_type_timeseries/public/application/lib/get_split_by_terms_color.ts index adcf1f3ad63cd..028ce3d028997 100644 --- a/src/plugins/vis_type_timeseries/public/application/lib/get_split_by_terms_color.ts +++ b/src/plugins/vis_type_timeseries/public/application/lib/get_split_by_terms_color.ts @@ -58,7 +58,7 @@ export const getSplitByTermsColor = ({ } : seriesPalette.params; - const outputColor = palettesRegistry?.get(paletteName || 'default').getColor( + const outputColor = palettesRegistry?.get(paletteName || 'default').getCategoricalColor( [ { name: seriesName || emptyLabel, diff --git a/src/plugins/vis_type_xy/public/vis_component.tsx b/src/plugins/vis_type_xy/public/vis_component.tsx index 5da5ffcc637c6..dd88822f7f0f3 100644 --- a/src/plugins/vis_type_xy/public/vis_component.tsx +++ b/src/plugins/vis_type_xy/public/vis_component.tsx @@ -245,7 +245,7 @@ const VisComponent = (props: VisComponentProps) => { if (Object.keys(overwriteColors).includes(seriesName)) { return overwriteColors[seriesName]; } - const outputColor = palettesRegistry?.get(visParams.palette.name).getColor( + const outputColor = palettesRegistry?.get(visParams.palette.name).getCategoricalColor( [ { name: seriesName, diff --git a/x-pack/plugins/canvas/public/functions/pie.test.js b/x-pack/plugins/canvas/public/functions/pie.test.js index 915d8525079db..b1c1746340892 100644 --- a/x-pack/plugins/canvas/public/functions/pie.test.js +++ b/x-pack/plugins/canvas/public/functions/pie.test.js @@ -18,7 +18,7 @@ describe('pie', () => { const fn = functionWrapper( pieFunctionFactory({ get: () => ({ - getColors: () => ['red', 'black'], + getCategoricalColors: () => ['red', 'black'], }), }) ); @@ -59,7 +59,7 @@ describe('pie', () => { const mockedFn = functionWrapper( pieFunctionFactory({ get: () => ({ - getColors: mockedColors, + getCategoricalColors: mockedColors, }), }) ); diff --git a/x-pack/plugins/canvas/public/functions/pie.ts b/x-pack/plugins/canvas/public/functions/pie.ts index 0840667302ebe..a91dc16b770c9 100644 --- a/x-pack/plugins/canvas/public/functions/pie.ts +++ b/x-pack/plugins/canvas/public/functions/pie.ts @@ -173,7 +173,7 @@ export function pieFunctionFactory( canvas: false, colors: paletteService .get(palette.name || 'custom') - .getColors(data.length, palette.params), + .getCategoricalColors(data.length, palette.params), legend: getLegendConfig(legend, data.length), grid: { show: false, diff --git a/x-pack/plugins/canvas/public/functions/plot.test.js b/x-pack/plugins/canvas/public/functions/plot.test.js index 849752d2c984b..5ed858961d798 100644 --- a/x-pack/plugins/canvas/public/functions/plot.test.js +++ b/x-pack/plugins/canvas/public/functions/plot.test.js @@ -21,7 +21,7 @@ describe('plot', () => { const fn = functionWrapper( plotFunctionFactory({ get: () => ({ - getColors: () => ['red', 'black'], + getCategoricalColors: () => ['red', 'black'], }), }) ); @@ -121,7 +121,7 @@ describe('plot', () => { const mockedFn = functionWrapper( plotFunctionFactory({ get: () => ({ - getColors: mockedColors, + getCategoricalColors: mockedColors, }), }) ); diff --git a/x-pack/plugins/canvas/public/functions/plot/index.ts b/x-pack/plugins/canvas/public/functions/plot/index.ts index c0c73c3a21bc6..477c704190146 100644 --- a/x-pack/plugins/canvas/public/functions/plot/index.ts +++ b/x-pack/plugins/canvas/public/functions/plot/index.ts @@ -144,7 +144,7 @@ export function plotFunctionFactory( canvas: false, colors: paletteService .get(args.palette.name || 'custom') - .getColors(data.length, args.palette.params), + .getCategoricalColors(data.length, args.palette.params), legend: getLegendConfig(args.legend, data.length), grid: gridConfig, xaxis: getFlotAxisConfig('x', args.xaxis, { diff --git a/x-pack/plugins/lens/public/datatable_visualization/components/__snapshots__/table_basic.test.tsx.snap b/x-pack/plugins/lens/public/datatable_visualization/components/__snapshots__/table_basic.test.tsx.snap index afc69c2e8861f..a4be46f61990b 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/components/__snapshots__/table_basic.test.tsx.snap +++ b/x-pack/plugins/lens/public/datatable_visualization/components/__snapshots__/table_basic.test.tsx.snap @@ -13,6 +13,13 @@ exports[`DatatableComponent it renders actions column when there are row actions "b": "left", "c": "right", }, + "getColorForValue": [MockFunction], + "minMaxByColumnId": Object { + "c": Object { + "max": 3, + "min": 3, + }, + }, "rowHasRowClickTriggerActions": Array [ true, true, @@ -244,6 +251,13 @@ exports[`DatatableComponent it renders the title and value 1`] = ` "b": "left", "c": "right", }, + "getColorForValue": [MockFunction], + "minMaxByColumnId": Object { + "c": Object { + "max": 3, + "min": 3, + }, + }, "rowHasRowClickTriggerActions": undefined, "table": Object { "columns": Array [ @@ -462,6 +476,13 @@ exports[`DatatableComponent it should not render actions on header when it is in "b": "left", "c": "right", }, + "getColorForValue": [MockFunction], + "minMaxByColumnId": Object { + "c": Object { + "max": 3, + "min": 3, + }, + }, "rowHasRowClickTriggerActions": Array [ false, false, diff --git a/x-pack/plugins/lens/public/datatable_visualization/components/cell_value.test.tsx b/x-pack/plugins/lens/public/datatable_visualization/components/cell_value.test.tsx index 9bc982ebd9944..67255dc8a953e 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/components/cell_value.test.tsx +++ b/x-pack/plugins/lens/public/datatable_visualization/components/cell_value.test.tsx @@ -11,6 +11,12 @@ import { DataContext } from './table_basic'; import { createGridCell } from './cell_value'; import { FieldFormat } from 'src/plugins/data/public'; import { Datatable } from 'src/plugins/expressions/public'; +import { IUiSettingsClient } from 'kibana/public'; +import { act } from 'react-dom/test-utils'; +import { ReactWrapper } from 'enzyme'; +import { Args, ColumnConfigArg } from '../expression'; +import { DataContextType } from './types'; +import { chartPluginMock } from 'src/plugins/charts/public/mocks'; describe('datatable cell renderer', () => { const table: Datatable = { @@ -30,7 +36,9 @@ describe('datatable cell renderer', () => { { a: { convert: (x) => `formatted ${x}` } as FieldFormat, }, - DataContext + { columns: [], sortingColumnId: '', sortingDirection: 'none' }, + DataContext, + ({ get: jest.fn() } as unknown) as IUiSettingsClient ); it('renders formatted value', () => { @@ -78,4 +86,111 @@ describe('datatable cell renderer', () => { ); expect(cell.find('.lnsTableCell').prop('className')).toContain('--right'); }); + + describe('dynamic coloring', () => { + const paletteRegistry = chartPluginMock.createPaletteRegistry(); + const customPalette = paletteRegistry.get('custom'); + + function getCellRenderer(columnConfig: Args) { + return createGridCell( + { + a: { convert: (x) => `formatted ${x}` } as FieldFormat, + }, + columnConfig, + DataContext, + ({ get: jest.fn() } as unknown) as IUiSettingsClient + ); + } + function getColumnConfiguration(): Args { + return { + title: 'myData', + columns: [ + { + columnId: 'a', + colorMode: 'none', + palette: { + type: 'palette', + name: 'custom', + params: { + colors: ['#aaa', '#bbb', '#ccc', '#ddd', '#eee'], + gradient: false, + stops: [20, 40, 60, 80, 100], + range: 'percent', + rangeMin: 0, + rangeMax: 100, + }, + }, + type: 'lens_datatable_column', + } as ColumnConfigArg, + ], + sortingColumnId: '', + sortingDirection: 'none', + }; + } + + function flushEffect(component: ReactWrapper) { + return act(async () => { + await component; + await new Promise((r) => setImmediate(r)); + component.update(); + }); + } + + async function renderCellComponent(columnConfig: Args, context: Partial = {}) { + const CellRendererWithPalette = getCellRenderer(columnConfig); + const setCellProps = jest.fn(); + + const cell = mountWithIntl( + 123 */ } }, + getColorForValue: customPalette.getColorForValue, + ...context, + }} + > + + + ); + + await flushEffect(cell); + + return { setCellProps, cell }; + } + + it('ignores coloring when colorMode is set to "none"', async () => { + const { setCellProps } = await renderCellComponent(getColumnConfiguration()); + + expect(setCellProps).not.toHaveBeenCalled(); + }); + + it('should set the coloring of the cell when enabled', async () => { + const columnConfig = getColumnConfiguration(); + columnConfig.columns[0].colorMode = 'cell'; + + const { setCellProps } = await renderCellComponent(columnConfig, {}); + + expect(setCellProps).toHaveBeenCalledWith({ + style: expect.objectContaining({ backgroundColor: 'blue' }), + }); + }); + + it('should set the coloring of the text when enabled', async () => { + const columnConfig = getColumnConfiguration(); + columnConfig.columns[0].colorMode = 'text'; + + const { setCellProps } = await renderCellComponent(columnConfig, {}); + + expect(setCellProps).toHaveBeenCalledWith({ + style: expect.objectContaining({ color: 'blue' }), + }); + }); + }); }); diff --git a/x-pack/plugins/lens/public/datatable_visualization/components/cell_value.tsx b/x-pack/plugins/lens/public/datatable_visualization/components/cell_value.tsx index 2261dd06b532b..a6c50f00cb77f 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/components/cell_value.tsx +++ b/x-pack/plugins/lens/public/datatable_visualization/components/cell_value.tsx @@ -5,30 +5,74 @@ * 2.0. */ -import React, { useContext } from 'react'; +import React, { useContext, useEffect } from 'react'; import { EuiDataGridCellValueElementProps } from '@elastic/eui'; +import { IUiSettingsClient } from 'kibana/public'; import type { FormatFactory } from '../../types'; import type { DataContextType } from './types'; +import { ColumnConfig } from './table_basic'; +import { getContrastColor } from '../../shared_components/coloring/utils'; +import { getOriginalId } from '../transpose_helpers'; export const createGridCell = ( formatters: Record>, - DataContext: React.Context -) => ({ rowIndex, columnId }: EuiDataGridCellValueElementProps) => { - const { table, alignments } = useContext(DataContext); - const rowValue = table?.rows[rowIndex][columnId]; - const content = formatters[columnId]?.convert(rowValue, 'html'); - const currentAlignment = alignments && alignments[columnId]; - const alignmentClassName = `lnsTableCell--${currentAlignment}`; + columnConfig: ColumnConfig, + DataContext: React.Context, + uiSettings: IUiSettingsClient +) => { + // Changing theme requires a full reload of the page, so we can cache here + const IS_DARK_THEME = uiSettings.get('theme:darkMode'); + return ({ rowIndex, columnId, setCellProps }: EuiDataGridCellValueElementProps) => { + const { table, alignments, minMaxByColumnId, getColorForValue } = useContext(DataContext); + const rowValue = table?.rows[rowIndex][columnId]; + const content = formatters[columnId]?.convert(rowValue, 'html'); + const currentAlignment = alignments && alignments[columnId]; + const alignmentClassName = `lnsTableCell--${currentAlignment}`; - return ( -
    - ); + const { colorMode, palette } = + columnConfig.columns.find(({ columnId: id }) => id === columnId) || {}; + + useEffect(() => { + const originalId = getOriginalId(columnId); + if (minMaxByColumnId?.[originalId]) { + if (colorMode !== 'none' && palette?.params && getColorForValue) { + // workout the bucket the value belongs to + const color = getColorForValue(rowValue, palette.params, minMaxByColumnId[originalId]); + if (color) { + const style = { [colorMode === 'cell' ? 'backgroundColor' : 'color']: color }; + if (colorMode === 'cell' && color) { + style.color = getContrastColor(color, IS_DARK_THEME); + } + setCellProps({ + style, + }); + } + } + } + // make sure to clean it up when something change + // this avoids cell's styling to stick forever + return () => { + if (minMaxByColumnId?.[originalId]) { + setCellProps({ + style: { + backgroundColor: undefined, + color: undefined, + }, + }); + } + }; + }, [rowValue, columnId, setCellProps, colorMode, palette, minMaxByColumnId, getColorForValue]); + + return ( +
    + ); + }; }; diff --git a/x-pack/plugins/lens/public/datatable_visualization/components/dimension_editor.scss b/x-pack/plugins/lens/public/datatable_visualization/components/dimension_editor.scss new file mode 100644 index 0000000000000..504adb05e57d7 --- /dev/null +++ b/x-pack/plugins/lens/public/datatable_visualization/components/dimension_editor.scss @@ -0,0 +1,7 @@ +.lnsDynamicColoringRow { + align-items: center; +} + +.lnsDynamicColoringClickable { + cursor: pointer; +} \ No newline at end of file diff --git a/x-pack/plugins/lens/public/datatable_visualization/components/dimension_editor.test.tsx b/x-pack/plugins/lens/public/datatable_visualization/components/dimension_editor.test.tsx index e0d31a3ed0201..88948e9a7615b 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/components/dimension_editor.test.tsx +++ b/x-pack/plugins/lens/public/datatable_visualization/components/dimension_editor.test.tsx @@ -12,12 +12,18 @@ import { DatatableVisualizationState } from '../visualization'; import { createMockDatasource, createMockFramePublicAPI } from '../../editor_frame_service/mocks'; import { mountWithIntl } from '@kbn/test/jest'; import { TableDimensionEditor } from './dimension_editor'; +import { chartPluginMock } from 'src/plugins/charts/public/mocks'; +import { PaletteRegistry } from 'src/plugins/charts/public'; +import { PalettePanelContainer } from './palette_panel_container'; +import { act } from 'react-dom/test-utils'; describe('data table dimension editor', () => { let frame: FramePublicAPI; let state: DatatableVisualizationState; let setState: (newState: DatatableVisualizationState) => void; - let props: VisualizationDimensionEditorProps; + let props: VisualizationDimensionEditorProps & { + paletteService: PaletteRegistry; + }; function testState(): DatatableVisualizationState { return { @@ -59,6 +65,8 @@ describe('data table dimension editor', () => { layerId: 'first', state, setState, + paletteService: chartPluginMock.createPaletteRegistry(), + panelRef: React.createRef(), }; }); @@ -72,17 +80,23 @@ describe('data table dimension editor', () => { it('should render default alignment for number', () => { frame.activeData!.first.columns[0].meta.type = 'number'; const instance = mountWithIntl(); - expect(instance.find(EuiButtonGroup).prop('idSelected')).toEqual( - expect.stringContaining('right') - ); + expect( + instance + .find('[data-test-subj="lnsDatatable_alignment_groups"]') + .find(EuiButtonGroup) + .prop('idSelected') + ).toEqual(expect.stringContaining('right')); }); it('should render specific alignment', () => { state.columns[0].alignment = 'center'; const instance = mountWithIntl(); - expect(instance.find(EuiButtonGroup).prop('idSelected')).toEqual( - expect.stringContaining('center') - ); + expect( + instance + .find('[data-test-subj="lnsDatatable_alignment_groups"]') + .find(EuiButtonGroup) + .prop('idSelected') + ).toEqual(expect.stringContaining('center')); }); it('should set state for the right column', () => { @@ -95,7 +109,10 @@ describe('data table dimension editor', () => { }, ]; const instance = mountWithIntl(); - instance.find(EuiButtonGroup).prop('onChange')('center'); + instance + .find('[data-test-subj="lnsDatatable_alignment_groups"]') + .find(EuiButtonGroup) + .prop('onChange')('center'); expect(setState).toHaveBeenCalledWith({ ...state, columns: [ @@ -109,4 +126,90 @@ describe('data table dimension editor', () => { ], }); }); + + it('should not show the dynamic coloring option for non numeric columns', () => { + const instance = mountWithIntl(); + expect(instance.find('[data-test-subj="lnsDatatable_dynamicColoring_groups"]').exists()).toBe( + false + ); + expect(instance.find('[data-test-subj="lnsDatatable_dynamicColoring_palette"]').exists()).toBe( + false + ); + }); + + it('should set the dynamic coloring default to "none"', () => { + frame.activeData!.first.columns[0].meta.type = 'number'; + const instance = mountWithIntl(); + expect( + instance + .find('[data-test-subj="lnsDatatable_dynamicColoring_groups"]') + .find(EuiButtonGroup) + .prop('idSelected') + ).toEqual(expect.stringContaining('none')); + + expect(instance.find('[data-test-subj="lnsDatatable_dynamicColoring_palette"]').exists()).toBe( + false + ); + }); + + it('should show the dynamic palette display ony when colorMode is different from "none"', () => { + frame.activeData!.first.columns[0].meta.type = 'number'; + state.columns[0].colorMode = 'text'; + const instance = mountWithIntl(); + expect( + instance + .find('[data-test-subj="lnsDatatable_dynamicColoring_groups"]') + .find(EuiButtonGroup) + .prop('idSelected') + ).toEqual(expect.stringContaining('text')); + + expect(instance.find('[data-test-subj="lnsDatatable_dynamicColoring_palette"]').exists()).toBe( + true + ); + }); + + it('should set the coloring mode to the right column', () => { + frame.activeData!.first.columns[0].meta.type = 'number'; + state.columns = [ + { + columnId: 'foo', + }, + { + columnId: 'bar', + }, + ]; + const instance = mountWithIntl(); + instance + .find('[data-test-subj="lnsDatatable_dynamicColoring_groups"]') + .find(EuiButtonGroup) + .prop('onChange')('cell'); + expect(setState).toHaveBeenCalledWith({ + ...state, + columns: [ + { + columnId: 'foo', + colorMode: 'cell', + palette: expect.objectContaining({ type: 'palette' }), + }, + { + columnId: 'bar', + }, + ], + }); + }); + + it('should open the palette panel when "Settings" link is clicked in the palette input', () => { + frame.activeData!.first.columns[0].meta.type = 'number'; + state.columns[0].colorMode = 'cell'; + const instance = mountWithIntl(); + + act(() => + (instance + .find('[data-test-subj="lnsDatatable_dynamicColoring_trigger"]') + .first() + .prop('onClick') as () => void)?.() + ); + + expect(instance.find(PalettePanelContainer).exists()).toBe(true); + }); }); diff --git a/x-pack/plugins/lens/public/datatable_visualization/components/dimension_editor.tsx b/x-pack/plugins/lens/public/datatable_visualization/components/dimension_editor.tsx index a750744811790..76c47a9c743c5 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/components/dimension_editor.tsx +++ b/x-pack/plugins/lens/public/datatable_visualization/components/dimension_editor.tsx @@ -5,36 +5,91 @@ * 2.0. */ -import React from 'react'; +import React, { useState } from 'react'; import { i18n } from '@kbn/i18n'; -import { EuiFormRow, EuiSwitch, EuiButtonGroup, htmlIdGenerator } from '@elastic/eui'; +import { + EuiFormRow, + EuiSwitch, + EuiButtonGroup, + htmlIdGenerator, + EuiColorPaletteDisplay, + EuiFlexItem, + EuiFlexGroup, + EuiButtonEmpty, +} from '@elastic/eui'; +import { PaletteRegistry } from 'src/plugins/charts/public'; import { VisualizationDimensionEditorProps } from '../../types'; import { DatatableVisualizationState } from '../visualization'; import { getOriginalId } from '../transpose_helpers'; +import { + CustomizablePalette, + applyPaletteParams, + defaultPaletteParams, + FIXED_PROGRESSION, + getStopsForFixedMode, +} from '../../shared_components/'; +import { PalettePanelContainer } from './palette_panel_container'; +import { findMinMaxByColumnId } from './shared_utils'; +import './dimension_editor.scss'; const idPrefix = htmlIdGenerator()(); +type ColumnType = DatatableVisualizationState['columns'][number]; + +function updateColumnWith( + state: DatatableVisualizationState, + columnId: string, + newColumnProps: Partial +) { + return state.columns.map((currentColumn) => { + if (currentColumn.columnId === columnId) { + return { ...currentColumn, ...newColumnProps }; + } else { + return currentColumn; + } + }); +} + export function TableDimensionEditor( - props: VisualizationDimensionEditorProps + props: VisualizationDimensionEditorProps & { + paletteService: PaletteRegistry; + } ) { const { state, setState, frame, accessor } = props; const column = state.columns.find(({ columnId }) => accessor === columnId); + const [isPaletteOpen, setIsPaletteOpen] = useState(false); if (!column) return null; if (column.isTransposed) return null; + const currentData = frame.activeData?.[state.layerId]; + // either read config state or use same logic as chart itself - const currentAlignment = - column?.alignment || - (frame.activeData && - frame.activeData[state.layerId]?.columns.find( - (col) => col.id === accessor || getOriginalId(col.id) === accessor - )?.meta.type === 'number' - ? 'right' - : 'left'); + const isNumericField = + currentData?.columns.find((col) => col.id === accessor || getOriginalId(col.id) === accessor) + ?.meta.type === 'number'; + + const currentAlignment = column?.alignment || (isNumericField ? 'right' : 'left'); + const currentColorMode = column?.colorMode || 'none'; + const hasDynamicColoring = currentColorMode !== 'none'; const visibleColumnsCount = state.columns.filter((c) => !c.hidden).length; + const hasTransposedColumn = state.columns.some(({ isTransposed }) => isTransposed); + const columnsToCheck = hasTransposedColumn + ? currentData?.columns.filter(({ id }) => getOriginalId(id) === accessor).map(({ id }) => id) || + [] + : [accessor]; + const minMaxByColumnId = findMinMaxByColumnId(columnsToCheck, currentData); + const currentMinMax = minMaxByColumnId[accessor]; + + const activePalette = column?.palette || { + type: 'palette', + name: defaultPaletteParams.name, + }; + // need to tell the helper that the colorStops are required to display + const displayStops = applyPaletteParams(props.paletteService, activePalette, currentMinMax); + return ( <> { - const newMode = id.replace(idPrefix, '') as 'left' | 'right' | 'center'; - const newColumns = state.columns.map((currentColumn) => { - if (currentColumn.columnId === accessor) { - return { - ...currentColumn, - alignment: newMode, - }; - } else { - return currentColumn; - } + const newMode = id.replace(idPrefix, '') as ColumnType['alignment']; + setState({ + ...state, + columns: updateColumnWith(state, accessor, { alignment: newMode }), }); - setState({ ...state, columns: newColumns }); }} /> @@ -127,6 +175,135 @@ export function TableDimensionEditor( /> )} + {isNumericField && ( + <> + + { + const newMode = id.replace(idPrefix, '') as ColumnType['colorMode']; + const params: Partial = { + colorMode: newMode, + }; + if (!column?.palette && newMode !== 'none') { + params.palette = { + ...activePalette, + params: { + ...activePalette.params, + // that's ok, at first open we're going to throw them away and recompute + stops: displayStops, + }, + }; + } + // clear up when switching to no coloring + if (column?.palette && newMode === 'none') { + params.palette = undefined; + } + setState({ + ...state, + columns: updateColumnWith(state, accessor, params), + }); + }} + /> + + {hasDynamicColoring && ( + + + + { + setIsPaletteOpen(!isPaletteOpen); + }} + /> + + + { + setIsPaletteOpen(!isPaletteOpen); + }} + size="xs" + flush="both" + > + {i18n.translate('xpack.lens.paletteTableGradient.customize', { + defaultMessage: 'Edit', + })} + + setIsPaletteOpen(!isPaletteOpen)} + > + { + setState({ + ...state, + columns: updateColumnWith(state, accessor, { palette: newPalette }), + }); + }} + /> + + + + + )} + + )} ); } diff --git a/x-pack/plugins/lens/public/datatable_visualization/components/palette_panel_container.scss b/x-pack/plugins/lens/public/datatable_visualization/components/palette_panel_container.scss new file mode 100644 index 0000000000000..db14d064d1881 --- /dev/null +++ b/x-pack/plugins/lens/public/datatable_visualization/components/palette_panel_container.scss @@ -0,0 +1,53 @@ +@import '@elastic/eui/src/components/flyout/variables'; +@import '@elastic/eui/src/components/flyout/mixins'; + +.lnsPalettePanelContainer { + // Use the EuiFlyout style + @include euiFlyout; + // But with custom positioning to keep it within the sidebar contents + position: absolute; + right: 0; + left: 0; + top: 0; + bottom: 0; + animation: euiFlyout $euiAnimSpeedNormal $euiAnimSlightResistance; + // making just a bit higher than the dimension flyout to stack on top of it + z-index: $euiZLevel3 + 1 +} + +.lnsPalettePanelContainer__footer { + padding: $euiSizeS; +} + +.lnsPalettePanelContainer__header { + padding: $euiSizeS $euiSizeXS; +} + +.lnsPalettePanelContainer__headerTitle { + padding: $euiSizeS $euiSizeXS; + cursor: pointer; + + &:hover { + text-decoration: underline; + } +} + +.lnsPalettePanelContainer__headerLink { + &:focus-within { + background-color: transparentize($euiColorVis1, .9); + + .lnsPalettePanelContainer__headerTitle { + text-decoration: underline; + } + } +} + +.lnsPalettePanelContainer__backIcon { + &:hover { + transform: none !important; // sass-lint:disable-line no-important + } + + &:focus { + background-color: transparent; + } +} diff --git a/x-pack/plugins/lens/public/datatable_visualization/components/palette_panel_container.tsx b/x-pack/plugins/lens/public/datatable_visualization/components/palette_panel_container.tsx new file mode 100644 index 0000000000000..1371fbe73ef84 --- /dev/null +++ b/x-pack/plugins/lens/public/datatable_visualization/components/palette_panel_container.tsx @@ -0,0 +1,112 @@ +/* + * 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 './palette_panel_container.scss'; + +import React, { useState, useEffect, MutableRefObject } from 'react'; +import { + EuiFlyoutHeader, + EuiFlyoutFooter, + EuiTitle, + EuiButtonIcon, + EuiButtonEmpty, + EuiFlexGroup, + EuiFlexItem, + EuiFocusTrap, + EuiOutsideClickDetector, + EuiPortal, +} from '@elastic/eui'; + +import { i18n } from '@kbn/i18n'; + +export function PalettePanelContainer({ + isOpen, + handleClose, + children, + siblingRef, +}: { + isOpen: boolean; + handleClose: () => void; + children: React.ReactElement | React.ReactElement[]; + siblingRef: MutableRefObject; +}) { + const [focusTrapIsEnabled, setFocusTrapIsEnabled] = useState(false); + + const closeFlyout = () => { + handleClose(); + setFocusTrapIsEnabled(false); + }; + + useEffect(() => { + if (isOpen) { + // without setTimeout here the flyout pushes content when animating + setTimeout(() => { + setFocusTrapIsEnabled(true); + }, 255); + } + }, [isOpen]); + + return isOpen && siblingRef.current ? ( + + + +
    + + + + + + + +

    + + {i18n.translate('xpack.lens.table.palettePanelTitle', { + defaultMessage: 'Edit color', + })} + +

    +
    +
    +
    +
    + + {children} + + + + {i18n.translate('xpack.lens.table.palettePanelContainer.back', { + defaultMessage: 'Back', + })} + + +
    +
    +
    +
    + ) : null; +} diff --git a/x-pack/plugins/lens/public/datatable_visualization/components/shared_utils.tsx b/x-pack/plugins/lens/public/datatable_visualization/components/shared_utils.tsx new file mode 100644 index 0000000000000..92a949e65c67e --- /dev/null +++ b/x-pack/plugins/lens/public/datatable_visualization/components/shared_utils.tsx @@ -0,0 +1,36 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { Datatable } from 'src/plugins/expressions'; +import { getOriginalId } from '../transpose_helpers'; + +export const findMinMaxByColumnId = (columnIds: string[], table: Datatable | undefined) => { + const minMax: Record = {}; + + if (table != null) { + for (const columnId of columnIds) { + const originalId = getOriginalId(columnId); + minMax[originalId] = minMax[originalId] || { max: -Infinity, min: Infinity }; + table.rows.forEach((row) => { + const rowValue = row[columnId]; + if (rowValue != null) { + if (minMax[originalId].min > rowValue) { + minMax[originalId].min = rowValue; + } + if (minMax[originalId].max < rowValue) { + minMax[originalId].max = rowValue; + } + } + }); + // what happens when there's no data in the table? Fallback to a percent range + if (minMax[originalId].max === -Infinity) { + minMax[originalId] = { max: 100, min: 0, fallback: true }; + } + } + } + return minMax; +}; diff --git a/x-pack/plugins/lens/public/datatable_visualization/components/table_basic.test.tsx b/x-pack/plugins/lens/public/datatable_visualization/components/table_basic.test.tsx index 22577e8ef5fd3..509969c2b71ec 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/components/table_basic.test.tsx +++ b/x-pack/plugins/lens/public/datatable_visualization/components/table_basic.test.tsx @@ -15,6 +15,8 @@ import { LensIconChartDatatable } from '../../assets/chart_datatable'; import { DataContext, DatatableComponent } from './table_basic'; import { LensMultiTable } from '../../types'; import { DatatableProps } from '../expression'; +import { chartPluginMock } from 'src/plugins/charts/public/mocks'; +import { IUiSettingsClient } from 'kibana/public'; function sampleArgs() { const indexPatternId = 'indexPatternId'; @@ -99,6 +101,8 @@ describe('DatatableComponent', () => { formatFactory={(x) => x as IFieldFormat} dispatchEvent={onDispatchEvent} getType={jest.fn()} + paletteService={chartPluginMock.createPaletteRegistry()} + uiSettings={({ get: jest.fn() } as unknown) as IUiSettingsClient} renderMode="edit" /> ) @@ -118,6 +122,8 @@ describe('DatatableComponent', () => { getType={jest.fn()} rowHasRowClickTriggerActions={[true, true, true]} renderMode="edit" + paletteService={chartPluginMock.createPaletteRegistry()} + uiSettings={({ get: jest.fn() } as unknown) as IUiSettingsClient} /> ) ).toMatchSnapshot(); @@ -136,6 +142,8 @@ describe('DatatableComponent', () => { getType={jest.fn()} rowHasRowClickTriggerActions={[false, false, false]} renderMode="display" + paletteService={chartPluginMock.createPaletteRegistry()} + uiSettings={({ get: jest.fn() } as unknown) as IUiSettingsClient} /> ) ).toMatchSnapshot(); @@ -158,6 +166,8 @@ describe('DatatableComponent', () => { dispatchEvent={onDispatchEvent} getType={jest.fn(() => ({ type: 'buckets' } as IAggType))} renderMode="edit" + paletteService={chartPluginMock.createPaletteRegistry()} + uiSettings={({ get: jest.fn() } as unknown) as IUiSettingsClient} /> ); @@ -199,6 +209,8 @@ describe('DatatableComponent', () => { dispatchEvent={onDispatchEvent} getType={jest.fn(() => ({ type: 'buckets' } as IAggType))} renderMode="edit" + paletteService={chartPluginMock.createPaletteRegistry()} + uiSettings={({ get: jest.fn() } as unknown) as IUiSettingsClient} /> ); @@ -279,6 +291,8 @@ describe('DatatableComponent', () => { dispatchEvent={onDispatchEvent} getType={jest.fn(() => ({ type: 'buckets' } as IAggType))} renderMode="edit" + paletteService={chartPluginMock.createPaletteRegistry()} + uiSettings={({ get: jest.fn() } as unknown) as IUiSettingsClient} /> ); @@ -325,6 +339,8 @@ describe('DatatableComponent', () => { type === 'count' ? ({ type: 'metrics' } as IAggType) : ({ type: 'buckets' } as IAggType) )} renderMode="edit" + paletteService={chartPluginMock.createPaletteRegistry()} + uiSettings={({ get: jest.fn() } as unknown) as IUiSettingsClient} /> ); expect(component.find(EmptyPlaceholder).prop('icon')).toEqual(LensIconChartDatatable); @@ -345,6 +361,8 @@ describe('DatatableComponent', () => { dispatchEvent={onDispatchEvent} getType={jest.fn()} renderMode="edit" + paletteService={chartPluginMock.createPaletteRegistry()} + uiSettings={({ get: jest.fn() } as unknown) as IUiSettingsClient} /> ); @@ -393,6 +411,8 @@ describe('DatatableComponent', () => { dispatchEvent={onDispatchEvent} getType={jest.fn()} renderMode="display" + paletteService={chartPluginMock.createPaletteRegistry()} + uiSettings={({ get: jest.fn() } as unknown) as IUiSettingsClient} /> ); @@ -421,6 +441,8 @@ describe('DatatableComponent', () => { dispatchEvent={onDispatchEvent} getType={jest.fn()} renderMode="display" + paletteService={chartPluginMock.createPaletteRegistry()} + uiSettings={({ get: jest.fn() } as unknown) as IUiSettingsClient} /> ); @@ -447,6 +469,8 @@ describe('DatatableComponent', () => { dispatchEvent={onDispatchEvent} getType={jest.fn()} renderMode="display" + paletteService={chartPluginMock.createPaletteRegistry()} + uiSettings={({ get: jest.fn() } as unknown) as IUiSettingsClient} /> ); @@ -471,6 +495,8 @@ describe('DatatableComponent', () => { dispatchEvent={onDispatchEvent} getType={jest.fn()} renderMode="edit" + paletteService={chartPluginMock.createPaletteRegistry()} + uiSettings={({ get: jest.fn() } as unknown) as IUiSettingsClient} /> ); // mnake a copy of the data, changing only the name of the first column @@ -483,4 +509,34 @@ describe('DatatableComponent', () => { 'new a' ); }); + + test('it does compute minMax for each numeric column', () => { + const { data, args } = sampleArgs(); + + const wrapper = shallow( + ({ convert: (x) => x } as IFieldFormat)} + dispatchEvent={onDispatchEvent} + getType={jest.fn()} + renderMode="display" + paletteService={chartPluginMock.createPaletteRegistry()} + uiSettings={({ get: jest.fn() } as unknown) as IUiSettingsClient} + /> + ); + + expect(wrapper.find(DataContext.Provider).prop('value').minMaxByColumnId).toEqual({ + c: { min: 3, max: 3 }, + }); + }); }); diff --git a/x-pack/plugins/lens/public/datatable_visualization/components/table_basic.tsx b/x-pack/plugins/lens/public/datatable_visualization/components/table_basic.tsx index 24cde07cebaa0..e6fcf3f321f7f 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/components/table_basic.tsx +++ b/x-pack/plugins/lens/public/datatable_visualization/components/table_basic.tsx @@ -18,6 +18,7 @@ import { EuiDataGridSorting, EuiDataGridStyle, } from '@elastic/eui'; +import { CustomPaletteState, PaletteOutput } from 'src/plugins/charts/common'; import { FormatFactory, LensFilterEvent, LensTableRowContextMenuEvent } from '../../types'; import { VisualizationContainer } from '../../visualization_container'; import { EmptyPlaceholder } from '../../shared_components'; @@ -40,6 +41,8 @@ import { createGridSortingConfig, createTransposeColumnFilterHandler, } from './table_actions'; +import { findMinMaxByColumnId } from './shared_utils'; +import { CUSTOM_PALETTE } from '../../shared_components/coloring/constants'; export const DataContext = React.createContext({}); @@ -50,8 +53,9 @@ const gridStyle: EuiDataGridStyle = { export interface ColumnConfig { columns: Array< - ColumnState & { + Omit & { type: 'lens_datatable_column'; + palette?: PaletteOutput; } >; sortingColumnId: string | undefined; @@ -203,20 +207,34 @@ export const DatatableComponent = (props: DatatableRenderProps) => { ] ); + const isNumericMap: Record = useMemo(() => { + const numericMap: Record = {}; + for (const column of firstLocalTable.columns) { + numericMap[column.id] = column.meta.type === 'number'; + } + return numericMap; + }, [firstLocalTable]); + const alignments: Record = useMemo(() => { const alignmentMap: Record = {}; columnConfig.columns.forEach((column) => { if (column.alignment) { alignmentMap[column.columnId] = column.alignment; } else { - const isNumeric = - firstLocalTable.columns.find((dataColumn) => dataColumn.id === column.columnId)?.meta - .type === 'number'; - alignmentMap[column.columnId] = isNumeric ? 'right' : 'left'; + alignmentMap[column.columnId] = isNumericMap[column.columnId] ? 'right' : 'left'; } }); return alignmentMap; - }, [firstLocalTable, columnConfig]); + }, [columnConfig, isNumericMap]); + + const minMaxByColumnId: Record = useMemo(() => { + return findMinMaxByColumnId( + columnConfig.columns + .filter(({ columnId }) => isNumericMap[columnId]) + .map(({ columnId }) => columnId), + firstTable + ); + }, [firstTable, isNumericMap, columnConfig]); const trailingControlColumns: EuiDataGridControlColumn[] = useMemo(() => { if (!hasAtLeastOneRowClickAction || !onRowContextMenuClick) { @@ -254,7 +272,10 @@ export const DatatableComponent = (props: DatatableRenderProps) => { ]; }, [firstTableRef, onRowContextMenuClick, columnConfig, hasAtLeastOneRowClickAction]); - const renderCellValue = useMemo(() => createGridCell(formatters, DataContext), [formatters]); + const renderCellValue = useMemo( + () => createGridCell(formatters, columnConfig, DataContext, props.uiSettings), + [formatters, columnConfig, props.uiSettings] + ); const columnVisibility = useMemo(() => ({ visibleColumns, setVisibleColumns: () => {} }), [ visibleColumns, @@ -286,6 +307,8 @@ export const DatatableComponent = (props: DatatableRenderProps) => { table: firstLocalTable, rowHasRowClickTriggerActions: props.rowHasRowClickTriggerActions, alignments, + minMaxByColumnId, + getColorForValue: props.paletteService.get(CUSTOM_PALETTE).getColorForValue!, }} > IAggType; renderMode: RenderMode; + paletteService: PaletteRegistry; + uiSettings: IUiSettingsClient; /** * A boolean for each table row, which is true if the row active @@ -55,4 +59,10 @@ export interface DataContextType { table?: Datatable; rowHasRowClickTriggerActions?: boolean[]; alignments?: Record; + minMaxByColumnId?: Record; + getColorForValue?: ( + value: number | undefined, + state: CustomPaletteState, + minMax: { min: number; max: number } + ) => string | undefined; } diff --git a/x-pack/plugins/lens/public/datatable_visualization/expression.tsx b/x-pack/plugins/lens/public/datatable_visualization/expression.tsx index 7d879217abf8b..2d5f4aea98856 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/expression.tsx +++ b/x-pack/plugins/lens/public/datatable_visualization/expression.tsx @@ -17,6 +17,9 @@ import { ExpressionFunctionDefinition, ExpressionRenderDefinition, } from 'src/plugins/expressions'; +import { CustomPaletteState, PaletteOutput } from 'src/plugins/charts/common'; +import { PaletteRegistry } from 'src/plugins/charts/public'; +import { IUiSettingsClient } from 'kibana/public'; import { getSortingCriteria } from './sorting'; import { DatatableComponent } from './components/table_basic'; @@ -26,10 +29,15 @@ import type { FormatFactory, ILensInterpreterRenderHandlers, LensMultiTable } fr import type { DatatableRender } from './components/types'; import { transposeTable } from './transpose_helpers'; +export type ColumnConfigArg = Omit & { + type: 'lens_datatable_column'; + palette?: PaletteOutput; +}; + export interface Args { title: string; description?: string; - columns: Array; + columns: ColumnConfigArg[]; sortingColumnId: string | undefined; sortingDirection: 'asc' | 'desc' | 'none'; } @@ -160,6 +168,11 @@ export const datatableColumn: ExpressionFunctionDefinition< width: { types: ['number'], help: '' }, isTransposed: { types: ['boolean'], help: '' }, transposable: { types: ['boolean'], help: '' }, + colorMode: { types: ['string'], help: '' }, + palette: { + types: ['palette'], + help: '', + }, }, fn: function fn(input: unknown, args: ColumnState) { return { @@ -172,6 +185,8 @@ export const datatableColumn: ExpressionFunctionDefinition< export const getDatatableRenderer = (dependencies: { formatFactory: FormatFactory; getType: Promise<(name: string) => IAggType>; + paletteService: PaletteRegistry; + uiSettings: IUiSettingsClient; }): ExpressionRenderDefinition => ({ name: 'lens_datatable_renderer', displayName: i18n.translate('xpack.lens.datatable.visualizationName', { @@ -222,8 +237,10 @@ export const getDatatableRenderer = (dependencies: { formatFactory={dependencies.formatFactory} dispatchEvent={handlers.event} renderMode={handlers.getRenderMode()} + paletteService={dependencies.paletteService} getType={resolvedGetType} rowHasRowClickTriggerActions={rowHasRowClickTriggerActions} + uiSettings={dependencies.uiSettings} /> , domNode, diff --git a/x-pack/plugins/lens/public/datatable_visualization/index.ts b/x-pack/plugins/lens/public/datatable_visualization/index.ts index f0939f6195229..7f48d00d00f7f 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/index.ts +++ b/x-pack/plugins/lens/public/datatable_visualization/index.ts @@ -6,6 +6,7 @@ */ import { CoreSetup } from 'kibana/public'; +import { ChartsPluginSetup } from 'src/plugins/charts/public'; import { ExpressionsSetup } from '../../../../../src/plugins/expressions/public'; import { EditorFrameSetup, FormatFactory } from '../types'; import { DataPublicPluginStart } from '../../../../../src/plugins/data/public'; @@ -17,6 +18,7 @@ export interface DatatableVisualizationPluginSetupPlugins { expressions: ExpressionsSetup; formatFactory: Promise; editorFrame: EditorFrameSetup; + charts: ChartsPluginSetup; } export class DatatableVisualization { @@ -24,15 +26,16 @@ export class DatatableVisualization { setup( core: CoreSetup, - { expressions, formatFactory, editorFrame }: DatatableVisualizationPluginSetupPlugins + { expressions, formatFactory, editorFrame, charts }: DatatableVisualizationPluginSetupPlugins ) { editorFrame.registerVisualization(async () => { const { getDatatable, datatableColumn, getDatatableRenderer, - datatableVisualization, + getDatatableVisualization, } = await import('../async_services'); + const palettes = await charts.palettes.getPalettes(); const resolvedFormatFactory = await formatFactory; expressions.registerFunction(() => datatableColumn); @@ -43,9 +46,11 @@ export class DatatableVisualization { getType: core .getStartServices() .then(([_, { data: dataStart }]) => dataStart.search.aggs.types.get), + paletteService: palettes, + uiSettings: core.uiSettings, }) ); - return datatableVisualization; + return getDatatableVisualization({ paletteService: palettes }); }); } } diff --git a/x-pack/plugins/lens/public/datatable_visualization/transpose_helpers.ts b/x-pack/plugins/lens/public/datatable_visualization/transpose_helpers.ts index 6e29e018b481e..a35edf7499073 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/transpose_helpers.ts +++ b/x-pack/plugins/lens/public/datatable_visualization/transpose_helpers.ts @@ -7,9 +7,9 @@ import type { FieldFormat } from 'src/plugins/data/public'; import type { Datatable, DatatableColumn, DatatableRow } from 'src/plugins/expressions'; +import { ColumnConfig } from './components/table_basic'; -import { Args } from './expression'; -import { ColumnState } from './visualization'; +import { Args, ColumnConfigArg } from './expression'; const TRANSPOSE_SEPARATOR = '---'; @@ -87,11 +87,11 @@ export function transposeTable( function transposeRows( firstTable: Datatable, - bucketsColumnArgs: Array, + bucketsColumnArgs: ColumnConfigArg[], formatters: Record, transposedColumnFormatter: FieldFormat, transposedColumnId: string, - metricsColumnArgs: Array + metricsColumnArgs: ColumnConfigArg[] ) { const rowsByBucketColumns: Record = groupRowsByBucketColumns( firstTable, @@ -113,8 +113,8 @@ function transposeRows( */ function updateColumnArgs( args: Args, - bucketsColumnArgs: Array, - transposedColumnGroups: Array> + bucketsColumnArgs: ColumnConfig['columns'], + transposedColumnGroups: Array ) { args.columns = [...bucketsColumnArgs]; // add first column from each group, then add second column for each group, ... @@ -151,8 +151,8 @@ function getUniqueValues(table: Datatable, formatter: FieldFormat, columnId: str */ function transposeColumns( args: Args, - bucketsColumnArgs: Array, - metricColumns: Array, + bucketsColumnArgs: ColumnConfig['columns'], + metricColumns: ColumnConfig['columns'], firstTable: Datatable, uniqueValues: string[], uniqueRawValues: unknown[], @@ -196,10 +196,10 @@ function transposeColumns( */ function mergeRowGroups( rowsByBucketColumns: Record, - bucketColumns: ColumnState[], + bucketColumns: ColumnConfigArg[], formatter: FieldFormat, transposedColumnId: string, - metricColumns: ColumnState[] + metricColumns: ColumnConfigArg[] ) { return Object.values(rowsByBucketColumns).map((rows) => { const mergedRow: DatatableRow = {}; @@ -222,7 +222,7 @@ function mergeRowGroups( */ function groupRowsByBucketColumns( firstTable: Datatable, - bucketColumns: ColumnState[], + bucketColumns: ColumnConfigArg[], formatters: Record ) { const rowsByBucketColumns: Record = {}; diff --git a/x-pack/plugins/lens/public/datatable_visualization/visualization.test.tsx b/x-pack/plugins/lens/public/datatable_visualization/visualization.test.tsx index 1848565114dea..ea8237defc291 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/visualization.test.tsx +++ b/x-pack/plugins/lens/public/datatable_visualization/visualization.test.tsx @@ -8,7 +8,7 @@ import { Ast } from '@kbn/interpreter/common'; import { buildExpression } from '../../../../../src/plugins/expressions/public'; import { createMockDatasource, createMockFramePublicAPI } from '../editor_frame_service/mocks'; -import { DatatableVisualizationState, datatableVisualization } from './visualization'; +import { DatatableVisualizationState, getDatatableVisualization } from './visualization'; import { Operation, DataType, @@ -16,6 +16,7 @@ import { TableSuggestionColumn, VisualizationDimensionGroupConfig, } from '../types'; +import { chartPluginMock } from 'src/plugins/charts/public/mocks'; function mockFrame(): FramePublicAPI { return { @@ -32,6 +33,10 @@ function mockFrame(): FramePublicAPI { }; } +const datatableVisualization = getDatatableVisualization({ + paletteService: chartPluginMock.createPaletteRegistry(), +}); + describe('Datatable Visualization', () => { describe('#initialize', () => { it('should initialize from the empty state', () => { @@ -427,22 +432,28 @@ describe('Datatable Visualization', () => { ); const columnArgs = buildExpression(expression).findFunction('lens_datatable_column'); expect(columnArgs).toHaveLength(2); - expect(columnArgs[0].arguments).toEqual({ - columnId: ['c'], - hidden: [], - width: [], - isTransposed: [], - transposable: [true], - alignment: [], - }); - expect(columnArgs[1].arguments).toEqual({ - columnId: ['b'], - hidden: [], - width: [], - isTransposed: [], - transposable: [true], - alignment: [], - }); + expect(columnArgs[0].arguments).toEqual( + expect.objectContaining({ + columnId: ['c'], + hidden: [], + width: [], + isTransposed: [], + transposable: [true], + alignment: [], + colorMode: ['none'], + }) + ); + expect(columnArgs[1].arguments).toEqual( + expect.objectContaining({ + columnId: ['b'], + hidden: [], + width: [], + isTransposed: [], + transposable: [true], + alignment: [], + colorMode: ['none'], + }) + ); }); it('returns no expression if the metric dimension is not defined', () => { diff --git a/x-pack/plugins/lens/public/datatable_visualization/visualization.tsx b/x-pack/plugins/lens/public/datatable_visualization/visualization.tsx index 9bd482c73bff5..efde4160019e7 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/visualization.tsx +++ b/x-pack/plugins/lens/public/datatable_visualization/visualization.tsx @@ -11,6 +11,7 @@ import { Ast } from '@kbn/interpreter/common'; import { I18nProvider } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; import { DatatableColumn } from 'src/plugins/expressions/public'; +import { PaletteOutput, PaletteRegistry } from 'src/plugins/charts/public'; import { SuggestionRequest, Visualization, @@ -19,6 +20,9 @@ import { } from '../types'; import { LensIconChartDatatable } from '../assets/chart_datatable'; import { TableDimensionEditor } from './components/dimension_editor'; +import { CUSTOM_PALETTE } from '../shared_components/coloring/constants'; +import { CustomPaletteParams } from '../shared_components/coloring/types'; +import { getStopsForFixedMode } from '../shared_components'; export interface ColumnState { columnId: string; @@ -32,6 +36,8 @@ export interface ColumnState { originalName?: string; bucketValues?: Array<{ originalBucketColumn: DatatableColumn; value: unknown }>; alignment?: 'left' | 'right' | 'center'; + palette?: PaletteOutput; + colorMode?: 'none' | 'cell' | 'text'; } export interface SortingState { @@ -49,7 +55,11 @@ const visualizationLabel = i18n.translate('xpack.lens.datatable.label', { defaultMessage: 'Table', }); -export const datatableVisualization: Visualization = { +export const getDatatableVisualization = ({ + paletteService, +}: { + paletteService: PaletteRegistry; +}): Visualization => ({ id: 'lnsDatatable', visualizationTypes: [ @@ -239,10 +249,26 @@ export const datatableVisualization: Visualization layerId: state.layerId, accessors: sortedColumns .filter((c) => !datasource!.getOperationForColumnId(c)?.isBucketed) - .map((accessor) => ({ - columnId: accessor, - triggerIcon: columnMap[accessor].hidden ? 'invisible' : undefined, - })), + .map((accessor) => { + const columnConfig = columnMap[accessor]; + const hasColoring = Boolean( + columnConfig.colorMode !== 'none' && columnConfig.palette?.params?.stops + ); + return { + columnId: accessor, + triggerIcon: columnConfig.hidden + ? 'invisible' + : hasColoring + ? 'colorBy' + : undefined, + palette: hasColoring + ? getStopsForFixedMode( + columnConfig.palette?.params?.stops || [], + columnConfig.palette?.params?.colorStops + ) + : undefined, + }; + }), supportsMoreColumns: true, filterOperations: (op) => !op.isBucketed, required: true, @@ -285,7 +311,7 @@ export const datatableVisualization: Visualization renderDimensionEditor(domElement, props) { render( - + , domElement ); @@ -320,26 +346,41 @@ export const datatableVisualization: Visualization arguments: { title: [title || ''], description: [description || ''], - columns: columns.map((column) => ({ - type: 'expression', - chain: [ - { - type: 'function', - function: 'lens_datatable_column', - arguments: { - columnId: [column.columnId], - hidden: typeof column.hidden === 'undefined' ? [] : [column.hidden], - width: typeof column.width === 'undefined' ? [] : [column.width], - isTransposed: - typeof column.isTransposed === 'undefined' ? [] : [column.isTransposed], - transposable: [ - !datasource!.getOperationForColumnId(column.columnId)?.isBucketed, - ], - alignment: typeof column.alignment === 'undefined' ? [] : [column.alignment], + columns: columns.map((column) => { + const paletteParams = { + ...column.palette?.params, + // rewrite colors and stops as two distinct arguments + colors: (column.palette?.params?.stops || []).map(({ color }) => color), + stops: + column.palette?.params?.name === 'custom' + ? (column.palette?.params?.stops || []).map(({ stop }) => stop) + : [], + reverse: false, // managed at UI level + }; + + return { + type: 'expression', + chain: [ + { + type: 'function', + function: 'lens_datatable_column', + arguments: { + columnId: [column.columnId], + hidden: typeof column.hidden === 'undefined' ? [] : [column.hidden], + width: typeof column.width === 'undefined' ? [] : [column.width], + isTransposed: + typeof column.isTransposed === 'undefined' ? [] : [column.isTransposed], + transposable: [ + !datasource!.getOperationForColumnId(column.columnId)?.isBucketed, + ], + alignment: typeof column.alignment === 'undefined' ? [] : [column.alignment], + colorMode: [column.colorMode ?? 'none'], + palette: [paletteService.get(CUSTOM_PALETTE).toExpression(paletteParams)], + }, }, - }, - ], - })), + ], + }; + }), sortingColumnId: [state.sorting?.columnId || ''], sortingDirection: [state.sorting?.direction || 'none'], }, @@ -395,7 +436,7 @@ export const datatableVisualization: Visualization return state; } }, -}; +}); function getDataSourceAndSortedColumns( state: DatatableVisualizationState, diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/dimension_container.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/dimension_container.tsx index b8d3170b3e165..a8d610f2740de 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/dimension_container.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/dimension_container.tsx @@ -29,11 +29,13 @@ export function DimensionContainer({ groupLabel, handleClose, panel, + panelRef, }: { isOpen: boolean; handleClose: () => void; panel: React.ReactElement; groupLabel: string; + panelRef: (el: HTMLDivElement) => void; }) { const [focusTrapIsEnabled, setFocusTrapIsEnabled] = useState(false); @@ -73,65 +75,67 @@ export function DimensionContainer({ }); return isOpen ? ( - - - -
    - - - - - - - -

    - - {i18n.translate('xpack.lens.configure.configurePanelTitle', { - defaultMessage: '{groupLabel} configuration', - values: { - groupLabel, - }, - })} - -

    -
    -
    -
    -
    - - {panel} - - - - {i18n.translate('xpack.lens.dimensionContainer.close', { - defaultMessage: 'Close', - })} - - -
    -
    -
    +
    + + + +
    + + + + +

    + + {i18n.translate('xpack.lens.configure.configurePanelTitle', { + defaultMessage: '{groupLabel} configuration', + values: { + groupLabel, + }, + })} + +

    +
    +
    + + + +
    +
    + + {panel} + + + + {i18n.translate('xpack.lens.dimensionContainer.close', { + defaultMessage: 'Close', + })} + + +
    +
    +
    +
    ) : null; } diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/layer_panel.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/layer_panel.tsx index cf3c9099d4b0d..a605a94a34646 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/layer_panel.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/layer_panel.tsx @@ -7,7 +7,7 @@ import './layer_panel.scss'; -import React, { useState, useEffect, useMemo, useCallback } from 'react'; +import React, { useState, useEffect, useMemo, useCallback, useRef } from 'react'; import { EuiPanel, EuiSpacer, @@ -72,6 +72,7 @@ export function LayerPanel( setActiveDimension(initialActiveDimensionState); }, [activeVisualization.id]); + const panelRef = useRef(null); const registerLayerRef = useCallback((el) => registerNewLayerRef(layerId, el), [ layerId, registerNewLayerRef, @@ -405,6 +406,7 @@ export function LayerPanel( (panelRef.current = el)} isOpen={!!activeId} groupLabel={activeGroup?.groupLabel || ''} handleClose={() => { @@ -484,6 +486,7 @@ export function LayerPanel( groupId: activeGroup.groupId, accessor: activeId, setState: props.updateVisualization, + panelRef, }} />
    diff --git a/x-pack/plugins/lens/public/editor_frame_service/mocks.tsx b/x-pack/plugins/lens/public/editor_frame_service/mocks.tsx index a56b3ccaa5bde..38669d72474df 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/mocks.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/mocks.tsx @@ -105,10 +105,9 @@ export type FrameMock = jest.Mocked; export function createMockPaletteDefinition(): jest.Mocked { return { - getColors: jest.fn((_) => ['#ff0000', '#00ff00']), + getCategoricalColors: jest.fn((_) => ['#ff0000', '#00ff00']), title: 'Mock Palette', id: 'default', - renderEditor: jest.fn(), toExpression: jest.fn(() => ({ type: 'expression', chain: [ @@ -119,7 +118,7 @@ export function createMockPaletteDefinition(): jest.Mocked { }, ], })), - getColor: jest.fn().mockReturnValue('#ff0000'), + getCategoricalColor: jest.fn().mockReturnValue('#ff0000'), }; } diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/calculations/moving_average.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/calculations/moving_average.tsx index 8d18a2752fd7e..0e74ef6b85c80 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/calculations/moving_average.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/calculations/moving_average.tsx @@ -9,6 +9,7 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import React, { useState } from 'react'; import { EuiFieldNumber, EuiFormRow } from '@elastic/eui'; +import { useDebounceWithOptions } from '../../../../shared_components'; import { FormattedIndexPatternColumn, ReferenceBasedIndexPatternColumn } from '../column_types'; import { IndexPatternLayer } from '../../../types'; import { @@ -19,12 +20,7 @@ import { hasDateField, } from './utils'; import { updateColumnParam } from '../../layer_helpers'; -import { - getFormatFromPreviousColumn, - isValidNumber, - useDebounceWithOptions, - getFilter, -} from '../helpers'; +import { getFormatFromPreviousColumn, isValidNumber, getFilter } from '../helpers'; import { adjustTimeScaleOnOtherColumnChange } from '../../time_scale_utils'; import { HelpPopover, HelpPopoverButton } from '../../../help_popover'; import type { OperationDefinition, ParamEditorProps } from '..'; diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/helpers.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/helpers.tsx index f719ac4250912..45abbcd3d9cf9 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/helpers.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/helpers.tsx @@ -5,35 +5,11 @@ * 2.0. */ -import { useRef } from 'react'; -import useDebounce from 'react-use/lib/useDebounce'; import { i18n } from '@kbn/i18n'; import { IndexPatternColumn, operationDefinitionMap } from '.'; import { FieldBasedIndexPatternColumn } from './column_types'; import { IndexPattern } from '../../types'; -export const useDebounceWithOptions = ( - fn: Function, - { skipFirstRender }: { skipFirstRender: boolean } = { skipFirstRender: false }, - ms?: number | undefined, - deps?: React.DependencyList | undefined -) => { - const isFirstRender = useRef(true); - const newDeps = [...(deps || []), isFirstRender]; - - return useDebounce( - () => { - if (skipFirstRender && isFirstRender.current) { - isFirstRender.current = false; - return; - } - return fn(); - }, - ms, - newDeps - ); -}; - export function getInvalidFieldMessage( column: FieldBasedIndexPatternColumn, indexPattern?: IndexPattern diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/percentile.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/percentile.tsx index 705a1f7172fff..4c09ae4ed8c47 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/percentile.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/percentile.tsx @@ -16,10 +16,10 @@ import { getInvalidFieldMessage, getSafeName, isValidNumber, - useDebounceWithOptions, getFilter, } from './helpers'; import { FieldBasedIndexPatternColumn } from './column_types'; +import { useDebounceWithOptions } from '../../../shared_components'; export interface PercentileIndexPatternColumn extends FieldBasedIndexPatternColumn { operationType: 'percentile'; diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/advanced_editor.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/advanced_editor.tsx index b3ffb58df00d3..43f5527e42d4b 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/advanced_editor.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/advanced_editor.tsx @@ -22,6 +22,7 @@ import { htmlIdGenerator, keys, } from '@elastic/eui'; +import { useDebounceWithOptions } from '../../../../shared_components'; import { IFieldFormat } from '../../../../../../../../src/plugins/data/common'; import { RangeTypeLens, isValidRange } from './ranges'; import { FROM_PLACEHOLDER, TO_PLACEHOLDER, TYPING_DEBOUNCE_TIME } from './constants'; @@ -31,7 +32,7 @@ import { DraggableBucketContainer, LabelInput, } from '../shared_components'; -import { isValidNumber, useDebounceWithOptions } from '../helpers'; +import { isValidNumber } from '../helpers'; const generateId = htmlIdGenerator(); diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/range_editor.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/range_editor.tsx index 4851b6ff3ec97..3389c723b4daf 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/range_editor.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/range_editor.tsx @@ -23,7 +23,7 @@ import { UI_SETTINGS } from '../../../../../../../../src/plugins/data/public'; import { RangeColumnParams, UpdateParamsFnType, MODES_TYPES } from './ranges'; import { AdvancedRangeEditor } from './advanced_editor'; import { TYPING_DEBOUNCE_TIME, MODES, MIN_HISTOGRAM_BARS } from './constants'; -import { useDebounceWithOptions } from '../helpers'; +import { useDebounceWithOptions } from '../../../../shared_components'; import { HelpPopover, HelpPopoverButton } from '../../../help_popover'; const GranularityHelpPopover = () => { diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/values_input.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/values_input.tsx index 915e67c4eba0b..a4c0f8f1c50e0 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/values_input.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/values_input.tsx @@ -8,7 +8,7 @@ import React, { useState } from 'react'; import { i18n } from '@kbn/i18n'; import { EuiFieldNumber } from '@elastic/eui'; -import { useDebounceWithOptions } from '../helpers'; +import { useDebounceWithOptions } from '../../../../shared_components'; export const ValuesInput = ({ value, diff --git a/x-pack/plugins/lens/public/pie_visualization/render_function.test.tsx b/x-pack/plugins/lens/public/pie_visualization/render_function.test.tsx index 7191da0af6bfe..a9e7e4adb9ca7 100644 --- a/x-pack/plugins/lens/public/pie_visualization/render_function.test.tsx +++ b/x-pack/plugins/lens/public/pie_visualization/render_function.test.tsx @@ -161,7 +161,7 @@ describe('PieVisualization component', () => { [] as HierarchyOfArrays ); - expect(defaultArgs.paletteService.get('mock').getColor).toHaveBeenCalledWith( + expect(defaultArgs.paletteService.get('mock').getCategoricalColor).toHaveBeenCalledWith( [ { name: 'css', diff --git a/x-pack/plugins/lens/public/pie_visualization/render_function.tsx b/x-pack/plugins/lens/public/pie_visualization/render_function.tsx index cc31222f6b9ab..6c1cbe63a5a3e 100644 --- a/x-pack/plugins/lens/public/pie_visualization/render_function.tsx +++ b/x-pack/plugins/lens/public/pie_visualization/render_function.tsx @@ -150,7 +150,7 @@ export function PieComponent( } } - const outputColor = paletteService.get(palette.name).getColor( + const outputColor = paletteService.get(palette.name).getCategoricalColor( seriesLayers, { behindText: categoryDisplay !== 'hide', diff --git a/x-pack/plugins/lens/public/pie_visualization/visualization.tsx b/x-pack/plugins/lens/public/pie_visualization/visualization.tsx index ad8d87292b1d8..f413b122d913c 100644 --- a/x-pack/plugins/lens/public/pie_visualization/visualization.tsx +++ b/x-pack/plugins/lens/public/pie_visualization/visualization.tsx @@ -126,7 +126,7 @@ export const getPieVisualization = ({ triggerIcon: 'colorBy', palette: paletteService .get(state.palette?.name || 'default') - .getColors(10, state.palette?.params), + .getCategoricalColors(10, state.palette?.params), }; } diff --git a/x-pack/plugins/lens/public/shared_components/coloring/color_stops.test.tsx b/x-pack/plugins/lens/public/shared_components/coloring/color_stops.test.tsx new file mode 100644 index 0000000000000..54c7f3cef90fe --- /dev/null +++ b/x-pack/plugins/lens/public/shared_components/coloring/color_stops.test.tsx @@ -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 { EuiColorPicker } from '@elastic/eui'; +import { mount } from 'enzyme'; +import React from 'react'; +import { act } from 'react-dom/test-utils'; +import { CustomStops, CustomStopsProps } from './color_stops'; + +describe('Color Stops component', () => { + let props: CustomStopsProps; + beforeEach(() => { + props = { + colorStops: [ + { color: '#aaa', stop: 20 }, + { color: '#bbb', stop: 40 }, + { color: '#ccc', stop: 60 }, + ], + paletteConfiguration: {}, + dataBounds: { min: 0, max: 200 }, + onChange: jest.fn(), + 'data-test-prefix': 'my-test', + }; + }); + it('should display all the color stops passed', () => { + const component = mount(); + expect( + component.find('input[data-test-subj^="my-test_dynamicColoring_stop_value_"]') + ).toHaveLength(3); + }); + + it('should disable the delete buttons when there are 2 stops or less', () => { + // reduce to 2 stops + props.colorStops = props.colorStops.slice(0, 2); + const component = mount(); + expect( + component + .find('[data-test-subj="my-test_dynamicColoring_removeStop_0"]') + .first() + .prop('isDisabled') + ).toBe(true); + }); + + it('should add a new stop with default color and reasonable distance from last one', () => { + let component = mount(); + const addStopButton = component + .find('[data-test-subj="my-test_dynamicColoring_addStop"]') + .first(); + act(() => { + addStopButton.prop('onClick')!({} as React.MouseEvent); + }); + component = component.update(); + + expect( + component.find('input[data-test-subj^="my-test_dynamicColoring_stop_value_"]') + ).toHaveLength(4); + expect( + component.find('input[data-test-subj="my-test_dynamicColoring_stop_value_3"]').prop('value') + ).toBe('80'); // 60-40 + 60 + expect( + component + // workaround for https://github.com/elastic/eui/issues/4792 + .find('[data-test-subj="my-test_dynamicColoring_stop_color_3"]') + .last() // pick the inner element + .childAt(0) + .prop('color') + ).toBe('#ccc'); // pick previous color + }); + + it('should restore previous color when abandoning the field with an empty color', () => { + let component = mount(); + expect( + component + .find('[data-test-subj="my-test_dynamicColoring_stop_row_0"]') + .first() + .find(EuiColorPicker) + .first() + .prop('color') + ).toBe('#aaa'); + act(() => { + component + .find('[data-test-subj="my-test_dynamicColoring_stop_row_0"]') + .first() + .find(EuiColorPicker) + .first() + .prop('onChange')!('', { + rgba: [NaN, NaN, NaN, NaN], + hex: '', + isValid: false, + }); + }); + component = component.update(); + expect( + component + .find('[data-test-subj="my-test_dynamicColoring_stop_row_0"]') + .first() + .find(EuiColorPicker) + .first() + .prop('color') + ).toBe(''); + act(() => { + component + .find('[data-test-subj="my-test_dynamicColoring_stop_color_0"]') + .first() + .prop('onBlur')!({} as React.FocusEvent); + }); + component = component.update(); + expect( + component + .find('[data-test-subj="my-test_dynamicColoring_stop_row_0"]') + .first() + .find(EuiColorPicker) + .first() + .prop('color') + ).toBe('#aaa'); + }); + + it('should sort stops value on whole component blur', () => { + let component = mount(); + let firstStopValueInput = component + .find('[data-test-subj="my-test_dynamicColoring_stop_value_0"]') + .first(); + act(() => { + firstStopValueInput.prop('onChange')!(({ + target: { value: ' 90' }, + } as unknown) as React.ChangeEvent); + }); + + component = component.update(); + + act(() => { + component + .find('[data-test-subj="my-test_dynamicColoring_stop_row_0"]') + .first() + .prop('onBlur')!({} as React.FocusEvent); + }); + component = component.update(); + + // retrieve again the input + firstStopValueInput = component + .find('[data-test-subj="my-test_dynamicColoring_stop_value_0"]') + .first(); + expect(firstStopValueInput.prop('value')).toBe('40'); + // the previous one move at the bottom + expect( + component + .find('[data-test-subj="my-test_dynamicColoring_stop_value_2"]') + .first() + .prop('value') + ).toBe('90'); + }); +}); diff --git a/x-pack/plugins/lens/public/shared_components/coloring/color_stops.tsx b/x-pack/plugins/lens/public/shared_components/coloring/color_stops.tsx new file mode 100644 index 0000000000000..37197b232ddf5 --- /dev/null +++ b/x-pack/plugins/lens/public/shared_components/coloring/color_stops.tsx @@ -0,0 +1,294 @@ +/* + * 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, { useState, useCallback, useMemo } from 'react'; +import type { FocusEvent } from 'react'; +import { i18n } from '@kbn/i18n'; +import { + EuiFieldNumber, + EuiColorPicker, + EuiButtonIcon, + EuiFlexItem, + EuiFlexGroup, + EuiButtonEmpty, + EuiSpacer, + EuiScreenReaderOnly, + htmlIdGenerator, +} from '@elastic/eui'; +import useUnmount from 'react-use/lib/useUnmount'; +import { DEFAULT_COLOR } from './constants'; +import { getDataMinMax, getStepValue, isValidColor } from './utils'; +import { TooltipWrapper, useDebouncedValue } from '../index'; +import { ColorStop, CustomPaletteParams } from './types'; + +const idGeneratorFn = htmlIdGenerator(); + +function areStopsValid(colorStops: Array<{ color: string; stop: string }>) { + return colorStops.every( + ({ color, stop }) => isValidColor(color) && !Number.isNaN(parseFloat(stop)) + ); +} + +function shouldSortStops(colorStops: Array<{ color: string; stop: string | number }>) { + return colorStops.some(({ stop }, i) => { + const numberStop = Number(stop); + const prevNumberStop = Number(colorStops[i - 1]?.stop ?? -Infinity); + return numberStop < prevNumberStop; + }); +} + +export interface CustomStopsProps { + colorStops: ColorStop[]; + onChange: (colorStops: ColorStop[]) => void; + dataBounds: { min: number; max: number }; + paletteConfiguration: CustomPaletteParams | undefined; + 'data-test-prefix': string; +} +export const CustomStops = ({ + colorStops, + onChange, + paletteConfiguration, + dataBounds, + ['data-test-prefix']: dataTestPrefix, +}: CustomStopsProps) => { + const onChangeWithValidation = useCallback( + (newColorStops: Array<{ color: string; stop: string }>) => { + const areStopsValuesValid = areStopsValid(newColorStops); + const shouldSort = shouldSortStops(newColorStops); + if (areStopsValuesValid && !shouldSort) { + onChange(newColorStops.map(({ color, stop }) => ({ color, stop: Number(stop) }))); + } + }, + [onChange] + ); + + const memoizedValues = useMemo(() => { + return colorStops.map(({ color, stop }, i) => ({ + color, + stop: String(stop), + id: idGeneratorFn(), + })); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [paletteConfiguration?.name, paletteConfiguration?.reverse, paletteConfiguration?.rangeType]); + + const { inputValue: localColorStops, handleInputChange: setLocalColorStops } = useDebouncedValue({ + onChange: onChangeWithValidation, + value: memoizedValues, + }); + const [sortedReason, setSortReason] = useState(''); + const shouldEnableDelete = localColorStops.length > 2; + + const [popoverInFocus, setPopoverInFocus] = useState(false); + + // refresh on unmount: + // the onChange logic here is a bit different than the one above as it has to actively sort if required + useUnmount(() => { + const areStopsValuesValid = areStopsValid(localColorStops); + const shouldSort = shouldSortStops(localColorStops); + if (areStopsValuesValid && shouldSort) { + onChange( + localColorStops + .map(({ color, stop }) => ({ color, stop: Number(stop) })) + .sort(({ stop: stopA }, { stop: stopB }) => Number(stopA) - Number(stopB)) + ); + } + }); + + const rangeType = paletteConfiguration?.rangeType || 'percent'; + + return ( + <> + {sortedReason ? ( + +

    + {i18n.translate('xpack.lens.dynamicColoring.customPalette.sortReason', { + defaultMessage: 'Color stops have been sorted due to new stop value {value}', + values: { + value: sortedReason, + }, + })} +

    +
    + ) : null} + + + {localColorStops.map(({ color, stop, id }, index) => { + const prevStopValue = Number(localColorStops[index - 1]?.stop ?? -Infinity); + const nextStopValue = Number(localColorStops[index + 1]?.stop ?? Infinity); + + return ( + ) => { + // sort the stops when the focus leaves the row container + const shouldSort = Number(stop) > nextStopValue || prevStopValue > Number(stop); + const isFocusStillInContent = + (e.currentTarget as Node)?.contains(e.relatedTarget as Node) || popoverInFocus; + const hasInvalidColor = !isValidColor(color); + if ((shouldSort && !isFocusStillInContent) || hasInvalidColor) { + // replace invalid color with previous valid one + const lastValidColor = hasInvalidColor ? colorStops[index].color : color; + const localColorStopsCopy = localColorStops.map((item, i) => + i === index ? { color: lastValidColor, stop, id } : item + ); + setLocalColorStops( + localColorStopsCopy.sort( + ({ stop: stopA }, { stop: stopB }) => Number(stopA) - Number(stopB) + ) + ); + setSortReason(stop); + } + }} + > + + + { + const newStopString = target.value.trim(); + const newColorStops = [...localColorStops]; + newColorStops[index] = { + color, + stop: newStopString, + id, + }; + setLocalColorStops(newColorStops); + }} + append={rangeType === 'percent' ? '%' : undefined} + aria-label={i18n.translate( + 'xpack.lens.dynamicColoring.customPalette.stopAriaLabel', + { + defaultMessage: 'Stop {index}', + values: { + index: index + 1, + }, + } + )} + /> + + + { + // make sure that the popover is closed + if (color === '' && !popoverInFocus) { + const newColorStops = [...localColorStops]; + newColorStops[index] = { color: colorStops[index].color, stop, id }; + setLocalColorStops(newColorStops); + } + }} + > + { + const newColorStops = [...localColorStops]; + newColorStops[index] = { color: newColor, stop, id }; + setLocalColorStops(newColorStops); + }} + secondaryInputDisplay="top" + color={color} + isInvalid={!isValidColor(color)} + showAlpha + compressed + onFocus={() => setPopoverInFocus(true)} + onBlur={() => { + setPopoverInFocus(false); + if (color === '') { + const newColorStops = [...localColorStops]; + newColorStops[index] = { color: colorStops[index].color, stop, id }; + setLocalColorStops(newColorStops); + } + }} + placeholder=" " + /> + + + + + { + const newColorStops = localColorStops.filter((_, i) => i !== index); + setLocalColorStops(newColorStops); + }} + data-test-subj={`${dataTestPrefix}_dynamicColoring_removeStop_${index}`} + isDisabled={!shouldEnableDelete} + /> + + + + + ); + })} + + + + + { + const newColorStops = [...localColorStops]; + const length = newColorStops.length; + const { max } = getDataMinMax(rangeType, dataBounds); + const step = getStepValue( + colorStops, + newColorStops.map(({ color, stop }) => ({ color, stop: Number(stop) })), + max + ); + const prevColor = localColorStops[length - 1].color || DEFAULT_COLOR; + const newStop = step + Number(localColorStops[length - 1].stop); + newColorStops.push({ + color: prevColor, + stop: String(newStop), + id: idGeneratorFn(), + }); + setLocalColorStops(newColorStops); + }} + > + {i18n.translate('xpack.lens.dynamicColoring.customPalette.addColorStop', { + defaultMessage: 'Add color stop', + })} + + + ); +}; diff --git a/x-pack/plugins/lens/public/shared_components/coloring/constants.ts b/x-pack/plugins/lens/public/shared_components/coloring/constants.ts new file mode 100644 index 0000000000000..5e6fc207656ac --- /dev/null +++ b/x-pack/plugins/lens/public/shared_components/coloring/constants.ts @@ -0,0 +1,29 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { RequiredPaletteParamTypes } from './types'; + +export const DEFAULT_PALETTE_NAME = 'positive'; +export const FIXED_PROGRESSION = 'fixed' as const; +export const CUSTOM_PALETTE = 'custom'; +export const DEFAULT_CONTINUITY = 'above'; +export const DEFAULT_MIN_STOP = 0; +export const DEFAULT_MAX_STOP = 100; +export const DEFAULT_COLOR_STEPS = 5; +export const DEFAULT_COLOR = '#6092C0'; // Same as EUI ColorStops default for new stops +export const defaultPaletteParams: RequiredPaletteParamTypes = { + name: DEFAULT_PALETTE_NAME, + reverse: false, + rangeType: 'percent', + rangeMin: DEFAULT_MIN_STOP, + rangeMax: DEFAULT_MAX_STOP, + progression: FIXED_PROGRESSION, + stops: [], + steps: DEFAULT_COLOR_STEPS, + colorStops: [], + continuity: DEFAULT_CONTINUITY, +}; diff --git a/x-pack/plugins/lens/public/shared_components/coloring/index.ts b/x-pack/plugins/lens/public/shared_components/coloring/index.ts new file mode 100644 index 0000000000000..3b34c6662c681 --- /dev/null +++ b/x-pack/plugins/lens/public/shared_components/coloring/index.ts @@ -0,0 +1,12 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { CustomizablePalette } from './palette_configuration'; +export { CustomStops } from './color_stops'; +export * from './types'; +export * from './utils'; +export * from './constants'; diff --git a/x-pack/plugins/lens/public/shared_components/coloring/palette_configuration.scss b/x-pack/plugins/lens/public/shared_components/coloring/palette_configuration.scss new file mode 100644 index 0000000000000..c6b14c5c5f9a3 --- /dev/null +++ b/x-pack/plugins/lens/public/shared_components/coloring/palette_configuration.scss @@ -0,0 +1,7 @@ +.lnsPalettePanel__section--shaded { + background-color: $euiColorLightestShade; +} + +.lnsPalettePanel__section { + padding: $euiSizeS; +} \ No newline at end of file diff --git a/x-pack/plugins/lens/public/shared_components/coloring/palette_configuration.test.tsx b/x-pack/plugins/lens/public/shared_components/coloring/palette_configuration.test.tsx new file mode 100644 index 0000000000000..28ba28a5801e4 --- /dev/null +++ b/x-pack/plugins/lens/public/shared_components/coloring/palette_configuration.test.tsx @@ -0,0 +1,185 @@ +/* + * 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 { EuiColorPalettePickerPaletteProps } from '@elastic/eui'; +import { mountWithIntl } from '@kbn/test/jest'; +import { chartPluginMock } from 'src/plugins/charts/public/mocks'; +import { PaletteOutput, PaletteRegistry } from 'src/plugins/charts/public'; +import { ReactWrapper } from 'enzyme'; +import { CustomPaletteParams } from './types'; +import { applyPaletteParams } from './utils'; +import { CustomizablePalette } from './palette_configuration'; + +describe('palette utilities', () => { + const paletteRegistry = chartPluginMock.createPaletteRegistry(); + describe('applyPaletteParams', () => { + it('should return a set of colors for a basic configuration', () => { + expect( + applyPaletteParams( + paletteRegistry, + { type: 'palette', name: 'positive' }, + { min: 0, max: 100 } + ) + ).toEqual([ + { color: 'blue', stop: 20 }, + { color: 'yellow', stop: 70 }, + ]); + }); + + it('should reverse the palette color stops correctly', () => { + expect( + applyPaletteParams( + paletteRegistry, + { + type: 'palette', + name: 'positive', + params: { reverse: true }, + }, + { min: 0, max: 100 } + ) + ).toEqual([ + { color: 'yellow', stop: 20 }, + { color: 'blue', stop: 70 }, + ]); + }); + }); +}); + +describe('palette panel', () => { + const paletteRegistry = chartPluginMock.createPaletteRegistry(); + let props: { + palettes: PaletteRegistry; + activePalette: PaletteOutput; + setPalette: (palette: PaletteOutput) => void; + dataBounds: { min: number; max: number }; + }; + + describe('palette picker', () => { + beforeEach(() => { + props = { + activePalette: { type: 'palette', name: 'positive' }, + palettes: paletteRegistry, + setPalette: jest.fn(), + dataBounds: { min: 0, max: 100 }, + }; + }); + + function changePaletteIn(instance: ReactWrapper, newPaletteName: string) { + return ((instance + .find('[data-test-subj="lnsDatatable_dynamicColoring_palette_picker"]') + .at(1) + .prop('onChange') as unknown) as (value: string) => void)?.(newPaletteName); + } + + it('should show only dynamic coloring enabled palette + custom option', () => { + const instance = mountWithIntl(); + const paletteOptions = instance + .find('[data-test-subj="lnsDatatable_dynamicColoring_palette_picker"]') + .at(1) + .prop('palettes') as EuiColorPalettePickerPaletteProps[]; + expect(paletteOptions.length).toEqual(2); + + expect(paletteOptions[paletteOptions.length - 1]).toEqual({ + title: 'Custom Mocked Palette', // <- picks the title of the custom palette + type: 'fixed', + value: 'custom', + palette: ['blue', 'yellow'], + 'data-test-subj': 'custom-palette', + }); + }); + + it('should set the colorStops and stops when selecting the Custom palette from the list', () => { + const instance = mountWithIntl(); + + changePaletteIn(instance, 'custom'); + + expect(props.setPalette).toHaveBeenCalledWith({ + type: 'palette', + name: 'custom', + params: expect.objectContaining({ + colorStops: [ + { color: 'blue', stop: 0 }, + { color: 'yellow', stop: 50 }, + ], + stops: [ + { color: 'blue', stop: 50 }, + { color: 'yellow', stop: 100 }, + ], + name: 'custom', + }), + }); + }); + + describe('reverse option', () => { + beforeEach(() => { + props = { + activePalette: { type: 'palette', name: 'positive' }, + palettes: paletteRegistry, + setPalette: jest.fn(), + dataBounds: { min: 0, max: 100 }, + }; + }); + + function toggleReverse(instance: ReactWrapper, checked: boolean) { + return instance + .find('[data-test-subj="lnsDatatable_dynamicColoring_reverse"]') + .first() + .prop('onClick')!({} as React.MouseEvent); + } + + it('should reverse the colorStops on click', () => { + const instance = mountWithIntl(); + + toggleReverse(instance, true); + + expect(props.setPalette).toHaveBeenCalledWith( + expect.objectContaining({ + params: expect.objectContaining({ + reverse: true, + }), + }) + ); + }); + }); + + describe('custom stops', () => { + beforeEach(() => { + props = { + activePalette: { type: 'palette', name: 'positive' }, + palettes: paletteRegistry, + setPalette: jest.fn(), + dataBounds: { min: 0, max: 100 }, + }; + }); + it('should be visible for predefined palettes', () => { + const instance = mountWithIntl(); + expect( + instance.find('[data-test-subj="lnsDatatable_dynamicColoring_custom_stops"]').exists() + ).toEqual(true); + }); + + it('should be visible for custom palettes', () => { + const instance = mountWithIntl( + + ); + expect( + instance.find('[data-test-subj="lnsDatatable_dynamicColoring_custom_stops"]').exists() + ).toEqual(true); + }); + }); + }); +}); diff --git a/x-pack/plugins/lens/public/shared_components/coloring/palette_configuration.tsx b/x-pack/plugins/lens/public/shared_components/coloring/palette_configuration.tsx new file mode 100644 index 0000000000000..df01b3e57cd7d --- /dev/null +++ b/x-pack/plugins/lens/public/shared_components/coloring/palette_configuration.tsx @@ -0,0 +1,340 @@ +/* + * 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 { PaletteOutput, PaletteRegistry } from 'src/plugins/charts/public'; +import { + EuiFormRow, + htmlIdGenerator, + EuiButtonGroup, + EuiFlexGroup, + EuiFlexItem, + EuiSuperSelect, + EuiIcon, + EuiIconTip, + EuiLink, + EuiText, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { PalettePicker } from './palette_picker'; + +import './palette_configuration.scss'; + +import { CustomStops } from './color_stops'; +import { defaultPaletteParams, CUSTOM_PALETTE, DEFAULT_COLOR_STEPS } from './constants'; +import { CustomPaletteParams, RequiredPaletteParamTypes } from './types'; +import { + getColorStops, + getPaletteStops, + mergePaletteParams, + getDataMinMax, + remapStopsByNewInterval, + getSwitchToCustomParams, + reversePalette, + roundStopValues, +} from './utils'; +const idPrefix = htmlIdGenerator()(); + +/** + * Some name conventions here: + * * `displayStops` => It's an additional transformation of `stops` into a [0, N] domain for the EUIPaletteDisplay component. + * * `stops` => final steps used to table coloring. It is a rightShift of the colorStops + * * `colorStops` => user's color stop inputs. Used to compute range min. + * + * When the user inputs the colorStops, they are designed to be the initial part of the color segment, + * so the next stops indicate where the previous stop ends. + * Both table coloring logic and EuiPaletteDisplay format implementation works differently than our current `colorStops`, + * by having the stop values at the end of each color segment rather than at the beginning: `stops` values are computed by a rightShift of `colorStops`. + * EuiPaletteDisplay has an additional requirement as it is always mapped against a domain [0, N]: from `stops` the `displayStops` are computed with + * some continuity enrichment and a remap against a [0, 100] domain to make the palette component work ok. + * + * These naming conventions would be useful to track the code flow in this feature as multiple transformations are happening + * for a single change. + */ + +export function CustomizablePalette({ + palettes, + activePalette, + setPalette, + dataBounds, +}: { + palettes: PaletteRegistry; + activePalette: PaletteOutput; + setPalette: (palette: PaletteOutput) => void; + dataBounds: { min: number; max: number }; +}) { + const isCurrentPaletteCustom = activePalette.params?.name === CUSTOM_PALETTE; + + const colorStopsToShow = roundStopValues( + getColorStops(palettes, activePalette?.params?.colorStops || [], activePalette, dataBounds) + ); + + return ( + <> +
    + + { + const isNewPaletteCustom = newPalette.name === CUSTOM_PALETTE; + const newParams: CustomPaletteParams = { + ...activePalette.params, + name: newPalette.name, + colorStops: undefined, + }; + + if (isNewPaletteCustom) { + newParams.colorStops = getColorStops(palettes, [], activePalette, dataBounds); + } + + newParams.stops = getPaletteStops(palettes, newParams, { + prevPalette: + isNewPaletteCustom || isCurrentPaletteCustom ? undefined : newPalette.name, + dataBounds, + }); + + setPalette({ + ...newPalette, + params: newParams, + }); + }} + showCustomPalette + showDynamicColorOnly + /> + + + ['continuity']) => + setPalette( + mergePaletteParams(activePalette, { + continuity, + }) + ) + } + /> + + + {i18n.translate('xpack.lens.table.dynamicColoring.rangeType.label', { + defaultMessage: 'Value type', + })}{' '} + + + } + display="rowCompressed" + > + { + const newRangeType = id.replace( + idPrefix, + '' + ) as RequiredPaletteParamTypes['rangeType']; + + const params: CustomPaletteParams = { rangeType: newRangeType }; + if (isCurrentPaletteCustom) { + const { min: newMin, max: newMax } = getDataMinMax(newRangeType, dataBounds); + const { min: oldMin, max: oldMax } = getDataMinMax( + activePalette.params?.rangeType, + dataBounds + ); + const newColorStops = remapStopsByNewInterval(colorStopsToShow, { + oldInterval: oldMax - oldMin, + newInterval: newMax - newMin, + newMin, + oldMin, + }); + const stops = getPaletteStops( + palettes, + { ...activePalette.params, colorStops: newColorStops, ...params }, + { dataBounds } + ); + params.colorStops = newColorStops; + params.stops = stops; + params.rangeMin = newColorStops[0].stop; + params.rangeMax = newColorStops[newColorStops.length - 1].stop; + } else { + params.stops = getPaletteStops( + palettes, + { ...activePalette.params, ...params }, + { prevPalette: activePalette.name, dataBounds } + ); + } + setPalette(mergePaletteParams(activePalette, params)); + }} + /> + + + { + const params: CustomPaletteParams = { reverse: !activePalette.params?.reverse }; + if (isCurrentPaletteCustom) { + params.colorStops = reversePalette(colorStopsToShow); + params.stops = getPaletteStops( + palettes, + { + ...(activePalette?.params || {}), + colorStops: params.colorStops, + }, + { dataBounds } + ); + } else { + params.stops = reversePalette( + activePalette?.params?.stops || + getPaletteStops( + palettes, + { ...activePalette.params, ...params }, + { prevPalette: activePalette.name, dataBounds } + ) + ); + } + setPalette(mergePaletteParams(activePalette, params)); + }} + > + + + + + + {i18n.translate('xpack.lens.table.dynamicColoring.reverse.label', { + defaultMessage: 'Reverse colors', + })} + + + + + } + > + { + const newParams = getSwitchToCustomParams( + palettes, + activePalette, + { + colorStops, + steps: activePalette.params!.steps || DEFAULT_COLOR_STEPS, + rangeMin: colorStops[0]?.stop, + rangeMax: colorStops[colorStops.length - 1]?.stop, + }, + dataBounds + ); + return setPalette(newParams); + }} + /> + +
    + + ); +} diff --git a/x-pack/plugins/lens/public/shared_components/coloring/palette_picker.tsx b/x-pack/plugins/lens/public/shared_components/coloring/palette_picker.tsx new file mode 100644 index 0000000000000..164ed9bf067a6 --- /dev/null +++ b/x-pack/plugins/lens/public/shared_components/coloring/palette_picker.tsx @@ -0,0 +1,109 @@ +/* + * 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 { EuiColorPalettePicker, EuiColorPalettePickerPaletteProps } from '@elastic/eui'; +import { PaletteOutput, PaletteRegistry } from 'src/plugins/charts/public'; +import { + CUSTOM_PALETTE, + DEFAULT_COLOR_STEPS, + FIXED_PROGRESSION, + defaultPaletteParams, +} from '../../shared_components/coloring/constants'; +import { CustomPaletteParams } from '../../shared_components/coloring/types'; +import { getStopsForFixedMode } from '../../shared_components/coloring/utils'; + +function getCustomPaletteConfig( + palettes: PaletteRegistry, + activePalette: PaletteOutput | undefined +) { + const { id, title } = palettes.get(CUSTOM_PALETTE); + + // Try to generate a palette from the current one + if (activePalette && activePalette.name !== CUSTOM_PALETTE) { + const currentPalette = palettes.get(activePalette.name); + if (currentPalette) { + const stops = currentPalette.getCategoricalColors(DEFAULT_COLOR_STEPS, activePalette?.params); + const palette = activePalette.params?.reverse ? stops.reverse() : stops; + return { + value: id, + title, + type: FIXED_PROGRESSION, + palette, + 'data-test-subj': `custom-palette`, + }; + } + } + // if not possible just show some text + if (!activePalette?.params?.stops) { + return { value: id, title, type: 'text' as const, 'data-test-subj': `custom-palette` }; + } + + // full custom palette + return { + value: id, + title, + type: FIXED_PROGRESSION, + 'data-test-subj': `custom-palette`, + palette: getStopsForFixedMode(activePalette.params.stops, activePalette.params.colorStops), + }; +} + +// Note: this is a special palette picker different from the one in the root shared folder +// ideally these should be merged together, but as for now this holds some custom logic hard to remove +export function PalettePicker({ + palettes, + activePalette, + setPalette, + showCustomPalette, + showDynamicColorOnly, + ...rest +}: { + palettes: PaletteRegistry; + activePalette?: PaletteOutput; + setPalette: (palette: PaletteOutput) => void; + showCustomPalette?: boolean; + showDynamicColorOnly?: boolean; +}) { + const palettesToShow: EuiColorPalettePickerPaletteProps[] = palettes + .getAll() + .filter(({ internal, canDynamicColoring }) => + showDynamicColorOnly ? canDynamicColoring : !internal + ) + .map(({ id, title, getCategoricalColors }) => { + const colors = getCategoricalColors( + DEFAULT_COLOR_STEPS, + id === activePalette?.name ? activePalette?.params : undefined + ); + return { + value: id, + title, + type: FIXED_PROGRESSION, + palette: activePalette?.params?.reverse ? colors.reverse() : colors, + 'data-test-subj': `${id}-palette`, + }; + }); + if (showCustomPalette) { + palettesToShow.push(getCustomPaletteConfig(palettes, activePalette)); + } + return ( + { + setPalette({ + type: 'palette', + name: newPalette, + }); + }} + valueOfSelected={activePalette?.name || defaultPaletteParams.name} + selectionDisplay="palette" + {...rest} + /> + ); +} diff --git a/x-pack/plugins/lens/public/shared_components/coloring/types.ts b/x-pack/plugins/lens/public/shared_components/coloring/types.ts new file mode 100644 index 0000000000000..d9a8edf0ccb62 --- /dev/null +++ b/x-pack/plugins/lens/public/shared_components/coloring/types.ts @@ -0,0 +1,25 @@ +/* + * 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. + */ +export interface ColorStop { + color: string; + stop: number; +} + +export interface CustomPaletteParams { + name?: string; + reverse?: boolean; + rangeType?: 'number' | 'percent'; + continuity?: 'above' | 'below' | 'all' | 'none'; + progression?: 'fixed'; + rangeMin?: number; + rangeMax?: number; + stops?: ColorStop[]; + colorStops?: ColorStop[]; + steps?: number; +} + +export type RequiredPaletteParamTypes = Required; diff --git a/x-pack/plugins/lens/public/shared_components/coloring/utils.test.ts b/x-pack/plugins/lens/public/shared_components/coloring/utils.test.ts new file mode 100644 index 0000000000000..8aaab0923584d --- /dev/null +++ b/x-pack/plugins/lens/public/shared_components/coloring/utils.test.ts @@ -0,0 +1,399 @@ +/* + * 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 { chartPluginMock } from 'src/plugins/charts/public/mocks'; +import { + applyPaletteParams, + getContrastColor, + getDataMinMax, + getPaletteStops, + getStepValue, + isValidColor, + mergePaletteParams, + remapStopsByNewInterval, + reversePalette, + roundStopValues, +} from './utils'; + +describe('applyPaletteParams', () => { + const paletteRegistry = chartPluginMock.createPaletteRegistry(); + it('should return a palette stops array only by the name', () => { + expect( + applyPaletteParams( + paletteRegistry, + { name: 'default', type: 'palette', params: { name: 'default' } }, + { min: 0, max: 100 } + ) + ).toEqual([ + // stops are 0 and 50 by with a 20 offset (100 divided by 5 steps) for display + // the mock palette service has only 2 colors so tests are a bit off by that + { color: 'red', stop: 20 }, + { color: 'black', stop: 70 }, + ]); + }); + + it('should return a palette stops array reversed', () => { + expect( + applyPaletteParams( + paletteRegistry, + { name: 'default', type: 'palette', params: { name: 'default', reverse: true } }, + { min: 0, max: 100 } + ) + ).toEqual([ + { color: 'black', stop: 20 }, + { color: 'red', stop: 70 }, + ]); + }); +}); + +describe('remapStopsByNewInterval', () => { + it('should correctly remap the current palette from 0..1 to 0...100', () => { + expect( + remapStopsByNewInterval( + [ + { color: 'black', stop: 0 }, + { color: 'green', stop: 0.5 }, + { color: 'red', stop: 0.9 }, + ], + { newInterval: 100, oldInterval: 1, newMin: 0, oldMin: 0 } + ) + ).toEqual([ + { color: 'black', stop: 0 }, + { color: 'green', stop: 50 }, + { color: 'red', stop: 90 }, + ]); + + // now test the other way around + expect( + remapStopsByNewInterval( + [ + { color: 'black', stop: 0 }, + { color: 'green', stop: 50 }, + { color: 'red', stop: 90 }, + ], + { newInterval: 1, oldInterval: 100, newMin: 0, oldMin: 0 } + ) + ).toEqual([ + { color: 'black', stop: 0 }, + { color: 'green', stop: 0.5 }, + { color: 'red', stop: 0.9 }, + ]); + }); + + it('should correctly handle negative numbers to/from', () => { + expect( + remapStopsByNewInterval( + [ + { color: 'black', stop: -100 }, + { color: 'green', stop: -50 }, + { color: 'red', stop: -1 }, + ], + { newInterval: 100, oldInterval: 100, newMin: 0, oldMin: -100 } + ) + ).toEqual([ + { color: 'black', stop: 0 }, + { color: 'green', stop: 50 }, + { color: 'red', stop: 99 }, + ]); + + // now map the other way around + expect( + remapStopsByNewInterval( + [ + { color: 'black', stop: 0 }, + { color: 'green', stop: 50 }, + { color: 'red', stop: 99 }, + ], + { newInterval: 100, oldInterval: 100, newMin: -100, oldMin: 0 } + ) + ).toEqual([ + { color: 'black', stop: -100 }, + { color: 'green', stop: -50 }, + { color: 'red', stop: -1 }, + ]); + + // and test also palettes that also contains negative values + expect( + remapStopsByNewInterval( + [ + { color: 'black', stop: -50 }, + { color: 'green', stop: 0 }, + { color: 'red', stop: 50 }, + ], + { newInterval: 100, oldInterval: 100, newMin: 0, oldMin: -50 } + ) + ).toEqual([ + { color: 'black', stop: 0 }, + { color: 'green', stop: 50 }, + { color: 'red', stop: 100 }, + ]); + }); +}); + +describe('getDataMinMax', () => { + it('should pick the correct min/max based on the current range type', () => { + expect(getDataMinMax('percent', { min: -100, max: 0 })).toEqual({ min: 0, max: 100 }); + }); + + it('should pick the correct min/max apply percent by default', () => { + expect(getDataMinMax(undefined, { min: -100, max: 0 })).toEqual({ min: 0, max: 100 }); + }); +}); + +describe('getPaletteStops', () => { + const paletteRegistry = chartPluginMock.createPaletteRegistry(); + it('should correctly compute a predefined palette stops definition from only the name', () => { + expect( + getPaletteStops(paletteRegistry, { name: 'mock' }, { dataBounds: { min: 0, max: 100 } }) + ).toEqual([ + { color: 'blue', stop: 20 }, + { color: 'yellow', stop: 70 }, + ]); + }); + + it('should correctly compute a predefined palette stops definition from explicit prevPalette (override)', () => { + expect( + getPaletteStops( + paletteRegistry, + { name: 'default' }, + { dataBounds: { min: 0, max: 100 }, prevPalette: 'mock' } + ) + ).toEqual([ + { color: 'blue', stop: 20 }, + { color: 'yellow', stop: 70 }, + ]); + }); + + it('should infer the domain from dataBounds but start from 0', () => { + expect( + getPaletteStops( + paletteRegistry, + { name: 'default', rangeType: 'number' }, + { dataBounds: { min: 1, max: 11 }, prevPalette: 'mock' } + ) + ).toEqual([ + { color: 'blue', stop: 2 }, + { color: 'yellow', stop: 7 }, + ]); + }); + + it('should override the minStop when requested', () => { + expect( + getPaletteStops( + paletteRegistry, + { name: 'default', rangeType: 'number' }, + { dataBounds: { min: 1, max: 11 }, mapFromMinValue: true } + ) + ).toEqual([ + { color: 'red', stop: 1 }, + { color: 'black', stop: 6 }, + ]); + }); + + it('should compute a display stop palette from custom colorStops defined by the user', () => { + expect( + getPaletteStops( + paletteRegistry, + { + name: 'custom', + rangeType: 'number', + colorStops: [ + { color: 'green', stop: 0 }, + { color: 'blue', stop: 40 }, + { color: 'red', stop: 80 }, + ], + }, + { dataBounds: { min: 0, max: 100 } } + ) + ).toEqual([ + { color: 'green', stop: 40 }, + { color: 'blue', stop: 80 }, + { color: 'red', stop: 100 }, + ]); + }); + + it('should compute a display stop palette from custom colorStops defined by the user - handle stop at the end', () => { + expect( + getPaletteStops( + paletteRegistry, + { + name: 'custom', + rangeType: 'number', + colorStops: [ + { color: 'green', stop: 0 }, + { color: 'blue', stop: 40 }, + { color: 'red', stop: 100 }, + ], + }, + { dataBounds: { min: 0, max: 100 } } + ) + ).toEqual([ + { color: 'green', stop: 40 }, + { color: 'blue', stop: 100 }, + { color: 'red', stop: 101 }, + ]); + }); + + it('should compute a display stop palette from custom colorStops defined by the user - handle stop at the end (fractional)', () => { + expect( + getPaletteStops( + paletteRegistry, + { + name: 'custom', + rangeType: 'number', + colorStops: [ + { color: 'green', stop: 0 }, + { color: 'blue', stop: 0.4 }, + { color: 'red', stop: 1 }, + ], + }, + { dataBounds: { min: 0, max: 1 } } + ) + ).toEqual([ + { color: 'green', stop: 0.4 }, + { color: 'blue', stop: 1 }, + { color: 'red', stop: 2 }, + ]); + }); + + it('should compute a display stop palette from custom colorStops defined by the user - stretch the stops to 100% percent', () => { + expect( + getPaletteStops( + paletteRegistry, + { + name: 'custom', + colorStops: [ + { color: 'green', stop: 0 }, + { color: 'blue', stop: 0.4 }, + { color: 'red', stop: 1 }, + ], + }, + { dataBounds: { min: 0, max: 1 } } + ) + ).toEqual([ + { color: 'green', stop: 0.4 }, + { color: 'blue', stop: 1 }, + { color: 'red', stop: 100 }, // default rangeType is percent, hence stretch to 100% + ]); + }); +}); + +describe('reversePalette', () => { + it('should correctly reverse color and stops', () => { + expect( + reversePalette([ + { color: 'red', stop: 0 }, + { color: 'green', stop: 0.5 }, + { color: 'blue', stop: 0.9 }, + ]) + ).toEqual([ + { color: 'blue', stop: 0 }, + { color: 'green', stop: 0.5 }, + { color: 'red', stop: 0.9 }, + ]); + }); +}); + +describe('mergePaletteParams', () => { + it('should return a full palette', () => { + expect(mergePaletteParams({ type: 'palette', name: 'myPalette' }, { reverse: true })).toEqual({ + type: 'palette', + name: 'myPalette', + params: { reverse: true }, + }); + }); +}); + +describe('isValidColor', () => { + it('should return ok for valid hex color notation', () => { + expect(isValidColor('#fff')).toBe(true); + expect(isValidColor('#ffffff')).toBe(true); + expect(isValidColor('#ffffffaa')).toBe(true); + }); + + it('should return false for non valid strings', () => { + expect(isValidColor('')).toBe(false); + expect(isValidColor('#')).toBe(false); + expect(isValidColor('#ff')).toBe(false); + expect(isValidColor('123')).toBe(false); + expect(isValidColor('rgb(1, 1, 1)')).toBe(false); + expect(isValidColor('rgba(1, 1, 1, 0)')).toBe(false); + expect(isValidColor('#ffffffgg')).toBe(false); + expect(isValidColor('#fff00')).toBe(false); + // this version of chroma does not support hex4 format + expect(isValidColor('#fffa')).toBe(false); + }); +}); + +describe('roundStopValues', () => { + it('should round very long values', () => { + expect(roundStopValues([{ color: 'red', stop: 0.1515 }])).toEqual([ + { color: 'red', stop: 0.15 }, + ]); + }); +}); + +describe('getStepValue', () => { + it('should compute the next step based on the last 2 stops', () => { + expect( + getStepValue( + // first arg is taken as max reference + [ + { color: 'red', stop: 0 }, + { color: 'red', stop: 50 }, + ], + [ + { color: 'red', stop: 0 }, + { color: 'red', stop: 50 }, + ], + 100 + ) + ).toBe(50); + + expect( + getStepValue( + // first arg is taken as max reference + [ + { color: 'red', stop: 0 }, + { color: 'red', stop: 80 }, + ], + [ + { color: 'red', stop: 0 }, + { color: 'red', stop: 50 }, + ], + 90 + ) + ).toBe(10); // 90 - 80 + + expect( + getStepValue( + // first arg is taken as max reference + [ + { color: 'red', stop: 0 }, + { color: 'red', stop: 100 }, + ], + [ + { color: 'red', stop: 0 }, + { color: 'red', stop: 50 }, + ], + 100 + ) + ).toBe(1); + }); +}); + +describe('getContrastColor', () => { + it('should pick the light color when the passed one is dark', () => { + expect(getContrastColor('#000', true)).toBe('#ffffff'); + expect(getContrastColor('#000', false)).toBe('#ffffff'); + }); + + it('should pick the dark color when the passed one is light', () => { + expect(getContrastColor('#fff', true)).toBe('#000000'); + expect(getContrastColor('#fff', false)).toBe('#000000'); + }); +}); diff --git a/x-pack/plugins/lens/public/shared_components/coloring/utils.ts b/x-pack/plugins/lens/public/shared_components/coloring/utils.ts new file mode 100644 index 0000000000000..89fceec533493 --- /dev/null +++ b/x-pack/plugins/lens/public/shared_components/coloring/utils.ts @@ -0,0 +1,308 @@ +/* + * 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 chroma from 'chroma-js'; +import { PaletteOutput, PaletteRegistry } from 'src/plugins/charts/public'; +import { euiLightVars, euiDarkVars } from '@kbn/ui-shared-deps/theme'; +import { isColorDark } from '@elastic/eui'; +import { + CUSTOM_PALETTE, + defaultPaletteParams, + DEFAULT_COLOR_STEPS, + DEFAULT_MAX_STOP, + DEFAULT_MIN_STOP, +} from './constants'; +import { CustomPaletteParams, ColorStop } from './types'; + +/** + * Some name conventions here: + * * `displayStops` => It's an additional transformation of `stops` into a [0, N] domain for the EUIPaletteDisplay component. + * * `stops` => final steps used to table coloring. It is a rightShift of the colorStops + * * `colorStops` => user's color stop inputs. Used to compute range min. + * + * When the user inputs the colorStops, they are designed to be the initial part of the color segment, + * so the next stops indicate where the previous stop ends. + * Both table coloring logic and EuiPaletteDisplay format implementation works differently than our current `colorStops`, + * by having the stop values at the end of each color segment rather than at the beginning: `stops` values are computed by a rightShift of `colorStops`. + * EuiPaletteDisplay has an additional requirement as it is always mapped against a domain [0, N]: from `stops` the `displayStops` are computed with + * some continuity enrichment and a remap against a [0, 100] domain to make the palette component work ok. + * + * These naming conventions would be useful to track the code flow in this feature as multiple transformations are happening + * for a single change. + */ + +export function applyPaletteParams( + palettes: PaletteRegistry, + activePalette: PaletteOutput, + dataBounds: { min: number; max: number } +) { + // make a copy of it as they have to be manipulated later on + let displayStops = getPaletteStops(palettes, activePalette?.params || {}, { + dataBounds, + }); + + if (activePalette?.params?.reverse && activePalette?.params?.name !== CUSTOM_PALETTE) { + displayStops = reversePalette(displayStops); + } + return displayStops; +} + +// Need to shift the Custom palette in order to correctly visualize it when in display mode +function shiftPalette(stops: ColorStop[], max: number) { + // shift everything right and add an additional stop at the end + const result = stops.map((entry, i, array) => ({ + ...entry, + stop: i + 1 < array.length ? array[i + 1].stop : max, + })); + if (stops[stops.length - 1].stop === max) { + // extends the range by a fair amount to make it work the extra case for the last stop === max + const computedStep = getStepValue(stops, result, max) || 1; + // do not go beyond the unit step in this case + const step = Math.min(1, computedStep); + result[stops.length - 1].stop = max + step; + } + return result; +} + +// Utility to remap color stops within new domain +export function remapStopsByNewInterval( + controlStops: ColorStop[], + { + newInterval, + oldInterval, + newMin, + oldMin, + }: { newInterval: number; oldInterval: number; newMin: number; oldMin: number } +) { + return (controlStops || []).map(({ color, stop }) => { + return { + color, + stop: newMin + ((stop - oldMin) * newInterval) / oldInterval, + }; + }); +} + +function getOverallMinMax( + params: CustomPaletteParams | undefined, + dataBounds: { min: number; max: number } +) { + const { min: dataMin, max: dataMax } = getDataMinMax(params?.rangeType, dataBounds); + const minStopValue = params?.colorStops?.[0]?.stop ?? Infinity; + const maxStopValue = params?.colorStops?.[params.colorStops.length - 1]?.stop ?? -Infinity; + const overallMin = Math.min(dataMin, minStopValue); + const overallMax = Math.max(dataMax, maxStopValue); + return { min: overallMin, max: overallMax }; +} + +export function getDataMinMax( + rangeType: CustomPaletteParams['rangeType'] | undefined, + dataBounds: { min: number; max: number } +) { + const dataMin = rangeType === 'number' ? dataBounds.min : DEFAULT_MIN_STOP; + const dataMax = rangeType === 'number' ? dataBounds.max : DEFAULT_MAX_STOP; + return { min: dataMin, max: dataMax }; +} + +/** + * This is a generic function to compute stops from the current parameters. + */ +export function getPaletteStops( + palettes: PaletteRegistry, + activePaletteParams: CustomPaletteParams, + // used to customize color resolution + { + prevPalette, + dataBounds, + mapFromMinValue, + }: { prevPalette?: string; dataBounds: { min: number; max: number }; mapFromMinValue?: boolean } +) { + const { min: minValue, max: maxValue } = getOverallMinMax(activePaletteParams, dataBounds); + const interval = maxValue - minValue; + const { stops: currentStops, ...otherParams } = activePaletteParams || {}; + + if (activePaletteParams.name === 'custom' && activePaletteParams?.colorStops) { + // need to generate the palette from the existing controlStops + return shiftPalette(activePaletteParams.colorStops, maxValue); + } + // generate a palette from predefined ones and customize the domain + const colorStopsFromPredefined = palettes + .get(prevPalette || activePaletteParams?.name || defaultPaletteParams.name) + .getCategoricalColors(defaultPaletteParams.steps, otherParams); + + const newStopsMin = mapFromMinValue ? minValue : interval / defaultPaletteParams.steps; + + const stops = remapStopsByNewInterval( + colorStopsFromPredefined.map((color, index) => ({ color, stop: index })), + { + newInterval: interval, + oldInterval: colorStopsFromPredefined.length, + newMin: newStopsMin, + oldMin: 0, + } + ); + return stops; +} + +export function reversePalette(paletteColorRepresentation: ColorStop[] = []) { + const stops = paletteColorRepresentation.map(({ stop }) => stop); + return paletteColorRepresentation + .map(({ color }, i) => ({ + color, + stop: stops[paletteColorRepresentation.length - i - 1], + })) + .reverse(); +} + +export function mergePaletteParams( + activePalette: PaletteOutput, + newParams: CustomPaletteParams +): PaletteOutput { + return { + ...activePalette, + params: { + ...activePalette.params, + ...newParams, + }, + }; +} + +function isValidPonyfill(colorString: string) { + // we're using an old version of chroma without the valid function + try { + chroma(colorString); + return true; + } catch (e) { + return false; + } +} + +export function isValidColor(colorString: string) { + // chroma can handle also hex values with alpha channel/transparency + // chroma accepts also hex without #, so test for it + return colorString !== '' && /^#/.test(colorString) && isValidPonyfill(colorString); +} + +export function roundStopValues(colorStops: ColorStop[]) { + return colorStops.map(({ color, stop }) => { + const roundedStop = Number(stop.toFixed(2)); + return { color, stop: roundedStop }; + }); +} + +// very simple heuristic: pick last two stops and compute a new stop based on the same distance +// if the new stop is above max, then reduce the step to reach max, or if zero then just 1. +// +// it accepts two series of stops as the function is used also when computing stops from colorStops +export function getStepValue(colorStops: ColorStop[], newColorStops: ColorStop[], max: number) { + const length = newColorStops.length; + // workout the steps from the last 2 items + const dataStep = newColorStops[length - 1].stop - newColorStops[length - 2].stop || 1; + let step = Number(dataStep.toFixed(2)); + if (max < colorStops[length - 1].stop + step) { + const diffToMax = max - colorStops[length - 1].stop; + // if the computed step goes way out of bound, fallback to 1, otherwise reach max + step = diffToMax > 0 ? diffToMax : 1; + } + return step; +} + +export function getSwitchToCustomParams( + palettes: PaletteRegistry, + activePalette: PaletteOutput, + newParams: CustomPaletteParams, + dataBounds: { min: number; max: number } +) { + // if it's already a custom palette just return the params + if (activePalette?.params?.name === CUSTOM_PALETTE) { + const stops = getPaletteStops( + palettes, + { + steps: DEFAULT_COLOR_STEPS, + ...activePalette.params, + ...newParams, + }, + { + dataBounds, + } + ); + return mergePaletteParams(activePalette, { + ...newParams, + stops, + }); + } + // prepare everything to switch to custom palette + const newPaletteParams = { + steps: DEFAULT_COLOR_STEPS, + ...activePalette.params, + ...newParams, + name: CUSTOM_PALETTE, + }; + + const stops = getPaletteStops(palettes, newPaletteParams, { + prevPalette: newPaletteParams.colorStops ? undefined : activePalette.name, + dataBounds, + }); + return mergePaletteParams( + { name: CUSTOM_PALETTE, type: 'palette' }, + { + ...newPaletteParams, + stops, + } + ); +} + +export function getColorStops( + palettes: PaletteRegistry, + colorStops: Required['stops'], + activePalette: PaletteOutput, + dataBounds: { min: number; max: number } +) { + // just forward the current stops if custom + if (activePalette?.name === CUSTOM_PALETTE) { + return colorStops; + } + // for predefined palettes create some stops, then drop the last one. + // we're using these as starting point for the user + let freshColorStops = getPaletteStops( + palettes, + { ...activePalette?.params }, + // mapFromMinValue is a special flag to offset the stops values + // used here to avoid a new remap/left shift + { dataBounds, mapFromMinValue: true } + ); + if (activePalette?.params?.reverse) { + freshColorStops = reversePalette(freshColorStops); + } + return freshColorStops; +} + +export function getContrastColor(color: string, isDarkTheme: boolean) { + const darkColor = isDarkTheme ? euiDarkVars.euiColorInk : euiLightVars.euiColorInk; + const lightColor = isDarkTheme ? euiDarkVars.euiColorGhost : euiLightVars.euiColorGhost; + return isColorDark(...chroma(color).rgb()) ? lightColor : darkColor; +} + +/** + * Same as stops, but remapped against a range 0-100 + */ +export function getStopsForFixedMode(stops: ColorStop[], colorStops?: ColorStop[]) { + const referenceStops = + colorStops || stops.map(({ color }, index) => ({ color, stop: 20 * index })); + const fallbackStops = stops; + + // what happens when user set two stops with the same value? we'll fallback to the display interval + const oldInterval = + referenceStops[referenceStops.length - 1].stop - referenceStops[0].stop || + fallbackStops[fallbackStops.length - 1].stop - fallbackStops[0].stop; + + return remapStopsByNewInterval(stops, { + newInterval: 100, + oldInterval, + newMin: 0, + oldMin: referenceStops[0].stop, + }); +} diff --git a/x-pack/plugins/lens/public/shared_components/helpers.ts b/x-pack/plugins/lens/public/shared_components/helpers.ts new file mode 100644 index 0000000000000..a9f35757c4cbf --- /dev/null +++ b/x-pack/plugins/lens/public/shared_components/helpers.ts @@ -0,0 +1,31 @@ +/* + * 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 { useRef } from 'react'; +import useDebounce from 'react-use/lib/useDebounce'; + +export const useDebounceWithOptions = ( + fn: Function, + { skipFirstRender }: { skipFirstRender: boolean } = { skipFirstRender: false }, + ms?: number | undefined, + deps?: React.DependencyList | undefined +) => { + const isFirstRender = useRef(true); + const newDeps = [...(deps || []), isFirstRender]; + + return useDebounce( + () => { + if (skipFirstRender && isFirstRender.current) { + isFirstRender.current = false; + return; + } + return fn(); + }, + ms, + newDeps + ); +}; diff --git a/x-pack/plugins/lens/public/shared_components/index.ts b/x-pack/plugins/lens/public/shared_components/index.ts index ae57da976a881..cf8536884acdf 100644 --- a/x-pack/plugins/lens/public/shared_components/index.ts +++ b/x-pack/plugins/lens/public/shared_components/index.ts @@ -9,4 +9,7 @@ export * from './empty_placeholder'; export { ToolbarPopoverProps, ToolbarPopover } from './toolbar_popover'; export { LegendSettingsPopover } from './legend_settings_popover'; export { PalettePicker } from './palette_picker'; +export { TooltipWrapper } from './tooltip_wrapper'; +export * from './coloring'; export { useDebouncedValue } from './debounced_value'; +export * from './helpers'; diff --git a/x-pack/plugins/lens/public/shared_components/palette_picker.tsx b/x-pack/plugins/lens/public/shared_components/palette_picker.tsx index b15a6749d4c2d..6424dc8143f95 100644 --- a/x-pack/plugins/lens/public/shared_components/palette_picker.tsx +++ b/x-pack/plugins/lens/public/shared_components/palette_picker.tsx @@ -7,10 +7,9 @@ import React from 'react'; import { PaletteOutput, PaletteRegistry } from 'src/plugins/charts/public'; -import { EuiColorPalettePicker } from '@elastic/eui'; +import { EuiColorPalettePicker, EuiColorPalettePickerPaletteProps } from '@elastic/eui'; import { EuiFormRow } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { NativeRenderer } from '../native_renderer'; export function PalettePicker({ palettes, @@ -21,6 +20,20 @@ export function PalettePicker({ activePalette?: PaletteOutput; setPalette: (palette: PaletteOutput) => void; }) { + const palettesToShow: EuiColorPalettePickerPaletteProps[] = palettes + .getAll() + .filter(({ internal }) => !internal) + .map(({ id, title, getCategoricalColors }) => { + return { + value: id, + title, + type: 'fixed', + palette: getCategoricalColors( + 10, + id === activePalette?.name ? activePalette?.params : undefined + ), + }; + }); return ( !internal) - .map(({ id, title, getColors }) => { - return { - value: id, - title, - type: 'fixed', - palette: getColors( - 10, - id === activePalette?.name ? activePalette?.params : undefined - ), - }; - })} + palettes={palettesToShow} onChange={(newPalette) => { setPalette({ type: 'palette', @@ -56,21 +56,6 @@ export function PalettePicker({ valueOfSelected={activePalette?.name || 'default'} selectionDisplay={'palette'} /> - {activePalette && palettes.get(activePalette.name).renderEditor && ( - { - setPalette({ - type: 'palette', - name: activePalette.name, - params: updater(activePalette.params), - }); - }, - }} - /> - )} ); diff --git a/x-pack/plugins/lens/public/xy_visualization/tooltip_wrapper.tsx b/x-pack/plugins/lens/public/shared_components/tooltip_wrapper.tsx similarity index 100% rename from x-pack/plugins/lens/public/xy_visualization/tooltip_wrapper.tsx rename to x-pack/plugins/lens/public/shared_components/tooltip_wrapper.tsx diff --git a/x-pack/plugins/lens/public/types.ts b/x-pack/plugins/lens/public/types.ts index 5a632e03f8f36..984fbf5555949 100644 --- a/x-pack/plugins/lens/public/types.ts +++ b/x-pack/plugins/lens/public/types.ts @@ -9,6 +9,7 @@ import { IconType } from '@elastic/eui/src/components/icon/icon'; import { CoreSetup } from 'kibana/public'; import { PaletteOutput, PaletteRegistry } from 'src/plugins/charts/public'; import { SavedObjectReference } from 'kibana/public'; +import { MutableRefObject } from 'react'; import { RowClickContext } from '../../../../src/plugins/ui_actions/public'; import { ExpressionAstExpression, @@ -391,13 +392,14 @@ export type VisualizationDimensionEditorProps = VisualizationConfig groupId: string; accessor: string; setState: (newState: T) => void; + panelRef: MutableRefObject; }; export interface AccessorConfig { columnId: string; triggerIcon?: 'color' | 'disabled' | 'colorBy' | 'none' | 'invisible'; color?: string; - palette?: string[]; + palette?: string[] | Array<{ color: string; stop: number }>; } export type VisualizationDimensionGroupConfig = SharedDimensionProps & { diff --git a/x-pack/plugins/lens/public/xy_visualization/color_assignment.ts b/x-pack/plugins/lens/public/xy_visualization/color_assignment.ts index d2e87ece5b5ec..ef0c350f20961 100644 --- a/x-pack/plugins/lens/public/xy_visualization/color_assignment.ts +++ b/x-pack/plugins/lens/public/xy_visualization/color_assignment.ts @@ -118,7 +118,7 @@ export function getAccessorColorConfig( ); const customColor = currentYConfig?.color || - paletteService.get(currentPalette.name).getColor( + paletteService.get(currentPalette.name).getCategoricalColor( [ { name: columnToLabel[accessor] || accessor, diff --git a/x-pack/plugins/lens/public/xy_visualization/expression.tsx b/x-pack/plugins/lens/public/xy_visualization/expression.tsx index e3b4565913ad8..608971d281981 100644 --- a/x-pack/plugins/lens/public/xy_visualization/expression.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/expression.tsx @@ -798,7 +798,7 @@ export function XYChart({ ), }, ]; - return paletteService.get(palette.name).getColor( + return paletteService.get(palette.name).getCategoricalColor( seriesLayers, { maxDepth: 1, diff --git a/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/visual_options_popover.tsx b/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/visual_options_popover.tsx index b07feb85892e5..843680e3f28ac 100644 --- a/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/visual_options_popover.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/visual_options_popover.tsx @@ -7,14 +7,13 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; -import { ToolbarPopover } from '../../shared_components'; +import { ToolbarPopover, TooltipWrapper } from '../../shared_components'; import { MissingValuesOptions } from './missing_values_option'; import { LineCurveOption } from './line_curve_option'; import { FillOpacityOption } from './fill_opacity_option'; import { XYState } from '../types'; import { hasHistogramSeries } from '../state_helpers'; import { ValidLayer } from '../types'; -import { TooltipWrapper } from '../tooltip_wrapper'; import { FramePublicAPI } from '../../types'; function getValueLabelDisableReason({ diff --git a/x-pack/plugins/lens/public/xy_visualization/visualization.test.ts b/x-pack/plugins/lens/public/xy_visualization/visualization.test.ts index aa4b91b840db3..8fbc8e8b2ef7a 100644 --- a/x-pack/plugins/lens/public/xy_visualization/visualization.test.ts +++ b/x-pack/plugins/lens/public/xy_visualization/visualization.test.ts @@ -481,12 +481,12 @@ describe('xy_visualization', () => { it('should query palette to fill in colors for other dimensions', () => { const palette = paletteServiceMock.get('default'); - (palette.getColor as jest.Mock).mockClear(); + (palette.getCategoricalColor as jest.Mock).mockClear(); const accessorConfig = callConfigAndFindYConfig({}, 'c'); expect(accessorConfig.triggerIcon).toEqual('color'); // black is the color returned from the palette mock expect(accessorConfig.color).toEqual('black'); - expect(palette.getColor).toHaveBeenCalledWith( + expect(palette.getCategoricalColor).toHaveBeenCalledWith( [ { name: 'c', @@ -505,9 +505,9 @@ describe('xy_visualization', () => { label: 'Overwritten label', }); const palette = paletteServiceMock.get('default'); - (palette.getColor as jest.Mock).mockClear(); + (palette.getCategoricalColor as jest.Mock).mockClear(); callConfigAndFindYConfig({}, 'c'); - expect(palette.getColor).toHaveBeenCalledWith( + expect(palette.getCategoricalColor).toHaveBeenCalledWith( [ expect.objectContaining({ name: 'Overwritten label', @@ -526,7 +526,7 @@ describe('xy_visualization', () => { }, 'c' ); - expect(palette.getColor).toHaveBeenCalled(); + expect(palette.getCategoricalColor).toHaveBeenCalled(); }); it('should not show any indicator as long as there is no data', () => { @@ -551,7 +551,7 @@ describe('xy_visualization', () => { it('should show current palette for break down by dimension', () => { const palette = paletteServiceMock.get('mock'); const customColors = ['yellow', 'green']; - (palette.getColors as jest.Mock).mockReturnValue(customColors); + (palette.getCategoricalColors as jest.Mock).mockReturnValue(customColors); const breakdownConfig = callConfigForBreakdownConfigs({ palette: { type: 'palette', name: 'mock', params: {} }, splitAccessor: 'd', @@ -570,9 +570,9 @@ describe('xy_visualization', () => { paletteGetter.mockReturnValue({ id: 'default', title: '', - getColors: jest.fn(), + getCategoricalColors: jest.fn(), toExpression: jest.fn(), - getColor: jest.fn().mockReturnValueOnce('blue').mockReturnValueOnce('green'), + getCategoricalColor: jest.fn().mockReturnValueOnce('blue').mockReturnValueOnce('green'), }); const yConfigs = callConfigForYConfigs({}); diff --git a/x-pack/plugins/lens/public/xy_visualization/visualization.tsx b/x-pack/plugins/lens/public/xy_visualization/visualization.tsx index 19cfcb1a60cc7..fa9d46be11d68 100644 --- a/x-pack/plugins/lens/public/xy_visualization/visualization.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/visualization.tsx @@ -235,7 +235,7 @@ export const getXyVisualization = ({ triggerIcon: 'colorBy', palette: paletteService .get(layer.palette?.name || 'default') - .getColors(10, layer.palette?.params), + .getCategoricalColors(10, layer.palette?.params), }, ] : [], diff --git a/x-pack/plugins/lens/public/xy_visualization/xy_config_panel.test.tsx b/x-pack/plugins/lens/public/xy_visualization/xy_config_panel.test.tsx index 0bafbead7d543..bc10236cf1977 100644 --- a/x-pack/plugins/lens/public/xy_visualization/xy_config_panel.test.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/xy_config_panel.test.tsx @@ -260,6 +260,7 @@ describe('XY Config panels', () => { state={{ ...state, layers: [{ ...state.layers[0], seriesType: 'bar_horizontal' }] }} formatFactory={jest.fn()} paletteService={chartPluginMock.createPaletteRegistry()} + panelRef={React.createRef()} /> ); @@ -283,6 +284,7 @@ describe('XY Config panels', () => { state={state} formatFactory={jest.fn()} paletteService={chartPluginMock.createPaletteRegistry()} + panelRef={React.createRef()} /> ); @@ -326,6 +328,7 @@ describe('XY Config panels', () => { }} formatFactory={jest.fn()} paletteService={chartPluginMock.createPaletteRegistry()} + panelRef={React.createRef()} /> ); @@ -365,6 +368,7 @@ describe('XY Config panels', () => { }} formatFactory={jest.fn()} paletteService={chartPluginMock.createPaletteRegistry()} + panelRef={React.createRef()} /> ); diff --git a/x-pack/plugins/lens/public/xy_visualization/xy_config_panel.tsx b/x-pack/plugins/lens/public/xy_visualization/xy_config_panel.tsx index a6517894654ed..48f0cacf75938 100644 --- a/x-pack/plugins/lens/public/xy_visualization/xy_config_panel.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/xy_config_panel.tsx @@ -41,9 +41,8 @@ import { isHorizontalChart, isHorizontalSeries, getSeriesColor } from './state_h import { trackUiEvent } from '../lens_ui_telemetry'; import { LegendSettingsPopover } from '../shared_components'; import { AxisSettingsPopover } from './axis_settings_popover'; -import { TooltipWrapper } from './tooltip_wrapper'; import { getAxesConfiguration, GroupsConfiguration } from './axes_configuration'; -import { PalettePicker } from '../shared_components'; +import { PalettePicker, TooltipWrapper } from '../shared_components'; import { getAccessorColorConfig, getColorAssignments } from './color_assignment'; import { getScaleType, getSortedAccessors } from './to_expression'; import { VisualOptionsPopover } from './visual_options_popover/visual_options_popover'; diff --git a/x-pack/plugins/maps/public/kibana_services.ts b/x-pack/plugins/maps/public/kibana_services.ts index 1652e78d3d2cb..4fce4c276c336 100644 --- a/x-pack/plugins/maps/public/kibana_services.ts +++ b/x-pack/plugins/maps/public/kibana_services.ts @@ -112,7 +112,7 @@ export async function getChartsPaletteServiceGetColor(): Promise< const chartConfiguration = { syncColors: true }; return (value: string) => { const series = [{ name: value, rankAtDepth: 0, totalSeriesAtDepth: 1 }]; - const color = paletteDefinition.getColor(series, chartConfiguration); + const color = paletteDefinition.getCategoricalColor(series, chartConfiguration); return color ? color : '#3d3d3d'; }; } diff --git a/x-pack/test/accessibility/apps/lens.ts b/x-pack/test/accessibility/apps/lens.ts index a8d20ff56de08..682aa5a576f9e 100644 --- a/x-pack/test/accessibility/apps/lens.ts +++ b/x-pack/test/accessibility/apps/lens.ts @@ -69,6 +69,29 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await a11y.testAppSnapshot(); }); + it('lens datatable with dynamic cell colouring', async () => { + await PageObjects.lens.openDimensionEditor('lnsDatatable_metrics > lns-dimensionTrigger'); + await PageObjects.lens.setTableDynamicColoring('cell'); + await a11y.testAppSnapshot(); + }); + + it('lens datatable with dynamic text colouring', async () => { + await PageObjects.lens.setTableDynamicColoring('text'); + await a11y.testAppSnapshot(); + }); + + it('lens datatable with palette panel open', async () => { + await PageObjects.lens.openTablePalettePanel(); + await a11y.testAppSnapshot(); + }); + + it('lens datatable with custom palette stops', async () => { + await PageObjects.lens.changePaletteTo('custom'); + await a11y.testAppSnapshot(); + await PageObjects.lens.closePaletteEditor(); + await PageObjects.lens.closeDimensionEditor(); + }); + it('lens metric chart', async () => { await PageObjects.lens.switchToVisualization('lnsMetric'); await a11y.testAppSnapshot(); diff --git a/x-pack/test/functional/apps/lens/table.ts b/x-pack/test/functional/apps/lens/table.ts index f0f3ce27f4c31..f048bf47991f2 100644 --- a/x-pack/test/functional/apps/lens/table.ts +++ b/x-pack/test/functional/apps/lens/table.ts @@ -13,6 +13,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const listingTable = getService('listingTable'); const find = getService('find'); const retry = getService('retry'); + const testSubjects = getService('testSubjects'); describe('lens datatable', () => { it('should able to sort a table by a column', async () => { @@ -93,5 +94,55 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.header.waitUntilLoadingHasFinished(); expect(await PageObjects.lens.getDatatableCellText(0, 2)).to.eql('17,246'); }); + + it('should show dynamic coloring feature for numeric columns', async () => { + await PageObjects.lens.openDimensionEditor('lnsDatatable_metrics > lns-dimensionTrigger'); + await PageObjects.lens.setTableDynamicColoring('text'); + await PageObjects.header.waitUntilLoadingHasFinished(); + const styleObj = await PageObjects.lens.getDatatableCellStyle(0, 2); + expect(styleObj['background-color']).to.be(undefined); + expect(styleObj.color).to.be('rgb(133, 189, 177)'); + }); + + it('should allow to color cell background rather than text', async () => { + await PageObjects.lens.setTableDynamicColoring('cell'); + await PageObjects.header.waitUntilLoadingHasFinished(); + const styleObj = await PageObjects.lens.getDatatableCellStyle(0, 2); + expect(styleObj['background-color']).to.be('rgb(133, 189, 177)'); + // should also set text color when in cell mode + expect(styleObj.color).to.be('rgb(0, 0, 0)'); + }); + + it('should open the palette panel to customize the palette look', async () => { + await PageObjects.lens.openTablePalettePanel(); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.lens.changePaletteTo('temperature'); + await PageObjects.header.waitUntilLoadingHasFinished(); + const styleObj = await PageObjects.lens.getDatatableCellStyle(0, 2); + expect(styleObj['background-color']).to.be('rgb(235, 239, 245)'); + }); + + it('tweak the color stops numeric value', async () => { + await testSubjects.setValue('lnsDatatable_dynamicColoring_stop_value_0', '30', { + clearWithKeyboard: true, + }); + // when clicking on another row will trigger a sorting + update + await testSubjects.click('lnsDatatable_dynamicColoring_stop_value_1'); + await PageObjects.header.waitUntilLoadingHasFinished(); + // pick a cell without color as is below the range + const styleObj = await PageObjects.lens.getDatatableCellStyle(3, 3); + expect(styleObj['background-color']).to.be(undefined); + // should also set text color when in cell mode + expect(styleObj.color).to.be(undefined); + }); + + it('should allow the user to reverse the palette', async () => { + await testSubjects.click('lnsDatatable_dynamicColoring_reverse'); + await PageObjects.header.waitUntilLoadingHasFinished(); + const styleObj = await PageObjects.lens.getDatatableCellStyle(1, 1); + expect(styleObj['background-color']).to.be('rgb(168, 191, 218)'); + // should also set text color when in cell mode + expect(styleObj.color).to.be('rgb(0, 0, 0)'); + }); }); } diff --git a/x-pack/test/functional/page_objects/lens_page.ts b/x-pack/test/functional/page_objects/lens_page.ts index f73440e331466..b16944cd73060 100644 --- a/x-pack/test/functional/page_objects/lens_page.ts +++ b/x-pack/test/functional/page_objects/lens_page.ts @@ -126,8 +126,7 @@ export function LensPageProvider({ getService, getPageObjects }: FtrProviderCont } if (opts.palette) { - await testSubjects.click('lns-palettePicker'); - await find.clickByCssSelector(`#${opts.palette}`); + await this.setPalette(opts.palette); } if (!opts.keepOpen) { @@ -671,6 +670,18 @@ export function LensPageProvider({ getService, getPageObjects }: FtrProviderCont return el.getVisibleText(); }, + async getDatatableCellStyle(rowIndex = 0, colIndex = 0) { + const el = await this.getDatatableCell(rowIndex, colIndex); + const styleString = await el.getAttribute('style'); + return styleString.split(';').reduce>((memo, cssLine) => { + const [prop, value] = cssLine.split(':'); + if (prop && value) { + memo[prop.trim()] = value.trim(); + } + return memo; + }, {}); + }, + async getDatatableHeader(index = 0) { return find.byCssSelector( `[data-test-subj="lnsDataTable"] [data-test-subj="dataGridHeader"] [role=columnheader]:nth-child(${ @@ -714,6 +725,46 @@ export function LensPageProvider({ getService, getPageObjects }: FtrProviderCont return buttonEl.click(); }, + async setTableDynamicColoring(coloringType: 'none' | 'cell' | 'text') { + await testSubjects.click('lnsDatatable_dynamicColoring_groups_' + coloringType); + }, + + async openTablePalettePanel() { + await testSubjects.click('lnsDatatable_dynamicColoring_trigger'); + }, + + // different picker from the next one + async changePaletteTo(paletteName: string) { + await testSubjects.click('lnsDatatable_dynamicColoring_palette_picker'); + await testSubjects.click(`${paletteName}-palette`); + }, + + async setPalette(paletteName: string) { + await testSubjects.click('lns-palettePicker'); + await find.clickByCssSelector(`#${paletteName}`); + }, + + async closePaletteEditor() { + await retry.try(async () => { + await testSubjects.click('lns-indexPattern-PalettePanelContainerBack'); + await testSubjects.missingOrFail('lns-indexPattern-PalettePanelContainerBack'); + }); + }, + + async openColorStopPopup(index = 0) { + const stopEls = await testSubjects.findAll('euiColorStopThumb'); + if (stopEls[index]) { + await stopEls[index].click(); + } + }, + + async setColorStopValue(value: number | string) { + await testSubjects.setValue( + 'lnsDatatable_dynamicColoring_progression_custom_stops_value', + String(value) + ); + }, + async toggleColumnVisibility(dimension: string) { await this.openDimensionEditor(dimension); const id = 'lns-table-column-hidden'; From 8715de8c5ec98c91c58cd5597e0f1f7e91caf8e5 Mon Sep 17 00:00:00 2001 From: Alexey Antonov Date: Fri, 28 May 2021 16:39:38 +0300 Subject: [PATCH 60/77] [TSVB] Fix Upgrading from 7.12.1 to 7.13.0 breaks TSVB (#100864) Closes: #100778 --- .../common/index_patterns_utils.test.ts | 6 +-- .../common/index_patterns_utils.ts | 6 +-- .../application/components/index_pattern.js | 46 +++++++++++++++++-- .../index_pattern_select.tsx | 31 ++----------- .../server/lib/get_vis_data.ts | 28 +++++------ .../lib/cached_index_pattern_fetcher.ts | 9 +++- 6 files changed, 75 insertions(+), 51 deletions(-) diff --git a/src/plugins/vis_type_timeseries/common/index_patterns_utils.test.ts b/src/plugins/vis_type_timeseries/common/index_patterns_utils.test.ts index 7828ee33736ee..a601da234e078 100644 --- a/src/plugins/vis_type_timeseries/common/index_patterns_utils.test.ts +++ b/src/plugins/vis_type_timeseries/common/index_patterns_utils.test.ts @@ -90,7 +90,7 @@ describe('fetchIndexPattern', () => { ] as IndexPattern[]; const value = await fetchIndexPattern('indexTitle', indexPatternsService, { - fetchKibabaIndexForStringIndexes: true, + fetchKibanaIndexForStringIndexes: true, }); expect(value).toMatchInlineSnapshot(` @@ -104,9 +104,9 @@ describe('fetchIndexPattern', () => { `); }); - test('should return only indexPatternString if Kibana index does not exist (fetchKibabaIndexForStringIndexes is true)', async () => { + test('should return only indexPatternString if Kibana index does not exist (fetchKibanaIndexForStringIndexes is true)', async () => { const value = await fetchIndexPattern('indexTitle', indexPatternsService, { - fetchKibabaIndexForStringIndexes: true, + fetchKibanaIndexForStringIndexes: true, }); expect(value).toMatchInlineSnapshot(` diff --git a/src/plugins/vis_type_timeseries/common/index_patterns_utils.ts b/src/plugins/vis_type_timeseries/common/index_patterns_utils.ts index 152fd5182225b..1224fd33daee3 100644 --- a/src/plugins/vis_type_timeseries/common/index_patterns_utils.ts +++ b/src/plugins/vis_type_timeseries/common/index_patterns_utils.ts @@ -51,9 +51,9 @@ export const fetchIndexPattern = async ( indexPatternValue: IndexPatternValue | undefined, indexPatternsService: Pick, options: { - fetchKibabaIndexForStringIndexes: boolean; + fetchKibanaIndexForStringIndexes: boolean; } = { - fetchKibabaIndexForStringIndexes: false, + fetchKibanaIndexForStringIndexes: false, } ): Promise => { let indexPattern: FetchedIndexPattern['indexPattern']; @@ -63,7 +63,7 @@ export const fetchIndexPattern = async ( indexPattern = await indexPatternsService.getDefault(); } else { if (isStringTypeIndexPattern(indexPatternValue)) { - if (options.fetchKibabaIndexForStringIndexes) { + if (options.fetchKibanaIndexForStringIndexes) { indexPattern = (await indexPatternsService.find(indexPatternValue)).find( (index) => index.title === indexPatternValue ); diff --git a/src/plugins/vis_type_timeseries/public/application/components/index_pattern.js b/src/plugins/vis_type_timeseries/public/application/components/index_pattern.js index bc2d9124e9c4a..7d18af2bd0d59 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/index_pattern.js +++ b/src/plugins/vis_type_timeseries/public/application/components/index_pattern.js @@ -8,7 +8,7 @@ import { get } from 'lodash'; import PropTypes from 'prop-types'; -import React, { useContext, useCallback, useEffect } from 'react'; +import React, { useContext, useCallback, useEffect, useState } from 'react'; import { htmlIdGenerator, EuiFieldText, @@ -29,15 +29,17 @@ import { LastValueModePopover } from './last_value_mode_popover'; import { KBN_FIELD_TYPES } from '../../../../data/public'; import { FormValidationContext } from '../contexts/form_validation_context'; import { DefaultIndexPatternContext } from '../contexts/default_index_context'; +import { PanelModelContext } from '../contexts/panel_model_context'; import { isGteInterval, validateReInterval, isAutoInterval } from './lib/get_interval'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import { PANEL_TYPES, TIME_RANGE_DATA_MODES, TIME_RANGE_MODE_KEY } from '../../../common/enums'; -import { AUTO_INTERVAL } from '../../../common/constants'; +import { AUTO_INTERVAL, USE_KIBANA_INDEXES_KEY } from '../../../common/constants'; import { isTimerangeModeEnabled } from '../lib/check_ui_restrictions'; import { VisDataContext } from '../contexts/vis_data_context'; -import { getUISettings } from '../../services'; +import { getDataStart, getUISettings } from '../../services'; import { UI_SETTINGS } from '../../../../data/common'; +import { fetchIndexPattern } from '../../../common/index_patterns_utils'; const RESTRICT_FIELDS = [KBN_FIELD_TYPES.DATE]; const LEVEL_OF_DETAIL_STEPS = 10; @@ -77,8 +79,13 @@ export const IndexPattern = ({ const dropBucketName = `${prefix}drop_last_bucket`; const updateControlValidity = useContext(FormValidationContext); const defaultIndex = useContext(DefaultIndexPatternContext); + const panelModel = useContext(PanelModelContext); + const uiRestrictions = get(useContext(VisDataContext), 'uiRestrictions'); const maxBarsUiSettings = config.get(UI_SETTINGS.HISTOGRAM_MAX_BARS); + const useKibanaIndices = Boolean(panelModel?.[USE_KIBANA_INDEXES_KEY]); + + const [fetchedIndex, setFetchedIndex] = useState(); const handleMaxBarsChange = useCallback( ({ target }) => { @@ -118,6 +125,7 @@ export const IndexPattern = ({ }; const model = { ...defaults, ..._model }; + const index = model[indexPatternName]; const intervalValidation = validateIntervalValue(model[intervalName]); const selectedTimeRangeOption = timeRangeOptions.find( @@ -133,11 +141,40 @@ export const IndexPattern = ({ updateControlValidity(intervalName, intervalValidation.isValid); }, [intervalName, intervalValidation.isValid, updateControlValidity]); + useEffect(() => { + async function fetchIndex() { + const { indexPatterns } = getDataStart(); + + setFetchedIndex( + index + ? await fetchIndexPattern(index, indexPatterns, { + fetchKibanaIndexForStringIndexes: true, + }) + : { + indexPattern: undefined, + indexPatternString: undefined, + } + ); + } + + fetchIndex(); + }, [index]); + const toggleIndicatorDisplay = useCallback( () => onChange({ [HIDE_LAST_VALUE_INDICATOR]: !model.hide_last_value_indicator }), [model.hide_last_value_indicator, onChange] ); + const getTimefieldPlaceholder = () => { + if (!model[indexPatternName]) { + return defaultIndex?.timeFieldName; + } + + if (useKibanaIndices) { + return fetchedIndex?.indexPattern?.timeFieldName ?? undefined; + } + }; + return (
    {!isTimeSeries && ( @@ -207,6 +244,7 @@ export const IndexPattern = ({ diff --git a/src/plugins/vis_type_timeseries/public/application/components/lib/index_pattern_select/index_pattern_select.tsx b/src/plugins/vis_type_timeseries/public/application/components/lib/index_pattern_select/index_pattern_select.tsx index ece90d4799309..07edfc2e6e0d7 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/lib/index_pattern_select/index_pattern_select.tsx +++ b/src/plugins/vis_type_timeseries/public/application/components/lib/index_pattern_select/index_pattern_select.tsx @@ -6,18 +6,15 @@ * Side Public License, v 1. */ -import React, { useState, useContext, useCallback, useEffect } from 'react'; +import React, { useContext, useCallback } from 'react'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import { EuiFormRow, EuiText, EuiLink, htmlIdGenerator } from '@elastic/eui'; -import { getCoreStart, getDataStart } from '../../../../services'; +import { getCoreStart } from '../../../../services'; import { PanelModelContext } from '../../../contexts/panel_model_context'; -import { - isStringTypeIndexPattern, - fetchIndexPattern, -} from '../../../../../common/index_patterns_utils'; +import { isStringTypeIndexPattern } from '../../../../../common/index_patterns_utils'; import { FieldTextSelect } from './field_text_select'; import { ComboBoxSelect } from './combo_box_select'; @@ -32,6 +29,7 @@ interface IndexPatternSelectProps { onChange: Function; disabled?: boolean; allowIndexSwitchingMode?: boolean; + fetchedIndex: FetchedIndexPattern | null; } const defaultIndexPatternHelpText = i18n.translate( @@ -57,13 +55,13 @@ export const IndexPatternSelect = ({ indexPatternName, onChange, disabled, + fetchedIndex, allowIndexSwitchingMode, }: IndexPatternSelectProps) => { const htmlId = htmlIdGenerator(); const panelModel = useContext(PanelModelContext); const defaultIndex = useContext(DefaultIndexPatternContext); - const [fetchedIndex, setFetchedIndex] = useState(); const useKibanaIndices = Boolean(panelModel?.[USE_KIBANA_INDEXES_KEY]); const Component = useKibanaIndices ? ComboBoxSelect : FieldTextSelect; @@ -98,25 +96,6 @@ export const IndexPatternSelect = ({ }); }, [fetchedIndex]); - useEffect(() => { - async function fetchIndex() { - const { indexPatterns } = getDataStart(); - - setFetchedIndex( - value - ? await fetchIndexPattern(value, indexPatterns, { - fetchKibabaIndexForStringIndexes: true, - }) - : { - indexPattern: undefined, - indexPatternString: undefined, - } - ); - } - - fetchIndex(); - }, [value]); - if (!fetchedIndex) { return null; } diff --git a/src/plugins/vis_type_timeseries/server/lib/get_vis_data.ts b/src/plugins/vis_type_timeseries/server/lib/get_vis_data.ts index cb105d7b439cc..5cdea62af9536 100644 --- a/src/plugins/vis_type_timeseries/server/lib/get_vis_data.ts +++ b/src/plugins/vis_type_timeseries/server/lib/get_vis_data.ts @@ -31,20 +31,22 @@ export async function getVisData( const indexPatternsService = await framework.getIndexPatternsService(requestContext); const esQueryConfig = await getEsQueryConfig(uiSettings); - const services: VisTypeTimeseriesRequestServices = { - esQueryConfig, - esShardTimeout, - indexPatternsService, - uiSettings, - searchStrategyRegistry: framework.searchStrategyRegistry, - cachedIndexPatternFetcher: getCachedIndexPatternFetcher(indexPatternsService), - }; - const promises = request.body.panels.map((panel) => { - if (panel.type === PANEL_TYPES.TABLE) { - return getTableData(requestContext, request, panel, services); - } - return getSeriesData(requestContext, request, panel, services); + const services: VisTypeTimeseriesRequestServices = { + esQueryConfig, + esShardTimeout, + indexPatternsService, + uiSettings, + searchStrategyRegistry: framework.searchStrategyRegistry, + cachedIndexPatternFetcher: getCachedIndexPatternFetcher( + indexPatternsService, + Boolean(panel.use_kibana_indexes) + ), + }; + + return panel.type === PANEL_TYPES.TABLE + ? getTableData(requestContext, request, panel, services) + : getSeriesData(requestContext, request, panel, services); }); return Promise.all(promises).then((res) => { diff --git a/src/plugins/vis_type_timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.ts b/src/plugins/vis_type_timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.ts index b03fa973e9da9..26ea191ab9217 100644 --- a/src/plugins/vis_type_timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.ts +++ b/src/plugins/vis_type_timeseries/server/lib/search_strategies/lib/cached_index_pattern_fetcher.ts @@ -11,7 +11,10 @@ import { getIndexPatternKey, fetchIndexPattern } from '../../../../common/index_ import type { IndexPatternsService } from '../../../../../data/server'; import type { IndexPatternValue, FetchedIndexPattern } from '../../../../common/types'; -export const getCachedIndexPatternFetcher = (indexPatternsService: IndexPatternsService) => { +export const getCachedIndexPatternFetcher = ( + indexPatternsService: IndexPatternsService, + fetchKibanaIndexForStringIndexes: boolean = false +) => { const cache = new Map(); return async (indexPatternValue: IndexPatternValue): Promise => { @@ -21,7 +24,9 @@ export const getCachedIndexPatternFetcher = (indexPatternsService: IndexPatterns return cache.get(key); } - const fetchedIndex = fetchIndexPattern(indexPatternValue, indexPatternsService); + const fetchedIndex = fetchIndexPattern(indexPatternValue, indexPatternsService, { + fetchKibanaIndexForStringIndexes, + }); cache.set(key, fetchedIndex); From c0f9970a5553b293d7044f3f0ad3baeeaa090960 Mon Sep 17 00:00:00 2001 From: ymao1 Date: Fri, 28 May 2021 09:52:58 -0400 Subject: [PATCH 61/77] [Alerting] Adding feature flag for enabling/disabling rule import and export (#100718) * Adding feature flag for enabling rule import and export * Removing item from docs Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- docs/user/alerting/rule-management.asciidoc | 9 -- x-pack/plugins/alerting/server/config.test.ts | 3 +- x-pack/plugins/alerting/server/config.ts | 1 + .../alerting/server/health/get_state.test.ts | 8 ++ x-pack/plugins/alerting/server/plugin.test.ts | 73 ++++++++++++ x-pack/plugins/alerting/server/plugin.ts | 2 +- .../alerting/server/saved_objects/index.ts | 104 ++++++++++-------- 7 files changed, 141 insertions(+), 59 deletions(-) diff --git a/docs/user/alerting/rule-management.asciidoc b/docs/user/alerting/rule-management.asciidoc index e47858f58cd1a..b908bd03b0992 100644 --- a/docs/user/alerting/rule-management.asciidoc +++ b/docs/user/alerting/rule-management.asciidoc @@ -57,15 +57,6 @@ These operations can also be performed in bulk by multi-selecting rules and clic [role="screenshot"] image:images/bulk-mute-disable.png[The Manage rules button lets you mute/unmute, enable/disable, and delete in bulk] -[float] -[[importing-and-exporting-rules]] -=== Importing and exporting rules - -To import and export rules, use the <>. -After the succesful import the proper banner will be displayed: -[role="screenshot"] -image::images/rules-imported-banner.png[Rules import banner, width=50%] - [float] === Required permissions diff --git a/x-pack/plugins/alerting/server/config.test.ts b/x-pack/plugins/alerting/server/config.test.ts index 069c41605ccfb..a8befe5210752 100644 --- a/x-pack/plugins/alerting/server/config.test.ts +++ b/x-pack/plugins/alerting/server/config.test.ts @@ -8,10 +8,11 @@ import { configSchema } from './config'; describe('config validation', () => { - test('alerts defaults', () => { + test('alerting defaults', () => { const config: Record = {}; expect(configSchema.validate(config)).toMatchInlineSnapshot(` Object { + "enableImportExport": false, "healthCheck": Object { "interval": "60m", }, diff --git a/x-pack/plugins/alerting/server/config.ts b/x-pack/plugins/alerting/server/config.ts index e42955b385bf1..d50917fd13578 100644 --- a/x-pack/plugins/alerting/server/config.ts +++ b/x-pack/plugins/alerting/server/config.ts @@ -16,6 +16,7 @@ export const configSchema = schema.object({ interval: schema.string({ validate: validateDurationSchema, defaultValue: '5m' }), removalDelay: schema.string({ validate: validateDurationSchema, defaultValue: '1h' }), }), + enableImportExport: schema.boolean({ defaultValue: false }), }); export type AlertsConfig = TypeOf; diff --git a/x-pack/plugins/alerting/server/health/get_state.test.ts b/x-pack/plugins/alerting/server/health/get_state.test.ts index 643d966d1fad0..96627e10fb3bd 100644 --- a/x-pack/plugins/alerting/server/health/get_state.test.ts +++ b/x-pack/plugins/alerting/server/health/get_state.test.ts @@ -72,6 +72,7 @@ describe('getHealthServiceStatusWithRetryAndErrorHandling', () => { interval: '5m', removalDelay: '1h', }, + enableImportExport: false, }), pollInterval ).subscribe(); @@ -107,6 +108,7 @@ describe('getHealthServiceStatusWithRetryAndErrorHandling', () => { interval: '5m', removalDelay: '1h', }, + enableImportExport: false, }), pollInterval, retryDelay @@ -152,6 +154,7 @@ describe('getHealthServiceStatusWithRetryAndErrorHandling', () => { interval: '5m', removalDelay: '1h', }, + enableImportExport: false, }) ).toPromise(); @@ -182,6 +185,7 @@ describe('getHealthServiceStatusWithRetryAndErrorHandling', () => { interval: '5m', removalDelay: '1h', }, + enableImportExport: false, }) ).toPromise(); @@ -212,6 +216,7 @@ describe('getHealthServiceStatusWithRetryAndErrorHandling', () => { interval: '5m', removalDelay: '1h', }, + enableImportExport: false, }) ).toPromise(); @@ -239,6 +244,7 @@ describe('getHealthServiceStatusWithRetryAndErrorHandling', () => { interval: '5m', removalDelay: '1h', }, + enableImportExport: false, }), retryDelay ).subscribe((status) => { @@ -269,6 +275,7 @@ describe('getHealthServiceStatusWithRetryAndErrorHandling', () => { interval: '5m', removalDelay: '1h', }, + enableImportExport: false, }), retryDelay ).subscribe((status) => { @@ -305,6 +312,7 @@ describe('getHealthServiceStatusWithRetryAndErrorHandling', () => { interval: '5m', removalDelay: '1h', }, + enableImportExport: false, }) ).toPromise(); diff --git a/x-pack/plugins/alerting/server/plugin.test.ts b/x-pack/plugins/alerting/server/plugin.test.ts index ec4b7095d67f7..4e9249944a6bf 100644 --- a/x-pack/plugins/alerting/server/plugin.test.ts +++ b/x-pack/plugins/alerting/server/plugin.test.ts @@ -18,6 +18,7 @@ import { AlertsConfig } from './config'; import { AlertType } from './types'; import { eventLogMock } from '../../event_log/server/mocks'; import { actionsMock } from '../../actions/server/mocks'; +import mappings from './saved_objects/mappings.json'; describe('Alerting Plugin', () => { describe('setup()', () => { @@ -25,6 +26,8 @@ describe('Alerting Plugin', () => { let coreSetup: ReturnType; let pluginsSetup: jest.Mocked; + beforeEach(() => jest.clearAllMocks()); + it('should log warning when Encrypted Saved Objects plugin is missing encryption key', async () => { const context = coreMock.createPluginInitializerContext({ healthCheck: { @@ -34,6 +37,7 @@ describe('Alerting Plugin', () => { interval: '5m', removalDelay: '1h', }, + enableImportExport: false, }); plugin = new AlertingPlugin(context); @@ -57,6 +61,72 @@ describe('Alerting Plugin', () => { ); }); + it('should register saved object with no management capability if enableImportExport is false', async () => { + const context = coreMock.createPluginInitializerContext({ + healthCheck: { + interval: '5m', + }, + invalidateApiKeysTask: { + interval: '5m', + removalDelay: '1h', + }, + enableImportExport: false, + }); + plugin = new AlertingPlugin(context); + + const setupMocks = coreMock.createSetup(); + await plugin.setup(setupMocks, { + licensing: licensingMock.createSetup(), + encryptedSavedObjects: encryptedSavedObjectsMock.createSetup(), + taskManager: taskManagerMock.createSetup(), + eventLog: eventLogServiceMock.create(), + actions: actionsMock.createSetup(), + statusService: statusServiceMock.createSetupContract(), + }); + + expect(setupMocks.savedObjects.registerType).toHaveBeenCalledTimes(2); + const registerAlertingSavedObject = setupMocks.savedObjects.registerType.mock.calls[0][0]; + expect(registerAlertingSavedObject.name).toEqual('alert'); + expect(registerAlertingSavedObject.hidden).toBe(true); + expect(registerAlertingSavedObject.mappings).toEqual(mappings.alert); + expect(registerAlertingSavedObject.management).toBeUndefined(); + }); + + it('should register saved object with import/export capability if enableImportExport is true', async () => { + const context = coreMock.createPluginInitializerContext({ + healthCheck: { + interval: '5m', + }, + invalidateApiKeysTask: { + interval: '5m', + removalDelay: '1h', + }, + enableImportExport: true, + }); + plugin = new AlertingPlugin(context); + + const setupMocks = coreMock.createSetup(); + await plugin.setup(setupMocks, { + licensing: licensingMock.createSetup(), + encryptedSavedObjects: encryptedSavedObjectsMock.createSetup(), + taskManager: taskManagerMock.createSetup(), + eventLog: eventLogServiceMock.create(), + actions: actionsMock.createSetup(), + statusService: statusServiceMock.createSetupContract(), + }); + + expect(setupMocks.savedObjects.registerType).toHaveBeenCalledTimes(2); + const registerAlertingSavedObject = setupMocks.savedObjects.registerType.mock.calls[0][0]; + expect(registerAlertingSavedObject.name).toEqual('alert'); + expect(registerAlertingSavedObject.hidden).toBe(true); + expect(registerAlertingSavedObject.mappings).toEqual(mappings.alert); + expect(registerAlertingSavedObject.management).not.toBeUndefined(); + expect(registerAlertingSavedObject.management?.importableAndExportable).toBe(true); + expect(registerAlertingSavedObject.management?.getTitle).not.toBeUndefined(); + expect(registerAlertingSavedObject.management?.onImport).not.toBeUndefined(); + expect(registerAlertingSavedObject.management?.onExport).not.toBeUndefined(); + }); + describe('registerType()', () => { let setup: PluginSetupContract; const sampleAlertType: AlertType = { @@ -119,6 +189,7 @@ describe('Alerting Plugin', () => { interval: '5m', removalDelay: '1h', }, + enableImportExport: false, }); const plugin = new AlertingPlugin(context); @@ -158,6 +229,7 @@ describe('Alerting Plugin', () => { interval: '5m', removalDelay: '1h', }, + enableImportExport: false, }); const plugin = new AlertingPlugin(context); @@ -211,6 +283,7 @@ describe('Alerting Plugin', () => { interval: '5m', removalDelay: '1h', }, + enableImportExport: false, }); const plugin = new AlertingPlugin(context); diff --git a/x-pack/plugins/alerting/server/plugin.ts b/x-pack/plugins/alerting/server/plugin.ts index 990733c320dfe..769243b8feaf6 100644 --- a/x-pack/plugins/alerting/server/plugin.ts +++ b/x-pack/plugins/alerting/server/plugin.ts @@ -190,7 +190,7 @@ export class AlertingPlugin { event: { provider: EVENT_LOG_PROVIDER }, }); - setupSavedObjects(core.savedObjects, plugins.encryptedSavedObjects); + setupSavedObjects(core.savedObjects, plugins.encryptedSavedObjects, this.config); this.eventLogService = plugins.eventLog; plugins.eventLog.registerProviderActions(EVENT_LOG_PROVIDER, Object.values(EVENT_LOG_ACTIONS)); diff --git a/x-pack/plugins/alerting/server/saved_objects/index.ts b/x-pack/plugins/alerting/server/saved_objects/index.ts index 6b76fd97dc53b..c339183eeedcd 100644 --- a/x-pack/plugins/alerting/server/saved_objects/index.ts +++ b/x-pack/plugins/alerting/server/saved_objects/index.ts @@ -16,6 +16,7 @@ import { EncryptedSavedObjectsPluginSetup } from '../../../encrypted_saved_objec import { transformRulesForExport } from './transform_rule_for_export'; import { RawAlert } from '../types'; import { getImportWarnings } from './get_import_warnings'; +import { AlertsConfig } from '../config'; export { partiallyUpdateAlert } from './partially_update_alert'; export const AlertAttributesExcludedFromAAD = [ @@ -41,59 +42,66 @@ export type AlertAttributesExcludedFromAADType = export function setupSavedObjects( savedObjects: SavedObjectsServiceSetup, - encryptedSavedObjects: EncryptedSavedObjectsPluginSetup + encryptedSavedObjects: EncryptedSavedObjectsPluginSetup, + alertingConfig: Promise ) { - savedObjects.registerType({ - name: 'alert', - hidden: true, - namespaceType: 'single', - migrations: getMigrations(encryptedSavedObjects), - mappings: mappings.alert, - management: { - importableAndExportable: true, - getTitle(ruleSavedObject: SavedObject) { - return `Rule: [${ruleSavedObject.attributes.name}]`; - }, - onImport(ruleSavedObjects) { - return { - warnings: getImportWarnings(ruleSavedObjects), - }; - }, - onExport( - context: SavedObjectsExportTransformContext, - objects: Array> - ) { - return transformRulesForExport(objects); - }, - }, - }); + alertingConfig.then((config: AlertsConfig) => { + savedObjects.registerType({ + name: 'alert', + hidden: true, + namespaceType: 'single', + migrations: getMigrations(encryptedSavedObjects), + mappings: mappings.alert, + ...(config.enableImportExport + ? { + management: { + importableAndExportable: true, + getTitle(ruleSavedObject: SavedObject) { + return `Rule: [${ruleSavedObject.attributes.name}]`; + }, + onImport(ruleSavedObjects) { + return { + warnings: getImportWarnings(ruleSavedObjects), + }; + }, + onExport( + context: SavedObjectsExportTransformContext, + objects: Array> + ) { + return transformRulesForExport(objects); + }, + }, + } + : {}), + }); - savedObjects.registerType({ - name: 'api_key_pending_invalidation', - hidden: true, - namespaceType: 'agnostic', - mappings: { - properties: { - apiKeyId: { - type: 'keyword', - }, - createdAt: { - type: 'date', + savedObjects.registerType({ + name: 'api_key_pending_invalidation', + hidden: true, + namespaceType: 'agnostic', + mappings: { + properties: { + apiKeyId: { + type: 'keyword', + }, + createdAt: { + type: 'date', + }, }, }, - }, - }); + }); - // Encrypted attributes - encryptedSavedObjects.registerType({ - type: 'alert', - attributesToEncrypt: new Set(['apiKey']), - attributesToExcludeFromAAD: new Set(AlertAttributesExcludedFromAAD), - }); + // Encrypted attributes + encryptedSavedObjects.registerType({ + type: 'alert', + attributesToEncrypt: new Set(['apiKey']), + attributesToExcludeFromAAD: new Set(AlertAttributesExcludedFromAAD), + }); - // Encrypted attributes - encryptedSavedObjects.registerType({ - type: 'api_key_pending_invalidation', - attributesToEncrypt: new Set(['apiKeyId']), + // Encrypted attributes + encryptedSavedObjects.registerType({ + type: 'api_key_pending_invalidation', + attributesToEncrypt: new Set(['apiKeyId']), + }); }); } From b575a4545f35268e33904d3b625e3cb7990c3930 Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Fri, 28 May 2021 15:02:44 +0100 Subject: [PATCH 62/77] chore(NA): moving @kbn/io-ts-utils into bazel (#100810) --- .../monorepo-packages.asciidoc | 1 + package.json | 2 +- packages/BUILD.bazel | 1 + packages/kbn-io-ts-utils/BUILD.bazel | 85 +++++++++++++++++++ packages/kbn-io-ts-utils/package.json | 7 +- packages/kbn-io-ts-utils/tsconfig.json | 2 +- .../kbn-server-route-repository/package.json | 3 - yarn.lock | 2 +- 8 files changed, 91 insertions(+), 12 deletions(-) create mode 100644 packages/kbn-io-ts-utils/BUILD.bazel diff --git a/docs/developer/getting-started/monorepo-packages.asciidoc b/docs/developer/getting-started/monorepo-packages.asciidoc index 4e8bbf76eaacb..dbfbe90ec9263 100644 --- a/docs/developer/getting-started/monorepo-packages.asciidoc +++ b/docs/developer/getting-started/monorepo-packages.asciidoc @@ -80,6 +80,7 @@ yarn kbn watch-bazel - @kbn/eslint-plugin-eslint - @kbn/expect - @kbn/i18n +- @kbn/io-ts-utils - @kbn/legacy-logging - @kbn/logging - @kbn/mapbox-gl diff --git a/package.json b/package.json index 627e8abd9d259..f41c85c4c7b80 100644 --- a/package.json +++ b/package.json @@ -133,7 +133,7 @@ "@kbn/mapbox-gl": "link:bazel-bin/packages/kbn-mapbox-gl/npm_module", "@kbn/i18n": "link:bazel-bin/packages/kbn-i18n/npm_module", "@kbn/interpreter": "link:packages/kbn-interpreter", - "@kbn/io-ts-utils": "link:packages/kbn-io-ts-utils", + "@kbn/io-ts-utils": "link:bazel-bin/packages/kbn-io-ts-utils/npm_module", "@kbn/legacy-logging": "link:bazel-bin/packages/kbn-legacy-logging/npm_module", "@kbn/logging": "link:bazel-bin/packages/kbn-logging/npm_module", "@kbn/monaco": "link:bazel-bin/packages/kbn-monaco/npm_module", diff --git a/packages/BUILD.bazel b/packages/BUILD.bazel index c885666f7a916..de3498da1a697 100644 --- a/packages/BUILD.bazel +++ b/packages/BUILD.bazel @@ -22,6 +22,7 @@ filegroup( "//packages/kbn-eslint-plugin-eslint:build", "//packages/kbn-expect:build", "//packages/kbn-i18n:build", + "//packages/kbn-io-ts-utils:build", "//packages/kbn-legacy-logging:build", "//packages/kbn-logging:build", "//packages/kbn-mapbox-gl:build", diff --git a/packages/kbn-io-ts-utils/BUILD.bazel b/packages/kbn-io-ts-utils/BUILD.bazel new file mode 100644 index 0000000000000..6b26173fe8f36 --- /dev/null +++ b/packages/kbn-io-ts-utils/BUILD.bazel @@ -0,0 +1,85 @@ +load("@npm//@bazel/typescript:index.bzl", "ts_config", "ts_project") +load("@build_bazel_rules_nodejs//:index.bzl", "js_library", "pkg_npm") + +PKG_BASE_NAME = "kbn-io-ts-utils" +PKG_REQUIRE_NAME = "@kbn/io-ts-utils" + +SOURCE_FILES = glob( + [ + "src/**/*.ts", + ], + exclude = [ + "**/*.test.*" + ], +) + +SRCS = SOURCE_FILES + +filegroup( + name = "srcs", + srcs = SRCS, +) + +NPM_MODULE_EXTRA_FILES = [ + "package.json", +] + +SRC_DEPS = [ + "@npm//fp-ts", + "@npm//io-ts", + "@npm//lodash", + "@npm//tslib", +] + +TYPES_DEPS = [ + "@npm//@types/jest", + "@npm//@types/lodash", + "@npm//@types/node", +] + +DEPS = SRC_DEPS + TYPES_DEPS + +ts_config( + name = "tsconfig", + src = "tsconfig.json", + deps = [ + "//:tsconfig.base.json", + ], +) + +ts_project( + name = "tsc", + args = ['--pretty'], + srcs = SRCS, + deps = DEPS, + declaration = True, + declaration_map = True, + incremental = True, + out_dir = "target", + source_map = True, + root_dir = "src", + tsconfig = ":tsconfig", +) + +js_library( + name = PKG_BASE_NAME, + srcs = NPM_MODULE_EXTRA_FILES, + deps = DEPS + [":tsc"], + package_name = PKG_REQUIRE_NAME, + visibility = ["//visibility:public"], +) + +pkg_npm( + name = "npm_module", + deps = [ + ":%s" % PKG_BASE_NAME, + ] +) + +filegroup( + name = "build", + srcs = [ + ":npm_module", + ], + visibility = ["//visibility:public"], +) diff --git a/packages/kbn-io-ts-utils/package.json b/packages/kbn-io-ts-utils/package.json index 4d6f02d3f85a6..9d22277f27c01 100644 --- a/packages/kbn-io-ts-utils/package.json +++ b/packages/kbn-io-ts-utils/package.json @@ -4,10 +4,5 @@ "types": "./target/index.d.ts", "version": "1.0.0", "license": "SSPL-1.0 OR Elastic License 2.0", - "private": true, - "scripts": { - "build": "../../node_modules/.bin/tsc", - "kbn:bootstrap": "yarn build", - "kbn:watch": "yarn build --watch" - } + "private": true } diff --git a/packages/kbn-io-ts-utils/tsconfig.json b/packages/kbn-io-ts-utils/tsconfig.json index 6c67518e21073..7b8f255275499 100644 --- a/packages/kbn-io-ts-utils/tsconfig.json +++ b/packages/kbn-io-ts-utils/tsconfig.json @@ -1,7 +1,7 @@ { "extends": "../../tsconfig.base.json", "compilerOptions": { - "incremental": false, + "incremental": true, "outDir": "./target", "stripInternal": false, "declaration": true, diff --git a/packages/kbn-server-route-repository/package.json b/packages/kbn-server-route-repository/package.json index ce1ca02d0c4f6..4ae625d83a700 100644 --- a/packages/kbn-server-route-repository/package.json +++ b/packages/kbn-server-route-repository/package.json @@ -9,8 +9,5 @@ "build": "../../node_modules/.bin/tsc", "kbn:bootstrap": "yarn build", "kbn:watch": "yarn build --watch" - }, - "dependencies": { - "@kbn/io-ts-utils": "link:../kbn-io-ts-utils" } } diff --git a/yarn.lock b/yarn.lock index a92dadf08dde7..ee4fadac018bc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2666,7 +2666,7 @@ version "0.0.0" uid "" -"@kbn/io-ts-utils@link:packages/kbn-io-ts-utils": +"@kbn/io-ts-utils@link:bazel-bin/packages/kbn-io-ts-utils/npm_module": version "0.0.0" uid "" From bd2bf74de837f98f42aabcb599990ab72fd38e97 Mon Sep 17 00:00:00 2001 From: Alexey Antonov Date: Fri, 28 May 2021 17:13:13 +0300 Subject: [PATCH 63/77] [TSVB] [Table tab] Fix "Math" aggregation (#100765) --- .../server/lib/vis_data/response_processors/table/math.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/table/math.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/table/math.js index fd7f5a06cac56..5abfc3e26ffcd 100644 --- a/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/table/math.js +++ b/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/table/math.js @@ -8,9 +8,9 @@ import { mathAgg } from '../series/math'; -export function math(bucket, panel, series) { +export function math(bucket, panel, series, meta, extractFields) { return (next) => (results) => { - const mathFn = mathAgg({ aggregations: bucket }, panel, series); + const mathFn = mathAgg({ aggregations: bucket }, panel, series, meta, extractFields); return mathFn(next)(results); }; } From 1dad47fdf25e8ffb903c4f17be4258740307dbe1 Mon Sep 17 00:00:00 2001 From: Kaarina Tungseth Date: Fri, 28 May 2021 09:38:14 -0500 Subject: [PATCH 64/77] [DOCS] Adds Lens video (#100898) --- docs/user/dashboard/lens.asciidoc | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/docs/user/dashboard/lens.asciidoc b/docs/user/dashboard/lens.asciidoc index 613432908df3d..1f3b4c429f704 100644 --- a/docs/user/dashboard/lens.asciidoc +++ b/docs/user/dashboard/lens.asciidoc @@ -4,8 +4,19 @@ To create visualizations with *Lens*, you drag and drop data fields onto the visualization builder, then *Lens* uses heuristics to apply each field. -[role="screenshot"] -image:dashboard/images/lens.png[Lens] +++++ + + +
    +++++ [float] [[lens-required-choices]] From e3517edd22f6308edde5584b39015bd37e94fb62 Mon Sep 17 00:00:00 2001 From: Paul Tavares <56442535+paul-tavares@users.noreply.github.com> Date: Fri, 28 May 2021 10:40:34 -0400 Subject: [PATCH 65/77] [Security Solution][Endpoint] Endpoint generator and data loader support for Host Isolation (#100813) Re-introduces the changes from #100727 which was backed out due to a bug. Changes included: * Generate random isolation values for endpoint metadata * Generator for Fleet Actions * Added creation of actions to the index test data loader Plus: * Fix generator `randomBoolean()` to ensure it works with seeded random numbers * Update resolver snapshots due to additional call to randomizer --- .../data_generators/base_data_generator.ts | 20 ++++ .../data_generators/fleet_action_generator.ts | 62 ++++++++++++ .../common/endpoint/generate_data.test.ts | 4 +- .../common/endpoint/generate_data.ts | 6 +- .../common/endpoint/index_data.ts | 45 +++++++++ .../common/endpoint/types/actions.ts | 15 +++ .../isometric_taxi_layout.test.ts.snap | 96 +++++++++---------- 7 files changed, 197 insertions(+), 51 deletions(-) create mode 100644 x-pack/plugins/security_solution/common/endpoint/data_generators/fleet_action_generator.ts diff --git a/x-pack/plugins/security_solution/common/endpoint/data_generators/base_data_generator.ts b/x-pack/plugins/security_solution/common/endpoint/data_generators/base_data_generator.ts index c0888a6c2a4bd..35c976fbdfb1d 100644 --- a/x-pack/plugins/security_solution/common/endpoint/data_generators/base_data_generator.ts +++ b/x-pack/plugins/security_solution/common/endpoint/data_generators/base_data_generator.ts @@ -9,6 +9,8 @@ import seedrandom from 'seedrandom'; import uuid from 'uuid'; const OS_FAMILY = ['windows', 'macos', 'linux']; +/** Array of 14 day offsets */ +const DAY_OFFSETS = Array.from({ length: 14 }, (_, i) => 8.64e7 * (i + 1)); /** * A generic base class to assist in creating domain specific data generators. It includes @@ -16,6 +18,7 @@ const OS_FAMILY = ['windows', 'macos', 'linux']; * public method named `generate()` which should be implemented by sub-classes. */ export class BaseDataGenerator { + /** A javascript seeded random number (float between 0 and 1). Don't use `Math.random()` */ protected random: seedrandom.prng; constructor(seed: string | seedrandom.prng = Math.random().toString()) { @@ -33,6 +36,23 @@ export class BaseDataGenerator { throw new Error('method not implemented!'); } + /** Returns a future ISO date string */ + protected randomFutureDate(from?: Date): string { + const now = from ? from.getTime() : Date.now(); + return new Date(now + this.randomChoice(DAY_OFFSETS)).toISOString(); + } + + /** Returns a past ISO date string */ + protected randomPastDate(from?: Date): string { + const now = from ? from.getTime() : Date.now(); + return new Date(now - this.randomChoice(DAY_OFFSETS)).toISOString(); + } + + /** Generate either `true` or `false` */ + protected randomBoolean(): boolean { + return this.random() < 0.5; + } + /** generate random OS family value */ protected randomOSFamily(): string { return this.randomChoice(OS_FAMILY); diff --git a/x-pack/plugins/security_solution/common/endpoint/data_generators/fleet_action_generator.ts b/x-pack/plugins/security_solution/common/endpoint/data_generators/fleet_action_generator.ts new file mode 100644 index 0000000000000..af799de782f48 --- /dev/null +++ b/x-pack/plugins/security_solution/common/endpoint/data_generators/fleet_action_generator.ts @@ -0,0 +1,62 @@ +/* + * 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 { DeepPartial } from 'utility-types'; +import { merge } from 'lodash'; +import { BaseDataGenerator } from './base_data_generator'; +import { EndpointAction, EndpointActionResponse, ISOLATION_ACTIONS } from '../types'; + +const ISOLATION_COMMANDS: ISOLATION_ACTIONS[] = ['isolate', 'unisolate']; + +export class FleetActionGenerator extends BaseDataGenerator { + /** Generate an Action */ + generate(overrides: DeepPartial = {}): EndpointAction { + const timeStamp = new Date(this.randomPastDate()); + + return merge( + { + action_id: this.randomUUID(), + '@timestamp': timeStamp.toISOString(), + expiration: this.randomFutureDate(timeStamp), + type: 'INPUT_ACTION', + input_type: 'endpoint', + agents: [this.randomUUID()], + user_id: 'elastic', + data: { + command: this.randomIsolateCommand(), + comment: this.randomString(15), + }, + }, + overrides + ); + } + + /** Generates an action response */ + generateResponse(overrides: DeepPartial = {}): EndpointActionResponse { + const timeStamp = new Date(); + + return merge( + { + action_data: { + command: this.randomIsolateCommand(), + comment: '', + }, + action_id: this.randomUUID(), + agent_id: this.randomUUID(), + started_at: this.randomPastDate(), + completed_at: timeStamp.toISOString(), + error: 'some error happen', + '@timestamp': timeStamp.toISOString(), + }, + overrides + ); + } + + protected randomIsolateCommand() { + return this.randomChoice(ISOLATION_COMMANDS); + } +} diff --git a/x-pack/plugins/security_solution/common/endpoint/generate_data.test.ts b/x-pack/plugins/security_solution/common/endpoint/generate_data.test.ts index e29a121668bd3..301a032fb47df 100644 --- a/x-pack/plugins/security_solution/common/endpoint/generate_data.test.ts +++ b/x-pack/plugins/security_solution/common/endpoint/generate_data.test.ts @@ -87,7 +87,9 @@ describe('data generator', () => { expect(event2.event?.sequence).toBe((firstNonNullValue(event1.event?.sequence) ?? 0) + 1); }); - it('creates the same documents with same random seed', () => { + // Lets run this one multiple times just to ensure that the randomness + // is truly predicable based on the seed passed + it.each([1, 2, 3, 4, 5])('[%#] creates the same documents with same random seed', () => { const generator1 = new EndpointDocGenerator('seed'); const generator2 = new EndpointDocGenerator('seed'); const timestamp = new Date().getTime(); 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 fa7ee84441a9b..436f1573639c8 100644 --- a/x-pack/plugins/security_solution/common/endpoint/generate_data.ts +++ b/x-pack/plugins/security_solution/common/endpoint/generate_data.ts @@ -439,6 +439,8 @@ export class EndpointDocGenerator extends BaseDataGenerator { private createHostData(): HostInfo { const hostName = this.randomHostname(); + const isIsolated = this.randomBoolean(); + return { agent: { version: this.randomVersion(), @@ -465,10 +467,10 @@ export class EndpointDocGenerator extends BaseDataGenerator { applied: this.randomChoice(APPLIED_POLICIES), }, configuration: { - isolation: false, + isolation: isIsolated, }, state: { - isolation: false, + isolation: isIsolated, }, }, }; diff --git a/x-pack/plugins/security_solution/common/endpoint/index_data.ts b/x-pack/plugins/security_solution/common/endpoint/index_data.ts index 0dc7891560c2d..021b9bcb1eccc 100644 --- a/x-pack/plugins/security_solution/common/endpoint/index_data.ts +++ b/x-pack/plugins/security_solution/common/endpoint/index_data.ts @@ -28,8 +28,10 @@ import { policyFactory as policyConfigFactory } from './models/policy_config'; import { HostMetadata } from './types'; import { KbnClientWithApiKeySupport } from '../../scripts/endpoint/kbn_client_with_api_key_support'; import { FleetAgentGenerator } from './data_generators/fleet_agent_generator'; +import { FleetActionGenerator } from './data_generators/fleet_action_generator'; const fleetAgentGenerator = new FleetAgentGenerator(); +const fleetActionGenerator = new FleetActionGenerator(); export async function indexHostsAndAlerts( client: Client, @@ -175,6 +177,9 @@ async function indexHostDocs({ }, }, }; + + // Create some actions for this Host + await indexFleetActionsForHost(client, hostMetadata); } await client.index({ @@ -397,3 +402,43 @@ const indexFleetAgentForHost = async ( return agentDoc; }; + +const indexFleetActionsForHost = async ( + esClient: Client, + endpointHost: HostMetadata +): Promise => { + const ES_INDEX_OPTIONS = { headers: { 'X-elastic-product-origin': 'fleet' } }; + const agentId = endpointHost.elastic.agent.id; + + for (let i = 0; i < 5; i++) { + // create an action + const isolateAction = fleetActionGenerator.generate({ + data: { comment: 'data generator: this host is bad' }, + }); + + isolateAction.agents = [agentId]; + + await esClient.index( + { + index: '.fleet-actions', + body: isolateAction, + }, + ES_INDEX_OPTIONS + ); + + // Create an action response for the above + const unIsolateAction = fleetActionGenerator.generateResponse({ + action_id: isolateAction.action_id, + agent_id: agentId, + action_data: isolateAction.data, + }); + + await esClient.index( + { + index: '.fleet-actions-results', + body: unIsolateAction, + }, + ES_INDEX_OPTIONS + ); + } +}; diff --git a/x-pack/plugins/security_solution/common/endpoint/types/actions.ts b/x-pack/plugins/security_solution/common/endpoint/types/actions.ts index 99dac5ea5cda6..fcfda9c9a30d9 100644 --- a/x-pack/plugins/security_solution/common/endpoint/types/actions.ts +++ b/x-pack/plugins/security_solution/common/endpoint/types/actions.ts @@ -24,6 +24,21 @@ export interface EndpointAction { }; } +export interface EndpointActionResponse { + '@timestamp': string; + /** The id of the action for which this response is associated with */ + action_id: string; + /** The agent id that sent this action response */ + agent_id: string; + started_at: string; + completed_at: string; + error: string; + action_data: { + command: ISOLATION_ACTIONS; + comment?: string; + }; +} + export type HostIsolationRequestBody = TypeOf; export interface HostIsolationResponse { diff --git a/x-pack/plugins/security_solution/public/resolver/models/indexed_process_tree/__snapshots__/isometric_taxi_layout.test.ts.snap b/x-pack/plugins/security_solution/public/resolver/models/indexed_process_tree/__snapshots__/isometric_taxi_layout.test.ts.snap index 7a79adbff2d74..1eda3a0980191 100644 --- a/x-pack/plugins/security_solution/public/resolver/models/indexed_process_tree/__snapshots__/isometric_taxi_layout.test.ts.snap +++ b/x-pack/plugins/security_solution/public/resolver/models/indexed_process_tree/__snapshots__/isometric_taxi_layout.test.ts.snap @@ -15,11 +15,11 @@ Object { "data": Object { "@timestamp": 1606234833273, "process.entity_id": "A", - "process.name": "powershell.exe", + "process.name": "lsass.exe", "process.parent.entity_id": "", }, "id": "A", - "name": "powershell.exe", + "name": "lsass.exe", "parent": undefined, "stats": Object { "byCategory": Object {}, @@ -33,11 +33,11 @@ Object { "data": Object { "@timestamp": 1606234833273, "process.entity_id": "A", - "process.name": "powershell.exe", + "process.name": "lsass.exe", "process.parent.entity_id": "", }, "id": "A", - "name": "powershell.exe", + "name": "lsass.exe", "parent": undefined, "stats": Object { "byCategory": Object {}, @@ -58,11 +58,11 @@ Object { "data": Object { "@timestamp": 1606234833273, "process.entity_id": "A", - "process.name": "lsass.exe", + "process.name": "notepad.exe", "process.parent.entity_id": "", }, "id": "A", - "name": "lsass.exe", + "name": "notepad.exe", "parent": undefined, "stats": Object { "byCategory": Object {}, @@ -73,11 +73,11 @@ Object { "data": Object { "@timestamp": 1606234833273, "process.entity_id": "B", - "process.name": "lsass.exe", + "process.name": "mimikatz.exe", "process.parent.entity_id": "A", }, "id": "B", - "name": "lsass.exe", + "name": "mimikatz.exe", "parent": "A", "stats": Object { "byCategory": Object {}, @@ -88,11 +88,11 @@ Object { "data": Object { "@timestamp": 1606234833273, "process.entity_id": "C", - "process.name": "powershell.exe", + "process.name": "notepad.exe", "process.parent.entity_id": "A", }, "id": "C", - "name": "powershell.exe", + "name": "notepad.exe", "parent": "A", "stats": Object { "byCategory": Object {}, @@ -103,11 +103,11 @@ Object { "data": Object { "@timestamp": 1606234833273, "process.entity_id": "I", - "process.name": "lsass.exe", + "process.name": "mimikatz.exe", "process.parent.entity_id": "A", }, "id": "I", - "name": "lsass.exe", + "name": "mimikatz.exe", "parent": "A", "stats": Object { "byCategory": Object {}, @@ -118,11 +118,11 @@ Object { "data": Object { "@timestamp": 1606234833273, "process.entity_id": "D", - "process.name": "notepad.exe", + "process.name": "powershell.exe", "process.parent.entity_id": "B", }, "id": "D", - "name": "notepad.exe", + "name": "powershell.exe", "parent": "B", "stats": Object { "byCategory": Object {}, @@ -133,11 +133,11 @@ Object { "data": Object { "@timestamp": 1606234833273, "process.entity_id": "E", - "process.name": "notepad.exe", + "process.name": "powershell.exe", "process.parent.entity_id": "B", }, "id": "E", - "name": "notepad.exe", + "name": "powershell.exe", "parent": "B", "stats": Object { "byCategory": Object {}, @@ -148,11 +148,11 @@ Object { "data": Object { "@timestamp": 1606234833273, "process.entity_id": "F", - "process.name": "explorer.exe", + "process.name": "iexlorer.exe", "process.parent.entity_id": "C", }, "id": "F", - "name": "explorer.exe", + "name": "iexlorer.exe", "parent": "C", "stats": Object { "byCategory": Object {}, @@ -163,11 +163,11 @@ Object { "data": Object { "@timestamp": 1606234833273, "process.entity_id": "G", - "process.name": "explorer.exe", + "process.name": "iexlorer.exe", "process.parent.entity_id": "C", }, "id": "G", - "name": "explorer.exe", + "name": "iexlorer.exe", "parent": "C", "stats": Object { "byCategory": Object {}, @@ -178,11 +178,11 @@ Object { "data": Object { "@timestamp": 1606234833273, "process.entity_id": "H", - "process.name": "mimikatz.exe", + "process.name": "iexlorer.exe", "process.parent.entity_id": "G", }, "id": "H", - "name": "mimikatz.exe", + "name": "iexlorer.exe", "parent": "G", "stats": Object { "byCategory": Object {}, @@ -439,11 +439,11 @@ Object { "data": Object { "@timestamp": 1606234833273, "process.entity_id": "A", - "process.name": "lsass.exe", + "process.name": "notepad.exe", "process.parent.entity_id": "", }, "id": "A", - "name": "lsass.exe", + "name": "notepad.exe", "parent": undefined, "stats": Object { "byCategory": Object {}, @@ -457,11 +457,11 @@ Object { "data": Object { "@timestamp": 1606234833273, "process.entity_id": "B", - "process.name": "lsass.exe", + "process.name": "mimikatz.exe", "process.parent.entity_id": "A", }, "id": "B", - "name": "lsass.exe", + "name": "mimikatz.exe", "parent": "A", "stats": Object { "byCategory": Object {}, @@ -475,11 +475,11 @@ Object { "data": Object { "@timestamp": 1606234833273, "process.entity_id": "C", - "process.name": "powershell.exe", + "process.name": "notepad.exe", "process.parent.entity_id": "A", }, "id": "C", - "name": "powershell.exe", + "name": "notepad.exe", "parent": "A", "stats": Object { "byCategory": Object {}, @@ -493,11 +493,11 @@ Object { "data": Object { "@timestamp": 1606234833273, "process.entity_id": "I", - "process.name": "lsass.exe", + "process.name": "mimikatz.exe", "process.parent.entity_id": "A", }, "id": "I", - "name": "lsass.exe", + "name": "mimikatz.exe", "parent": "A", "stats": Object { "byCategory": Object {}, @@ -511,11 +511,11 @@ Object { "data": Object { "@timestamp": 1606234833273, "process.entity_id": "D", - "process.name": "notepad.exe", + "process.name": "powershell.exe", "process.parent.entity_id": "B", }, "id": "D", - "name": "notepad.exe", + "name": "powershell.exe", "parent": "B", "stats": Object { "byCategory": Object {}, @@ -529,11 +529,11 @@ Object { "data": Object { "@timestamp": 1606234833273, "process.entity_id": "E", - "process.name": "notepad.exe", + "process.name": "powershell.exe", "process.parent.entity_id": "B", }, "id": "E", - "name": "notepad.exe", + "name": "powershell.exe", "parent": "B", "stats": Object { "byCategory": Object {}, @@ -547,11 +547,11 @@ Object { "data": Object { "@timestamp": 1606234833273, "process.entity_id": "F", - "process.name": "explorer.exe", + "process.name": "iexlorer.exe", "process.parent.entity_id": "C", }, "id": "F", - "name": "explorer.exe", + "name": "iexlorer.exe", "parent": "C", "stats": Object { "byCategory": Object {}, @@ -565,11 +565,11 @@ Object { "data": Object { "@timestamp": 1606234833273, "process.entity_id": "G", - "process.name": "explorer.exe", + "process.name": "iexlorer.exe", "process.parent.entity_id": "C", }, "id": "G", - "name": "explorer.exe", + "name": "iexlorer.exe", "parent": "C", "stats": Object { "byCategory": Object {}, @@ -583,11 +583,11 @@ Object { "data": Object { "@timestamp": 1606234833273, "process.entity_id": "H", - "process.name": "mimikatz.exe", + "process.name": "iexlorer.exe", "process.parent.entity_id": "G", }, "id": "H", - "name": "mimikatz.exe", + "name": "iexlorer.exe", "parent": "G", "stats": Object { "byCategory": Object {}, @@ -608,11 +608,11 @@ Object { "data": Object { "@timestamp": 1606234833273, "process.entity_id": "A", - "process.name": "iexlorer.exe", + "process.name": "powershell.exe", "process.parent.entity_id": "", }, "id": "A", - "name": "iexlorer.exe", + "name": "powershell.exe", "parent": undefined, "stats": Object { "byCategory": Object {}, @@ -623,11 +623,11 @@ Object { "data": Object { "@timestamp": 1606234833273, "process.entity_id": "B", - "process.name": "notepad.exe", + "process.name": "powershell.exe", "process.parent.entity_id": "A", }, "id": "B", - "name": "notepad.exe", + "name": "powershell.exe", "parent": "A", "stats": Object { "byCategory": Object {}, @@ -661,11 +661,11 @@ Object { "data": Object { "@timestamp": 1606234833273, "process.entity_id": "A", - "process.name": "iexlorer.exe", + "process.name": "powershell.exe", "process.parent.entity_id": "", }, "id": "A", - "name": "iexlorer.exe", + "name": "powershell.exe", "parent": undefined, "stats": Object { "byCategory": Object {}, @@ -679,11 +679,11 @@ Object { "data": Object { "@timestamp": 1606234833273, "process.entity_id": "B", - "process.name": "notepad.exe", + "process.name": "powershell.exe", "process.parent.entity_id": "A", }, "id": "B", - "name": "notepad.exe", + "name": "powershell.exe", "parent": "A", "stats": Object { "byCategory": Object {}, From a0622d51da2d1527d64c3dc783fe461cc770c63e Mon Sep 17 00:00:00 2001 From: Nicolas Chaulet Date: Fri, 28 May 2021 11:25:20 -0400 Subject: [PATCH 66/77] [Fleet] Improve combo box for fleet settings (#100603) --- .../settings_flyout/hosts_input.test.tsx | 68 +++++ .../settings_flyout/hosts_input.tsx | 247 ++++++++++++++++++ .../components/settings_flyout/index.tsx | 211 +++++++-------- .../applications/fleet/hooks/use_input.ts | 43 +-- .../translations/translations/ja-JP.json | 1 - .../translations/translations/zh-CN.json | 1 - 6 files changed, 445 insertions(+), 126 deletions(-) create mode 100644 x-pack/plugins/fleet/public/applications/fleet/components/settings_flyout/hosts_input.test.tsx create mode 100644 x-pack/plugins/fleet/public/applications/fleet/components/settings_flyout/hosts_input.tsx diff --git a/x-pack/plugins/fleet/public/applications/fleet/components/settings_flyout/hosts_input.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/components/settings_flyout/hosts_input.test.tsx new file mode 100644 index 0000000000000..27bf5af72fb61 --- /dev/null +++ b/x-pack/plugins/fleet/public/applications/fleet/components/settings_flyout/hosts_input.test.tsx @@ -0,0 +1,68 @@ +/* + * 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 { fireEvent, act } from '@testing-library/react'; + +import { createTestRendererMock } from '../../mock'; + +import { HostsInput } from './hosts_input'; + +function renderInput(value = ['http://host1.com']) { + const renderer = createTestRendererMock(); + const mockOnChange = jest.fn(); + + const utils = renderer.render( + + ); + + return { utils, mockOnChange }; +} + +test('it should allow to add a new host', async () => { + const { utils, mockOnChange } = renderInput(); + + const addRowEl = await utils.findByText('Add row'); + fireEvent.click(addRowEl); + expect(mockOnChange).toHaveBeenCalledWith(['http://host1.com', '']); +}); + +test('it should allow to remove an host', async () => { + const { utils, mockOnChange } = renderInput(['http://host1.com', 'http://host2.com']); + + await act(async () => { + const deleteRowEl = await utils.container.querySelector('[aria-label="Delete host"]'); + if (!deleteRowEl) { + throw new Error('Delete host button not found'); + } + fireEvent.click(deleteRowEl); + }); + + expect(mockOnChange).toHaveBeenCalledWith(['http://host2.com']); +}); + +test('it should allow to update existing host with single host', async () => { + const { utils, mockOnChange } = renderInput(['http://host1.com']); + + const inputEl = await utils.findByDisplayValue('http://host1.com'); + fireEvent.change(inputEl, { target: { value: 'http://newhost.com' } }); + expect(mockOnChange).toHaveBeenCalledWith(['http://newhost.com']); +}); + +test('it should allow to update existing host with multiple hosts', async () => { + const { utils, mockOnChange } = renderInput(['http://host1.com', 'http://host2.com']); + + const inputEl = await utils.findByDisplayValue('http://host1.com'); + fireEvent.change(inputEl, { target: { value: 'http://newhost.com' } }); + expect(mockOnChange).toHaveBeenCalledWith(['http://newhost.com', 'http://host2.com']); +}); diff --git a/x-pack/plugins/fleet/public/applications/fleet/components/settings_flyout/hosts_input.tsx b/x-pack/plugins/fleet/public/applications/fleet/components/settings_flyout/hosts_input.tsx new file mode 100644 index 0000000000000..0e5f9a5e028b5 --- /dev/null +++ b/x-pack/plugins/fleet/public/applications/fleet/components/settings_flyout/hosts_input.tsx @@ -0,0 +1,247 @@ +/* + * 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, { useMemo, useCallback, useState } from 'react'; +import type { ReactNode, FunctionComponent, ChangeEvent } from 'react'; +import sytled, { useTheme } from 'styled-components'; + +import { + EuiFlexGroup, + EuiFlexItem, + EuiButtonEmpty, + EuiFormRow, + EuiFieldText, + EuiDragDropContext, + EuiDroppable, + EuiDraggable, + EuiIcon, + EuiButtonIcon, + EuiSpacer, + EuiFormHelpText, + euiDragDropReorder, + EuiFormErrorText, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; + +import type { EuiTheme } from '../../../../../../../../src/plugins/kibana_react/common'; + +interface Props { + id: string; + value: string[]; + onChange: (newValue: string[]) => void; + label: string; + helpText: ReactNode; + errors?: Array<{ message: string; index?: number }>; + isInvalid?: boolean; +} + +interface SortableTextFieldProps { + id: string; + index: number; + value: string; + onChange: (e: ChangeEvent) => void; + onDelete: (index: number) => void; + errors?: string[]; + autoFocus?: boolean; +} + +const DraggableDiv = sytled.div` + margin: ${(props) => props.theme.eui.euiSizeS}; +`; + +function displayErrors(errors?: string[]) { + return errors?.length + ? errors.map((error, errorIndex) => ( + {error} + )) + : null; +} + +const SortableTextField: FunctionComponent = React.memo( + ({ id, index, value, onChange, onDelete, autoFocus, errors }) => { + const onDeleteHandler = useCallback(() => { + onDelete(index); + }, [onDelete, index]); + + const isInvalid = (errors?.length ?? 0) > 0; + const theme = useTheme() as EuiTheme; + + return ( + + {(provided, state) => ( + + + + + + + + + {displayErrors(errors)} + + + + + + )} + + ); + } +); + +export const HostsInput: FunctionComponent = ({ + id, + value, + onChange, + helpText, + label, + isInvalid, + errors, +}) => { + const [autoFocus, setAutoFocus] = useState(false); + const rows = useMemo( + () => + value.map((host, idx) => ({ + value: host, + onChange: (e: ChangeEvent) => { + const newValue = [...value]; + newValue[idx] = e.target.value; + + onChange(newValue); + }, + })), + [value, onChange] + ); + + const onDelete = useCallback( + (idx: number) => { + onChange([...value.slice(0, idx), ...value.slice(idx + 1)]); + }, + [value, onChange] + ); + + const addRowHandler = useCallback(() => { + setAutoFocus(true); + onChange([...value, '']); + }, [value, onChange]); + + const onDragEndHandler = useCallback( + ({ source, destination }) => { + if (source && destination) { + const items = euiDragDropReorder(value, source.index, destination.index); + + onChange(items); + } + }, + [value, onChange] + ); + + const globalErrors = useMemo(() => { + return errors && errors.filter((err) => err.index === undefined).map(({ message }) => message); + }, [errors]); + + const indexedErrors = useMemo(() => { + if (!errors) { + return []; + } + return errors.reduce((acc, err) => { + if (err.index === undefined) { + return acc; + } + + if (!acc[err.index]) { + acc[err.index] = []; + } + + acc[err.index].push(err.message); + + return acc; + }, [] as string[][]); + }, [errors]); + + const isSortable = rows.length > 1; + return ( + + <> + {helpText} + + + + {rows.map((row, idx) => ( + + {isSortable ? ( + + ) : ( + <> + + {displayErrors(indexedErrors[idx])} + + )} + + ))} + + + {displayErrors(globalErrors)} + + + + + + + ); +}; diff --git a/x-pack/plugins/fleet/public/applications/fleet/components/settings_flyout/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/components/settings_flyout/index.tsx index b802854791009..ea2e795d5fabb 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/components/settings_flyout/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/components/settings_flyout/index.tsx @@ -20,10 +20,10 @@ import { EuiFlyoutFooter, EuiForm, EuiFormRow, - EuiComboBox, EuiCode, EuiCodeEditor, EuiLink, + EuiPanel, } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import { EuiText } from '@elastic/eui'; @@ -41,6 +41,7 @@ import { isDiffPathProtocol } from '../../../../../common/'; import { SettingsConfirmModal } from './confirm_modal'; import type { SettingsConfirmModalProps } from './confirm_modal'; +import { HostsInput } from './hosts_input'; import 'brace/mode/yaml'; import 'brace/theme/textmate'; @@ -59,37 +60,60 @@ function useSettingsForm(outputId: string | undefined, onSuccess: () => void) { const [isLoading, setIsloading] = React.useState(false); const { notifications } = useStartServices(); - const fleetServerHostsInput = useComboInput([], (value) => { + const fleetServerHostsInput = useComboInput('fleetServerHostsComboBox', [], (value) => { if (value.length === 0) { return [ - i18n.translate('xpack.fleet.settings.fleetServerHostsEmptyError', { - defaultMessage: 'At least one URL is required', - }), + { + message: i18n.translate('xpack.fleet.settings.fleetServerHostsEmptyError', { + defaultMessage: 'At least one URL is required', + }), + }, ]; } - if (value.some((v) => !v.match(URL_REGEX))) { - return [ - i18n.translate('xpack.fleet.settings.fleetServerHostsError', { - defaultMessage: 'Invalid URL', - }), - ]; + + const res: Array<{ message: string; index: number }> = []; + value.forEach((val, idx) => { + if (!val.match(URL_REGEX)) { + res.push({ + message: i18n.translate('xpack.fleet.settings.fleetServerHostsError', { + defaultMessage: 'Invalid URL', + }), + index: idx, + }); + } + }); + if (res.length) { + return res; } + if (value.length && isDiffPathProtocol(value)) { return [ - i18n.translate('xpack.fleet.settings.fleetServerHostsDifferentPathOrProtocolError', { - defaultMessage: 'Protocol and path must be the same for each URL', - }), + { + message: i18n.translate( + 'xpack.fleet.settings.fleetServerHostsDifferentPathOrProtocolError', + { + defaultMessage: 'Protocol and path must be the same for each URL', + } + ), + }, ]; } }); - const elasticsearchUrlInput = useComboInput([], (value) => { - if (value.some((v) => !v.match(URL_REGEX))) { - return [ - i18n.translate('xpack.fleet.settings.elasticHostError', { - defaultMessage: 'Invalid URL', - }), - ]; + const elasticsearchUrlInput = useComboInput('esHostsComboxBox', [], (value) => { + const res: Array<{ message: string; index: number }> = []; + value.forEach((val, idx) => { + if (!val.match(URL_REGEX)) { + res.push({ + message: i18n.translate('xpack.fleet.settings.elasticHostError', { + defaultMessage: 'Invalid URL', + }), + index: idx, + }); + } + }); + if (res.length) { + return res; } }); @@ -264,91 +288,72 @@ export const SettingFlyout: React.FunctionComponent = ({ onClose }) => { /> - - - - - ), - }} - /> - } - {...inputs.fleetServerHosts.formRowProps} - > - - - + + + + + ), + }} + /> + } + /> + - - - - ), + + + + + + + - } - {...inputs.elasticsearchUrl.formRowProps} - > - - - - - - + + ); diff --git a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_input.ts b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_input.ts index 6314fbeb0c72e..e4a517dbae9c8 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_input.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_input.ts @@ -5,11 +5,12 @@ * 2.0. */ -import React from 'react'; +import { useState, useCallback } from 'react'; +import type React from 'react'; export function useInput(defaultValue = '', validate?: (value: string) => string[] | undefined) { - const [value, setValue] = React.useState(defaultValue); - const [errors, setErrors] = React.useState(); + const [value, setValue] = useState(defaultValue); + const [errors, setErrors] = useState(); const onChange = (e: React.ChangeEvent) => { const newValue = e.target.value; @@ -50,31 +51,31 @@ export function useInput(defaultValue = '', validate?: (value: string) => string } export function useComboInput( + id: string, defaultValue = [], - validate?: (value: string[]) => string[] | undefined + validate?: (value: string[]) => Array<{ message: string; index?: number }> | undefined ) { - const [value, setValue] = React.useState(defaultValue); - const [errors, setErrors] = React.useState(); + const [value, setValue] = useState(defaultValue); + const [errors, setErrors] = useState | undefined>(); const isInvalid = errors !== undefined; + const onChange = useCallback( + (newValues: string[]) => { + setValue(newValues); + if (errors && validate && validate(newValues) === undefined) { + setErrors(undefined); + } + }, + [validate, errors] + ); + return { props: { - selectedOptions: value.map((val: string) => ({ label: val })), - onCreateOption: (newVal: any) => { - setValue([...value, newVal]); - }, - onChange: (newSelectedOptions: any[]) => { - const newValues = newSelectedOptions.map((option) => option.label); - setValue(newValues); - if (errors && validate && validate(newValues) === undefined) { - setErrors(undefined); - } - }, - isInvalid, - }, - formRowProps: { - error: errors, + id, + value, + onChange, + errors, isInvalid, }, value, diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index d829c8eb22a98..55a38353cba13 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -9490,7 +9490,6 @@ "xpack.fleet.settings.cancelButtonLabel": "キャンセル", "xpack.fleet.settings.elasticHostError": "無効なURL", "xpack.fleet.settings.elasticsearchUrlLabel": "Elasticsearchホスト", - "xpack.fleet.settings.elasticsearchUrlsHelpTect": "エージェントがデータを送信するElasticsearch URLを指定します。{link}を参照してください。", "xpack.fleet.settings.fleetServerHostsDifferentPathOrProtocolError": "各URLのプロトコルとパスは同じでなければなりません", "xpack.fleet.settings.fleetServerHostsEmptyError": "1つ以上のURLが必要です。", "xpack.fleet.settings.fleetServerHostsError": "無効なURL", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index a7cd8b5fe8d51..972e3ff299b75 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -9575,7 +9575,6 @@ "xpack.fleet.settings.cancelButtonLabel": "取消", "xpack.fleet.settings.elasticHostError": "URL 无效", "xpack.fleet.settings.elasticsearchUrlLabel": "Elasticsearch 主机", - "xpack.fleet.settings.elasticsearchUrlsHelpTect": "指定代理用于发送数据的 Elasticsearch URL。请参阅 {link}。", "xpack.fleet.settings.fleetServerHostsDifferentPathOrProtocolError": "对于每个 URL,协议和路径必须相同", "xpack.fleet.settings.fleetServerHostsEmptyError": "至少需要一个 URL", "xpack.fleet.settings.fleetServerHostsError": "URL 无效", From b2e6028327630a596faf66e27b721fd15496f059 Mon Sep 17 00:00:00 2001 From: gchaps <33642766+gchaps@users.noreply.github.com> Date: Fri, 28 May 2021 08:37:25 -0700 Subject: [PATCH 67/77] [DOCS] Adds video to introduction (#100906) --- docs/user/introduction.asciidoc | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/docs/user/introduction.asciidoc b/docs/user/introduction.asciidoc index 8a0dd5e4e2a2b..38435708aaf99 100644 --- a/docs/user/introduction.asciidoc +++ b/docs/user/introduction.asciidoc @@ -20,6 +20,20 @@ Manage your indices and ingest pipelines, monitor the health of your Elastic Stack cluster, and control which users have access to which features. +++++ + + +
    +++++ + *{kib} is for administrators, analysts, and business users.* As an admin, your role is to manage the Elastic Stack, from creating your deployment to getting {es} data into {kib}, and then @@ -43,9 +57,6 @@ If you’re not ready to use your own data, you can add a sample data set. The home page provides access to the *Enterprise Search*, *Observability*, and *Security* solutions, and everything you need to visualize and analyze your data. -[role="screenshot"] -image::images/home-page.png[Kibana home page] - To access all of {kib} features, use the main menu. Open this menu by clicking the menu icon. To keep the main menu visible at all times, click *Dock navigation*. From 7f6d7b3642a3c83def893b4cb2b651accaeaa4c9 Mon Sep 17 00:00:00 2001 From: Marshall Main <55718608+marshallmain@users.noreply.github.com> Date: Fri, 28 May 2021 11:49:49 -0400 Subject: [PATCH 68/77] [Security Solution] Improve find rule and find rule status route performance (#99678) * Fetch rule statuses using single aggregation instead of N separate requests * Optimize _find API and _find_statuses * Merge alerting framework errors into rule statuses * Add sortSchema for top hits agg, update terms.order schema Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../aggregations/aggs_types/bucket_aggs.ts | 9 ++- .../aggregations/aggs_types/common_schemas.ts | 29 ++++++++ .../aggregations/aggs_types/metrics_aggs.ts | 3 +- .../routes/__mocks__/request_responses.ts | 66 +++++++++++++++++++ .../routes/rules/find_rules_route.test.ts | 4 +- .../routes/rules/find_rules_route.ts | 46 ++----------- .../rules/find_rules_status_route.test.ts | 4 +- .../routes/rules/find_rules_status_route.ts | 49 +++++--------- .../routes/rules/utils.test.ts | 20 +----- .../detection_engine/routes/rules/utils.ts | 43 +++++------- .../lib/detection_engine/routes/utils.test.ts | 6 +- .../lib/detection_engine/routes/utils.ts | 19 +++--- .../get_bulk_rule_actions_saved_object.ts | 40 +++++++++++ .../lib/detection_engine/rules/types.ts | 6 -- .../schemas/rule_converters.ts | 41 ++++++++---- .../rule_status_saved_objects_client.mock.ts | 1 + .../rule_status_saved_objects_client.ts | 51 ++++++++++++++ .../detection_engine/signals/utils.test.ts | 23 +++++++ .../lib/detection_engine/signals/utils.ts | 15 ++++- 19 files changed, 321 insertions(+), 154 deletions(-) create mode 100644 src/core/server/saved_objects/service/lib/aggregations/aggs_types/common_schemas.ts create mode 100644 x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/get_bulk_rule_actions_saved_object.ts diff --git a/src/core/server/saved_objects/service/lib/aggregations/aggs_types/bucket_aggs.ts b/src/core/server/saved_objects/service/lib/aggregations/aggs_types/bucket_aggs.ts index 186962b568792..cf27505e8f073 100644 --- a/src/core/server/saved_objects/service/lib/aggregations/aggs_types/bucket_aggs.ts +++ b/src/core/server/saved_objects/service/lib/aggregations/aggs_types/bucket_aggs.ts @@ -7,6 +7,7 @@ */ import { schema as s, ObjectType } from '@kbn/config-schema'; +import { sortOrderSchema } from './common_schemas'; /** * Schemas for the Bucket aggregations. @@ -85,6 +86,12 @@ export const bucketAggsSchemas: Record = { min_doc_count: s.maybe(s.number({ min: 1 })), size: s.maybe(s.number()), show_term_doc_count_error: s.maybe(s.boolean()), - order: s.maybe(s.oneOf([s.literal('asc'), s.literal('desc')])), + order: s.maybe( + s.oneOf([ + sortOrderSchema, + s.recordOf(s.string(), sortOrderSchema), + s.arrayOf(s.recordOf(s.string(), sortOrderSchema)), + ]) + ), }), }; diff --git a/src/core/server/saved_objects/service/lib/aggregations/aggs_types/common_schemas.ts b/src/core/server/saved_objects/service/lib/aggregations/aggs_types/common_schemas.ts new file mode 100644 index 0000000000000..92a3096374687 --- /dev/null +++ b/src/core/server/saved_objects/service/lib/aggregations/aggs_types/common_schemas.ts @@ -0,0 +1,29 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { schema as s } from '@kbn/config-schema'; + +// note: these schemas are not exhaustive. See the `Sort` type of `@elastic/elasticsearch` if you need to enhance it. +const fieldSchema = s.string(); +export const sortOrderSchema = s.oneOf([s.literal('asc'), s.literal('desc'), s.literal('_doc')]); +const sortModeSchema = s.oneOf([ + s.literal('min'), + s.literal('max'), + s.literal('sum'), + s.literal('avg'), + s.literal('median'), +]); +const fieldSortSchema = s.object({ + missing: s.maybe(s.oneOf([s.string(), s.number(), s.boolean()])), + mode: s.maybe(sortModeSchema), + order: s.maybe(sortOrderSchema), + // nested and unmapped_type not implemented yet +}); +const sortContainerSchema = s.recordOf(s.string(), s.oneOf([sortOrderSchema, fieldSortSchema])); +const sortCombinationsSchema = s.oneOf([fieldSchema, sortContainerSchema]); +export const sortSchema = s.oneOf([sortCombinationsSchema, s.arrayOf(sortCombinationsSchema)]); diff --git a/src/core/server/saved_objects/service/lib/aggregations/aggs_types/metrics_aggs.ts b/src/core/server/saved_objects/service/lib/aggregations/aggs_types/metrics_aggs.ts index c05ae67cd2164..fb7e25fae19f2 100644 --- a/src/core/server/saved_objects/service/lib/aggregations/aggs_types/metrics_aggs.ts +++ b/src/core/server/saved_objects/service/lib/aggregations/aggs_types/metrics_aggs.ts @@ -7,6 +7,7 @@ */ import { schema as s, ObjectType } from '@kbn/config-schema'; +import { sortSchema } from './common_schemas'; /** * Schemas for the metrics Aggregations @@ -68,7 +69,7 @@ export const metricsAggsSchemas: Record = { stored_fields: s.maybe(s.oneOf([s.string(), s.arrayOf(s.string())])), from: s.maybe(s.number()), size: s.maybe(s.number()), - sort: s.maybe(s.oneOf([s.literal('asc'), s.literal('desc')])), + sort: s.maybe(sortSchema), seq_no_primary_term: s.maybe(s.boolean()), version: s.maybe(s.boolean()), track_scores: s.maybe(s.boolean()), diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_responses.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_responses.ts index 4337725101917..857762dec45e9 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_responses.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_responses.ts @@ -491,6 +491,72 @@ export const getFindResultStatus = (): SavedObjectsFindResponse => ({ + page: 1, + per_page: 6, + total: 2, + saved_objects: [], + aggregations: { + alertIds: { + buckets: [ + { + key: '04128c15-0d1b-4716-a4c5-46997ac7f3bd', + most_recent_statuses: { + hits: { + hits: [ + { + _source: { + 'siem-detection-engine-rule-status': { + alertId: '04128c15-0d1b-4716-a4c5-46997ac7f3bd', + statusDate: '2020-02-18T15:26:49.783Z', + status: 'succeeded', + lastFailureAt: undefined, + lastSuccessAt: '2020-02-18T15:26:49.783Z', + lastFailureMessage: undefined, + lastSuccessMessage: 'succeeded', + lastLookBackDate: new Date('2020-02-18T15:14:58.806Z').toISOString(), + gap: '500.32', + searchAfterTimeDurations: ['200.00'], + bulkCreateTimeDurations: ['800.43'], + }, + }, + }, + ], + }, + }, + }, + { + key: '1ea5a820-4da1-4e82-92a1-2b43a7bece08', + most_recent_statuses: { + hits: { + hits: [ + { + _source: { + 'siem-detection-engine-rule-status': { + alertId: '1ea5a820-4da1-4e82-92a1-2b43a7bece08', + statusDate: '2020-02-18T15:15:58.806Z', + status: 'failed', + lastFailureAt: '2020-02-18T15:15:58.806Z', + lastSuccessAt: '2020-02-13T20:31:59.855Z', + lastFailureMessage: + 'Signal rule name: "Query with a rule id Number 1", id: "1ea5a820-4da1-4e82-92a1-2b43a7bece08", rule_id: "query-rule-id-1" has a time gap of 5 days (412682928ms), and could be missing signals within that time. Consider increasing your look behind time or adding more Kibana instances.', + lastSuccessMessage: 'succeeded', + lastLookBackDate: new Date('2020-02-18T15:14:58.806Z').toISOString(), + gap: '500.32', + searchAfterTimeDurations: ['200.00'], + bulkCreateTimeDurations: ['800.43'], + }, + }, + }, + ], + }, + }, + }, + ], + }, + }, +}); + export const getEmptySignalsResponse = (): SignalSearchResponse => ({ took: 1, timed_out: false, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/find_rules_route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/find_rules_route.test.ts index 434ef0f88b196..06f3ca83c4722 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/find_rules_route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/find_rules_route.test.ts @@ -10,7 +10,7 @@ import { getAlertMock, getFindRequest, getFindResultWithSingleHit, - getFindResultStatus, + getFindBulkResultStatus, } from '../__mocks__/request_responses'; import { requestContextMock, serverMock, requestMock } from '../__mocks__'; import { findRulesRoute } from './find_rules_route'; @@ -27,7 +27,7 @@ describe('find_rules', () => { clients.alertsClient.find.mockResolvedValue(getFindResultWithSingleHit()); clients.alertsClient.get.mockResolvedValue(getAlertMock(getQueryRuleParams())); - clients.savedObjectsClient.find.mockResolvedValue(getFindResultStatus()); + clients.savedObjectsClient.find.mockResolvedValue(getFindBulkResultStatus()); findRulesRoute(server.router); }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/find_rules_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/find_rules_route.ts index ccf0a59e87c74..347d005c58a4a 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/find_rules_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/find_rules_route.ts @@ -15,11 +15,10 @@ import type { SecuritySolutionPluginRouter } from '../../../../types'; import { DETECTION_ENGINE_RULES_URL } from '../../../../../common/constants'; import { findRules } from '../../rules/find_rules'; import { buildSiemResponse } from '../utils'; - -import { getRuleActionsSavedObject } from '../../rule_actions/get_rule_actions_saved_object'; import { ruleStatusSavedObjectsClientFactory } from '../../signals/rule_status_saved_objects_client'; import { buildRouteValidation } from '../../../../utils/build_validation/route_validation'; import { transformFindAlerts } from './utils'; +import { getBulkRuleActionsSavedObject } from '../../rule_actions/get_bulk_rule_actions_saved_object'; export const findRulesRoute = (router: SecuritySolutionPluginRouter) => { router.get( @@ -60,44 +59,11 @@ export const findRulesRoute = (router: SecuritySolutionPluginRouter) => { filter: query.filter, fields: query.fields, }); - - // if any rules attempted to execute but failed before the rule executor is called, - // an execution status will be written directly onto the rule via the kibana alerting framework, - // which we are filtering on and will write a failure status - // for any rules found to be in a failing state into our rule status saved objects - const failingRules = rules.data.filter( - (rule) => rule.executionStatus != null && rule.executionStatus.status === 'error' - ); - - const ruleStatuses = await Promise.all( - rules.data.map(async (rule) => { - const results = await ruleStatusClient.find({ - perPage: 1, - sortField: 'statusDate', - sortOrder: 'desc', - search: rule.id, - searchFields: ['alertId'], - }); - const failingRule = failingRules.find((badRule) => badRule.id === rule.id); - if (failingRule != null) { - if (results.saved_objects.length > 0) { - results.saved_objects[0].attributes.status = 'failed'; - results.saved_objects[0].attributes.lastFailureAt = failingRule.executionStatus.lastExecutionDate.toISOString(); - } - } - return results; - }) - ); - const ruleActions = await Promise.all( - rules.data.map(async (rule) => { - const results = await getRuleActionsSavedObject({ - savedObjectsClient, - ruleAlertId: rule.id, - }); - - return results; - }) - ); + const alertIds = rules.data.map((rule) => rule.id); + const [ruleStatuses, ruleActions] = await Promise.all([ + ruleStatusClient.findBulk(alertIds, 1), + getBulkRuleActionsSavedObject({ alertIds, savedObjectsClient }), + ]); const transformed = transformFindAlerts(rules, ruleActions, ruleStatuses); if (transformed == null) { return siemResponse.error({ statusCode: 500, body: 'Internal error transforming' }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/find_rules_status_route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/find_rules_status_route.test.ts index c3a53a1f393ec..73f076649b72f 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/find_rules_status_route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/find_rules_status_route.test.ts @@ -7,9 +7,9 @@ import { DETECTION_ENGINE_RULES_URL } from '../../../../../common/constants'; import { - getFindResultStatus, ruleStatusRequest, getAlertMock, + getFindBulkResultStatus, } from '../__mocks__/request_responses'; import { serverMock, requestContextMock, requestMock } from '../__mocks__'; import { findRulesStatusesRoute } from './find_rules_status_route'; @@ -26,7 +26,7 @@ describe('find_statuses', () => { beforeEach(async () => { server = serverMock.create(); ({ clients, context } = requestContextMock.createTools()); - clients.savedObjectsClient.find.mockResolvedValue(getFindResultStatus()); // successful status search + clients.savedObjectsClient.find.mockResolvedValue(getFindBulkResultStatus()); // successful status search clients.alertsClient.get.mockResolvedValue(getAlertMock(getQueryRuleParams())); findRulesStatusesRoute(server.router); }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/find_rules_status_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/find_rules_status_route.ts index bd6e8fc9e7aad..aed8b80e4f133 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/find_rules_status_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/find_rules_status_route.ts @@ -9,14 +9,13 @@ import { transformError } from '@kbn/securitysolution-es-utils'; import { buildRouteValidation } from '../../../../utils/build_validation/route_validation'; import type { SecuritySolutionPluginRouter } from '../../../../types'; import { DETECTION_ENGINE_RULES_URL } from '../../../../../common/constants'; -import { RuleStatusResponse } from '../../rules/types'; import { buildSiemResponse, mergeStatuses, getFailingRules } from '../utils'; - import { ruleStatusSavedObjectsClientFactory } from '../../signals/rule_status_saved_objects_client'; import { findRulesStatusesSchema, FindRulesStatusesSchemaDecoded, } from '../../../../../common/detection_engine/schemas/request/find_rule_statuses_schema'; +import { mergeAlertWithSidecarStatus } from '../../schemas/rule_converters'; /** * Given a list of rule ids, return the current status and @@ -51,45 +50,27 @@ export const findRulesStatusesRoute = (router: SecuritySolutionPluginRouter) => const ids = body.ids; try { const ruleStatusClient = ruleStatusSavedObjectsClientFactory(savedObjectsClient); - const failingRules = await getFailingRules(ids, alertsClient); + const [statusesById, failingRules] = await Promise.all([ + ruleStatusClient.findBulk(ids, 6), + getFailingRules(ids, alertsClient), + ]); - const statuses = await ids.reduce(async (acc, id) => { - const accumulated = await acc; - const lastFiveErrorsForId = await ruleStatusClient.find({ - perPage: 6, - sortField: 'statusDate', - sortOrder: 'desc', - search: id, - searchFields: ['alertId'], - }); + const statuses = ids.reduce((acc, id) => { + const lastFiveErrorsForId = statusesById[id]; - if (lastFiveErrorsForId.saved_objects.length === 0) { - return accumulated; + if (lastFiveErrorsForId == null || lastFiveErrorsForId.length === 0) { + return acc; } const failingRule = failingRules[id]; - const lastFailureAt = lastFiveErrorsForId.saved_objects[0].attributes.lastFailureAt; - - if ( - failingRule != null && - (lastFailureAt == null || - new Date(failingRule.executionStatus.lastExecutionDate) > new Date(lastFailureAt)) - ) { - const currentStatus = lastFiveErrorsForId.saved_objects[0]; - currentStatus.attributes.lastFailureMessage = `Reason: ${failingRule.executionStatus.error?.reason} Message: ${failingRule.executionStatus.error?.message}`; - currentStatus.attributes.lastFailureAt = failingRule.executionStatus.lastExecutionDate.toISOString(); - currentStatus.attributes.statusDate = failingRule.executionStatus.lastExecutionDate.toISOString(); - currentStatus.attributes.status = 'failed'; - const updatedLastFiveErrorsSO = [ - currentStatus, - ...lastFiveErrorsForId.saved_objects.slice(1), - ]; - return mergeStatuses(id, updatedLastFiveErrorsSO, accumulated); + if (failingRule != null) { + const currentStatus = mergeAlertWithSidecarStatus(failingRule, lastFiveErrorsForId[0]); + const updatedLastFiveErrorsSO = [currentStatus, ...lastFiveErrorsForId.slice(1)]; + return mergeStatuses(id, updatedLastFiveErrorsSO, acc); } - return mergeStatuses(id, [...lastFiveErrorsForId.saved_objects], accumulated); - }, Promise.resolve({})); - + return mergeStatuses(id, [...lastFiveErrorsForId], acc); + }, {}); return response.ok({ body: statuses }); } catch (err) { const error = transformError(err); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils.test.ts index f2788ab1bd4c9..29e322d7fcab5 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils.test.ts @@ -27,7 +27,6 @@ import { PartialFilter } from '../../types'; import { BulkError, ImportSuccessError } from '../utils'; import { getOutputRuleAlertForRest } from '../__mocks__/utils'; import { PartialAlert } from '../../../../../../alerting/server'; -import { SanitizedAlert } from '../../../../../../alerting/server/types'; import { createRulesStreamFromNdJson } from '../../rules/create_rules_stream_from_ndjson'; import { RuleAlertType } from '../../rules/types'; import { ImportRulesSchemaDecoded } from '../../../../../common/detection_engine/schemas/request/import_rules_schema'; @@ -256,7 +255,7 @@ describe('utils', () => { describe('transformFindAlerts', () => { test('outputs empty data set when data set is empty correct', () => { - const output = transformFindAlerts({ data: [], page: 1, perPage: 0, total: 0 }, []); + const output = transformFindAlerts({ data: [], page: 1, perPage: 0, total: 0 }, {}, {}); expect(output).toEqual({ data: [], page: 1, perPage: 0, total: 0 }); }); @@ -268,7 +267,8 @@ describe('utils', () => { total: 0, data: [getAlertMock(getQueryRuleParams())], }, - [] + {}, + {} ); const expected = getOutputRuleAlertForRest(); expect(output).toEqual({ @@ -278,20 +278,6 @@ describe('utils', () => { data: [expected], }); }); - - test('returns 500 if the data is not of type siem alert', () => { - const unsafeCast = ([{ name: 'something else' }] as unknown) as SanitizedAlert[]; - const output = transformFindAlerts( - { - data: unsafeCast, - page: 1, - perPage: 1, - total: 1, - }, - [] - ); - expect(output).toBeNull(); - }); }); describe('transform', () => { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils.ts index 466b8dd184227..dc0cd2e497215 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils.ts @@ -6,7 +6,7 @@ */ import { countBy } from 'lodash/fp'; -import { SavedObject, SavedObjectsFindResponse } from 'kibana/server'; +import { SavedObject } from 'kibana/server'; import uuid from 'uuid'; import { RulesSchema } from '../../../../../common/detection_engine/schemas/response/rules_schema'; @@ -17,11 +17,10 @@ import { INTERNAL_IDENTIFIER } from '../../../../../common/constants'; import { RuleAlertType, isAlertType, - isAlertTypes, IRuleSavedAttributesSavedObjectAttributes, isRuleStatusFindType, - isRuleStatusFindTypes, isRuleStatusSavedObjectType, + IRuleStatusSOAttributes, } from '../../rules/types'; import { createBulkErrorObject, @@ -34,6 +33,7 @@ import { import { RuleActions } from '../../rule_actions/types'; import { internalRuleToAPIResponse } from '../../schemas/rule_converters'; import { RuleParams } from '../../schemas/rule_schemas'; +import { SanitizedAlert } from '../../../../../../alerting/common'; type PromiseFromStreams = ImportRulesSchemaDecoded | Error; @@ -103,11 +103,11 @@ export const transformTags = (tags: string[]): string[] => { // Transforms the data but will remove any null or undefined it encounters and not include // those on the export export const transformAlertToRule = ( - alert: RuleAlertType, + alert: SanitizedAlert, ruleActions?: RuleActions | null, ruleStatus?: SavedObject ): Partial => { - return internalRuleToAPIResponse(alert, ruleActions, ruleStatus); + return internalRuleToAPIResponse(alert, ruleActions, ruleStatus?.attributes); }; export const transformAlertsToRules = (alerts: RuleAlertType[]): Array> => { @@ -116,33 +116,24 @@ export const transformAlertsToRules = (alerts: RuleAlertType[]): Array, - ruleActions: Array, - ruleStatuses?: Array> + ruleActions: { [key: string]: RuleActions | undefined }, + ruleStatuses: { [key: string]: IRuleStatusSOAttributes[] | undefined } ): { page: number; perPage: number; total: number; data: Array>; } | null => { - if (!ruleStatuses && isAlertTypes(findResults.data)) { - return { - page: findResults.page, - perPage: findResults.perPage, - total: findResults.total, - data: findResults.data.map((alert, idx) => transformAlertToRule(alert, ruleActions[idx])), - }; - } else if (isAlertTypes(findResults.data) && isRuleStatusFindTypes(ruleStatuses)) { - return { - page: findResults.page, - perPage: findResults.perPage, - total: findResults.total, - data: findResults.data.map((alert, idx) => - transformAlertToRule(alert, ruleActions[idx], ruleStatuses[idx].saved_objects[0]) - ), - }; - } else { - return null; - } + return { + page: findResults.page, + perPage: findResults.perPage, + total: findResults.total, + data: findResults.data.map((alert) => { + const statuses = ruleStatuses[alert.id]; + const status = statuses ? statuses[0] : undefined; + return internalRuleToAPIResponse(alert, ruleActions[alert.id], status); + }), + }; }; export const transform = ( diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/utils.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/utils.test.ts index a09c4cd257618..ce7d4b3173370 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/utils.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/utils.test.ts @@ -25,7 +25,7 @@ import { getFailingRules, } from './utils'; import { responseMock } from './__mocks__'; -import { exampleRuleStatus, exampleFindRuleStatusResponse } from '../signals/__mocks__/es_results'; +import { exampleRuleStatus } from '../signals/__mocks__/es_results'; import { getAlertMock } from './__mocks__/request_responses'; import { AlertExecutionStatusErrorReasons } from '../../../../../alerting/common'; import { getQueryRuleParams } from '../schemas/rule_schemas.mock'; @@ -301,8 +301,8 @@ describe('utils', () => { const statusTwo = exampleRuleStatus(); statusTwo.attributes.status = 'failed'; const currentStatus = exampleRuleStatus(); - const foundRules = exampleFindRuleStatusResponse([currentStatus, statusOne, statusTwo]); - const res = mergeStatuses(currentStatus.attributes.alertId, foundRules.saved_objects, { + const foundRules = [currentStatus.attributes, statusOne.attributes, statusTwo.attributes]; + const res = mergeStatuses(currentStatus.attributes.alertId, foundRules, { 'myfakealertid-8cfac': { current_status: { alert_id: 'myfakealertid-8cfac', diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/utils.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/utils.ts index 130084da21591..9ff75726322a1 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/utils.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/utils.ts @@ -14,11 +14,12 @@ import { RouteValidationFunction, KibanaResponseFactory, CustomHttpResponseOptions, - SavedObjectsFindResult, } from '../../../../../../../src/core/server'; import { AlertsClient } from '../../../../../alerting/server'; import { RuleStatusResponse, IRuleStatusSOAttributes } from '../rules/types'; +import { RuleParams } from '../schemas/rule_schemas'; + export interface OutputError { message: string; statusCode: number; @@ -277,7 +278,7 @@ export const convertToSnakeCase = >( */ export const mergeStatuses = ( id: string, - currentStatusAndFailures: Array>, + currentStatusAndFailures: IRuleStatusSOAttributes[], acc: RuleStatusResponse ): RuleStatusResponse => { if (currentStatusAndFailures.length === 0) { @@ -286,7 +287,7 @@ export const mergeStatuses = ( }; } const convertedCurrentStatus = convertToSnakeCase( - currentStatusAndFailures[0].attributes + currentStatusAndFailures[0] ); return { ...acc, @@ -294,12 +295,12 @@ export const mergeStatuses = ( current_status: convertedCurrentStatus, failures: currentStatusAndFailures .slice(1) - .map((errorItem) => convertToSnakeCase(errorItem.attributes)), + .map((errorItem) => convertToSnakeCase(errorItem)), }, } as RuleStatusResponse; }; -export type GetFailingRulesResult = Record; +export type GetFailingRulesResult = Record>; export const getFailingRules = async ( ids: string[], @@ -316,13 +317,11 @@ export const getFailingRules = async ( return errorRules .filter((rule) => rule.executionStatus.status === 'error') .reduce((acc, failingRule) => { - const accum = acc; - const theRule = failingRule; return { - [theRule.id]: { - ...theRule, + [failingRule.id]: { + ...failingRule, }, - ...accum, + ...acc, }; }, {}); } catch (exc) { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/get_bulk_rule_actions_saved_object.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/get_bulk_rule_actions_saved_object.ts new file mode 100644 index 0000000000000..1abb16ba4612c --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/get_bulk_rule_actions_saved_object.ts @@ -0,0 +1,40 @@ +/* + * 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 { AlertServices } from '../../../../../alerting/server'; +import { ruleActionsSavedObjectType } from './saved_object_mappings'; +import { IRuleActionsAttributesSavedObjectAttributes } from './types'; +import { getRuleActionsFromSavedObject } from './utils'; +import { RulesActionsSavedObject } from './get_rule_actions_saved_object'; +import { buildChunkedOrFilter } from '../signals/utils'; + +interface GetBulkRuleActionsSavedObject { + alertIds: string[]; + savedObjectsClient: AlertServices['savedObjectsClient']; +} + +export const getBulkRuleActionsSavedObject = async ({ + alertIds, + savedObjectsClient, +}: GetBulkRuleActionsSavedObject): Promise> => { + const filter = buildChunkedOrFilter( + `${ruleActionsSavedObjectType}.attributes.ruleAlertId`, + alertIds + ); + const { + // eslint-disable-next-line @typescript-eslint/naming-convention + saved_objects, + } = await savedObjectsClient.find({ + type: ruleActionsSavedObjectType, + perPage: 10000, + filter, + }); + return saved_objects.reduce((acc: { [key: string]: RulesActionsSavedObject }, savedObject) => { + acc[savedObject.attributes.ruleAlertId] = getRuleActionsFromSavedObject(savedObject); + return acc; + }, {}); +}; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/types.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/types.ts index 380eb085e0d5a..601f3ebaa0f9e 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/types.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/types.ts @@ -211,12 +211,6 @@ export const isRuleStatusFindType = ( return get('saved_objects', obj) != null; }; -export const isRuleStatusFindTypes = ( - obj: unknown[] | undefined -): obj is Array> => { - return obj ? obj.every((ruleStatus) => isRuleStatusFindType(ruleStatus)) : false; -}; - export interface CreateRulesOptions { alertsClient: AlertsClient; anomalyThreshold: AnomalyThresholdOrUndefined; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/schemas/rule_converters.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/schemas/rule_converters.ts index ee7ecaadfd95c..a215da021d15a 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/schemas/rule_converters.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/schemas/rule_converters.ts @@ -6,7 +6,6 @@ */ import uuid from 'uuid'; -import { SavedObject } from 'kibana/server'; import { normalizeMachineLearningJobIds, normalizeThresholdObject, @@ -29,8 +28,8 @@ import { AppClient } from '../../../types'; import { addTags } from '../rules/add_tags'; import { DEFAULT_MAX_SIGNALS, SERVER_APP_ID, SIGNALS_ID } from '../../../../common/constants'; import { transformRuleToAlertAction } from '../../../../common/detection_engine/transform_actions'; -import { Alert } from '../../../../../alerting/common'; -import { IRuleSavedAttributesSavedObjectAttributes } from '../rules/types'; +import { SanitizedAlert } from '../../../../../alerting/common'; +import { IRuleStatusSOAttributes } from '../rules/types'; import { transformTags } from '../routes/rules/utils'; // These functions provide conversions from the request API schema to the internal rule schema and from the internal rule schema @@ -270,10 +269,11 @@ export const commonParamsCamelToSnake = (params: BaseRuleParams) => { }; export const internalRuleToAPIResponse = ( - rule: Alert, + rule: SanitizedAlert, ruleActions?: RuleActions | null, - ruleStatus?: SavedObject + ruleStatus?: IRuleStatusSOAttributes ): FullResponseSchema => { + const mergedStatus = ruleStatus ? mergeAlertWithSidecarStatus(rule, ruleStatus) : undefined; return { // Alerting framework params id: rule.id, @@ -293,11 +293,30 @@ export const internalRuleToAPIResponse = ( throttle: ruleActions?.ruleThrottle || 'no_actions', actions: ruleActions?.actions ?? [], // Rule status - status: ruleStatus?.attributes.status ?? undefined, - status_date: ruleStatus?.attributes.statusDate ?? undefined, - last_failure_at: ruleStatus?.attributes.lastFailureAt ?? undefined, - last_success_at: ruleStatus?.attributes.lastSuccessAt ?? undefined, - last_failure_message: ruleStatus?.attributes.lastFailureMessage ?? undefined, - last_success_message: ruleStatus?.attributes.lastSuccessMessage ?? undefined, + status: mergedStatus?.status ?? undefined, + status_date: mergedStatus?.statusDate ?? undefined, + last_failure_at: mergedStatus?.lastFailureAt ?? undefined, + last_success_at: mergedStatus?.lastSuccessAt ?? undefined, + last_failure_message: mergedStatus?.lastFailureMessage ?? undefined, + last_success_message: mergedStatus?.lastSuccessMessage ?? undefined, }; }; + +export const mergeAlertWithSidecarStatus = ( + alert: SanitizedAlert, + status: IRuleStatusSOAttributes +): IRuleStatusSOAttributes => { + if ( + new Date(alert.executionStatus.lastExecutionDate) > new Date(status.statusDate) && + alert.executionStatus.status === 'error' + ) { + return { + ...status, + lastFailureMessage: `Reason: ${alert.executionStatus.error?.reason} Message: ${alert.executionStatus.error?.message}`, + lastFailureAt: alert.executionStatus.lastExecutionDate.toISOString(), + statusDate: alert.executionStatus.lastExecutionDate.toISOString(), + status: 'failed', + }; + } + return status; +}; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/__mocks__/rule_status_saved_objects_client.mock.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/__mocks__/rule_status_saved_objects_client.mock.ts index b760cec9226db..3dd328a949938 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/__mocks__/rule_status_saved_objects_client.mock.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/__mocks__/rule_status_saved_objects_client.mock.ts @@ -9,6 +9,7 @@ import { RuleStatusSavedObjectsClient } from '../rule_status_saved_objects_clien const createMockRuleStatusSavedObjectsClient = (): jest.Mocked => ({ find: jest.fn(), + findBulk: jest.fn(), create: jest.fn(), update: jest.fn(), delete: jest.fn(), diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/rule_status_saved_objects_client.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/rule_status_saved_objects_client.ts index ff1b0e27019ed..25d315279ad60 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/rule_status_saved_objects_client.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/rule_status_saved_objects_client.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { get } from 'lodash'; import { SavedObjectsClientContract, SavedObject, @@ -14,11 +15,13 @@ import { } from '../../../../../../../src/core/server'; import { ruleStatusSavedObjectType } from '../rules/saved_object_mappings'; import { IRuleStatusSOAttributes } from '../rules/types'; +import { buildChunkedOrFilter } from './utils'; export interface RuleStatusSavedObjectsClient { find: ( options?: Omit ) => Promise>; + findBulk: (ids: string[], statusesPerId: number) => Promise; create: (attributes: IRuleStatusSOAttributes) => Promise>; update: ( id: string, @@ -27,6 +30,10 @@ export interface RuleStatusSavedObjectsClient { delete: (id: string) => Promise<{}>; } +interface FindBulkResponse { + [key: string]: IRuleStatusSOAttributes[] | undefined; +} + export const ruleStatusSavedObjectsClientFactory = ( savedObjectsClient: SavedObjectsClientContract ): RuleStatusSavedObjectsClient => ({ @@ -35,6 +42,50 @@ export const ruleStatusSavedObjectsClientFactory = ( ...options, type: ruleStatusSavedObjectType, }), + findBulk: async (ids, statusesPerId) => { + if (ids.length === 0) { + return {}; + } + const filter = buildChunkedOrFilter(`${ruleStatusSavedObjectType}.attributes.alertId`, ids); + const order: 'desc' = 'desc'; + const aggs = { + alertIds: { + terms: { + field: `${ruleStatusSavedObjectType}.attributes.alertId`, + size: ids.length, + }, + aggs: { + most_recent_statuses: { + top_hits: { + sort: [ + { + [`${ruleStatusSavedObjectType}.statusDate`]: { + order, + }, + }, + ], + size: statusesPerId, + }, + }, + }, + }, + }; + const results = await savedObjectsClient.find({ + filter, + aggs, + type: ruleStatusSavedObjectType, + perPage: 0, + }); + const buckets = get(results, 'aggregations.alertIds.buckets'); + return buckets.reduce((acc: Record, bucket: unknown) => { + const key = get(bucket, 'key'); + const hits = get(bucket, 'most_recent_statuses.hits.hits'); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const statuses = hits.map((hit: any) => hit._source['siem-detection-engine-rule-status']); + acc[key] = statuses; + return acc; + }, {}); + }, create: (attributes) => savedObjectsClient.create(ruleStatusSavedObjectType, attributes), update: (id, attributes) => savedObjectsClient.update(ruleStatusSavedObjectType, id, attributes), delete: (id) => savedObjectsClient.delete(ruleStatusSavedObjectType, id), diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.test.ts index b04eab1496e96..f49492939eeb1 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.test.ts @@ -39,6 +39,7 @@ import { createTotalHitsFromSearchResult, lastValidDate, calculateThresholdSignalUuid, + buildChunkedOrFilter, } from './utils'; import { BulkResponseErrorAggregation, SearchAfterAndBulkCreateReturnType } from './types'; import { @@ -1473,4 +1474,26 @@ describe('utils', () => { expect(signalUuid).toEqual('ee8870dc-45ff-5e6c-a2f9-80886651ce03'); }); }); + + describe('buildChunkedOrFilter', () => { + test('should return undefined if no values are provided', () => { + const filter = buildChunkedOrFilter('field.name', []); + expect(filter).toEqual(undefined); + }); + + test('should return a filter with a single value', () => { + const filter = buildChunkedOrFilter('field.name', ['id-1']); + expect(filter).toEqual('field.name: ("id-1")'); + }); + + test('should return a filter with a multiple values', () => { + const filter = buildChunkedOrFilter('field.name', ['id-1', 'id-2']); + expect(filter).toEqual('field.name: ("id-1" OR "id-2")'); + }); + + test('should return a filter with a multiple values chunked', () => { + const filter = buildChunkedOrFilter('field.name', ['id-1', 'id-2', 'id-3'], 2); + expect(filter).toEqual('field.name: ("id-1" OR "id-2") OR field.name: ("id-3")'); + }); + }); }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.ts index 03a067af6066d..cc4ed6a45807b 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.ts @@ -10,7 +10,7 @@ import moment from 'moment'; import uuidv5 from 'uuid/v5'; import dateMath from '@elastic/datemath'; import type { estypes } from '@elastic/elasticsearch'; -import { isEmpty, partition } from 'lodash'; +import { chunk, isEmpty, partition } from 'lodash'; import { ApiResponse, Context } from '@elastic/elasticsearch/lib/Transport'; import { SortResults } from '@elastic/elasticsearch/api/types'; @@ -868,3 +868,16 @@ export const getSafeSortIds = (sortIds: SortResults | undefined) => { return sortId; }); }; + +export const buildChunkedOrFilter = (field: string, values: string[], chunkSize: number = 1024) => { + if (values.length === 0) { + return undefined; + } + const chunkedValues = chunk(values, chunkSize); + return chunkedValues + .map((subArray) => { + const joinedValues = subArray.map((value) => `"${value}"`).join(' OR '); + return `${field}: (${joinedValues})`; + }) + .join(' OR '); +}; From 8fba2d93a60e6937e9fcd448eb795ae66e4c0260 Mon Sep 17 00:00:00 2001 From: Stacey Gammon Date: Fri, 28 May 2021 11:56:31 -0400 Subject: [PATCH 69/77] Ensure comments on parameters in arrow functions are captured in the docs and ci metrics. (#100823) * Make sure arrow functions capture parameter comments. * Update docs --- api_docs/apm.json | 14 +- api_docs/charts.json | 8 +- api_docs/core.json | 56 +- api_docs/core_application.json | 20 +- api_docs/core_saved_objects.json | 16 +- api_docs/data.json | 516 ++++--- api_docs/data_field_formats.json | 20 +- api_docs/data_index_patterns.json | 146 +- api_docs/data_query.json | 40 +- api_docs/data_search.json | 14 +- api_docs/deprecations.mdx | 24 +- api_docs/embeddable.json | 8 +- api_docs/expressions.json | 48 +- api_docs/fleet.json | 1196 +++++++++++------ api_docs/home.json | 6 +- api_docs/kibana_react.json | 30 +- api_docs/kibana_utils.json | 48 +- api_docs/lens.json | 52 +- api_docs/licensing.json | 2 +- api_docs/maps.json | 380 ++++-- api_docs/observability.json | 84 +- api_docs/presentation_util.json | 8 +- api_docs/reporting.json | 102 +- api_docs/rule_registry.json | 47 +- api_docs/spaces.json | 8 +- api_docs/triggers_actions_ui.json | 200 +-- api_docs/visualizations.json | 20 +- .../build_arrow_fn_dec.ts | 5 +- .../src/api_docs/tests/api_doc_suite.test.ts | 7 + .../api_docs/tests/snapshots/plugin_a.json | 26 +- 30 files changed, 1996 insertions(+), 1155 deletions(-) diff --git a/api_docs/apm.json b/api_docs/apm.json index 95cc86814e99a..7eee0349fa349 100644 --- a/api_docs/apm.json +++ b/api_docs/apm.json @@ -309,7 +309,7 @@ ], "source": { "path": "x-pack/plugins/apm/server/plugin.ts", - "lineNumber": 270 + "lineNumber": 269 }, "deprecated": false, "children": [ @@ -331,7 +331,7 @@ ], "source": { "path": "x-pack/plugins/apm/server/plugin.ts", - "lineNumber": 270 + "lineNumber": 269 }, "deprecated": false, "isRequired": true @@ -351,7 +351,7 @@ ], "source": { "path": "x-pack/plugins/apm/server/plugin.ts", - "lineNumber": 289 + "lineNumber": 288 }, "deprecated": false, "children": [], @@ -653,7 +653,13 @@ ">; delete: (deleteParams: { id: string; }) => Promise<", "DeleteResponse", ">; } | undefined>; }; start: () => Promise; }; ruleRegistry: { setup: ", - "RuleDataPluginService", + { + "pluginId": "ruleRegistry", + "scope": "server", + "docId": "kibRuleRegistryPluginApi", + "section": "def-server.RuleRegistryPluginSetupContract", + "text": "RuleRegistryPluginSetupContract" + }, "; start: () => Promise; }; security?: { setup: ", { "pluginId": "security", diff --git a/api_docs/charts.json b/api_docs/charts.json index d74e0209d6395..29c1c163d19a0 100644 --- a/api_docs/charts.json +++ b/api_docs/charts.json @@ -179,7 +179,9 @@ "type": "Array", "tags": [], "label": "xValues", - "description": [], + "description": [ + "sorted and unquie x values" + ], "signature": [ "number[]" ], @@ -417,7 +419,9 @@ "type": "Object", "tags": [], "label": "splitSeriesAccessorFnMap", - "description": [], + "description": [ + "needed when using `splitSeriesAccessors` as `AccessorFn`" + ], "signature": [ "Map; readonly filebeat: { readonly base: string; readonly installation: string; readonly configuration: string; readonly elasticsearchOutput: string; readonly elasticsearchModule: string; readonly startup: string; readonly exportedFields: string; }; readonly auditbeat: { readonly base: string; }; readonly metricbeat: { readonly base: string; readonly configure: string; readonly httpEndpoint: string; readonly install: string; readonly start: string; }; readonly enterpriseSearch: { readonly base: string; readonly appSearchBase: string; readonly workplaceSearchBase: string; }; readonly heartbeat: { readonly base: string; }; readonly logstash: { readonly base: string; }; readonly functionbeat: { readonly base: string; }; readonly winlogbeat: { readonly base: string; }; readonly aggs: { readonly composite: string; readonly composite_missing_bucket: string; readonly date_histogram: string; readonly date_range: string; readonly date_format_pattern: string; readonly filter: string; readonly filters: string; readonly geohash_grid: string; readonly histogram: string; readonly ip_range: string; readonly range: string; readonly significant_terms: string; readonly terms: string; readonly avg: string; readonly avg_bucket: string; readonly max_bucket: string; readonly min_bucket: string; readonly sum_bucket: string; readonly cardinality: string; readonly count: string; readonly cumulative_sum: string; readonly derivative: string; readonly geo_bounds: string; readonly geo_centroid: string; readonly max: string; readonly median: string; readonly min: string; readonly moving_avg: string; readonly percentile_ranks: string; readonly serial_diff: string; readonly std_dev: string; readonly sum: string; readonly top_hits: string; }; readonly runtimeFields: { readonly overview: string; readonly mapping: string; }; readonly scriptedFields: { readonly scriptFields: string; readonly scriptAggs: string; readonly painless: string; readonly painlessApi: string; readonly painlessLangSpec: string; readonly painlessSyntax: string; readonly painlessWalkthrough: string; readonly luceneExpressions: string; }; readonly search: { readonly sessions: string; }; readonly indexPatterns: { readonly introduction: string; readonly fieldFormattersNumber: string; readonly fieldFormattersString: string; }; readonly addData: string; readonly kibana: string; readonly upgradeAssistant: string; readonly elasticsearch: Record; readonly siem: { readonly guide: string; readonly gettingStarted: string; }; readonly query: { readonly eql: string; readonly kueryQuerySyntax: string; readonly luceneQuerySyntax: string; readonly percolate: string; readonly queryDsl: string; }; readonly date: { readonly dateMath: string; readonly dateMathIndexNames: string; }; readonly management: Record; readonly ml: Record; readonly transforms: Record; readonly visualize: Record; readonly apis: Readonly<{ bulkIndexAlias: string; byteSizeUnits: string; createAutoFollowPattern: string; createFollower: string; createIndex: string; createSnapshotLifecyclePolicy: string; createRoleMapping: string; createRoleMappingTemplates: string; createRollupJobsRequest: string; createApiKey: string; createPipeline: string; createTransformRequest: string; cronExpressions: string; executeWatchActionModes: string; indexExists: string; openIndex: string; putComponentTemplate: string; painlessExecute: string; painlessExecuteAPIContexts: string; putComponentTemplateMetadata: string; putSnapshotLifecyclePolicy: string; putIndexTemplateV1: string; putWatch: string; simulatePipeline: string; timeUnits: string; updateTransform: string; }>; readonly observability: Record; readonly alerting: Record; readonly maps: Record; readonly monitoring: Record; readonly security: Readonly<{ apiKeyServiceSettings: string; clusterPrivileges: string; elasticsearchSettings: string; elasticsearchEnableSecurity: string; indicesPrivileges: string; kibanaTLS: string; kibanaPrivileges: string; mappingRoles: string; mappingRolesFieldRules: string; runAsPrivilege: string; }>; readonly watcher: Record; readonly ccs: Record; readonly plugins: Record; readonly snapshotRestore: Record; readonly ingest: Record; }" + "{ readonly canvas: { readonly guide: string; }; readonly dashboard: { readonly guide: string; readonly drilldowns: string; readonly drilldownsTriggerPicker: string; readonly urlDrilldownTemplateSyntax: string; readonly urlDrilldownVariables: string; }; readonly discover: Record; readonly filebeat: { readonly base: string; readonly installation: string; readonly configuration: string; readonly elasticsearchOutput: string; readonly elasticsearchModule: string; readonly startup: string; readonly exportedFields: string; }; readonly auditbeat: { readonly base: string; }; readonly metricbeat: { readonly base: string; readonly configure: string; readonly httpEndpoint: string; readonly install: string; readonly start: string; }; readonly enterpriseSearch: { readonly base: string; readonly appSearchBase: string; readonly workplaceSearchBase: string; }; readonly heartbeat: { readonly base: string; }; readonly logstash: { readonly base: string; }; readonly functionbeat: { readonly base: string; }; readonly winlogbeat: { readonly base: string; }; readonly aggs: { readonly composite: string; readonly composite_missing_bucket: string; readonly date_histogram: string; readonly date_range: string; readonly date_format_pattern: string; readonly filter: string; readonly filters: string; readonly geohash_grid: string; readonly histogram: string; readonly ip_range: string; readonly range: string; readonly significant_terms: string; readonly terms: string; readonly avg: string; readonly avg_bucket: string; readonly max_bucket: string; readonly min_bucket: string; readonly sum_bucket: string; readonly cardinality: string; readonly count: string; readonly cumulative_sum: string; readonly derivative: string; readonly geo_bounds: string; readonly geo_centroid: string; readonly max: string; readonly median: string; readonly min: string; readonly moving_avg: string; readonly percentile_ranks: string; readonly serial_diff: string; readonly std_dev: string; readonly sum: string; readonly top_hits: string; }; readonly runtimeFields: { readonly overview: string; readonly mapping: string; }; readonly scriptedFields: { readonly scriptFields: string; readonly scriptAggs: string; readonly painless: string; readonly painlessApi: string; readonly painlessLangSpec: string; readonly painlessSyntax: string; readonly painlessWalkthrough: string; readonly luceneExpressions: string; }; readonly search: { readonly sessions: string; }; readonly indexPatterns: { readonly introduction: string; readonly fieldFormattersNumber: string; readonly fieldFormattersString: string; readonly runtimeFields: string; }; readonly addData: string; readonly kibana: string; readonly upgradeAssistant: string; readonly elasticsearch: Record; readonly siem: { readonly guide: string; readonly gettingStarted: string; }; readonly query: { readonly eql: string; readonly kueryQuerySyntax: string; readonly luceneQuerySyntax: string; readonly percolate: string; readonly queryDsl: string; }; readonly date: { readonly dateMath: string; readonly dateMathIndexNames: string; }; readonly management: Record; readonly ml: Record; readonly transforms: Record; readonly visualize: Record; readonly apis: Readonly<{ bulkIndexAlias: string; byteSizeUnits: string; createAutoFollowPattern: string; createFollower: string; createIndex: string; createSnapshotLifecyclePolicy: string; createRoleMapping: string; createRoleMappingTemplates: string; createRollupJobsRequest: string; createApiKey: string; createPipeline: string; createTransformRequest: string; cronExpressions: string; executeWatchActionModes: string; indexExists: string; openIndex: string; putComponentTemplate: string; painlessExecute: string; painlessExecuteAPIContexts: string; putComponentTemplateMetadata: string; putSnapshotLifecyclePolicy: string; putIndexTemplateV1: string; putWatch: string; simulatePipeline: string; timeUnits: string; updateTransform: string; }>; readonly observability: Record; readonly alerting: Record; readonly maps: Record; readonly monitoring: Record; readonly security: Readonly<{ apiKeyServiceSettings: string; clusterPrivileges: string; elasticsearchSettings: string; elasticsearchEnableSecurity: string; indicesPrivileges: string; kibanaTLS: string; kibanaPrivileges: string; mappingRoles: string; mappingRolesFieldRules: string; runAsPrivilege: string; }>; readonly watcher: Record; readonly ccs: Record; readonly plugins: Record; readonly snapshotRestore: Record; readonly ingest: Record; }" ], "source": { "path": "src/core/public/doc_links/doc_links_service.ts", - "lineNumber": 411 + "lineNumber": 412 }, "deprecated": false } @@ -8748,7 +8748,9 @@ "type": "string", "tags": [], "label": "endpoint", - "description": [], + "description": [ + "- String descriptor of the endpoint e.g. `cluster.getSettings` or `ping`." + ], "signature": [ "string" ], @@ -8765,7 +8767,9 @@ "type": "Object", "tags": [], "label": "clientParams", - "description": [], + "description": [ + "- A dictionary of parameters that will be passed directly to the Elasticsearch JS client." + ], "signature": [ "Record" ], @@ -8782,7 +8786,9 @@ "type": "Object", "tags": [], "label": "options", - "description": [], + "description": [ + "- Options that affect the way we call the API and process the result." + ], "signature": [ { "pluginId": "core", @@ -10803,7 +10809,7 @@ ], "source": { "path": "node_modules/@kbn/config/target/deprecation/types.d.ts", - "lineNumber": 87 + "lineNumber": 96 }, "deprecated": false, "children": [ @@ -10824,7 +10830,7 @@ ], "source": { "path": "node_modules/@kbn/config/target/deprecation/types.d.ts", - "lineNumber": 100 + "lineNumber": 109 }, "deprecated": false, "children": [ @@ -10840,7 +10846,7 @@ ], "source": { "path": "node_modules/@kbn/config/target/deprecation/types.d.ts", - "lineNumber": 100 + "lineNumber": 109 }, "deprecated": false, "isRequired": true @@ -10857,7 +10863,7 @@ ], "source": { "path": "node_modules/@kbn/config/target/deprecation/types.d.ts", - "lineNumber": 100 + "lineNumber": 109 }, "deprecated": false, "isRequired": true @@ -10876,7 +10882,7 @@ ], "source": { "path": "node_modules/@kbn/config/target/deprecation/types.d.ts", - "lineNumber": 100 + "lineNumber": 109 }, "deprecated": false, "isRequired": false @@ -10901,7 +10907,7 @@ ], "source": { "path": "node_modules/@kbn/config/target/deprecation/types.d.ts", - "lineNumber": 116 + "lineNumber": 125 }, "deprecated": false, "children": [ @@ -10917,7 +10923,7 @@ ], "source": { "path": "node_modules/@kbn/config/target/deprecation/types.d.ts", - "lineNumber": 116 + "lineNumber": 125 }, "deprecated": false, "isRequired": true @@ -10934,7 +10940,7 @@ ], "source": { "path": "node_modules/@kbn/config/target/deprecation/types.d.ts", - "lineNumber": 116 + "lineNumber": 125 }, "deprecated": false, "isRequired": true @@ -10953,7 +10959,7 @@ ], "source": { "path": "node_modules/@kbn/config/target/deprecation/types.d.ts", - "lineNumber": 116 + "lineNumber": 125 }, "deprecated": false, "isRequired": false @@ -10978,7 +10984,7 @@ ], "source": { "path": "node_modules/@kbn/config/target/deprecation/types.d.ts", - "lineNumber": 129 + "lineNumber": 138 }, "deprecated": false, "children": [ @@ -10994,7 +11000,7 @@ ], "source": { "path": "node_modules/@kbn/config/target/deprecation/types.d.ts", - "lineNumber": 129 + "lineNumber": 138 }, "deprecated": false, "isRequired": true @@ -11013,7 +11019,7 @@ ], "source": { "path": "node_modules/@kbn/config/target/deprecation/types.d.ts", - "lineNumber": 129 + "lineNumber": 138 }, "deprecated": false, "isRequired": false @@ -11038,7 +11044,7 @@ ], "source": { "path": "node_modules/@kbn/config/target/deprecation/types.d.ts", - "lineNumber": 145 + "lineNumber": 154 }, "deprecated": false, "children": [ @@ -11054,7 +11060,7 @@ ], "source": { "path": "node_modules/@kbn/config/target/deprecation/types.d.ts", - "lineNumber": 145 + "lineNumber": 154 }, "deprecated": false, "isRequired": true @@ -11073,7 +11079,7 @@ ], "source": { "path": "node_modules/@kbn/config/target/deprecation/types.d.ts", - "lineNumber": 145 + "lineNumber": 154 }, "deprecated": false, "isRequired": false @@ -19544,7 +19550,7 @@ "The os platform" ], "signature": [ - "\"linux\" | \"aix\" | \"android\" | \"darwin\" | \"freebsd\" | \"openbsd\" | \"sunos\" | \"win32\" | \"cygwin\"" + "\"linux\" | \"aix\" | \"android\" | \"darwin\" | \"freebsd\" | \"openbsd\" | \"sunos\" | \"win32\" | \"cygwin\" | \"netbsd\"" ], "source": { "path": "src/core/server/metrics/collectors/types.ts", @@ -22315,7 +22321,7 @@ ], "source": { "path": "node_modules/@kbn/config/target/deprecation/types.d.ts", - "lineNumber": 70 + "lineNumber": 79 }, "deprecated": false, "initialIsOpen": false diff --git a/api_docs/core_application.json b/api_docs/core_application.json index 13b110900ab53..e890b6f92a2ad 100644 --- a/api_docs/core_application.json +++ b/api_docs/core_application.json @@ -115,7 +115,9 @@ "type": "string", "tags": [], "label": "basePath", - "description": [], + "description": [ + "the URL path scope for the sub history" + ], "signature": [ "string" ], @@ -207,7 +209,9 @@ "type": "CompoundType", "tags": [], "label": "pathOrLocation", - "description": [], + "description": [ + "a string or location descriptor" + ], "signature": [ "string | ", "LocationDescriptorObject", @@ -266,7 +270,9 @@ "type": "CompoundType", "tags": [], "label": "pathOrLocation", - "description": [], + "description": [ + "a string or location descriptor" + ], "signature": [ "string | ", "LocationDescriptorObject", @@ -323,7 +329,9 @@ "type": "number", "tags": [], "label": "n", - "description": [], + "description": [ + "number of positions in the stack to go. Negative numbers indicate number of entries backward, positive\nnumbers for forwards. If passed 0, the current location will be reloaded. If `n` exceeds the number of\nentries available, this is a no-op." + ], "signature": [ "number" ], @@ -449,7 +457,9 @@ "type": "Function", "tags": [], "label": "listener", - "description": [], + "description": [ + "a function that receives location updates." + ], "signature": [ "(location: ", "Location", diff --git a/api_docs/core_saved_objects.json b/api_docs/core_saved_objects.json index f18d9d7cf1277..adf0612a28faf 100644 --- a/api_docs/core_saved_objects.json +++ b/api_docs/core_saved_objects.json @@ -161,7 +161,9 @@ "type": "Array", "tags": [], "label": "objects", - "description": [], + "description": [ + "- [{ type, id, attributes, references, migrationVersion }]" + ], "signature": [ { "pluginId": "core", @@ -451,7 +453,9 @@ "type": "Array", "tags": [], "label": "objects", - "description": [], + "description": [ + "- an array ids, or an array of objects containing id and optionally type" + ], "signature": [ "{ id: string; type: string; }[]" ], @@ -9362,7 +9366,9 @@ "type": "string", "tags": [], "label": "namespace", - "description": [], + "description": [ + "The namespace ID, which must be either a non-empty string or `undefined`." + ], "signature": [ "string | undefined" ], @@ -9400,7 +9406,9 @@ "type": "string", "tags": [], "label": "namespace", - "description": [], + "description": [ + "The namespace string, which must be non-empty." + ], "signature": [ "string" ], diff --git a/api_docs/data.json b/api_docs/data.json index ab5196934d855..1ba62ea994654 100644 --- a/api_docs/data.json +++ b/api_docs/data.json @@ -5610,7 +5610,9 @@ "type": "boolean", "tags": [], "label": "refresh", - "description": [], + "description": [ + "Force refresh of index pattern list" + ], "signature": [ "boolean" ], @@ -5648,7 +5650,9 @@ "type": "boolean", "tags": [], "label": "refresh", - "description": [], + "description": [ + "Force refresh of index pattern list" + ], "signature": [ "boolean" ], @@ -5751,7 +5755,9 @@ "type": "boolean", "tags": [], "label": "refresh", - "description": [], + "description": [ + "Force refresh of index pattern list" + ], "signature": [ "boolean" ], @@ -5789,7 +5795,9 @@ "type": "string", "tags": [], "label": "id", - "description": [], + "description": [ + "optionally clear a single id" + ], "signature": [ "string | undefined" ], @@ -5853,6 +5861,26 @@ "children": [], "returnComment": [] }, + { + "parentPluginId": "data", + "id": "def-public.IndexPatternsService.getDefaultId", + "type": "Function", + "tags": [], + "label": "getDefaultId", + "description": [ + "\nGet default index pattern id" + ], + "signature": [ + "() => Promise" + ], + "source": { + "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", + "lineNumber": 206 + }, + "deprecated": false, + "children": [], + "returnComment": [] + }, { "parentPluginId": "data", "id": "def-public.IndexPatternsService.setDefault", @@ -5863,30 +5891,30 @@ "\nOptionally set default index pattern, unless force = true" ], "signature": [ - "(id: string, force?: boolean) => Promise" + "(id: string | null, force?: boolean) => Promise" ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 208 + "lineNumber": 216 }, "deprecated": false, "children": [ { "parentPluginId": "data", "id": "def-public.IndexPatternsService.setDefault.$1", - "type": "string", + "type": "CompoundType", "tags": [], "label": "id", "description": [], "signature": [ - "string" + "string | null" ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 208 + "lineNumber": 216 }, "deprecated": false, - "isRequired": true + "isRequired": false }, { "parentPluginId": "data", @@ -5900,7 +5928,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 208 + "lineNumber": 216 }, "deprecated": false, "isRequired": true @@ -5930,7 +5958,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 219 + "lineNumber": 227 }, "deprecated": false, "children": [ @@ -5952,7 +5980,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 219 + "lineNumber": 227 }, "deprecated": false, "isRequired": true @@ -6000,7 +6028,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 235 + "lineNumber": 243 }, "deprecated": false, "children": [ @@ -6030,7 +6058,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 236 + "lineNumber": 244 }, "deprecated": false, "isRequired": true @@ -6054,7 +6082,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 237 + "lineNumber": 245 }, "deprecated": false, "isRequired": false @@ -6086,7 +6114,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 250 + "lineNumber": 258 }, "deprecated": false, "children": [ @@ -6108,7 +6136,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 250 + "lineNumber": 258 }, "deprecated": false, "isRequired": true @@ -6154,7 +6182,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 327 + "lineNumber": 335 }, "deprecated": false, "children": [ @@ -6164,7 +6192,9 @@ "type": "Array", "tags": [], "label": "fields", - "description": [], + "description": [ + ": FieldSpec[]" + ], "signature": [ { "pluginId": "data", @@ -6177,7 +6207,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 327 + "lineNumber": 335 }, "deprecated": false, "isRequired": true @@ -6188,7 +6218,9 @@ "type": "Object", "tags": [], "label": "fieldAttrs", - "description": [], + "description": [ + ": FieldAttrs" + ], "signature": [ { "pluginId": "data", @@ -6201,7 +6233,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 327 + "lineNumber": 335 }, "deprecated": false, "isRequired": false @@ -6242,7 +6274,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 343 + "lineNumber": 351 }, "deprecated": false, "children": [ @@ -6267,7 +6299,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 343 + "lineNumber": 351 }, "deprecated": false, "isRequired": true @@ -6299,7 +6331,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 465 + "lineNumber": 473 }, "deprecated": false, "children": [ @@ -6315,7 +6347,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 465 + "lineNumber": 473 }, "deprecated": false, "isRequired": true @@ -6353,7 +6385,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 484 + "lineNumber": 492 }, "deprecated": false, "children": [ @@ -6375,7 +6407,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 484 + "lineNumber": 492 }, "deprecated": false, "isRequired": true @@ -6392,7 +6424,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 484 + "lineNumber": 492 }, "deprecated": false, "isRequired": true @@ -6432,7 +6464,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 509 + "lineNumber": 517 }, "deprecated": false, "children": [ @@ -6454,7 +6486,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 509 + "lineNumber": 517 }, "deprecated": false, "isRequired": true @@ -6473,7 +6505,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 509 + "lineNumber": 517 }, "deprecated": false, "isRequired": true @@ -6492,7 +6524,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 509 + "lineNumber": 517 }, "deprecated": false, "isRequired": true @@ -6530,7 +6562,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 522 + "lineNumber": 530 }, "deprecated": false, "children": [ @@ -6552,7 +6584,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 522 + "lineNumber": 530 }, "deprecated": false, "isRequired": true @@ -6571,7 +6603,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 522 + "lineNumber": 530 }, "deprecated": false, "isRequired": true @@ -6601,7 +6633,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 550 + "lineNumber": 558 }, "deprecated": false, "children": [ @@ -6623,7 +6655,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 551 + "lineNumber": 559 }, "deprecated": false, "isRequired": true @@ -6640,7 +6672,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 552 + "lineNumber": 560 }, "deprecated": false, "isRequired": true @@ -6657,7 +6689,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 553 + "lineNumber": 561 }, "deprecated": false, "isRequired": true @@ -6679,7 +6711,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 636 + "lineNumber": 644 }, "deprecated": false, "children": [ @@ -6697,7 +6729,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 636 + "lineNumber": 644 }, "deprecated": false, "isRequired": true @@ -7617,7 +7649,7 @@ "plugin": "maps", "link": { "path": "x-pack/plugins/maps/public/classes/sources/es_source/es_source.ts", - "lineNumber": 266 + "lineNumber": 273 } }, { @@ -8515,7 +8547,7 @@ ], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 103 + "lineNumber": 104 }, "deprecated": false, "children": [ @@ -8531,7 +8563,7 @@ ], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 103 + "lineNumber": 104 }, "deprecated": false, "isRequired": true @@ -8560,7 +8592,7 @@ ], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 110 + "lineNumber": 111 }, "deprecated": false, "children": [ @@ -8576,7 +8608,7 @@ ], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 110 + "lineNumber": 111 }, "deprecated": false, "isRequired": true @@ -10812,6 +10844,22 @@ "lineNumber": 23 }, "deprecated": false + }, + { + "parentPluginId": "data", + "id": "def-public.ApplyGlobalFilterActionContext.controlledBy", + "type": "string", + "tags": [], + "label": "controlledBy", + "description": [], + "signature": [ + "string | undefined" + ], + "source": { + "path": "src/plugins/data/public/actions/apply_filter_action.ts", + "lineNumber": 26 + }, + "deprecated": false } ], "initialIsOpen": false @@ -11489,29 +11537,29 @@ { "plugin": "maps", "link": { - "path": "x-pack/plugins/maps/public/classes/sources/es_source/es_source.ts", - "lineNumber": 10 + "path": "x-pack/plugins/maps/public/classes/fields/es_doc_field.ts", + "lineNumber": 12 } }, { "plugin": "maps", "link": { - "path": "x-pack/plugins/maps/public/classes/sources/es_source/es_source.ts", - "lineNumber": 360 + "path": "x-pack/plugins/maps/public/classes/fields/es_doc_field.ts", + "lineNumber": 45 } }, { "plugin": "maps", "link": { - "path": "x-pack/plugins/maps/public/classes/fields/es_doc_field.ts", - "lineNumber": 12 + "path": "x-pack/plugins/maps/public/classes/sources/es_source/es_source.ts", + "lineNumber": 10 } }, { "plugin": "maps", "link": { - "path": "x-pack/plugins/maps/public/classes/fields/es_doc_field.ts", - "lineNumber": 45 + "path": "x-pack/plugins/maps/public/classes/sources/es_source/es_source.ts", + "lineNumber": 367 } }, { @@ -14884,21 +14932,21 @@ "plugin": "securitySolution", "link": { "path": "x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts", - "lineNumber": 40 + "lineNumber": 44 } }, { "plugin": "securitySolution", "link": { "path": "x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts", - "lineNumber": 55 + "lineNumber": 60 } }, { "plugin": "securitySolution", "link": { "path": "x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts", - "lineNumber": 60 + "lineNumber": 65 } }, { @@ -15913,7 +15961,7 @@ "plugin": "maps", "link": { "path": "x-pack/plugins/maps/public/embeddable/types.ts", - "lineNumber": 44 + "lineNumber": 45 } }, { @@ -19699,7 +19747,7 @@ ], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 41 + "lineNumber": 42 }, "deprecated": false, "initialIsOpen": false @@ -20185,7 +20233,7 @@ "section": "def-common.IndexPattern", "text": "IndexPattern" }, - " | null>; setDefault: (id: string, force?: boolean) => Promise; getFieldsForWildcard: (options: ", + " | null>; getDefaultId: () => Promise; setDefault: (id: string | null, force?: boolean) => Promise; getFieldsForWildcard: (options: ", { "pluginId": "data", "scope": "common", @@ -20311,7 +20359,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 642 + "lineNumber": 650 }, "deprecated": false, "initialIsOpen": false @@ -21055,7 +21103,7 @@ "description": [], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 52 + "lineNumber": 53 }, "deprecated": false }, @@ -21071,7 +21119,7 @@ ], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 52 + "lineNumber": 53 }, "deprecated": false } @@ -21914,7 +21962,7 @@ ], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 66 + "lineNumber": 67 }, "deprecated": false } @@ -21936,7 +21984,7 @@ "section": "def-common.Filter", "text": "Filter" }, - ") => { meta: { negate: boolean; alias: string | null; disabled: boolean; controlledBy?: string | undefined; index?: string | undefined; type?: string | undefined; key?: string | undefined; params?: any; value?: string | undefined; }; $state?: ", + ") => { meta: { negate: boolean; alias: string | null; disabled: boolean; controlledBy?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; params?: any; value?: string | undefined; }; $state?: ", { "pluginId": "data", "scope": "common", @@ -21981,7 +22029,7 @@ ], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 77 + "lineNumber": 78 }, "deprecated": false } @@ -22047,7 +22095,7 @@ ], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 94 + "lineNumber": 95 }, "deprecated": false } @@ -26095,7 +26143,7 @@ "section": "def-common.IndexPattern", "text": "IndexPattern" }, - " | null>; setDefault: (id: string, force?: boolean) => Promise; getFieldsForWildcard: (options: ", + " | null>; getDefaultId: () => Promise; setDefault: (id: string | null, force?: boolean) => Promise; getFieldsForWildcard: (options: ", { "pluginId": "data", "scope": "common", @@ -28430,7 +28478,9 @@ "type": "boolean", "tags": [], "label": "refresh", - "description": [], + "description": [ + "Force refresh of index pattern list" + ], "signature": [ "boolean" ], @@ -28468,7 +28518,9 @@ "type": "boolean", "tags": [], "label": "refresh", - "description": [], + "description": [ + "Force refresh of index pattern list" + ], "signature": [ "boolean" ], @@ -28571,7 +28623,9 @@ "type": "boolean", "tags": [], "label": "refresh", - "description": [], + "description": [ + "Force refresh of index pattern list" + ], "signature": [ "boolean" ], @@ -28609,7 +28663,9 @@ "type": "string", "tags": [], "label": "id", - "description": [], + "description": [ + "optionally clear a single id" + ], "signature": [ "string | undefined" ], @@ -28673,6 +28729,26 @@ "children": [], "returnComment": [] }, + { + "parentPluginId": "data", + "id": "def-server.IndexPatternsService.getDefaultId", + "type": "Function", + "tags": [], + "label": "getDefaultId", + "description": [ + "\nGet default index pattern id" + ], + "signature": [ + "() => Promise" + ], + "source": { + "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", + "lineNumber": 206 + }, + "deprecated": false, + "children": [], + "returnComment": [] + }, { "parentPluginId": "data", "id": "def-server.IndexPatternsService.setDefault", @@ -28683,30 +28759,30 @@ "\nOptionally set default index pattern, unless force = true" ], "signature": [ - "(id: string, force?: boolean) => Promise" + "(id: string | null, force?: boolean) => Promise" ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 208 + "lineNumber": 216 }, "deprecated": false, "children": [ { "parentPluginId": "data", "id": "def-server.IndexPatternsService.setDefault.$1", - "type": "string", + "type": "CompoundType", "tags": [], "label": "id", "description": [], "signature": [ - "string" + "string | null" ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 208 + "lineNumber": 216 }, "deprecated": false, - "isRequired": true + "isRequired": false }, { "parentPluginId": "data", @@ -28720,7 +28796,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 208 + "lineNumber": 216 }, "deprecated": false, "isRequired": true @@ -28750,7 +28826,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 219 + "lineNumber": 227 }, "deprecated": false, "children": [ @@ -28772,7 +28848,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 219 + "lineNumber": 227 }, "deprecated": false, "isRequired": true @@ -28820,7 +28896,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 235 + "lineNumber": 243 }, "deprecated": false, "children": [ @@ -28850,7 +28926,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 236 + "lineNumber": 244 }, "deprecated": false, "isRequired": true @@ -28874,7 +28950,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 237 + "lineNumber": 245 }, "deprecated": false, "isRequired": false @@ -28906,7 +28982,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 250 + "lineNumber": 258 }, "deprecated": false, "children": [ @@ -28928,7 +29004,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 250 + "lineNumber": 258 }, "deprecated": false, "isRequired": true @@ -28974,7 +29050,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 327 + "lineNumber": 335 }, "deprecated": false, "children": [ @@ -28984,7 +29060,9 @@ "type": "Array", "tags": [], "label": "fields", - "description": [], + "description": [ + ": FieldSpec[]" + ], "signature": [ { "pluginId": "data", @@ -28997,7 +29075,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 327 + "lineNumber": 335 }, "deprecated": false, "isRequired": true @@ -29008,7 +29086,9 @@ "type": "Object", "tags": [], "label": "fieldAttrs", - "description": [], + "description": [ + ": FieldAttrs" + ], "signature": [ { "pluginId": "data", @@ -29021,7 +29101,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 327 + "lineNumber": 335 }, "deprecated": false, "isRequired": false @@ -29062,7 +29142,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 343 + "lineNumber": 351 }, "deprecated": false, "children": [ @@ -29087,7 +29167,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 343 + "lineNumber": 351 }, "deprecated": false, "isRequired": true @@ -29119,7 +29199,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 465 + "lineNumber": 473 }, "deprecated": false, "children": [ @@ -29135,7 +29215,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 465 + "lineNumber": 473 }, "deprecated": false, "isRequired": true @@ -29173,7 +29253,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 484 + "lineNumber": 492 }, "deprecated": false, "children": [ @@ -29195,7 +29275,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 484 + "lineNumber": 492 }, "deprecated": false, "isRequired": true @@ -29212,7 +29292,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 484 + "lineNumber": 492 }, "deprecated": false, "isRequired": true @@ -29252,7 +29332,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 509 + "lineNumber": 517 }, "deprecated": false, "children": [ @@ -29274,7 +29354,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 509 + "lineNumber": 517 }, "deprecated": false, "isRequired": true @@ -29293,7 +29373,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 509 + "lineNumber": 517 }, "deprecated": false, "isRequired": true @@ -29312,7 +29392,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 509 + "lineNumber": 517 }, "deprecated": false, "isRequired": true @@ -29350,7 +29430,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 522 + "lineNumber": 530 }, "deprecated": false, "children": [ @@ -29372,7 +29452,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 522 + "lineNumber": 530 }, "deprecated": false, "isRequired": true @@ -29391,7 +29471,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 522 + "lineNumber": 530 }, "deprecated": false, "isRequired": true @@ -29421,7 +29501,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 550 + "lineNumber": 558 }, "deprecated": false, "children": [ @@ -29443,7 +29523,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 551 + "lineNumber": 559 }, "deprecated": false, "isRequired": true @@ -29460,7 +29540,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 552 + "lineNumber": 560 }, "deprecated": false, "isRequired": true @@ -29477,7 +29557,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 553 + "lineNumber": 561 }, "deprecated": false, "isRequired": true @@ -29499,7 +29579,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 636 + "lineNumber": 644 }, "deprecated": false, "children": [ @@ -29517,7 +29597,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 636 + "lineNumber": 644 }, "deprecated": false, "isRequired": true @@ -29619,7 +29699,9 @@ "type": "boolean", "tags": [], "label": "refresh", - "description": [], + "description": [ + "Force refresh of index pattern list" + ], "signature": [ "boolean" ], @@ -29657,7 +29739,9 @@ "type": "boolean", "tags": [], "label": "refresh", - "description": [], + "description": [ + "Force refresh of index pattern list" + ], "signature": [ "boolean" ], @@ -29760,7 +29844,9 @@ "type": "boolean", "tags": [], "label": "refresh", - "description": [], + "description": [ + "Force refresh of index pattern list" + ], "signature": [ "boolean" ], @@ -29798,7 +29884,9 @@ "type": "string", "tags": [], "label": "id", - "description": [], + "description": [ + "optionally clear a single id" + ], "signature": [ "string | undefined" ], @@ -29862,6 +29950,26 @@ "children": [], "returnComment": [] }, + { + "parentPluginId": "data", + "id": "def-server.IndexPatternsService.getDefaultId", + "type": "Function", + "tags": [], + "label": "getDefaultId", + "description": [ + "\nGet default index pattern id" + ], + "signature": [ + "() => Promise" + ], + "source": { + "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", + "lineNumber": 206 + }, + "deprecated": false, + "children": [], + "returnComment": [] + }, { "parentPluginId": "data", "id": "def-server.IndexPatternsService.setDefault", @@ -29872,30 +29980,30 @@ "\nOptionally set default index pattern, unless force = true" ], "signature": [ - "(id: string, force?: boolean) => Promise" + "(id: string | null, force?: boolean) => Promise" ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 208 + "lineNumber": 216 }, "deprecated": false, "children": [ { "parentPluginId": "data", "id": "def-server.IndexPatternsService.setDefault.$1", - "type": "string", + "type": "CompoundType", "tags": [], "label": "id", "description": [], "signature": [ - "string" + "string | null" ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 208 + "lineNumber": 216 }, "deprecated": false, - "isRequired": true + "isRequired": false }, { "parentPluginId": "data", @@ -29909,7 +30017,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 208 + "lineNumber": 216 }, "deprecated": false, "isRequired": true @@ -29939,7 +30047,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 219 + "lineNumber": 227 }, "deprecated": false, "children": [ @@ -29961,7 +30069,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 219 + "lineNumber": 227 }, "deprecated": false, "isRequired": true @@ -30009,7 +30117,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 235 + "lineNumber": 243 }, "deprecated": false, "children": [ @@ -30039,7 +30147,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 236 + "lineNumber": 244 }, "deprecated": false, "isRequired": true @@ -30063,7 +30171,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 237 + "lineNumber": 245 }, "deprecated": false, "isRequired": false @@ -30095,7 +30203,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 250 + "lineNumber": 258 }, "deprecated": false, "children": [ @@ -30117,7 +30225,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 250 + "lineNumber": 258 }, "deprecated": false, "isRequired": true @@ -30163,7 +30271,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 327 + "lineNumber": 335 }, "deprecated": false, "children": [ @@ -30173,7 +30281,9 @@ "type": "Array", "tags": [], "label": "fields", - "description": [], + "description": [ + ": FieldSpec[]" + ], "signature": [ { "pluginId": "data", @@ -30186,7 +30296,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 327 + "lineNumber": 335 }, "deprecated": false, "isRequired": true @@ -30197,7 +30307,9 @@ "type": "Object", "tags": [], "label": "fieldAttrs", - "description": [], + "description": [ + ": FieldAttrs" + ], "signature": [ { "pluginId": "data", @@ -30210,7 +30322,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 327 + "lineNumber": 335 }, "deprecated": false, "isRequired": false @@ -30251,7 +30363,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 343 + "lineNumber": 351 }, "deprecated": false, "children": [ @@ -30276,7 +30388,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 343 + "lineNumber": 351 }, "deprecated": false, "isRequired": true @@ -30308,7 +30420,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 465 + "lineNumber": 473 }, "deprecated": false, "children": [ @@ -30324,7 +30436,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 465 + "lineNumber": 473 }, "deprecated": false, "isRequired": true @@ -30362,7 +30474,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 484 + "lineNumber": 492 }, "deprecated": false, "children": [ @@ -30384,7 +30496,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 484 + "lineNumber": 492 }, "deprecated": false, "isRequired": true @@ -30401,7 +30513,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 484 + "lineNumber": 492 }, "deprecated": false, "isRequired": true @@ -30441,7 +30553,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 509 + "lineNumber": 517 }, "deprecated": false, "children": [ @@ -30463,7 +30575,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 509 + "lineNumber": 517 }, "deprecated": false, "isRequired": true @@ -30482,7 +30594,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 509 + "lineNumber": 517 }, "deprecated": false, "isRequired": true @@ -30501,7 +30613,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 509 + "lineNumber": 517 }, "deprecated": false, "isRequired": true @@ -30539,7 +30651,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 522 + "lineNumber": 530 }, "deprecated": false, "children": [ @@ -30561,7 +30673,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 522 + "lineNumber": 530 }, "deprecated": false, "isRequired": true @@ -30580,7 +30692,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 522 + "lineNumber": 530 }, "deprecated": false, "isRequired": true @@ -30610,7 +30722,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 550 + "lineNumber": 558 }, "deprecated": false, "children": [ @@ -30632,7 +30744,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 551 + "lineNumber": 559 }, "deprecated": false, "isRequired": true @@ -30649,7 +30761,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 552 + "lineNumber": 560 }, "deprecated": false, "isRequired": true @@ -30666,7 +30778,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 553 + "lineNumber": 561 }, "deprecated": false, "isRequired": true @@ -30688,7 +30800,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 636 + "lineNumber": 644 }, "deprecated": false, "children": [ @@ -30706,7 +30818,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 636 + "lineNumber": 644 }, "deprecated": false, "isRequired": true @@ -33297,29 +33409,29 @@ { "plugin": "maps", "link": { - "path": "x-pack/plugins/maps/public/classes/sources/es_source/es_source.ts", - "lineNumber": 10 + "path": "x-pack/plugins/maps/public/classes/fields/es_doc_field.ts", + "lineNumber": 12 } }, { "plugin": "maps", "link": { - "path": "x-pack/plugins/maps/public/classes/sources/es_source/es_source.ts", - "lineNumber": 360 + "path": "x-pack/plugins/maps/public/classes/fields/es_doc_field.ts", + "lineNumber": 45 } }, { "plugin": "maps", "link": { - "path": "x-pack/plugins/maps/public/classes/fields/es_doc_field.ts", - "lineNumber": 12 + "path": "x-pack/plugins/maps/public/classes/sources/es_source/es_source.ts", + "lineNumber": 10 } }, { "plugin": "maps", "link": { - "path": "x-pack/plugins/maps/public/classes/fields/es_doc_field.ts", - "lineNumber": 45 + "path": "x-pack/plugins/maps/public/classes/sources/es_source/es_source.ts", + "lineNumber": 367 } }, { @@ -36850,7 +36962,7 @@ ], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 41 + "lineNumber": 42 }, "deprecated": false, "initialIsOpen": false @@ -37651,7 +37763,7 @@ "description": [], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 52 + "lineNumber": 53 }, "deprecated": false }, @@ -37667,7 +37779,7 @@ ], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 52 + "lineNumber": 53 }, "deprecated": false } @@ -40886,7 +40998,7 @@ ], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 52 + "lineNumber": 53 }, "deprecated": false, "children": [ @@ -40902,7 +41014,7 @@ ], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 52 + "lineNumber": 53 }, "deprecated": false, "isRequired": true @@ -40919,7 +41031,7 @@ ], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 52 + "lineNumber": 53 }, "deprecated": false, "isRequired": false @@ -42077,7 +42189,9 @@ "type": "Object", "tags": [], "label": "filter", - "description": [], + "description": [ + "The filter to clean" + ], "signature": [ { "pluginId": "data", @@ -42293,7 +42407,7 @@ ], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 94 + "lineNumber": 95 }, "deprecated": false, "children": [ @@ -42315,7 +42429,7 @@ ], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 94 + "lineNumber": 95 }, "deprecated": false, "isRequired": true @@ -42351,7 +42465,7 @@ ], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 91 + "lineNumber": 92 }, "deprecated": false, "children": [ @@ -42373,7 +42487,7 @@ ], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 91 + "lineNumber": 92 }, "deprecated": false, "isRequired": true @@ -43571,7 +43685,7 @@ ], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 103 + "lineNumber": 104 }, "deprecated": false, "children": [ @@ -43587,7 +43701,7 @@ ], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 103 + "lineNumber": 104 }, "deprecated": false, "isRequired": true @@ -43667,7 +43781,7 @@ ], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 66 + "lineNumber": 67 }, "deprecated": false, "children": [ @@ -43689,7 +43803,7 @@ ], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 66 + "lineNumber": 67 }, "deprecated": false, "isRequired": true @@ -43718,7 +43832,7 @@ ], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 110 + "lineNumber": 111 }, "deprecated": false, "children": [ @@ -43734,7 +43848,7 @@ ], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 110 + "lineNumber": 111 }, "deprecated": false, "isRequired": true @@ -44254,7 +44368,7 @@ ], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 97 + "lineNumber": 98 }, "deprecated": false, "children": [ @@ -44276,7 +44390,7 @@ ], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 97 + "lineNumber": 98 }, "deprecated": false, "isRequired": true @@ -44469,7 +44583,7 @@ "section": "def-common.Filter", "text": "Filter" }, - ") => { meta: { disabled: boolean; alias: string | null; negate: boolean; controlledBy?: string | undefined; index?: string | undefined; type?: string | undefined; key?: string | undefined; params?: any; value?: string | undefined; }; $state?: ", + ") => { meta: { disabled: boolean; alias: string | null; negate: boolean; controlledBy?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; params?: any; value?: string | undefined; }; $state?: ", { "pluginId": "data", "scope": "common", @@ -44481,7 +44595,7 @@ ], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 70 + "lineNumber": 71 }, "deprecated": false, "children": [ @@ -44503,7 +44617,7 @@ ], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 70 + "lineNumber": 71 }, "deprecated": false, "isRequired": true @@ -44528,7 +44642,7 @@ "section": "def-common.Filter", "text": "Filter" }, - ") => { meta: { negate: boolean; alias: string | null; disabled: boolean; controlledBy?: string | undefined; index?: string | undefined; type?: string | undefined; key?: string | undefined; params?: any; value?: string | undefined; }; $state?: ", + ") => { meta: { negate: boolean; alias: string | null; disabled: boolean; controlledBy?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; params?: any; value?: string | undefined; }; $state?: ", { "pluginId": "data", "scope": "common", @@ -44540,7 +44654,7 @@ ], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 77 + "lineNumber": 78 }, "deprecated": false, "children": [ @@ -44562,7 +44676,7 @@ ], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 77 + "lineNumber": 78 }, "deprecated": false, "isRequired": true @@ -44607,7 +44721,7 @@ ], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 84 + "lineNumber": 85 }, "deprecated": false, "children": [ @@ -44629,7 +44743,7 @@ ], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 84 + "lineNumber": 85 }, "deprecated": false, "isRequired": true @@ -44665,7 +44779,7 @@ ], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 100 + "lineNumber": 101 }, "deprecated": false, "children": [ @@ -44687,7 +44801,7 @@ ], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 100 + "lineNumber": 101 }, "deprecated": false, "isRequired": true @@ -45152,7 +45266,7 @@ "description": [], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 47 + "lineNumber": 48 }, "deprecated": false, "children": [ @@ -45165,7 +45279,7 @@ "description": [], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 48 + "lineNumber": 49 }, "deprecated": false }, @@ -45178,7 +45292,7 @@ "description": [], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 49 + "lineNumber": 50 }, "deprecated": false } @@ -45771,7 +45885,7 @@ "label": "ExistsFilterMeta", "description": [], "signature": [ - "{ alias: string | null; disabled: boolean; negate: boolean; controlledBy?: string | undefined; index?: string | undefined; type?: string | undefined; key?: string | undefined; params?: any; value?: string | undefined; }" + "{ alias: string | null; disabled: boolean; negate: boolean; controlledBy?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; params?: any; value?: string | undefined; }" ], "source": { "path": "src/plugins/data/common/es_query/filters/exists_filter.ts", @@ -45887,7 +46001,7 @@ ], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", - "lineNumber": 41 + "lineNumber": 42 }, "deprecated": false, "initialIsOpen": false @@ -45900,7 +46014,7 @@ "label": "FilterMeta", "description": [], "signature": [ - "{ alias: string | null; disabled: boolean; negate: boolean; controlledBy?: string | undefined; index?: string | undefined; type?: string | undefined; key?: string | undefined; params?: any; value?: string | undefined; }" + "{ alias: string | null; disabled: boolean; negate: boolean; controlledBy?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; params?: any; value?: string | undefined; }" ], "source": { "path": "src/plugins/data/common/es_query/filters/meta_filter.ts", @@ -46178,7 +46292,7 @@ "label": "MissingFilterMeta", "description": [], "signature": [ - "{ alias: string | null; disabled: boolean; negate: boolean; controlledBy?: string | undefined; index?: string | undefined; type?: string | undefined; key?: string | undefined; params?: any; value?: string | undefined; }" + "{ alias: string | null; disabled: boolean; negate: boolean; controlledBy?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; params?: any; value?: string | undefined; }" ], "source": { "path": "src/plugins/data/common/es_query/filters/missing_filter.ts", @@ -46339,7 +46453,7 @@ "label": "QueryStringFilterMeta", "description": [], "signature": [ - "{ alias: string | null; disabled: boolean; negate: boolean; controlledBy?: string | undefined; index?: string | undefined; type?: string | undefined; key?: string | undefined; params?: any; value?: string | undefined; }" + "{ alias: string | null; disabled: boolean; negate: boolean; controlledBy?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; params?: any; value?: string | undefined; }" ], "source": { "path": "src/plugins/data/common/es_query/filters/query_string_filter.ts", diff --git a/api_docs/data_field_formats.json b/api_docs/data_field_formats.json index 6fe1b64bd555b..1807c32a18389 100644 --- a/api_docs/data_field_formats.json +++ b/api_docs/data_field_formats.json @@ -1687,7 +1687,9 @@ "type": "Enum", "tags": [], "label": "fieldType", - "description": [], + "description": [ + "- the field type" + ], "signature": [ { "pluginId": "data", @@ -1710,7 +1712,9 @@ "type": "Array", "tags": [], "label": "esTypes", - "description": [], + "description": [ + "- Array of ES data types" + ], "signature": [ { "pluginId": "data", @@ -1759,7 +1763,9 @@ "type": "string", "tags": [], "label": "formatId", - "description": [], + "description": [ + "- the format id" + ], "signature": [ "string" ], @@ -1878,7 +1884,9 @@ "type": "Array", "tags": [], "label": "esTypes", - "description": [], + "description": [ + "- Array of ES data types" + ], "signature": [ { "pluginId": "data", @@ -1941,7 +1949,9 @@ "type": "Array", "tags": [], "label": "esTypes", - "description": [], + "description": [ + "- Array of ES data types" + ], "signature": [ { "pluginId": "data", diff --git a/api_docs/data_index_patterns.json b/api_docs/data_index_patterns.json index 6d9230cfb6a87..676ded76cb331 100644 --- a/api_docs/data_index_patterns.json +++ b/api_docs/data_index_patterns.json @@ -3291,7 +3291,9 @@ "type": "boolean", "tags": [], "label": "refresh", - "description": [], + "description": [ + "Force refresh of index pattern list" + ], "signature": [ "boolean" ], @@ -3329,7 +3331,9 @@ "type": "boolean", "tags": [], "label": "refresh", - "description": [], + "description": [ + "Force refresh of index pattern list" + ], "signature": [ "boolean" ], @@ -3432,7 +3436,9 @@ "type": "boolean", "tags": [], "label": "refresh", - "description": [], + "description": [ + "Force refresh of index pattern list" + ], "signature": [ "boolean" ], @@ -3470,7 +3476,9 @@ "type": "string", "tags": [], "label": "id", - "description": [], + "description": [ + "optionally clear a single id" + ], "signature": [ "string | undefined" ], @@ -3534,6 +3542,26 @@ "children": [], "returnComment": [] }, + { + "parentPluginId": "data", + "id": "def-common.IndexPatternsService.getDefaultId", + "type": "Function", + "tags": [], + "label": "getDefaultId", + "description": [ + "\nGet default index pattern id" + ], + "signature": [ + "() => Promise" + ], + "source": { + "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", + "lineNumber": 206 + }, + "deprecated": false, + "children": [], + "returnComment": [] + }, { "parentPluginId": "data", "id": "def-common.IndexPatternsService.setDefault", @@ -3544,30 +3572,30 @@ "\nOptionally set default index pattern, unless force = true" ], "signature": [ - "(id: string, force?: boolean) => Promise" + "(id: string | null, force?: boolean) => Promise" ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 208 + "lineNumber": 216 }, "deprecated": false, "children": [ { "parentPluginId": "data", "id": "def-common.IndexPatternsService.setDefault.$1", - "type": "string", + "type": "CompoundType", "tags": [], "label": "id", "description": [], "signature": [ - "string" + "string | null" ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 208 + "lineNumber": 216 }, "deprecated": false, - "isRequired": true + "isRequired": false }, { "parentPluginId": "data", @@ -3581,7 +3609,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 208 + "lineNumber": 216 }, "deprecated": false, "isRequired": true @@ -3611,7 +3639,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 219 + "lineNumber": 227 }, "deprecated": false, "children": [ @@ -3633,7 +3661,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 219 + "lineNumber": 227 }, "deprecated": false, "isRequired": true @@ -3681,7 +3709,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 235 + "lineNumber": 243 }, "deprecated": false, "children": [ @@ -3711,7 +3739,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 236 + "lineNumber": 244 }, "deprecated": false, "isRequired": true @@ -3735,7 +3763,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 237 + "lineNumber": 245 }, "deprecated": false, "isRequired": false @@ -3767,7 +3795,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 250 + "lineNumber": 258 }, "deprecated": false, "children": [ @@ -3789,7 +3817,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 250 + "lineNumber": 258 }, "deprecated": false, "isRequired": true @@ -3835,7 +3863,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 327 + "lineNumber": 335 }, "deprecated": false, "children": [ @@ -3845,7 +3873,9 @@ "type": "Array", "tags": [], "label": "fields", - "description": [], + "description": [ + ": FieldSpec[]" + ], "signature": [ { "pluginId": "data", @@ -3858,7 +3888,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 327 + "lineNumber": 335 }, "deprecated": false, "isRequired": true @@ -3869,7 +3899,9 @@ "type": "Object", "tags": [], "label": "fieldAttrs", - "description": [], + "description": [ + ": FieldAttrs" + ], "signature": [ { "pluginId": "data", @@ -3882,7 +3914,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 327 + "lineNumber": 335 }, "deprecated": false, "isRequired": false @@ -3923,7 +3955,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 343 + "lineNumber": 351 }, "deprecated": false, "children": [ @@ -3948,7 +3980,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 343 + "lineNumber": 351 }, "deprecated": false, "isRequired": true @@ -3980,7 +4012,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 465 + "lineNumber": 473 }, "deprecated": false, "children": [ @@ -3996,7 +4028,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 465 + "lineNumber": 473 }, "deprecated": false, "isRequired": true @@ -4034,7 +4066,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 484 + "lineNumber": 492 }, "deprecated": false, "children": [ @@ -4056,7 +4088,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 484 + "lineNumber": 492 }, "deprecated": false, "isRequired": true @@ -4073,7 +4105,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 484 + "lineNumber": 492 }, "deprecated": false, "isRequired": true @@ -4113,7 +4145,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 509 + "lineNumber": 517 }, "deprecated": false, "children": [ @@ -4135,7 +4167,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 509 + "lineNumber": 517 }, "deprecated": false, "isRequired": true @@ -4154,7 +4186,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 509 + "lineNumber": 517 }, "deprecated": false, "isRequired": true @@ -4173,7 +4205,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 509 + "lineNumber": 517 }, "deprecated": false, "isRequired": true @@ -4211,7 +4243,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 522 + "lineNumber": 530 }, "deprecated": false, "children": [ @@ -4233,7 +4265,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 522 + "lineNumber": 530 }, "deprecated": false, "isRequired": true @@ -4252,7 +4284,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 522 + "lineNumber": 530 }, "deprecated": false, "isRequired": true @@ -4282,7 +4314,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 550 + "lineNumber": 558 }, "deprecated": false, "children": [ @@ -4304,7 +4336,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 551 + "lineNumber": 559 }, "deprecated": false, "isRequired": true @@ -4321,7 +4353,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 552 + "lineNumber": 560 }, "deprecated": false, "isRequired": true @@ -4338,7 +4370,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 553 + "lineNumber": 561 }, "deprecated": false, "isRequired": true @@ -4360,7 +4392,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 636 + "lineNumber": 644 }, "deprecated": false, "children": [ @@ -4378,7 +4410,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 636 + "lineNumber": 644 }, "deprecated": false, "isRequired": true @@ -5516,29 +5548,29 @@ { "plugin": "maps", "link": { - "path": "x-pack/plugins/maps/public/classes/sources/es_source/es_source.ts", - "lineNumber": 10 + "path": "x-pack/plugins/maps/public/classes/fields/es_doc_field.ts", + "lineNumber": 12 } }, { "plugin": "maps", "link": { - "path": "x-pack/plugins/maps/public/classes/sources/es_source/es_source.ts", - "lineNumber": 360 + "path": "x-pack/plugins/maps/public/classes/fields/es_doc_field.ts", + "lineNumber": 45 } }, { "plugin": "maps", "link": { - "path": "x-pack/plugins/maps/public/classes/fields/es_doc_field.ts", - "lineNumber": 12 + "path": "x-pack/plugins/maps/public/classes/sources/es_source/es_source.ts", + "lineNumber": 10 } }, { "plugin": "maps", "link": { - "path": "x-pack/plugins/maps/public/classes/fields/es_doc_field.ts", - "lineNumber": 45 + "path": "x-pack/plugins/maps/public/classes/sources/es_source/es_source.ts", + "lineNumber": 367 } }, { @@ -8911,21 +8943,21 @@ "plugin": "securitySolution", "link": { "path": "x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts", - "lineNumber": 40 + "lineNumber": 44 } }, { "plugin": "securitySolution", "link": { "path": "x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts", - "lineNumber": 55 + "lineNumber": 60 } }, { "plugin": "securitySolution", "link": { "path": "x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts", - "lineNumber": 60 + "lineNumber": 65 } }, { @@ -9940,7 +9972,7 @@ "plugin": "maps", "link": { "path": "x-pack/plugins/maps/public/embeddable/types.ts", - "lineNumber": 44 + "lineNumber": 45 } }, { @@ -12499,7 +12531,7 @@ "section": "def-common.IndexPattern", "text": "IndexPattern" }, - " | null>; setDefault: (id: string, force?: boolean) => Promise; getFieldsForWildcard: (options: ", + " | null>; getDefaultId: () => Promise; setDefault: (id: string | null, force?: boolean) => Promise; getFieldsForWildcard: (options: ", { "pluginId": "data", "scope": "common", @@ -12625,7 +12657,7 @@ ], "source": { "path": "src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts", - "lineNumber": 642 + "lineNumber": 650 }, "deprecated": false, "initialIsOpen": false diff --git a/api_docs/data_query.json b/api_docs/data_query.json index 3e28da259b5e2..a9c1711136951 100644 --- a/api_docs/data_query.json +++ b/api_docs/data_query.json @@ -1056,7 +1056,9 @@ "type": "Object", "tags": [], "label": "stateContainer", - "description": [], + "description": [ + "to use for syncing" + ], "signature": [ { "pluginId": "kibanaUtils", @@ -1547,7 +1549,9 @@ "type": "Object", "tags": [], "label": "kbnUrlStateStorage", - "description": [], + "description": [ + "to use for syncing" + ], "signature": [ { "pluginId": "kibanaUtils", @@ -2563,7 +2567,9 @@ "type": "CompoundType", "tags": [], "label": "first", - "description": [], + "description": [ + "The first filter or filter array to compare" + ], "signature": [ { "pluginId": "data", @@ -2595,7 +2601,9 @@ "type": "CompoundType", "tags": [], "label": "second", - "description": [], + "description": [ + "The second filter or filter array to compare" + ], "signature": [ { "pluginId": "data", @@ -2627,7 +2635,9 @@ "type": "Object", "tags": [], "label": "comparatorOptions", - "description": [], + "description": [ + "Parameters to use for comparison" + ], "signature": [ { "pluginId": "data", @@ -2706,7 +2716,9 @@ "type": "Array", "tags": [], "label": "existingFilters", - "description": [], + "description": [ + "- The filters to compare to" + ], "signature": [ { "pluginId": "data", @@ -2730,7 +2742,9 @@ "type": "Array", "tags": [], "label": "filters", - "description": [], + "description": [ + "- The filters being added" + ], "signature": [ { "pluginId": "data", @@ -2754,7 +2768,9 @@ "type": "Object", "tags": [], "label": "comparatorOptions", - "description": [], + "description": [ + "- Parameters to use for comparison" + ], "signature": [ { "pluginId": "data", @@ -3132,7 +3148,9 @@ "type": "Array", "tags": [], "label": "filters", - "description": [], + "description": [ + "The filters to remove duplicates from" + ], "signature": [ { "pluginId": "data", @@ -3156,7 +3174,9 @@ "type": "Any", "tags": [], "label": "comparatorOptions", - "description": [], + "description": [ + "- Parameters to use for comparison" + ], "signature": [ "any" ], diff --git a/api_docs/data_search.json b/api_docs/data_search.json index 082553e94dcf4..d72ae79e79bd8 100644 --- a/api_docs/data_search.json +++ b/api_docs/data_search.json @@ -10230,7 +10230,7 @@ "plugin": "maps", "link": { "path": "x-pack/plugins/maps/public/classes/sources/es_source/es_source.ts", - "lineNumber": 266 + "lineNumber": 273 } }, { @@ -10506,7 +10506,7 @@ "section": "def-common.IndexPatternsService", "text": "IndexPatternsService" }, - ", \"get\" | \"delete\" | \"create\" | \"find\" | \"ensureDefaultIndexPattern\" | \"getIds\" | \"getTitles\" | \"getIdsWithTitle\" | \"clearCache\" | \"getCache\" | \"getDefault\" | \"setDefault\" | \"getFieldsForWildcard\" | \"getFieldsForIndexPattern\" | \"refreshFields\" | \"fieldArrayToMap\" | \"savedObjectToSpec\" | \"createAndSave\" | \"createSavedObject\" | \"updateSavedObject\">, dependencies: ", + ", \"get\" | \"delete\" | \"create\" | \"find\" | \"ensureDefaultIndexPattern\" | \"getIds\" | \"getTitles\" | \"getIdsWithTitle\" | \"clearCache\" | \"getCache\" | \"getDefault\" | \"getDefaultId\" | \"setDefault\" | \"getFieldsForWildcard\" | \"getFieldsForIndexPattern\" | \"refreshFields\" | \"fieldArrayToMap\" | \"savedObjectToSpec\" | \"createAndSave\" | \"createSavedObject\" | \"updateSavedObject\">, dependencies: ", { "pluginId": "data", "scope": "common", @@ -10562,7 +10562,7 @@ "section": "def-common.IndexPatternsService", "text": "IndexPatternsService" }, - ", \"get\" | \"delete\" | \"create\" | \"find\" | \"ensureDefaultIndexPattern\" | \"getIds\" | \"getTitles\" | \"getIdsWithTitle\" | \"clearCache\" | \"getCache\" | \"getDefault\" | \"setDefault\" | \"getFieldsForWildcard\" | \"getFieldsForIndexPattern\" | \"refreshFields\" | \"fieldArrayToMap\" | \"savedObjectToSpec\" | \"createAndSave\" | \"createSavedObject\" | \"updateSavedObject\">" + ", \"get\" | \"delete\" | \"create\" | \"find\" | \"ensureDefaultIndexPattern\" | \"getIds\" | \"getTitles\" | \"getIdsWithTitle\" | \"clearCache\" | \"getCache\" | \"getDefault\" | \"getDefaultId\" | \"setDefault\" | \"getFieldsForWildcard\" | \"getFieldsForIndexPattern\" | \"refreshFields\" | \"fieldArrayToMap\" | \"savedObjectToSpec\" | \"createAndSave\" | \"createSavedObject\" | \"updateSavedObject\">" ], "source": { "path": "src/plugins/data/common/search/search_source/search_source_service.ts", @@ -11620,7 +11620,7 @@ "section": "def-common.IndexPatternsService", "text": "IndexPatternsService" }, - ", \"get\" | \"delete\" | \"create\" | \"find\" | \"ensureDefaultIndexPattern\" | \"getIds\" | \"getTitles\" | \"getIdsWithTitle\" | \"clearCache\" | \"getCache\" | \"getDefault\" | \"setDefault\" | \"getFieldsForWildcard\" | \"getFieldsForIndexPattern\" | \"refreshFields\" | \"fieldArrayToMap\" | \"savedObjectToSpec\" | \"createAndSave\" | \"createSavedObject\" | \"updateSavedObject\">, searchSourceDependencies: ", + ", \"get\" | \"delete\" | \"create\" | \"find\" | \"ensureDefaultIndexPattern\" | \"getIds\" | \"getTitles\" | \"getIdsWithTitle\" | \"clearCache\" | \"getCache\" | \"getDefault\" | \"getDefaultId\" | \"setDefault\" | \"getFieldsForWildcard\" | \"getFieldsForIndexPattern\" | \"refreshFields\" | \"fieldArrayToMap\" | \"savedObjectToSpec\" | \"createAndSave\" | \"createSavedObject\" | \"updateSavedObject\">, searchSourceDependencies: ", { "pluginId": "data", "scope": "common", @@ -11658,7 +11658,9 @@ "type": "Object", "tags": [], "label": "indexPatterns", - "description": [], + "description": [ + "The index patterns contract of the data plugin" + ], "signature": [ "Pick<", { @@ -11668,7 +11670,7 @@ "section": "def-common.IndexPatternsService", "text": "IndexPatternsService" }, - ", \"get\" | \"delete\" | \"create\" | \"find\" | \"ensureDefaultIndexPattern\" | \"getIds\" | \"getTitles\" | \"getIdsWithTitle\" | \"clearCache\" | \"getCache\" | \"getDefault\" | \"setDefault\" | \"getFieldsForWildcard\" | \"getFieldsForIndexPattern\" | \"refreshFields\" | \"fieldArrayToMap\" | \"savedObjectToSpec\" | \"createAndSave\" | \"createSavedObject\" | \"updateSavedObject\">" + ", \"get\" | \"delete\" | \"create\" | \"find\" | \"ensureDefaultIndexPattern\" | \"getIds\" | \"getTitles\" | \"getIdsWithTitle\" | \"clearCache\" | \"getCache\" | \"getDefault\" | \"getDefaultId\" | \"setDefault\" | \"getFieldsForWildcard\" | \"getFieldsForIndexPattern\" | \"refreshFields\" | \"fieldArrayToMap\" | \"savedObjectToSpec\" | \"createAndSave\" | \"createSavedObject\" | \"updateSavedObject\">" ], "source": { "path": "src/plugins/data/common/search/search_source/create_search_source.ts", diff --git a/api_docs/deprecations.mdx b/api_docs/deprecations.mdx index 9eee6d51d84ab..99edad62075bc 100644 --- a/api_docs/deprecations.mdx +++ b/api_docs/deprecations.mdx @@ -946,11 +946,11 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | Deprecated API | Reference location | Remove By | | ---------------|-----------|-----------| | | [types.ts#L8](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/embeddable/types.ts#L8) | - | -| | [types.ts#L44](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/embeddable/types.ts#L44) | - | -| | [es_source.ts#L10](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/sources/es_source/es_source.ts#L10) | - | -| | [es_source.ts#L360](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/sources/es_source/es_source.ts#L360) | - | +| | [types.ts#L45](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/embeddable/types.ts#L45) | - | | | [es_doc_field.ts#L12](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/fields/es_doc_field.ts#L12) | - | | | [es_doc_field.ts#L45](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/fields/es_doc_field.ts#L45) | - | +| | [es_source.ts#L10](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/sources/es_source/es_source.ts#L10) | - | +| | [es_source.ts#L367](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/sources/es_source/es_source.ts#L367) | - | | | [index_pattern_util.ts#L8](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/index_pattern_util.ts#L8) | - | | | [index_pattern_util.ts#L15](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/index_pattern_util.ts#L15) | - | | | [index_pattern_util.ts#L49](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/index_pattern_util.ts#L49) | - | @@ -1041,10 +1041,10 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | | [create_source_editor.tsx#L35](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/sources/es_search_source/top_hits/create_source_editor.tsx#L35) | - | | | [get_docvalue_source_fields.test.ts#L10](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/sources/es_search_source/get_docvalue_source_fields.test.ts#L10) | - | | | [get_docvalue_source_fields.test.ts#L12](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/sources/es_search_source/get_docvalue_source_fields.test.ts#L12) | - | -| | [es_source.ts#L10](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/sources/es_source/es_source.ts#L10) | - | -| | [es_source.ts#L360](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/sources/es_source/es_source.ts#L360) | - | | | [es_doc_field.ts#L12](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/fields/es_doc_field.ts#L12) | - | | | [es_doc_field.ts#L45](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/fields/es_doc_field.ts#L45) | - | +| | [es_source.ts#L10](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/sources/es_source/es_source.ts#L10) | - | +| | [es_source.ts#L367](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/sources/es_source/es_source.ts#L367) | - | | | [index_pattern_util.ts#L8](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/index_pattern_util.ts#L8) | - | | | [index_pattern_util.ts#L15](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/index_pattern_util.ts#L15) | - | | | [index_pattern_util.ts#L49](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/index_pattern_util.ts#L49) | - | @@ -1136,11 +1136,11 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | | [get_docvalue_source_fields.test.ts#L10](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/sources/es_search_source/get_docvalue_source_fields.test.ts#L10) | - | | | [get_docvalue_source_fields.test.ts#L12](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/sources/es_search_source/get_docvalue_source_fields.test.ts#L12) | - | | | [types.ts#L8](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/embeddable/types.ts#L8) | - | -| | [types.ts#L44](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/embeddable/types.ts#L44) | - | -| | [es_source.ts#L10](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/sources/es_source/es_source.ts#L10) | - | -| | [es_source.ts#L360](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/sources/es_source/es_source.ts#L360) | - | +| | [types.ts#L45](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/embeddable/types.ts#L45) | - | | | [es_doc_field.ts#L12](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/fields/es_doc_field.ts#L12) | - | | | [es_doc_field.ts#L45](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/fields/es_doc_field.ts#L45) | - | +| | [es_source.ts#L10](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/sources/es_source/es_source.ts#L10) | - | +| | [es_source.ts#L367](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/classes/sources/es_source/es_source.ts#L367) | - | | | [index_pattern_util.ts#L8](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/index_pattern_util.ts#L8) | - | | | [index_pattern_util.ts#L15](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/index_pattern_util.ts#L15) | - | | | [index_pattern_util.ts#L49](https://github.com/elastic/kibana/tree/master/x-pack/plugins/maps/public/index_pattern_util.ts#L49) | - | @@ -1612,9 +1612,9 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | | [types.ts#L41](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/network/pages/details/types.ts#L41) | - | | | [index.tsx#L12](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/network/components/network_top_countries_table/index.tsx#L12) | - | | | [index.tsx#L34](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/network/components/network_top_countries_table/index.tsx#L34) | - | -| | [middleware.ts#L40](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts#L40) | - | -| | [middleware.ts#L55](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts#L55) | - | +| | [middleware.ts#L44](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts#L44) | - | | | [middleware.ts#L60](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts#L60) | - | +| | [middleware.ts#L65](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts#L65) | - | | | [types.ts#L12](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/detections/components/rules/description_step/types.ts#L12) | - | | | [types.ts#L28](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/detections/components/rules/description_step/types.ts#L28) | - | | | [index.tsx#L15](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/detections/components/rules/description_step/index.tsx#L15) | - | @@ -1824,9 +1824,9 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | | [types.ts#L41](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/network/pages/details/types.ts#L41) | - | | | [index.tsx#L12](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/network/components/network_top_countries_table/index.tsx#L12) | - | | | [index.tsx#L34](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/network/components/network_top_countries_table/index.tsx#L34) | - | -| | [middleware.ts#L40](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts#L40) | - | -| | [middleware.ts#L55](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts#L55) | - | +| | [middleware.ts#L44](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts#L44) | - | | | [middleware.ts#L60](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts#L60) | - | +| | [middleware.ts#L65](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts#L65) | - | | | [types.ts#L12](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/detections/components/rules/description_step/types.ts#L12) | - | | | [types.ts#L28](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/detections/components/rules/description_step/types.ts#L28) | - | | | [index.tsx#L15](https://github.com/elastic/kibana/tree/master/x-pack/plugins/security_solution/public/detections/components/rules/description_step/index.tsx#L15) | - | diff --git a/api_docs/embeddable.json b/api_docs/embeddable.json index c9fee3570688c..d560148f35b13 100644 --- a/api_docs/embeddable.json +++ b/api_docs/embeddable.json @@ -3847,7 +3847,9 @@ "type": "string", "tags": [], "label": "appId", - "description": [], + "description": [ + "- The id of the app to fetch the title for" + ], "signature": [ "string" ], @@ -4716,7 +4718,9 @@ "type": "CompoundType", "tags": [], "label": "props", - "description": [], + "description": [ + "- {@link EmbeddableRendererProps}" + ], "signature": [ { "pluginId": "embeddable", diff --git a/api_docs/expressions.json b/api_docs/expressions.json index 6d77161ae85a0..e981414fe7bda 100644 --- a/api_docs/expressions.json +++ b/api_docs/expressions.json @@ -4875,7 +4875,9 @@ "type": "Object", "tags": [], "label": "state", - "description": [], + "description": [ + "expression AST to extract references from" + ], "signature": [ { "pluginId": "expressions", @@ -4954,7 +4956,9 @@ "type": "Object", "tags": [], "label": "state", - "description": [], + "description": [ + "expression AST to extract references from" + ], "signature": [ { "pluginId": "expressions", @@ -5017,7 +5021,9 @@ "type": "Object", "tags": [], "label": "state", - "description": [], + "description": [ + "expression AST to update" + ], "signature": [ { "pluginId": "expressions", @@ -5040,7 +5046,9 @@ "type": "Array", "tags": [], "label": "references", - "description": [], + "description": [ + "array of saved object references" + ], "signature": [ "SavedObjectReference", "[]" @@ -5096,7 +5104,9 @@ "type": "Object", "tags": [], "label": "state", - "description": [], + "description": [ + "expression AST to update" + ], "signature": [ { "pluginId": "kibanaUtils", @@ -5119,7 +5129,9 @@ "type": "string", "tags": [], "label": "version", - "description": [], + "description": [ + "defines which migration version to run" + ], "signature": [ "string" ], @@ -25765,7 +25777,9 @@ "type": "Object", "tags": [], "label": "state", - "description": [], + "description": [ + "expression AST to extract references from" + ], "signature": [ { "pluginId": "expressions", @@ -25844,7 +25858,9 @@ "type": "Object", "tags": [], "label": "state", - "description": [], + "description": [ + "expression AST to extract references from" + ], "signature": [ { "pluginId": "expressions", @@ -25907,7 +25923,9 @@ "type": "Object", "tags": [], "label": "state", - "description": [], + "description": [ + "expression AST to update" + ], "signature": [ { "pluginId": "expressions", @@ -25930,7 +25948,9 @@ "type": "Array", "tags": [], "label": "references", - "description": [], + "description": [ + "array of saved object references" + ], "signature": [ "SavedObjectReference", "[]" @@ -25986,7 +26006,9 @@ "type": "Object", "tags": [], "label": "state", - "description": [], + "description": [ + "expression AST to update" + ], "signature": [ { "pluginId": "kibanaUtils", @@ -26009,7 +26031,9 @@ "type": "string", "tags": [], "label": "version", - "description": [], + "description": [ + "defines which migration version to run" + ], "signature": [ "string" ], diff --git a/api_docs/fleet.json b/api_docs/fleet.json index 389a56cccefc5..043dfcd16c2a7 100644 --- a/api_docs/fleet.json +++ b/api_docs/fleet.json @@ -373,6 +373,30 @@ "lineNumber": 60 }, "deprecated": false + }, + { + "parentPluginId": "fleet", + "id": "def-public.NewPackagePolicy.vars", + "type": "Object", + "tags": [], + "label": "vars", + "description": [], + "signature": [ + "Record | undefined" + ], + "source": { + "path": "x-pack/plugins/fleet/common/types/models/package_policy.ts", + "lineNumber": 61 + }, + "deprecated": false } ], "initialIsOpen": false @@ -1435,7 +1459,7 @@ "label": "integration_details_overview", "description": [], "signature": [ - "({ pkgkey }: ", + "({ pkgkey, integration }: ", "DynamicPagePathValues", ") => string" ], @@ -1450,7 +1474,7 @@ "id": "def-public.pagePathGetters.integration_details_overview.$1", "type": "Object", "tags": [], - "label": "{ pkgkey }", + "label": "{ pkgkey, integration }", "description": [], "signature": [ "DynamicPagePathValues" @@ -1473,13 +1497,13 @@ "label": "integration_details_policies", "description": [], "signature": [ - "({ pkgkey }: ", + "({ pkgkey, integration }: ", "DynamicPagePathValues", ") => string" ], "source": { "path": "x-pack/plugins/fleet/public/applications/fleet/constants/page_paths.ts", - "lineNumber": 81 + "lineNumber": 82 }, "deprecated": false, "children": [ @@ -1488,14 +1512,14 @@ "id": "def-public.pagePathGetters.integration_details_policies.$1", "type": "Object", "tags": [], - "label": "{ pkgkey }", + "label": "{ pkgkey, integration }", "description": [], "signature": [ "DynamicPagePathValues" ], "source": { "path": "x-pack/plugins/fleet/public/applications/fleet/constants/page_paths.ts", - "lineNumber": 81 + "lineNumber": 82 }, "deprecated": false, "isRequired": true @@ -1511,13 +1535,13 @@ "label": "integration_details_settings", "description": [], "signature": [ - "({ pkgkey }: ", + "({ pkgkey, integration }: ", "DynamicPagePathValues", ") => string" ], "source": { "path": "x-pack/plugins/fleet/public/applications/fleet/constants/page_paths.ts", - "lineNumber": 82 + "lineNumber": 84 }, "deprecated": false, "children": [ @@ -1526,14 +1550,14 @@ "id": "def-public.pagePathGetters.integration_details_settings.$1", "type": "Object", "tags": [], - "label": "{ pkgkey }", + "label": "{ pkgkey, integration }", "description": [], "signature": [ "DynamicPagePathValues" ], "source": { "path": "x-pack/plugins/fleet/public/applications/fleet/constants/page_paths.ts", - "lineNumber": 82 + "lineNumber": 84 }, "deprecated": false, "isRequired": true @@ -1549,13 +1573,13 @@ "label": "integration_details_custom", "description": [], "signature": [ - "({ pkgkey }: ", + "({ pkgkey, integration }: ", "DynamicPagePathValues", ") => string" ], "source": { "path": "x-pack/plugins/fleet/public/applications/fleet/constants/page_paths.ts", - "lineNumber": 83 + "lineNumber": 86 }, "deprecated": false, "children": [ @@ -1564,14 +1588,14 @@ "id": "def-public.pagePathGetters.integration_details_custom.$1", "type": "Object", "tags": [], - "label": "{ pkgkey }", + "label": "{ pkgkey, integration }", "description": [], "signature": [ "DynamicPagePathValues" ], "source": { "path": "x-pack/plugins/fleet/public/applications/fleet/constants/page_paths.ts", - "lineNumber": 83 + "lineNumber": 86 }, "deprecated": false, "isRequired": true @@ -1593,7 +1617,7 @@ ], "source": { "path": "x-pack/plugins/fleet/public/applications/fleet/constants/page_paths.ts", - "lineNumber": 84 + "lineNumber": 88 }, "deprecated": false, "children": [ @@ -1609,7 +1633,7 @@ ], "source": { "path": "x-pack/plugins/fleet/public/applications/fleet/constants/page_paths.ts", - "lineNumber": 84 + "lineNumber": 88 }, "deprecated": false, "isRequired": true @@ -1629,7 +1653,7 @@ ], "source": { "path": "x-pack/plugins/fleet/public/applications/fleet/constants/page_paths.ts", - "lineNumber": 86 + "lineNumber": 90 }, "deprecated": false, "children": [], @@ -1647,7 +1671,7 @@ ], "source": { "path": "x-pack/plugins/fleet/public/applications/fleet/constants/page_paths.ts", - "lineNumber": 87 + "lineNumber": 91 }, "deprecated": false, "children": [], @@ -1667,7 +1691,7 @@ ], "source": { "path": "x-pack/plugins/fleet/public/applications/fleet/constants/page_paths.ts", - "lineNumber": 88 + "lineNumber": 92 }, "deprecated": false, "children": [ @@ -1683,7 +1707,7 @@ ], "source": { "path": "x-pack/plugins/fleet/public/applications/fleet/constants/page_paths.ts", - "lineNumber": 88 + "lineNumber": 92 }, "deprecated": false, "isRequired": true @@ -1705,7 +1729,7 @@ ], "source": { "path": "x-pack/plugins/fleet/public/applications/fleet/constants/page_paths.ts", - "lineNumber": 89 + "lineNumber": 93 }, "deprecated": false, "children": [ @@ -1721,7 +1745,7 @@ ], "source": { "path": "x-pack/plugins/fleet/public/applications/fleet/constants/page_paths.ts", - "lineNumber": 89 + "lineNumber": 93 }, "deprecated": false, "isRequired": true @@ -1737,13 +1761,13 @@ "label": "add_integration_to_policy", "description": [], "signature": [ - "({ pkgkey }: ", + "({ pkgkey, integration }: ", "DynamicPagePathValues", ") => string" ], "source": { "path": "x-pack/plugins/fleet/public/applications/fleet/constants/page_paths.ts", - "lineNumber": 90 + "lineNumber": 94 }, "deprecated": false, "children": [ @@ -1752,14 +1776,14 @@ "id": "def-public.pagePathGetters.add_integration_to_policy.$1", "type": "Object", "tags": [], - "label": "{ pkgkey }", + "label": "{ pkgkey, integration }", "description": [], "signature": [ "DynamicPagePathValues" ], "source": { "path": "x-pack/plugins/fleet/public/applications/fleet/constants/page_paths.ts", - "lineNumber": 90 + "lineNumber": 94 }, "deprecated": false, "isRequired": true @@ -1781,7 +1805,7 @@ ], "source": { "path": "x-pack/plugins/fleet/public/applications/fleet/constants/page_paths.ts", - "lineNumber": 91 + "lineNumber": 96 }, "deprecated": false, "children": [ @@ -1797,7 +1821,7 @@ ], "source": { "path": "x-pack/plugins/fleet/public/applications/fleet/constants/page_paths.ts", - "lineNumber": 91 + "lineNumber": 96 }, "deprecated": false, "isRequired": true @@ -1817,7 +1841,7 @@ ], "source": { "path": "x-pack/plugins/fleet/public/applications/fleet/constants/page_paths.ts", - "lineNumber": 93 + "lineNumber": 98 }, "deprecated": false, "children": [], @@ -1837,7 +1861,7 @@ ], "source": { "path": "x-pack/plugins/fleet/public/applications/fleet/constants/page_paths.ts", - "lineNumber": 94 + "lineNumber": 99 }, "deprecated": false, "children": [ @@ -1853,7 +1877,7 @@ ], "source": { "path": "x-pack/plugins/fleet/public/applications/fleet/constants/page_paths.ts", - "lineNumber": 94 + "lineNumber": 99 }, "deprecated": false, "isRequired": true @@ -1875,7 +1899,7 @@ ], "source": { "path": "x-pack/plugins/fleet/public/applications/fleet/constants/page_paths.ts", - "lineNumber": 95 + "lineNumber": 100 }, "deprecated": false, "children": [ @@ -1891,7 +1915,7 @@ ], "source": { "path": "x-pack/plugins/fleet/public/applications/fleet/constants/page_paths.ts", - "lineNumber": 95 + "lineNumber": 100 }, "deprecated": false, "isRequired": true @@ -1911,7 +1935,7 @@ ], "source": { "path": "x-pack/plugins/fleet/public/applications/fleet/constants/page_paths.ts", - "lineNumber": 97 + "lineNumber": 102 }, "deprecated": false, "children": [], @@ -1929,7 +1953,7 @@ ], "source": { "path": "x-pack/plugins/fleet/public/applications/fleet/constants/page_paths.ts", - "lineNumber": 98 + "lineNumber": 103 }, "deprecated": false, "children": [], @@ -4777,7 +4801,7 @@ ], "source": { "path": "x-pack/plugins/fleet/server/services/package_policy.ts", - "lineNumber": 651 + "lineNumber": 655 }, "deprecated": false, "initialIsOpen": false @@ -5376,105 +5400,385 @@ }, { "parentPluginId": "fleet", - "id": "def-common.entries", + "id": "def-common.doesPackageHaveIntegrations", "type": "Function", "tags": [], - "label": "entries", + "label": "doesPackageHaveIntegrations", "description": [], "signature": [ - "(o: T) => [keyof T, T[keyof T]][]" - ], - "source": { - "path": "x-pack/plugins/fleet/common/types/index.ts", - "lineNumber": 35 - }, - "deprecated": false, - "returnComment": [], - "children": [ + "(pkgInfo: ", { - "parentPluginId": "fleet", - "id": "def-common.o", - "type": "Uncategorized", - "tags": [], - "label": "o", - "description": [], - "signature": [ - "T" - ], - "source": { - "path": "x-pack/plugins/fleet/common/types/index.ts", - "lineNumber": 35 - }, - "deprecated": false - } - ], - "initialIsOpen": false - }, - { - "parentPluginId": "fleet", - "id": "def-common.fullAgentPolicyToYaml", - "type": "Function", - "tags": [], - "label": "fullAgentPolicyToYaml", - "description": [], - "signature": [ - "(policy: ", + "pluginId": "fleet", + "scope": "common", + "docId": "kibFleetPluginApi", + "section": "def-common.Installed", + "text": "Installed" + }, + " string" + ", ", + { + "pluginId": "fleet", + "scope": "common", + "docId": "kibFleetPluginApi", + "section": "def-common.EpmPackageAdditions", + "text": "EpmPackageAdditions" + }, + ">> | ", + { + "pluginId": "fleet", + "scope": "common", + "docId": "kibFleetPluginApi", + "section": "def-common.NotInstalled", + "text": "NotInstalled" + }, + "> | ", + { + "pluginId": "fleet", + "scope": "common", + "docId": "kibFleetPluginApi", + "section": "def-common.Installed", + "text": "Installed" + }, + "> | ", + { + "pluginId": "fleet", + "scope": "common", + "docId": "kibFleetPluginApi", + "section": "def-common.NotInstalled", + "text": "NotInstalled" + }, + "> | (Pick<", + { + "pluginId": "fleet", + "scope": "common", + "docId": "kibFleetPluginApi", + "section": "def-common.RegistryPackage", + "text": "RegistryPackage" + }, + ", \"type\" | \"description\" | \"title\" | \"name\" | \"version\" | \"download\" | \"path\" | \"internal\" | \"data_streams\" | \"release\" | \"icons\" | \"policy_templates\"> & { status: \"installed\"; savedObject: ", + "SavedObject", + "<", + { + "pluginId": "fleet", + "scope": "common", + "docId": "kibFleetPluginApi", + "section": "def-common.Installation", + "text": "Installation" + }, + ">; } & { integration?: string | undefined; id: string; }) | (Pick<", + { + "pluginId": "fleet", + "scope": "common", + "docId": "kibFleetPluginApi", + "section": "def-common.RegistryPackage", + "text": "RegistryPackage" + }, + ", \"type\" | \"description\" | \"title\" | \"name\" | \"version\" | \"download\" | \"path\" | \"internal\" | \"data_streams\" | \"release\" | \"icons\" | \"policy_templates\"> & { status: \"not_installed\"; } & { integration?: string | undefined; id: string; })) => boolean" ], "source": { - "path": "x-pack/plugins/fleet/common/services/full_agent_policy_to_yaml.ts", - "lineNumber": 28 + "path": "x-pack/plugins/fleet/common/services/packages_with_integrations.ts", + "lineNumber": 9 }, "deprecated": false, "children": [ { "parentPluginId": "fleet", - "id": "def-common.fullAgentPolicyToYaml.$1", - "type": "Object", + "id": "def-common.doesPackageHaveIntegrations.$1", + "type": "CompoundType", "tags": [], - "label": "policy", + "label": "pkgInfo", "description": [], "signature": [ { "pluginId": "fleet", "scope": "common", "docId": "kibFleetPluginApi", - "section": "def-common.FullAgentPolicy", - "text": "FullAgentPolicy" - } - ], - "source": { - "path": "x-pack/plugins/fleet/common/services/full_agent_policy_to_yaml.ts", - "lineNumber": 28 - }, - "deprecated": false, - "isRequired": true - } - ], - "returnComment": [], - "initialIsOpen": false - }, - { - "parentPluginId": "fleet", - "id": "def-common.isAgentUpgradeable", - "type": "Function", - "tags": [], - "label": "isAgentUpgradeable", - "description": [], - "signature": [ - "(agent: ", - { - "pluginId": "fleet", - "scope": "common", - "docId": "kibFleetPluginApi", - "section": "def-common.Agent", + "section": "def-common.Installed", + "text": "Installed" + }, + "> | ", + { + "pluginId": "fleet", + "scope": "common", + "docId": "kibFleetPluginApi", + "section": "def-common.NotInstalled", + "text": "NotInstalled" + }, + "> | ", + { + "pluginId": "fleet", + "scope": "common", + "docId": "kibFleetPluginApi", + "section": "def-common.Installed", + "text": "Installed" + }, + "> | ", + { + "pluginId": "fleet", + "scope": "common", + "docId": "kibFleetPluginApi", + "section": "def-common.NotInstalled", + "text": "NotInstalled" + }, + "> | (Pick<", + { + "pluginId": "fleet", + "scope": "common", + "docId": "kibFleetPluginApi", + "section": "def-common.RegistryPackage", + "text": "RegistryPackage" + }, + ", \"type\" | \"description\" | \"title\" | \"name\" | \"version\" | \"download\" | \"path\" | \"internal\" | \"data_streams\" | \"release\" | \"icons\" | \"policy_templates\"> & { status: \"installed\"; savedObject: ", + "SavedObject", + "<", + { + "pluginId": "fleet", + "scope": "common", + "docId": "kibFleetPluginApi", + "section": "def-common.Installation", + "text": "Installation" + }, + ">; } & { integration?: string | undefined; id: string; }) | (Pick<", + { + "pluginId": "fleet", + "scope": "common", + "docId": "kibFleetPluginApi", + "section": "def-common.RegistryPackage", + "text": "RegistryPackage" + }, + ", \"type\" | \"description\" | \"title\" | \"name\" | \"version\" | \"download\" | \"path\" | \"internal\" | \"data_streams\" | \"release\" | \"icons\" | \"policy_templates\"> & { status: \"not_installed\"; } & { integration?: string | undefined; id: string; })" + ], + "source": { + "path": "x-pack/plugins/fleet/common/services/packages_with_integrations.ts", + "lineNumber": 9 + }, + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "fleet", + "id": "def-common.entries", + "type": "Function", + "tags": [], + "label": "entries", + "description": [], + "signature": [ + "(o: T) => [keyof T, T[keyof T]][]" + ], + "source": { + "path": "x-pack/plugins/fleet/common/types/index.ts", + "lineNumber": 35 + }, + "deprecated": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "fleet", + "id": "def-common.o", + "type": "Uncategorized", + "tags": [], + "label": "o", + "description": [], + "signature": [ + "T" + ], + "source": { + "path": "x-pack/plugins/fleet/common/types/index.ts", + "lineNumber": 35 + }, + "deprecated": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "fleet", + "id": "def-common.fullAgentPolicyToYaml", + "type": "Function", + "tags": [], + "label": "fullAgentPolicyToYaml", + "description": [], + "signature": [ + "(policy: ", + { + "pluginId": "fleet", + "scope": "common", + "docId": "kibFleetPluginApi", + "section": "def-common.FullAgentPolicy", + "text": "FullAgentPolicy" + }, + ") => string" + ], + "source": { + "path": "x-pack/plugins/fleet/common/services/full_agent_policy_to_yaml.ts", + "lineNumber": 28 + }, + "deprecated": false, + "children": [ + { + "parentPluginId": "fleet", + "id": "def-common.fullAgentPolicyToYaml.$1", + "type": "Object", + "tags": [], + "label": "policy", + "description": [], + "signature": [ + { + "pluginId": "fleet", + "scope": "common", + "docId": "kibFleetPluginApi", + "section": "def-common.FullAgentPolicy", + "text": "FullAgentPolicy" + } + ], + "source": { + "path": "x-pack/plugins/fleet/common/services/full_agent_policy_to_yaml.ts", + "lineNumber": 28 + }, + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "fleet", + "id": "def-common.isAgentUpgradeable", + "type": "Function", + "tags": [], + "label": "isAgentUpgradeable", + "description": [], + "signature": [ + "(agent: ", + { + "pluginId": "fleet", + "scope": "common", + "docId": "kibFleetPluginApi", + "section": "def-common.Agent", "text": "Agent" }, ", kibanaVersion: string) => boolean" @@ -5827,7 +6131,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/services/package_to_package_policy.ts", - "lineNumber": 46 + "lineNumber": 61 }, "deprecated": false, "children": [ @@ -5849,7 +6153,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/services/package_to_package_policy.ts", - "lineNumber": 47 + "lineNumber": 62 }, "deprecated": false, "isRequired": true @@ -6505,7 +6809,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 221 + "lineNumber": 236 }, "deprecated": false, "children": [ @@ -6518,7 +6822,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 222 + "lineNumber": 237 }, "deprecated": false }, @@ -6534,7 +6838,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 223 + "lineNumber": 238 }, "deprecated": false }, @@ -6550,7 +6854,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 224 + "lineNumber": 239 }, "deprecated": false }, @@ -6581,7 +6885,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 225 + "lineNumber": 240 }, "deprecated": false }, @@ -6594,7 +6898,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 226 + "lineNumber": 241 }, "deprecated": false } @@ -6818,7 +7122,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 214 + "lineNumber": 229 }, "deprecated": false, "children": [ @@ -6831,7 +7135,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 215 + "lineNumber": 230 }, "deprecated": false }, @@ -6844,7 +7148,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 216 + "lineNumber": 231 }, "deprecated": false }, @@ -6857,7 +7161,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 217 + "lineNumber": 232 }, "deprecated": false } @@ -7305,7 +7609,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 33 + "lineNumber": 38 }, "deprecated": false, "children": [ @@ -7321,7 +7625,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 34 + "lineNumber": 39 }, "deprecated": false }, @@ -7337,7 +7641,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 35 + "lineNumber": 40 }, "deprecated": false } @@ -7736,7 +8040,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 320 + "lineNumber": 335 }, "deprecated": false, "children": [ @@ -7749,7 +8053,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 321 + "lineNumber": 336 }, "deprecated": false }, @@ -7762,7 +8066,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 322 + "lineNumber": 337 }, "deprecated": false }, @@ -7810,7 +8114,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 323 + "lineNumber": 338 }, "deprecated": false }, @@ -7826,7 +8130,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 324 + "lineNumber": 339 }, "deprecated": false } @@ -9765,7 +10069,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/rest_spec/epm.ts", - "lineNumber": 18 + "lineNumber": 17 }, "deprecated": false, "children": [ @@ -9777,11 +10081,11 @@ "label": "query", "description": [], "signature": [ - "{ experimental?: boolean | undefined; }" + "{ experimental?: boolean | undefined; include_policy_templates?: boolean | undefined; }" ], "source": { "path": "x-pack/plugins/fleet/common/types/rest_spec/epm.ts", - "lineNumber": 19 + "lineNumber": 18 }, "deprecated": false } @@ -10910,18 +11214,10 @@ "pluginId": "fleet", "scope": "common", "docId": "kibFleetPluginApi", - "section": "def-common.Installable", - "text": "Installable" - }, - ">[]" + "[]" ], "source": { "path": "x-pack/plugins/fleet/common/types/rest_spec/epm.ts", @@ -11107,7 +11403,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 391 + "lineNumber": 409 }, "deprecated": false, "children": [ @@ -11120,7 +11416,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 392 + "lineNumber": 410 }, "deprecated": false }, @@ -11136,7 +11432,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 393 + "lineNumber": 411 }, "deprecated": false }, @@ -11152,7 +11448,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 394 + "lineNumber": 412 }, "deprecated": false }, @@ -11168,7 +11464,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 398 + "lineNumber": 416 }, "deprecated": false }, @@ -11184,7 +11480,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 399 + "lineNumber": 417 }, "deprecated": false }, @@ -11200,7 +11496,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 400 + "lineNumber": 418 }, "deprecated": false } @@ -11216,7 +11512,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 384 + "lineNumber": 402 }, "deprecated": false, "children": [ @@ -11232,7 +11528,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 385 + "lineNumber": 403 }, "deprecated": false } @@ -11259,7 +11555,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 339 + "lineNumber": 357 }, "deprecated": false, "children": [ @@ -11282,7 +11578,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 340 + "lineNumber": 358 }, "deprecated": false }, @@ -11305,7 +11601,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 341 + "lineNumber": 359 }, "deprecated": false }, @@ -11328,7 +11624,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 342 + "lineNumber": 360 }, "deprecated": false }, @@ -11344,7 +11640,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 343 + "lineNumber": 361 }, "deprecated": false }, @@ -11357,7 +11653,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 344 + "lineNumber": 362 }, "deprecated": false }, @@ -11370,7 +11666,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 345 + "lineNumber": 363 }, "deprecated": false }, @@ -11386,7 +11682,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 346 + "lineNumber": 364 }, "deprecated": false }, @@ -11399,7 +11695,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 347 + "lineNumber": 365 }, "deprecated": false }, @@ -11412,7 +11708,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 348 + "lineNumber": 366 }, "deprecated": false }, @@ -11428,7 +11724,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 349 + "lineNumber": 367 }, "deprecated": false } @@ -12327,7 +12623,31 @@ "lineNumber": 60 }, "deprecated": false - } + }, + { + "parentPluginId": "fleet", + "id": "def-common.NewPackagePolicy.vars", + "type": "Object", + "tags": [], + "label": "vars", + "description": [], + "signature": [ + "Record | undefined" + ], + "source": { + "path": "x-pack/plugins/fleet/common/types/models/package_policy.ts", + "lineNumber": 61 + }, + "deprecated": false + } ], "initialIsOpen": false }, @@ -12592,11 +12912,11 @@ "section": "def-common.NewPackagePolicy", "text": "NewPackagePolicy" }, - ", \"enabled\" | \"description\" | \"name\" | \"package\" | \"namespace\" | \"policy_id\" | \"output_id\">" + ", \"enabled\" | \"description\" | \"name\" | \"package\" | \"namespace\" | \"policy_id\" | \"output_id\" | \"vars\">" ], "source": { "path": "x-pack/plugins/fleet/common/types/models/package_policy.ts", - "lineNumber": 67 + "lineNumber": 68 }, "deprecated": false, "children": [ @@ -12609,7 +12929,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/package_policy.ts", - "lineNumber": 68 + "lineNumber": 69 }, "deprecated": false }, @@ -12632,7 +12952,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/package_policy.ts", - "lineNumber": 69 + "lineNumber": 70 }, "deprecated": false }, @@ -12648,7 +12968,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/package_policy.ts", - "lineNumber": 70 + "lineNumber": 71 }, "deprecated": false }, @@ -12661,7 +12981,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/package_policy.ts", - "lineNumber": 71 + "lineNumber": 72 }, "deprecated": false }, @@ -12674,7 +12994,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/package_policy.ts", - "lineNumber": 72 + "lineNumber": 73 }, "deprecated": false }, @@ -12687,7 +13007,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/package_policy.ts", - "lineNumber": 73 + "lineNumber": 74 }, "deprecated": false }, @@ -12700,7 +13020,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/package_policy.ts", - "lineNumber": 74 + "lineNumber": 75 }, "deprecated": false }, @@ -12713,7 +13033,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/package_policy.ts", - "lineNumber": 75 + "lineNumber": 76 }, "deprecated": false } @@ -12807,7 +13127,7 @@ "section": "def-common.NewPackagePolicyInput", "text": "NewPackagePolicyInput" }, - ", \"type\" | \"enabled\" | \"config\" | \"keep_enabled\" | \"vars\">" + ", \"type\" | \"enabled\" | \"config\" | \"vars\" | \"keep_enabled\">" ], "source": { "path": "x-pack/plugins/fleet/common/types/models/package_policy.ts", @@ -12983,7 +13303,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/package_spec.ts", - "lineNumber": 60 + "lineNumber": 61 }, "deprecated": false, "children": [ @@ -12996,7 +13316,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/package_spec.ts", - "lineNumber": 61 + "lineNumber": 62 }, "deprecated": false }, @@ -13012,7 +13332,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/package_spec.ts", - "lineNumber": 62 + "lineNumber": 63 }, "deprecated": false }, @@ -13028,7 +13348,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/package_spec.ts", - "lineNumber": 63 + "lineNumber": 64 }, "deprecated": false }, @@ -13044,7 +13364,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/package_spec.ts", - "lineNumber": 64 + "lineNumber": 65 }, "deprecated": false } @@ -13278,6 +13598,29 @@ }, "deprecated": false }, + { + "parentPluginId": "fleet", + "id": "def-common.PackageSpecManifest.vars", + "type": "Array", + "tags": [], + "label": "vars", + "description": [], + "signature": [ + { + "pluginId": "fleet", + "scope": "common", + "docId": "kibFleetPluginApi", + "section": "def-common.RegistryVarsEntry", + "text": "RegistryVarsEntry" + }, + "[] | undefined" + ], + "source": { + "path": "x-pack/plugins/fleet/common/types/models/package_spec.ts", + "lineNumber": 25 + }, + "deprecated": false + }, { "parentPluginId": "fleet", "id": "def-common.PackageSpecManifest.owner", @@ -13290,7 +13633,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/package_spec.ts", - "lineNumber": 25 + "lineNumber": 26 }, "deprecated": false } @@ -13306,7 +13649,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/package_spec.ts", - "lineNumber": 67 + "lineNumber": 68 }, "deprecated": false, "children": [ @@ -13319,7 +13662,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/package_spec.ts", - "lineNumber": 68 + "lineNumber": 69 }, "deprecated": false }, @@ -13332,7 +13675,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/package_spec.ts", - "lineNumber": 69 + "lineNumber": 70 }, "deprecated": false }, @@ -13348,7 +13691,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/package_spec.ts", - "lineNumber": 70 + "lineNumber": 71 }, "deprecated": false }, @@ -13364,7 +13707,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/package_spec.ts", - "lineNumber": 71 + "lineNumber": 72 }, "deprecated": false } @@ -13380,7 +13723,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 352 + "lineNumber": 370 }, "deprecated": false, "children": [ @@ -13393,7 +13736,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 353 + "lineNumber": 371 }, "deprecated": false } @@ -13987,7 +14330,7 @@ "section": "def-common.NewPackagePolicy", "text": "NewPackagePolicy" }, - ", \"enabled\" | \"description\" | \"name\" | \"namespace\" | \"policy_id\" | \"output_id\">> & { name: string; package: Partial<", + ", \"enabled\" | \"description\" | \"name\" | \"namespace\" | \"policy_id\" | \"output_id\" | \"vars\">> & { name: string; package: Partial<", { "pluginId": "fleet", "scope": "common", @@ -14243,7 +14586,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 266 + "lineNumber": 281 }, "deprecated": false, "children": [ @@ -14256,7 +14599,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 267 + "lineNumber": 282 }, "deprecated": false }, @@ -14272,7 +14615,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 268 + "lineNumber": 283 }, "deprecated": false }, @@ -14288,7 +14631,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 269 + "lineNumber": 284 }, "deprecated": false }, @@ -14301,7 +14644,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 270 + "lineNumber": 285 }, "deprecated": false }, @@ -14314,7 +14657,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 271 + "lineNumber": 286 }, "deprecated": false }, @@ -14327,7 +14670,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 272 + "lineNumber": 287 }, "deprecated": false }, @@ -14350,7 +14693,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 273 + "lineNumber": 288 }, "deprecated": false }, @@ -14363,7 +14706,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 274 + "lineNumber": 289 }, "deprecated": false }, @@ -14376,7 +14719,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 275 + "lineNumber": 290 }, "deprecated": false }, @@ -14387,9 +14730,12 @@ "tags": [], "label": "[RegistryDataStreamKeys.ingest_pipeline]", "description": [], + "signature": [ + "string | undefined" + ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 276 + "lineNumber": 291 }, "deprecated": false }, @@ -14412,7 +14758,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 277 + "lineNumber": 292 }, "deprecated": false }, @@ -14428,7 +14774,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 278 + "lineNumber": 293 }, "deprecated": false } @@ -14444,7 +14790,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 281 + "lineNumber": 296 }, "deprecated": false, "children": [ @@ -14460,7 +14806,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 282 + "lineNumber": 297 }, "deprecated": false }, @@ -14476,7 +14822,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 283 + "lineNumber": 298 }, "deprecated": false } @@ -14490,25 +14836,29 @@ "tags": [], "label": "RegistryImage", "description": [], + "signature": [ + { + "pluginId": "fleet", + "scope": "common", + "docId": "kibFleetPluginApi", + "section": "def-common.RegistryImage", + "text": "RegistryImage" + }, + " extends ", + { + "pluginId": "fleet", + "scope": "common", + "docId": "kibFleetPluginApi", + "section": "def-common.PackageSpecIcon", + "text": "PackageSpecIcon" + } + ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 121 + "lineNumber": 126 }, "deprecated": false, "children": [ - { - "parentPluginId": "fleet", - "id": "def-common.RegistryImage.src", - "type": "string", - "tags": [], - "label": "src", - "description": [], - "source": { - "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 122 - }, - "deprecated": false - }, { "parentPluginId": "fleet", "id": "def-common.RegistryImage.path", @@ -14518,55 +14868,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 123 - }, - "deprecated": false - }, - { - "parentPluginId": "fleet", - "id": "def-common.RegistryImage.title", - "type": "string", - "tags": [], - "label": "title", - "description": [], - "signature": [ - "string | undefined" - ], - "source": { - "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 124 - }, - "deprecated": false - }, - { - "parentPluginId": "fleet", - "id": "def-common.RegistryImage.size", - "type": "string", - "tags": [], - "label": "size", - "description": [], - "signature": [ - "string | undefined" - ], - "source": { - "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 125 - }, - "deprecated": false - }, - { - "parentPluginId": "fleet", - "id": "def-common.RegistryImage.type", - "type": "string", - "tags": [], - "label": "type", - "description": [], - "signature": [ - "string | undefined" - ], - "source": { - "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 126 + "lineNumber": 127 }, "deprecated": false } @@ -14582,7 +14884,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 154 + "lineNumber": 168 }, "deprecated": false, "children": [ @@ -14595,7 +14897,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 155 + "lineNumber": 169 }, "deprecated": false }, @@ -14608,7 +14910,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 156 + "lineNumber": 170 }, "deprecated": false }, @@ -14621,7 +14923,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 157 + "lineNumber": 171 }, "deprecated": false }, @@ -14637,7 +14939,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 158 + "lineNumber": 172 }, "deprecated": false }, @@ -14653,7 +14955,23 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 159 + "lineNumber": 173 + }, + "deprecated": false + }, + { + "parentPluginId": "fleet", + "id": "def-common.RegistryInput.RegistryInputKeys.input_group", + "type": "CompoundType", + "tags": [], + "label": "[RegistryInputKeys.input_group]", + "description": [], + "signature": [ + "\"metrics\" | \"logs\" | undefined" + ], + "source": { + "path": "x-pack/plugins/fleet/common/types/models/epm.ts", + "lineNumber": 174 }, "deprecated": false }, @@ -14676,7 +14994,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 160 + "lineNumber": 175 }, "deprecated": false } @@ -14692,7 +15010,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 137 + "lineNumber": 143 }, "deprecated": false, "children": [ @@ -14705,7 +15023,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 138 + "lineNumber": 144 }, "deprecated": false }, @@ -14718,7 +15036,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 139 + "lineNumber": 145 }, "deprecated": false }, @@ -14731,7 +15049,85 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 140 + "lineNumber": 146 + }, + "deprecated": false + }, + { + "parentPluginId": "fleet", + "id": "def-common.RegistryPolicyTemplate.RegistryPolicyTemplateKeys.icons", + "type": "Array", + "tags": [], + "label": "[RegistryPolicyTemplateKeys.icons]", + "description": [], + "signature": [ + { + "pluginId": "fleet", + "scope": "common", + "docId": "kibFleetPluginApi", + "section": "def-common.RegistryImage", + "text": "RegistryImage" + }, + "[] | undefined" + ], + "source": { + "path": "x-pack/plugins/fleet/common/types/models/epm.ts", + "lineNumber": 147 + }, + "deprecated": false + }, + { + "parentPluginId": "fleet", + "id": "def-common.RegistryPolicyTemplate.RegistryPolicyTemplateKeys.screenshots", + "type": "Array", + "tags": [], + "label": "[RegistryPolicyTemplateKeys.screenshots]", + "description": [], + "signature": [ + { + "pluginId": "fleet", + "scope": "common", + "docId": "kibFleetPluginApi", + "section": "def-common.RegistryImage", + "text": "RegistryImage" + }, + "[] | undefined" + ], + "source": { + "path": "x-pack/plugins/fleet/common/types/models/epm.ts", + "lineNumber": 148 + }, + "deprecated": false + }, + { + "parentPluginId": "fleet", + "id": "def-common.RegistryPolicyTemplate.RegistryPolicyTemplateKeys.categories", + "type": "Array", + "tags": [], + "label": "[RegistryPolicyTemplateKeys.categories]", + "description": [], + "signature": [ + "(\"custom\" | \"security\" | \"monitoring\" | \"cloud\" | \"kubernetes\" | \"aws\" | \"azure\" | \"config_management\" | \"containers\" | \"crm\" | \"datastore\" | \"elastic_stack\" | \"google_cloud\" | \"languages\" | \"message_queue\" | \"network\" | \"notification\" | \"os_system\" | \"productivity\" | \"support\" | \"ticketing\" | \"version_control\" | \"web\" | undefined)[] | undefined" + ], + "source": { + "path": "x-pack/plugins/fleet/common/types/models/epm.ts", + "lineNumber": 149 + }, + "deprecated": false + }, + { + "parentPluginId": "fleet", + "id": "def-common.RegistryPolicyTemplate.RegistryPolicyTemplateKeys.data_streams", + "type": "Array", + "tags": [], + "label": "[RegistryPolicyTemplateKeys.data_streams]", + "description": [], + "signature": [ + "string[] | undefined" + ], + "source": { + "path": "x-pack/plugins/fleet/common/types/models/epm.ts", + "lineNumber": 150 }, "deprecated": false }, @@ -14754,7 +15150,23 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 141 + "lineNumber": 151 + }, + "deprecated": false + }, + { + "parentPluginId": "fleet", + "id": "def-common.RegistryPolicyTemplate.RegistryPolicyTemplateKeys.readme", + "type": "string", + "tags": [], + "label": "[RegistryPolicyTemplateKeys.readme]", + "description": [], + "signature": [ + "string | undefined" + ], + "source": { + "path": "x-pack/plugins/fleet/common/types/models/epm.ts", + "lineNumber": 152 }, "deprecated": false }, @@ -14770,7 +15182,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 142 + "lineNumber": 153 }, "deprecated": false } @@ -14786,7 +15198,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 172 + "lineNumber": 187 }, "deprecated": false, "children": [ @@ -14799,7 +15211,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 173 + "lineNumber": 188 }, "deprecated": false }, @@ -14812,7 +15224,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 174 + "lineNumber": 189 }, "deprecated": false }, @@ -14828,7 +15240,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 175 + "lineNumber": 190 }, "deprecated": false }, @@ -14844,7 +15256,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 176 + "lineNumber": 191 }, "deprecated": false }, @@ -14867,7 +15279,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 177 + "lineNumber": 192 }, "deprecated": false }, @@ -14880,7 +15292,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 178 + "lineNumber": 193 }, "deprecated": false } @@ -14896,7 +15308,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 302 + "lineNumber": 317 }, "deprecated": false, "children": [ @@ -14909,7 +15321,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 303 + "lineNumber": 318 }, "deprecated": false }, @@ -14925,7 +15337,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 304 + "lineNumber": 319 }, "deprecated": false }, @@ -14941,7 +15353,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 305 + "lineNumber": 320 }, "deprecated": false }, @@ -14957,7 +15369,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 306 + "lineNumber": 321 }, "deprecated": false }, @@ -14973,7 +15385,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 307 + "lineNumber": 322 }, "deprecated": false }, @@ -14989,7 +15401,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 308 + "lineNumber": 323 }, "deprecated": false }, @@ -15005,7 +15417,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 309 + "lineNumber": 324 }, "deprecated": false }, @@ -15017,11 +15429,11 @@ "label": "[RegistryVarsEntryKeys.default]", "description": [], "signature": [ - "string | string[] | undefined" + "string | boolean | string[] | undefined" ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 310 + "lineNumber": 325 }, "deprecated": false }, @@ -15037,7 +15449,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 311 + "lineNumber": 326 }, "deprecated": false } @@ -15053,7 +15465,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 183 + "lineNumber": 198 }, "deprecated": false, "children": [ @@ -15066,7 +15478,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 184 + "lineNumber": 199 }, "deprecated": false } @@ -15162,7 +15574,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 403 + "lineNumber": 421 }, "deprecated": false, "children": [ @@ -15175,7 +15587,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 404 + "lineNumber": 422 }, "deprecated": false }, @@ -15197,7 +15609,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 405 + "lineNumber": 423 }, "deprecated": false } @@ -15316,7 +15728,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/package_policy.ts", - "lineNumber": 63 + "lineNumber": 64 }, "deprecated": false, "children": [ @@ -15332,7 +15744,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/package_policy.ts", - "lineNumber": 64 + "lineNumber": 65 }, "deprecated": false } @@ -15350,7 +15762,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 76 + "lineNumber": 81 }, "deprecated": false, "initialIsOpen": false @@ -15364,7 +15776,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 26 + "lineNumber": 31 }, "deprecated": false, "initialIsOpen": false @@ -15378,7 +15790,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 51 + "lineNumber": 56 }, "deprecated": false, "initialIsOpen": false @@ -15392,7 +15804,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 65 + "lineNumber": 70 }, "deprecated": false, "initialIsOpen": false @@ -15406,7 +15818,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 251 + "lineNumber": 266 }, "deprecated": false, "initialIsOpen": false @@ -15420,7 +15832,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 145 + "lineNumber": 156 }, "deprecated": false, "initialIsOpen": false @@ -15434,7 +15846,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 129 + "lineNumber": 130 }, "deprecated": false, "initialIsOpen": false @@ -15448,7 +15860,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 163 + "lineNumber": 178 }, "deprecated": false, "initialIsOpen": false @@ -15462,7 +15874,7 @@ "description": [], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 287 + "lineNumber": 302 }, "deprecated": false, "initialIsOpen": false @@ -15801,7 +16213,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 45 + "lineNumber": 50 }, "deprecated": false, "initialIsOpen": false @@ -16001,7 +16413,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 89 + "lineNumber": 94 }, "deprecated": false, "initialIsOpen": false @@ -16032,7 +16444,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 367 + "lineNumber": 385 }, "deprecated": false, "initialIsOpen": false @@ -16098,7 +16510,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 229 + "lineNumber": 244 }, "deprecated": false, "initialIsOpen": false @@ -16130,7 +16542,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 46 + "lineNumber": 51 }, "deprecated": false, "initialIsOpen": false @@ -16179,7 +16591,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 228 + "lineNumber": 243 }, "deprecated": false, "initialIsOpen": false @@ -16227,7 +16639,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 213 + "lineNumber": 228 }, "deprecated": false, "initialIsOpen": false @@ -16251,7 +16663,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 212 + "lineNumber": 227 }, "deprecated": false, "initialIsOpen": false @@ -16282,7 +16694,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 85 + "lineNumber": 90 }, "deprecated": false, "initialIsOpen": false @@ -16316,7 +16728,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 382 + "lineNumber": 400 }, "deprecated": false, "initialIsOpen": false @@ -16350,7 +16762,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 43 + "lineNumber": 48 }, "deprecated": false, "initialIsOpen": false @@ -16382,7 +16794,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 240 + "lineNumber": 255 }, "deprecated": false, "initialIsOpen": false @@ -16447,7 +16859,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 246 + "lineNumber": 261 }, "deprecated": false, "initialIsOpen": false @@ -16529,7 +16941,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 41 + "lineNumber": 46 }, "deprecated": false, "initialIsOpen": false @@ -16556,7 +16968,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 372 + "lineNumber": 390 }, "deprecated": false, "initialIsOpen": false @@ -16778,7 +17190,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 356 + "lineNumber": 374 }, "deprecated": false, "initialIsOpen": false @@ -16809,7 +17221,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 87 + "lineNumber": 92 }, "deprecated": false, "initialIsOpen": false @@ -16826,7 +17238,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 24 + "lineNumber": 29 }, "deprecated": false, "initialIsOpen": false @@ -16853,7 +17265,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 358 + "lineNumber": 376 }, "deprecated": false, "initialIsOpen": false @@ -16870,7 +17282,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 39 + "lineNumber": 44 }, "deprecated": false, "initialIsOpen": false @@ -16887,7 +17299,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 38 + "lineNumber": 43 }, "deprecated": false, "initialIsOpen": false @@ -16919,7 +17331,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 235 + "lineNumber": 250 }, "deprecated": false, "initialIsOpen": false @@ -16946,7 +17358,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 369 + "lineNumber": 387 }, "deprecated": false, "initialIsOpen": false @@ -17027,7 +17439,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 245 + "lineNumber": 260 }, "deprecated": false, "initialIsOpen": false @@ -17078,7 +17490,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 363 + "lineNumber": 381 }, "deprecated": false, "initialIsOpen": false @@ -17209,7 +17621,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 376 + "lineNumber": 394 }, "deprecated": false, "initialIsOpen": false @@ -17321,7 +17733,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 335 + "lineNumber": 353 }, "deprecated": false, "initialIsOpen": false @@ -17338,22 +17750,14 @@ "pluginId": "fleet", "scope": "common", "docId": "kibFleetPluginApi", - "section": "def-common.Installable", - "text": "Installable" - }, - ">[]" + "[]" ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 331 + "lineNumber": 346 }, "deprecated": false, "initialIsOpen": false @@ -17366,14 +17770,7 @@ "label": "PackageListItem", "description": [], "signature": [ - { - "pluginId": "fleet", - "scope": "common", - "docId": "kibFleetPluginApi", - "section": "def-common.Installed", - "text": "Installed" - }, - "> | ", + ", \"type\" | \"description\" | \"title\" | \"name\" | \"version\" | \"download\" | \"path\" | \"internal\" | \"data_streams\" | \"release\" | \"icons\" | \"policy_templates\"> & { status: \"installed\"; savedObject: ", + "SavedObject", + "<", { "pluginId": "fleet", "scope": "common", "docId": "kibFleetPluginApi", - "section": "def-common.NotInstalled", - "text": "NotInstalled" + "section": "def-common.Installation", + "text": "Installation" }, - "; } & { integration?: string | undefined; id: string; }) | (Pick<", { "pluginId": "fleet", "scope": "common", @@ -17397,11 +17796,11 @@ "section": "def-common.RegistryPackage", "text": "RegistryPackage" }, - ", \"type\" | \"description\" | \"title\" | \"name\" | \"version\" | \"download\" | \"path\" | \"internal\" | \"data_streams\" | \"release\" | \"icons\" | \"policy_templates\">>" + ", \"type\" | \"description\" | \"title\" | \"name\" | \"version\" | \"download\" | \"path\" | \"internal\" | \"data_streams\" | \"release\" | \"icons\" | \"policy_templates\"> & { status: \"not_installed\"; } & { integration?: string | undefined; id: string; })" ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 333 + "lineNumber": 347 }, "deprecated": false, "initialIsOpen": false @@ -17455,11 +17854,19 @@ "section": "def-common.PackagePolicyInput", "text": "PackagePolicyInput" }, - "[]; policy_id: string; output_id: string; revision: number; }" + "[]; policy_id: string; output_id: string; vars?: Record | undefined; revision: number; }" ], "source": { "path": "x-pack/plugins/fleet/common/types/models/package_policy.ts", - "lineNumber": 78 + "lineNumber": 79 }, "deprecated": false, "initialIsOpen": false @@ -17509,7 +17916,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 334 + "lineNumber": 352 }, "deprecated": false, "initialIsOpen": false @@ -17526,7 +17933,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/package_spec.ts", - "lineNumber": 28 + "lineNumber": 29 }, "deprecated": false, "initialIsOpen": false @@ -17543,7 +17950,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/package_spec.ts", - "lineNumber": 53 + "lineNumber": 54 }, "deprecated": false, "initialIsOpen": false @@ -17667,6 +18074,23 @@ "deprecated": false, "initialIsOpen": false }, + { + "parentPluginId": "fleet", + "id": "def-common.RegistryInputGroup", + "type": "Type", + "tags": [], + "label": "RegistryInputGroup", + "description": [], + "signature": [ + "\"metrics\" | \"logs\"" + ], + "source": { + "path": "x-pack/plugins/fleet/common/types/models/epm.ts", + "lineNumber": 166 + }, + "deprecated": false, + "initialIsOpen": false + }, { "parentPluginId": "fleet", "id": "def-common.RegistryPackage", @@ -17694,7 +18118,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 93 + "lineNumber": 98 }, "deprecated": false, "initialIsOpen": false @@ -17711,7 +18135,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 120 + "lineNumber": 125 }, "deprecated": false, "initialIsOpen": false @@ -17760,7 +18184,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 192 + "lineNumber": 207 }, "deprecated": false, "initialIsOpen": false @@ -17785,7 +18209,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 190 + "lineNumber": 205 }, "deprecated": false, "initialIsOpen": false @@ -17802,7 +18226,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 286 + "lineNumber": 301 }, "deprecated": false, "initialIsOpen": false @@ -17836,7 +18260,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 380 + "lineNumber": 398 }, "deprecated": false, "initialIsOpen": false @@ -17853,7 +18277,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 220 + "lineNumber": 235 }, "deprecated": false, "initialIsOpen": false @@ -17870,7 +18294,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 181 + "lineNumber": 196 }, "deprecated": false, "initialIsOpen": false @@ -17887,7 +18311,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 182 + "lineNumber": 197 }, "deprecated": false, "initialIsOpen": false @@ -17918,7 +18342,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 208 + "lineNumber": 223 }, "deprecated": false, "initialIsOpen": false @@ -17935,7 +18359,7 @@ ], "source": { "path": "x-pack/plugins/fleet/common/types/models/epm.ts", - "lineNumber": 44 + "lineNumber": 49 }, "deprecated": false, "initialIsOpen": false diff --git a/api_docs/home.json b/api_docs/home.json index 2aa23c1b756df..a1039beb8d3a2 100644 --- a/api_docs/home.json +++ b/api_docs/home.json @@ -1070,7 +1070,7 @@ }, ") => void; getSampleDatasets: () => ", "Writable", - "[]; previewImagePath: string; overviewDashboard: string; appLinks: Readonly<{} & { label: string; path: string; icon: string; }>[]; dataIndices: Readonly<{} & { id: string; fields: Record; timeFields: string[]; dataPath: string; currentTimeMarker: string; preserveDayOfWeekTimeOfDay: boolean; }>[]; }>>[]; addSavedObjectsToSampleDataset: (id: string, savedObjects: ", + "[]; previewImagePath: string; overviewDashboard: string; appLinks: Readonly<{} & { label: string; path: string; icon: string; }>[]; defaultIndex: string; dataIndices: Readonly<{} & { id: string; fields: Record; timeFields: string[]; dataPath: string; currentTimeMarker: string; preserveDayOfWeekTimeOfDay: boolean; }>[]; }>>[]; addSavedObjectsToSampleDataset: (id: string, savedObjects: ", "SavedObject", "[]) => void; addAppLinksToSampleDataset: (id: string, appLinks: Readonly<{} & { label: string; path: string; icon: string; }>[]) => void; replacePanelInSampleDatasetDashboard: ({ sampleDataId, dashboardId, oldEmbeddableId, embeddableId, embeddableType, embeddableConfig, }: ", "SampleDatasetDashboardPanel", @@ -1093,7 +1093,7 @@ "signature": [ "() => ", "Writable", - "[]; previewImagePath: string; overviewDashboard: string; appLinks: Readonly<{} & { label: string; path: string; icon: string; }>[]; dataIndices: Readonly<{} & { id: string; fields: Record; timeFields: string[]; dataPath: string; currentTimeMarker: string; preserveDayOfWeekTimeOfDay: boolean; }>[]; }>>" + "[]; previewImagePath: string; overviewDashboard: string; appLinks: Readonly<{} & { label: string; path: string; icon: string; }>[]; defaultIndex: string; dataIndices: Readonly<{} & { id: string; fields: Record; timeFields: string[]; dataPath: string; currentTimeMarker: string; preserveDayOfWeekTimeOfDay: boolean; }>[]; }>>" ], "source": { "path": "src/plugins/home/server/services/sample_data/lib/sample_dataset_registry_types.ts", @@ -1426,7 +1426,7 @@ }, ") => void; getSampleDatasets: () => ", "Writable", - "[]; previewImagePath: string; overviewDashboard: string; appLinks: Readonly<{} & { label: string; path: string; icon: string; }>[]; dataIndices: Readonly<{} & { id: string; fields: Record; timeFields: string[]; dataPath: string; currentTimeMarker: string; preserveDayOfWeekTimeOfDay: boolean; }>[]; }>>[]; addSavedObjectsToSampleDataset: (id: string, savedObjects: ", + "[]; previewImagePath: string; overviewDashboard: string; appLinks: Readonly<{} & { label: string; path: string; icon: string; }>[]; defaultIndex: string; dataIndices: Readonly<{} & { id: string; fields: Record; timeFields: string[]; dataPath: string; currentTimeMarker: string; preserveDayOfWeekTimeOfDay: boolean; }>[]; }>>[]; addSavedObjectsToSampleDataset: (id: string, savedObjects: ", "SavedObject", "[]) => void; addAppLinksToSampleDataset: (id: string, appLinks: Readonly<{} & { label: string; path: string; icon: string; }>[]) => void; replacePanelInSampleDatasetDashboard: ({ sampleDataId, dashboardId, oldEmbeddableId, embeddableId, embeddableType, embeddableConfig, }: ", "SampleDatasetDashboardPanel", diff --git a/api_docs/kibana_react.json b/api_docs/kibana_react.json index 9e144147e6919..98537d71d7b01 100644 --- a/api_docs/kibana_react.json +++ b/api_docs/kibana_react.json @@ -1055,7 +1055,7 @@ "label": "KibanaPageTemplate", "description": [], "signature": [ - "({ template, pageHeader, children, isEmptyState, restrictWidth, bottomBar, bottomBarProps, ...rest }: React.PropsWithChildren<", + "({ template, pageHeader, children, isEmptyState, restrictWidth, bottomBar, bottomBarProps, pageSideBar, solutionNav, ...rest }: React.PropsWithChildren<", { "pluginId": "kibanaReact", "scope": "public", @@ -1067,7 +1067,7 @@ ], "source": { "path": "src/plugins/kibana_react/public/page_template/page_template.tsx", - "lineNumber": 22 + "lineNumber": 37 }, "deprecated": false, "children": [ @@ -1076,7 +1076,7 @@ "id": "def-public.KibanaPageTemplate.$1", "type": "CompoundType", "tags": [], - "label": "{\n template,\n pageHeader,\n children,\n isEmptyState,\n restrictWidth = true,\n bottomBar,\n bottomBarProps,\n ...rest\n}", + "label": "{\n template,\n pageHeader,\n children,\n isEmptyState,\n restrictWidth = true,\n bottomBar,\n bottomBarProps,\n pageSideBar,\n solutionNav,\n ...rest\n}", "description": [], "signature": [ "React.PropsWithChildren<", @@ -1091,7 +1091,7 @@ ], "source": { "path": "src/plugins/kibana_react/public/page_template/page_template.tsx", - "lineNumber": 22 + "lineNumber": 37 }, "deprecated": false, "isRequired": true @@ -1581,7 +1581,9 @@ "type": "CompoundType", "tags": [], "label": "ReactComp", - "description": [], + "description": [ + "A React component." + ], "signature": [ "React.ComponentType" ], @@ -1667,7 +1669,9 @@ "type": "CompoundType", "tags": [], "label": "node", - "description": [], + "description": [ + "to get a mount point for" + ], "signature": [ "React.ReactNode" ], @@ -3936,7 +3940,9 @@ "type": "Type", "tags": [], "label": "KibanaPageTemplateProps", - "description": [], + "description": [ + "\nA thin wrapper around EuiPageTemplate with a few Kibana specific additions" + ], "signature": [ "(Pick<", "EuiPageProps", @@ -3960,7 +3966,9 @@ "EuiPageContentProps", " | undefined; pageContentBodyProps?: ", "EuiPageContentBodyProps", - " | undefined; } & { isEmptyState?: boolean | undefined; }) | (Pick<", + " | undefined; } & { isEmptyState?: boolean | undefined; solutionNav?: ", + "KibanaPageTemplateSolutionNavProps", + " | undefined; }) | (Pick<", "EuiPageProps", ", \"children\" | \"onClick\" | \"onChange\" | \"color\" | \"onKeyDown\" | \"title\" | \"id\" | \"defaultChecked\" | \"defaultValue\" | \"suppressContentEditableWarning\" | \"suppressHydrationWarning\" | \"accessKey\" | \"className\" | \"contentEditable\" | \"contextMenu\" | \"dir\" | \"draggable\" | \"hidden\" | \"lang\" | \"placeholder\" | \"slot\" | \"spellCheck\" | \"style\" | \"tabIndex\" | \"translate\" | \"radioGroup\" | \"role\" | \"about\" | \"datatype\" | \"inlist\" | \"prefix\" | \"property\" | \"resource\" | \"typeof\" | \"vocab\" | \"autoCapitalize\" | \"autoCorrect\" | \"autoSave\" | \"itemProp\" | \"itemScope\" | \"itemType\" | \"itemID\" | \"itemRef\" | \"results\" | \"security\" | \"unselectable\" | \"inputMode\" | \"is\" | \"aria-activedescendant\" | \"aria-atomic\" | \"aria-autocomplete\" | \"aria-busy\" | \"aria-checked\" | \"aria-colcount\" | \"aria-colindex\" | \"aria-colspan\" | \"aria-controls\" | \"aria-current\" | \"aria-describedby\" | \"aria-details\" | \"aria-disabled\" | \"aria-dropeffect\" | \"aria-errormessage\" | \"aria-expanded\" | \"aria-flowto\" | \"aria-grabbed\" | \"aria-haspopup\" | \"aria-hidden\" | \"aria-invalid\" | \"aria-keyshortcuts\" | \"aria-label\" | \"aria-labelledby\" | \"aria-level\" | \"aria-live\" | \"aria-modal\" | \"aria-multiline\" | \"aria-multiselectable\" | \"aria-orientation\" | \"aria-owns\" | \"aria-placeholder\" | \"aria-posinset\" | \"aria-pressed\" | \"aria-readonly\" | \"aria-relevant\" | \"aria-required\" | \"aria-roledescription\" | \"aria-rowcount\" | \"aria-rowindex\" | \"aria-rowspan\" | \"aria-selected\" | \"aria-setsize\" | \"aria-sort\" | \"aria-valuemax\" | \"aria-valuemin\" | \"aria-valuenow\" | \"aria-valuetext\" | \"dangerouslySetInnerHTML\" | \"onCopy\" | \"onCopyCapture\" | \"onCut\" | \"onCutCapture\" | \"onPaste\" | \"onPasteCapture\" | \"onCompositionEnd\" | \"onCompositionEndCapture\" | \"onCompositionStart\" | \"onCompositionStartCapture\" | \"onCompositionUpdate\" | \"onCompositionUpdateCapture\" | \"onFocus\" | \"onFocusCapture\" | \"onBlur\" | \"onBlurCapture\" | \"onChangeCapture\" | \"onBeforeInput\" | \"onBeforeInputCapture\" | \"onInput\" | \"onInputCapture\" | \"onReset\" | \"onResetCapture\" | \"onSubmit\" | \"onSubmitCapture\" | \"onInvalid\" | \"onInvalidCapture\" | \"onLoad\" | \"onLoadCapture\" | \"onError\" | \"onErrorCapture\" | \"onKeyDownCapture\" | \"onKeyPress\" | \"onKeyPressCapture\" | \"onKeyUp\" | \"onKeyUpCapture\" | \"onAbort\" | \"onAbortCapture\" | \"onCanPlay\" | \"onCanPlayCapture\" | \"onCanPlayThrough\" | \"onCanPlayThroughCapture\" | \"onDurationChange\" | \"onDurationChangeCapture\" | \"onEmptied\" | \"onEmptiedCapture\" | \"onEncrypted\" | \"onEncryptedCapture\" | \"onEnded\" | \"onEndedCapture\" | \"onLoadedData\" | \"onLoadedDataCapture\" | \"onLoadedMetadata\" | \"onLoadedMetadataCapture\" | \"onLoadStart\" | \"onLoadStartCapture\" | \"onPause\" | \"onPauseCapture\" | \"onPlay\" | \"onPlayCapture\" | \"onPlaying\" | \"onPlayingCapture\" | \"onProgress\" | \"onProgressCapture\" | \"onRateChange\" | \"onRateChangeCapture\" | \"onSeeked\" | \"onSeekedCapture\" | \"onSeeking\" | \"onSeekingCapture\" | \"onStalled\" | \"onStalledCapture\" | \"onSuspend\" | \"onSuspendCapture\" | \"onTimeUpdate\" | \"onTimeUpdateCapture\" | \"onVolumeChange\" | \"onVolumeChangeCapture\" | \"onWaiting\" | \"onWaitingCapture\" | \"onAuxClick\" | \"onAuxClickCapture\" | \"onClickCapture\" | \"onContextMenu\" | \"onContextMenuCapture\" | \"onDoubleClick\" | \"onDoubleClickCapture\" | \"onDrag\" | \"onDragCapture\" | \"onDragEnd\" | \"onDragEndCapture\" | \"onDragEnter\" | \"onDragEnterCapture\" | \"onDragExit\" | \"onDragExitCapture\" | \"onDragLeave\" | \"onDragLeaveCapture\" | \"onDragOver\" | \"onDragOverCapture\" | \"onDragStart\" | \"onDragStartCapture\" | \"onDrop\" | \"onDropCapture\" | \"onMouseDown\" | \"onMouseDownCapture\" | \"onMouseEnter\" | \"onMouseLeave\" | \"onMouseMove\" | \"onMouseMoveCapture\" | \"onMouseOut\" | \"onMouseOutCapture\" | \"onMouseOver\" | \"onMouseOverCapture\" | \"onMouseUp\" | \"onMouseUpCapture\" | \"onSelect\" | \"onSelectCapture\" | \"onTouchCancel\" | \"onTouchCancelCapture\" | \"onTouchEnd\" | \"onTouchEndCapture\" | \"onTouchMove\" | \"onTouchMoveCapture\" | \"onTouchStart\" | \"onTouchStartCapture\" | \"onPointerDown\" | \"onPointerDownCapture\" | \"onPointerMove\" | \"onPointerMoveCapture\" | \"onPointerUp\" | \"onPointerUpCapture\" | \"onPointerCancel\" | \"onPointerCancelCapture\" | \"onPointerEnter\" | \"onPointerEnterCapture\" | \"onPointerLeave\" | \"onPointerLeaveCapture\" | \"onPointerOver\" | \"onPointerOverCapture\" | \"onPointerOut\" | \"onPointerOutCapture\" | \"onGotPointerCapture\" | \"onGotPointerCaptureCapture\" | \"onLostPointerCapture\" | \"onLostPointerCaptureCapture\" | \"onScroll\" | \"onScrollCapture\" | \"onWheel\" | \"onWheelCapture\" | \"onAnimationStart\" | \"onAnimationStartCapture\" | \"onAnimationEnd\" | \"onAnimationEndCapture\" | \"onAnimationIteration\" | \"onAnimationIterationCapture\" | \"onTransitionEnd\" | \"onTransitionEndCapture\" | \"css\" | \"data-test-subj\" | \"grow\" | \"direction\" | \"restrictWidth\"> & ", "DisambiguateSet", @@ -3990,11 +3998,13 @@ "EuiPageContentProps", " | undefined; pageContentBodyProps?: ", "EuiPageContentBodyProps", - " | undefined; } & { isEmptyState?: boolean | undefined; })" + " | undefined; } & { isEmptyState?: boolean | undefined; solutionNav?: ", + "KibanaPageTemplateSolutionNavProps", + " | undefined; })" ], "source": { "path": "src/plugins/kibana_react/public/page_template/page_template.tsx", - "lineNumber": 12 + "lineNumber": 23 }, "deprecated": false, "initialIsOpen": false diff --git a/api_docs/kibana_utils.json b/api_docs/kibana_utils.json index 173348ea2f263..66eefa9097bfb 100644 --- a/api_docs/kibana_utils.json +++ b/api_docs/kibana_utils.json @@ -2551,7 +2551,9 @@ "type": "Object", "tags": [], "label": "storage", - "description": [], + "description": [ + "- Option {@link Storage} to use for storing state. By default window.sessionStorage." + ], "signature": [ "Storage" ], @@ -2616,7 +2618,9 @@ "type": "Function", "tags": [], "label": "accessor", - "description": [], + "description": [ + "Asynchronous start service accessor provided by platform." + ], "signature": [ { "pluginId": "core", @@ -3623,7 +3627,9 @@ "type": "Object", "tags": [], "label": "promise", - "description": [], + "description": [ + "Promise to convert to 3-tuple." + ], "signature": [ "Promise" ], @@ -4687,7 +4693,9 @@ "type": "Uncategorized", "tags": [], "label": "container", - "description": [], + "description": [ + "- {@link StateContainer} which state to track." + ], "signature": [ "Container" ], @@ -4704,7 +4712,9 @@ "type": "Function", "tags": [], "label": "selector", - "description": [], + "description": [ + "- Function used to pick parts of state." + ], "signature": [ "(state: ", { @@ -4729,7 +4739,9 @@ "type": "Function", "tags": [], "label": "comparator", - "description": [], + "description": [ + "- {@link Comparator} function used to memoize previous result, to not\nre-render React component if state did not change. By default uses\n`fast-deep-equal` package." + ], "signature": [ { "pluginId": "kibanaUtils", @@ -4793,7 +4805,9 @@ "type": "Uncategorized", "tags": [], "label": "container", - "description": [], + "description": [ + "- {@link StateContainer} which state to track." + ], "signature": [ "Container" ], @@ -10006,7 +10020,9 @@ "type": "Object", "tags": [], "label": "promise", - "description": [], + "description": [ + "Promise to convert to 3-tuple." + ], "signature": [ "Promise" ], @@ -10069,7 +10085,9 @@ "type": "Uncategorized", "tags": [], "label": "container", - "description": [], + "description": [ + "- {@link StateContainer} which state to track." + ], "signature": [ "Container" ], @@ -10086,7 +10104,9 @@ "type": "Function", "tags": [], "label": "selector", - "description": [], + "description": [ + "- Function used to pick parts of state." + ], "signature": [ "(state: ", { @@ -10111,7 +10131,9 @@ "type": "Function", "tags": [], "label": "comparator", - "description": [], + "description": [ + "- {@link Comparator} function used to memoize previous result, to not\nre-render React component if state did not change. By default uses\n`fast-deep-equal` package." + ], "signature": [ { "pluginId": "kibanaUtils", @@ -10175,7 +10197,9 @@ "type": "Uncategorized", "tags": [], "label": "container", - "description": [], + "description": [ + "- {@link StateContainer} which state to track." + ], "signature": [ "Container" ], diff --git a/api_docs/lens.json b/api_docs/lens.json index f81dbe4217f28..196361f65682b 100644 --- a/api_docs/lens.json +++ b/api_docs/lens.json @@ -1353,7 +1353,7 @@ "description": [], "source": { "path": "x-pack/plugins/lens/public/xy_visualization/types.ts", - "lineNumber": 473 + "lineNumber": 474 }, "deprecated": false, "children": [ @@ -1369,7 +1369,7 @@ ], "source": { "path": "x-pack/plugins/lens/public/xy_visualization/types.ts", - "lineNumber": 474 + "lineNumber": 475 }, "deprecated": false }, @@ -1391,7 +1391,7 @@ ], "source": { "path": "x-pack/plugins/lens/public/xy_visualization/types.ts", - "lineNumber": 475 + "lineNumber": 476 }, "deprecated": false }, @@ -1407,7 +1407,7 @@ ], "source": { "path": "x-pack/plugins/lens/public/xy_visualization/types.ts", - "lineNumber": 476 + "lineNumber": 477 }, "deprecated": false }, @@ -1423,7 +1423,7 @@ ], "source": { "path": "x-pack/plugins/lens/public/xy_visualization/types.ts", - "lineNumber": 477 + "lineNumber": 478 }, "deprecated": false }, @@ -1440,7 +1440,7 @@ ], "source": { "path": "x-pack/plugins/lens/public/xy_visualization/types.ts", - "lineNumber": 478 + "lineNumber": 479 }, "deprecated": false }, @@ -1457,7 +1457,7 @@ ], "source": { "path": "x-pack/plugins/lens/public/xy_visualization/types.ts", - "lineNumber": 479 + "lineNumber": 480 }, "deprecated": false }, @@ -1480,7 +1480,7 @@ ], "source": { "path": "x-pack/plugins/lens/public/xy_visualization/types.ts", - "lineNumber": 480 + "lineNumber": 481 }, "deprecated": false }, @@ -1496,7 +1496,7 @@ ], "source": { "path": "x-pack/plugins/lens/public/xy_visualization/types.ts", - "lineNumber": 481 + "lineNumber": 482 }, "deprecated": false }, @@ -1512,7 +1512,7 @@ ], "source": { "path": "x-pack/plugins/lens/public/xy_visualization/types.ts", - "lineNumber": 482 + "lineNumber": 483 }, "deprecated": false }, @@ -1528,7 +1528,7 @@ ], "source": { "path": "x-pack/plugins/lens/public/xy_visualization/types.ts", - "lineNumber": 483 + "lineNumber": 484 }, "deprecated": false }, @@ -1551,7 +1551,7 @@ ], "source": { "path": "x-pack/plugins/lens/public/xy_visualization/types.ts", - "lineNumber": 484 + "lineNumber": 485 }, "deprecated": false }, @@ -1574,7 +1574,7 @@ ], "source": { "path": "x-pack/plugins/lens/public/xy_visualization/types.ts", - "lineNumber": 485 + "lineNumber": 486 }, "deprecated": false }, @@ -1597,7 +1597,7 @@ ], "source": { "path": "x-pack/plugins/lens/public/xy_visualization/types.ts", - "lineNumber": 486 + "lineNumber": 487 }, "deprecated": false }, @@ -1613,7 +1613,23 @@ ], "source": { "path": "x-pack/plugins/lens/public/xy_visualization/types.ts", - "lineNumber": 487 + "lineNumber": 488 + }, + "deprecated": false + }, + { + "parentPluginId": "lens", + "id": "def-public.XYState.fillOpacity", + "type": "number", + "tags": [], + "label": "fillOpacity", + "description": [], + "signature": [ + "number | undefined" + ], + "source": { + "path": "x-pack/plugins/lens/public/xy_visualization/types.ts", + "lineNumber": 489 }, "deprecated": false }, @@ -1629,7 +1645,7 @@ ], "source": { "path": "x-pack/plugins/lens/public/xy_visualization/types.ts", - "lineNumber": 488 + "lineNumber": 490 }, "deprecated": false } @@ -2093,7 +2109,7 @@ ], "source": { "path": "x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/index.ts", - "lineNumber": 497 + "lineNumber": 498 }, "deprecated": false, "initialIsOpen": false @@ -2280,7 +2296,7 @@ ], "source": { "path": "x-pack/plugins/lens/public/xy_visualization/types.ts", - "lineNumber": 470 + "lineNumber": 471 }, "deprecated": false, "initialIsOpen": false diff --git a/api_docs/licensing.json b/api_docs/licensing.json index 873f40bd301a1..1451cff869f47 100644 --- a/api_docs/licensing.json +++ b/api_docs/licensing.json @@ -3088,7 +3088,7 @@ "plugin": "reporting", "link": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 228 + "lineNumber": 226 } }, { diff --git a/api_docs/maps.json b/api_docs/maps.json index a8c582800fc3b..d418518dcb0d2 100644 --- a/api_docs/maps.json +++ b/api_docs/maps.json @@ -57,7 +57,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 90 + "lineNumber": 95 }, "deprecated": false, "children": [ @@ -70,7 +70,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 93 + "lineNumber": 98 }, "deprecated": false }, @@ -86,7 +86,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 110 + "lineNumber": 118 }, "deprecated": false, "children": [ @@ -102,7 +102,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 110 + "lineNumber": 118 }, "deprecated": false, "isRequired": true @@ -125,7 +125,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 110 + "lineNumber": 118 }, "deprecated": false, "isRequired": true @@ -165,7 +165,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 110 + "lineNumber": 118 }, "deprecated": false, "isRequired": false @@ -194,7 +194,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 184 + "lineNumber": 200 }, "deprecated": false, "children": [ @@ -216,7 +216,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 185 + "lineNumber": 201 }, "deprecated": false, "isRequired": true @@ -238,7 +238,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 190 + "lineNumber": 206 }, "deprecated": false, "children": [], @@ -258,7 +258,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 198 + "lineNumber": 214 }, "deprecated": false, "children": [], @@ -276,7 +276,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 203 + "lineNumber": 219 }, "deprecated": false, "children": [], @@ -294,7 +294,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 207 + "lineNumber": 223 }, "deprecated": false, "children": [], @@ -314,7 +314,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 211 + "lineNumber": 227 }, "deprecated": false, "children": [ @@ -330,7 +330,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 211 + "lineNumber": 227 }, "deprecated": false, "isRequired": true @@ -352,7 +352,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 215 + "lineNumber": 231 }, "deprecated": false, "children": [ @@ -368,7 +368,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 215 + "lineNumber": 231 }, "deprecated": false, "isRequired": true @@ -395,7 +395,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 219 + "lineNumber": 235 }, "deprecated": false, "children": [], @@ -413,7 +413,51 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 223 + "lineNumber": 239 + }, + "deprecated": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "maps", + "id": "def-public.MapEmbeddable._getFilters", + "type": "Function", + "tags": [], + "label": "_getFilters", + "description": [], + "signature": [ + "() => ", + { + "pluginId": "data", + "scope": "common", + "docId": "kibDataPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]" + ], + "source": { + "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", + "lineNumber": 283 + }, + "deprecated": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "maps", + "id": "def-public.MapEmbeddable._getSearchSessionId", + "type": "Function", + "tags": [], + "label": "_getSearchSessionId", + "description": [], + "signature": [ + "() => string | undefined" + ], + "source": { + "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", + "lineNumber": 291 }, "deprecated": false, "children": [], @@ -431,7 +475,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 255 + "lineNumber": 301 }, "deprecated": false, "children": [ @@ -444,7 +488,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 255 + "lineNumber": 301 }, "deprecated": false, "children": [ @@ -457,7 +501,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 255 + "lineNumber": 301 }, "deprecated": false } @@ -486,7 +530,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 277 + "lineNumber": 321 }, "deprecated": false, "children": [ @@ -508,7 +552,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 277 + "lineNumber": 321 }, "deprecated": false, "isRequired": true @@ -528,7 +572,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 287 + "lineNumber": 331 }, "deprecated": false, "children": [ @@ -544,7 +588,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 287 + "lineNumber": 331 }, "deprecated": false, "isRequired": false @@ -566,7 +610,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 305 + "lineNumber": 349 }, "deprecated": false, "children": [ @@ -582,7 +626,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 305 + "lineNumber": 349 }, "deprecated": false, "isRequired": true @@ -604,7 +648,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 331 + "lineNumber": 375 }, "deprecated": false, "children": [ @@ -621,7 +665,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 331 + "lineNumber": 375 }, "deprecated": false, "isRequired": true @@ -649,7 +693,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 348 + "lineNumber": 392 }, "deprecated": false, "children": [ @@ -665,7 +709,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 348 + "lineNumber": 392 }, "deprecated": false, "isRequired": true @@ -682,7 +726,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 348 + "lineNumber": 392 }, "deprecated": false, "isRequired": true @@ -705,7 +749,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 348 + "lineNumber": 392 }, "deprecated": false, "isRequired": false @@ -733,7 +777,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 362 + "lineNumber": 406 }, "deprecated": false, "children": [ @@ -756,7 +800,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 362 + "lineNumber": 406 }, "deprecated": false, "isRequired": true @@ -773,7 +817,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 362 + "lineNumber": 406 }, "deprecated": false, "isRequired": true @@ -801,7 +845,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 374 + "lineNumber": 418 }, "deprecated": false, "children": [], @@ -827,7 +871,43 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 395 + "lineNumber": 439 + }, + "deprecated": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "maps", + "id": "def-public.MapEmbeddable.setMapExtentFilter", + "type": "Function", + "tags": [], + "label": "setMapExtentFilter", + "description": [], + "signature": [ + "() => void" + ], + "source": { + "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", + "lineNumber": 450 + }, + "deprecated": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "maps", + "id": "def-public.MapEmbeddable.clearMapExtentFilter", + "type": "Function", + "tags": [], + "label": "clearMapExtentFilter", + "description": [], + "signature": [ + "() => void" + ], + "source": { + "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", + "lineNumber": 487 }, "deprecated": false, "children": [], @@ -845,7 +925,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 406 + "lineNumber": 501 }, "deprecated": false, "children": [], @@ -863,7 +943,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 422 + "lineNumber": 517 }, "deprecated": false, "children": [], @@ -881,7 +961,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", - "lineNumber": 428 + "lineNumber": 523 }, "deprecated": false, "children": [], @@ -1297,7 +1377,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/types.ts", - "lineNumber": 41 + "lineNumber": 42 }, "deprecated": false, "initialIsOpen": false @@ -1329,7 +1409,7 @@ ], "source": { "path": "x-pack/plugins/maps/public/embeddable/types.ts", - "lineNumber": 43 + "lineNumber": 44 }, "deprecated": false, "initialIsOpen": false @@ -1535,7 +1615,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 66 + "lineNumber": 67 }, "deprecated": false, "children": [ @@ -1551,7 +1631,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 66 + "lineNumber": 67 }, "deprecated": false, "isRequired": true @@ -1572,7 +1652,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 63 + "lineNumber": 64 }, "deprecated": false, "children": [ @@ -1588,7 +1668,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 63 + "lineNumber": 64 }, "deprecated": false, "isRequired": true @@ -1609,7 +1689,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 60 + "lineNumber": 61 }, "deprecated": false, "children": [], @@ -1627,7 +1707,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/common/types.ts", - "lineNumber": 22 + "lineNumber": 23 }, "deprecated": false, "children": [ @@ -1643,7 +1723,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/types.ts", - "lineNumber": 23 + "lineNumber": 24 }, "deprecated": false } @@ -1663,6 +1743,22 @@ }, "deprecated": false, "children": [ + { + "parentPluginId": "maps", + "id": "def-common.CreateDocSourceResp.indexPatternId", + "type": "string", + "tags": [], + "label": "indexPatternId", + "description": [], + "signature": [ + "string | undefined" + ], + "source": { + "path": "x-pack/plugins/maps/common/types.ts", + "lineNumber": 9 + }, + "deprecated": false + }, { "parentPluginId": "maps", "id": "def-common.CreateDocSourceResp.success", @@ -1672,7 +1768,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/common/types.ts", - "lineNumber": 9 + "lineNumber": 10 }, "deprecated": false }, @@ -1688,7 +1784,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/types.ts", - "lineNumber": 10 + "lineNumber": 11 }, "deprecated": false } @@ -1704,7 +1800,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/common/types.ts", - "lineNumber": 13 + "lineNumber": 14 }, "deprecated": false, "children": [ @@ -1720,7 +1816,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/types.ts", - "lineNumber": 14 + "lineNumber": 15 }, "deprecated": false }, @@ -1736,7 +1832,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/types.ts", - "lineNumber": 17 + "lineNumber": 18 }, "deprecated": false } @@ -1752,7 +1848,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/common/types.ts", - "lineNumber": 26 + "lineNumber": 27 }, "deprecated": false, "children": [ @@ -1765,7 +1861,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/common/types.ts", - "lineNumber": 27 + "lineNumber": 28 }, "deprecated": false }, @@ -1781,7 +1877,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/types.ts", - "lineNumber": 28 + "lineNumber": 29 }, "deprecated": false }, @@ -1797,7 +1893,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/types.ts", - "lineNumber": 29 + "lineNumber": 30 }, "deprecated": false } @@ -1815,7 +1911,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 163 + "lineNumber": 164 }, "deprecated": false, "initialIsOpen": false @@ -1829,7 +1925,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 211 + "lineNumber": 212 }, "deprecated": false, "initialIsOpen": false @@ -1843,7 +1939,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 292 + "lineNumber": 293 }, "deprecated": false, "initialIsOpen": false @@ -1857,7 +1953,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 156 + "lineNumber": 157 }, "deprecated": false, "initialIsOpen": false @@ -1871,7 +1967,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 123 + "lineNumber": 124 }, "deprecated": false, "initialIsOpen": false @@ -1885,7 +1981,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 131 + "lineNumber": 132 }, "deprecated": false, "initialIsOpen": false @@ -1899,7 +1995,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 96 + "lineNumber": 97 }, "deprecated": false, "initialIsOpen": false @@ -1913,7 +2009,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 255 + "lineNumber": 256 }, "deprecated": false, "initialIsOpen": false @@ -1927,7 +2023,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 137 + "lineNumber": 138 }, "deprecated": false, "initialIsOpen": false @@ -1941,7 +2037,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 180 + "lineNumber": 181 }, "deprecated": false, "initialIsOpen": false @@ -1955,7 +2051,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 267 + "lineNumber": 268 }, "deprecated": false, "initialIsOpen": false @@ -1969,7 +2065,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 224 + "lineNumber": 225 }, "deprecated": false, "initialIsOpen": false @@ -1983,7 +2079,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 205 + "lineNumber": 206 }, "deprecated": false, "initialIsOpen": false @@ -1997,7 +2093,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 70 + "lineNumber": 71 }, "deprecated": false, "initialIsOpen": false @@ -2011,7 +2107,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 274 + "lineNumber": 275 }, "deprecated": false, "initialIsOpen": false @@ -2025,7 +2121,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 287 + "lineNumber": 288 }, "deprecated": false, "initialIsOpen": false @@ -2039,7 +2135,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 260 + "lineNumber": 261 }, "deprecated": false, "initialIsOpen": false @@ -2053,7 +2149,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 174 + "lineNumber": 175 }, "deprecated": false, "initialIsOpen": false @@ -2067,7 +2163,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 248 + "lineNumber": 249 }, "deprecated": false, "initialIsOpen": false @@ -2081,7 +2177,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 79 + "lineNumber": 80 }, "deprecated": false, "initialIsOpen": false @@ -2095,7 +2191,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 200 + "lineNumber": 201 }, "deprecated": false, "initialIsOpen": false @@ -2109,7 +2205,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 219 + "lineNumber": 220 }, "deprecated": false, "initialIsOpen": false @@ -2123,7 +2219,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 280 + "lineNumber": 281 }, "deprecated": false, "initialIsOpen": false @@ -2137,7 +2233,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 233 + "lineNumber": 234 }, "deprecated": false, "initialIsOpen": false @@ -2156,7 +2252,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 162 + "lineNumber": 163 }, "deprecated": false, "initialIsOpen": false @@ -2170,7 +2266,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 44 + "lineNumber": 45 }, "deprecated": false, "initialIsOpen": false @@ -2252,7 +2348,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 216 + "lineNumber": 217 }, "deprecated": false, "initialIsOpen": false @@ -2266,7 +2362,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 194 + "lineNumber": 195 }, "deprecated": false, "initialIsOpen": false @@ -2283,7 +2379,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 198 + "lineNumber": 199 }, "deprecated": false, "initialIsOpen": false @@ -2300,7 +2396,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 112 + "lineNumber": 113 }, "deprecated": false, "initialIsOpen": false @@ -2317,7 +2413,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 231 + "lineNumber": 232 }, "deprecated": false, "initialIsOpen": false @@ -2334,7 +2430,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 116 + "lineNumber": 117 }, "deprecated": false, "initialIsOpen": false @@ -2351,7 +2447,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 115 + "lineNumber": 116 }, "deprecated": false, "initialIsOpen": false @@ -2368,7 +2464,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 114 + "lineNumber": 115 }, "deprecated": false, "initialIsOpen": false @@ -2385,7 +2481,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 192 + "lineNumber": 193 }, "deprecated": false, "initialIsOpen": false @@ -2402,7 +2498,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 296 + "lineNumber": 297 }, "deprecated": false, "initialIsOpen": false @@ -2657,7 +2753,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 307 + "lineNumber": 308 }, "deprecated": false, "initialIsOpen": false @@ -2674,7 +2770,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 308 + "lineNumber": 309 }, "deprecated": false, "initialIsOpen": false @@ -2691,7 +2787,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 306 + "lineNumber": 307 }, "deprecated": false, "initialIsOpen": false @@ -2708,7 +2804,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 129 + "lineNumber": 130 }, "deprecated": false, "initialIsOpen": false @@ -2725,7 +2821,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 118 + "lineNumber": 119 }, "deprecated": false, "initialIsOpen": false @@ -2742,7 +2838,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 119 + "lineNumber": 120 }, "deprecated": false, "initialIsOpen": false @@ -2767,7 +2863,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 300 + "lineNumber": 301 }, "deprecated": false, "initialIsOpen": false @@ -2798,7 +2894,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 103 + "lineNumber": 104 }, "deprecated": false, "initialIsOpen": false @@ -2815,7 +2911,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 189 + "lineNumber": 190 }, "deprecated": false, "initialIsOpen": false @@ -2832,7 +2928,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 188 + "lineNumber": 189 }, "deprecated": false, "initialIsOpen": false @@ -2851,6 +2947,20 @@ "deprecated": false, "initialIsOpen": false }, + { + "parentPluginId": "maps", + "id": "def-common.INDEX_FEATURE_PATH", + "type": "string", + "tags": [], + "label": "INDEX_FEATURE_PATH", + "description": [], + "source": { + "path": "x-pack/plugins/maps/common/constants.ts", + "lineNumber": 44 + }, + "deprecated": false, + "initialIsOpen": false + }, { "parentPluginId": "maps", "id": "def-common.INDEX_META_DATA_CREATED_BY", @@ -2863,7 +2973,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 302 + "lineNumber": 303 }, "deprecated": false, "initialIsOpen": false @@ -2925,7 +3035,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 100 + "lineNumber": 101 }, "deprecated": false, "initialIsOpen": false @@ -2942,7 +3052,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 55 + "lineNumber": 56 }, "deprecated": false, "initialIsOpen": false @@ -2959,7 +3069,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 52 + "lineNumber": 53 }, "deprecated": false, "initialIsOpen": false @@ -2976,7 +3086,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 51 + "lineNumber": 52 }, "deprecated": false, "initialIsOpen": false @@ -2993,7 +3103,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 149 + "lineNumber": 150 }, "deprecated": false, "initialIsOpen": false @@ -3010,7 +3120,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 148 + "lineNumber": 149 }, "deprecated": false, "initialIsOpen": false @@ -3075,7 +3185,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 304 + "lineNumber": 305 }, "deprecated": false, "initialIsOpen": false @@ -3092,7 +3202,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 110 + "lineNumber": 111 }, "deprecated": false, "initialIsOpen": false @@ -3109,7 +3219,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 121 + "lineNumber": 122 }, "deprecated": false, "initialIsOpen": false @@ -3126,7 +3236,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 102 + "lineNumber": 103 }, "deprecated": false, "initialIsOpen": false @@ -3143,7 +3253,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 109 + "lineNumber": 110 }, "deprecated": false, "initialIsOpen": false @@ -3160,7 +3270,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 47 + "lineNumber": 48 }, "deprecated": false, "initialIsOpen": false @@ -3177,7 +3287,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 46 + "lineNumber": 47 }, "deprecated": false, "initialIsOpen": false @@ -3194,7 +3304,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 48 + "lineNumber": 49 }, "deprecated": false, "initialIsOpen": false @@ -3211,7 +3321,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 57 + "lineNumber": 58 }, "deprecated": false, "initialIsOpen": false @@ -3228,7 +3338,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 217 + "lineNumber": 218 }, "deprecated": false, "initialIsOpen": false @@ -3245,7 +3355,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 147 + "lineNumber": 148 }, "deprecated": false, "initialIsOpen": false @@ -3262,7 +3372,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 298 + "lineNumber": 299 }, "deprecated": false, "initialIsOpen": false @@ -3276,7 +3386,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 107 + "lineNumber": 108 }, "deprecated": false, "initialIsOpen": false @@ -3293,7 +3403,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 104 + "lineNumber": 105 }, "deprecated": false, "initialIsOpen": false @@ -3307,7 +3417,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 106 + "lineNumber": 107 }, "deprecated": false, "initialIsOpen": false @@ -3321,7 +3431,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 105 + "lineNumber": 106 }, "deprecated": false, "initialIsOpen": false @@ -3338,7 +3448,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 265 + "lineNumber": 266 }, "deprecated": false, "initialIsOpen": false @@ -3355,7 +3465,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 187 + "lineNumber": 188 }, "deprecated": false, "initialIsOpen": false @@ -3372,7 +3482,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 191 + "lineNumber": 192 }, "deprecated": false, "initialIsOpen": false @@ -3389,7 +3499,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 113 + "lineNumber": 114 }, "deprecated": false, "initialIsOpen": false @@ -3405,7 +3515,7 @@ "description": [], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 151 + "lineNumber": 152 }, "deprecated": false, "children": [ @@ -3421,7 +3531,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 152 + "lineNumber": 153 }, "deprecated": false }, @@ -3437,7 +3547,7 @@ ], "source": { "path": "x-pack/plugins/maps/common/constants.ts", - "lineNumber": 153 + "lineNumber": 154 }, "deprecated": false } diff --git a/api_docs/observability.json b/api_docs/observability.json index a80e8e44fe665..fc645dd7e2e6b 100644 --- a/api_docs/observability.json +++ b/api_docs/observability.json @@ -170,7 +170,7 @@ ], "source": { "path": "x-pack/plugins/observability/public/components/shared/index.tsx", - "lineNumber": 34 + "lineNumber": 36 }, "deprecated": false, "children": [ @@ -186,7 +186,7 @@ ], "source": { "path": "x-pack/plugins/observability/public/components/shared/index.tsx", - "lineNumber": 34 + "lineNumber": 36 }, "deprecated": false, "isRequired": true @@ -283,7 +283,7 @@ ], "source": { "path": "x-pack/plugins/observability/public/components/shared/index.tsx", - "lineNumber": 14 + "lineNumber": 16 }, "deprecated": false, "children": [ @@ -299,7 +299,7 @@ ], "source": { "path": "x-pack/plugins/observability/public/components/shared/index.tsx", - "lineNumber": 14 + "lineNumber": 16 }, "deprecated": false, "isRequired": true @@ -322,7 +322,7 @@ ], "source": { "path": "x-pack/plugins/observability/public/components/shared/index.tsx", - "lineNumber": 24 + "lineNumber": 26 }, "deprecated": false, "children": [ @@ -338,7 +338,7 @@ ], "source": { "path": "x-pack/plugins/observability/public/components/shared/index.tsx", - "lineNumber": 24 + "lineNumber": 26 }, "deprecated": false, "isRequired": true @@ -1050,7 +1050,7 @@ "label": "unsafe", "description": [], "signature": [ - "{ alertingExperience: { enabled: boolean; }; }" + "{ alertingExperience: { enabled: boolean; }; cases: { enabled: boolean; }; }" ], "source": { "path": "x-pack/plugins/observability/public/index.ts", @@ -2040,7 +2040,7 @@ "description": [], "source": { "path": "x-pack/plugins/observability/public/plugin.ts", - "lineNumber": 40 + "lineNumber": 42 }, "deprecated": false, "children": [ @@ -2062,7 +2062,7 @@ ], "source": { "path": "x-pack/plugins/observability/public/plugin.ts", - "lineNumber": 41 + "lineNumber": 43 }, "deprecated": false }, @@ -2084,7 +2084,7 @@ ], "source": { "path": "x-pack/plugins/observability/public/plugin.ts", - "lineNumber": 42 + "lineNumber": 44 }, "deprecated": false }, @@ -2107,7 +2107,7 @@ ], "source": { "path": "x-pack/plugins/observability/public/plugin.ts", - "lineNumber": 43 + "lineNumber": 45 }, "deprecated": false } @@ -2123,7 +2123,7 @@ "description": [], "source": { "path": "x-pack/plugins/observability/public/plugin.ts", - "lineNumber": 46 + "lineNumber": 48 }, "deprecated": false, "children": [ @@ -2146,7 +2146,7 @@ ], "source": { "path": "x-pack/plugins/observability/public/plugin.ts", - "lineNumber": 47 + "lineNumber": 49 }, "deprecated": false }, @@ -2168,7 +2168,7 @@ ], "source": { "path": "x-pack/plugins/observability/public/plugin.ts", - "lineNumber": 48 + "lineNumber": 50 }, "deprecated": false }, @@ -2190,7 +2190,7 @@ ], "source": { "path": "x-pack/plugins/observability/public/plugin.ts", - "lineNumber": 49 + "lineNumber": 51 }, "deprecated": false }, @@ -2212,7 +2212,7 @@ ], "source": { "path": "x-pack/plugins/observability/public/plugin.ts", - "lineNumber": 50 + "lineNumber": 52 }, "deprecated": false } @@ -2838,7 +2838,7 @@ "METRIC_TYPE" ], "source": { - "path": "node_modules/@kbn/analytics/target/types/metrics/index.d.ts", + "path": "node_modules/@kbn/analytics/target_types/metrics/index.d.ts", "lineNumber": 10 }, "deprecated": false, @@ -3142,11 +3142,15 @@ "section": "def-public.AlertTypeModel", "text": "AlertTypeModel" }, - " & { format: Formatter; }) => void; getFormatter: (typeId: string) => Formatter | undefined; }; isAlertingExperienceEnabled: () => boolean; }" + " & { format: Formatter; }) => void; getFormatter: (typeId: string) => Formatter | undefined; }; isAlertingExperienceEnabled: () => boolean; navigation: { registerSections: (sections$: ", + "Observable", + "<", + "NavigationSection", + "[]>) => void; }; }" ], "source": { "path": "x-pack/plugins/observability/public/plugin.ts", - "lineNumber": 38 + "lineNumber": 40 }, "deprecated": false, "lifecycle": "setup", @@ -3160,11 +3164,13 @@ "label": "ObservabilityPublicStart", "description": [], "signature": [ - "void" + "{ navigation: { PageTemplate: (pageTemplateProps: ", + "WrappedPageTemplateProps", + ") => JSX.Element; }; }" ], "source": { "path": "x-pack/plugins/observability/public/plugin.ts", - "lineNumber": 53 + "lineNumber": 55 }, "deprecated": false, "lifecycle": "start", @@ -3431,7 +3437,7 @@ ], "source": { "path": "x-pack/plugins/observability/server/utils/queries.ts", - "lineNumber": 25 + "lineNumber": 35 }, "deprecated": false, "children": [ @@ -3447,7 +3453,7 @@ ], "source": { "path": "x-pack/plugins/observability/server/utils/queries.ts", - "lineNumber": 25 + "lineNumber": 35 }, "deprecated": false, "isRequired": false @@ -3470,7 +3476,7 @@ ], "source": { "path": "x-pack/plugins/observability/server/utils/queries.ts", - "lineNumber": 11 + "lineNumber": 21 }, "deprecated": false, "children": [ @@ -3486,7 +3492,7 @@ ], "source": { "path": "x-pack/plugins/observability/server/utils/queries.ts", - "lineNumber": 11 + "lineNumber": 21 }, "deprecated": false, "isRequired": false @@ -3503,7 +3509,7 @@ ], "source": { "path": "x-pack/plugins/observability/server/utils/queries.ts", - "lineNumber": 11 + "lineNumber": 21 }, "deprecated": false, "isRequired": false @@ -3520,7 +3526,7 @@ ], "source": { "path": "x-pack/plugins/observability/server/utils/queries.ts", - "lineNumber": 11 + "lineNumber": 21 }, "deprecated": false, "isRequired": true @@ -3861,7 +3867,15 @@ "Type", "; end: ", "Type", - "; }>, ", + "; status: ", + "UnionC", + "<[", + "LiteralC", + "<\"all\">, ", + "LiteralC", + "<\"open\">, ", + "LiteralC", + "<\"closed\">]>; }>, ", "PartialC", "<{ kuery: ", "StringC", @@ -3928,11 +3942,11 @@ "label": "ObservabilityConfig", "description": [], "signature": [ - "{ readonly enabled: boolean; readonly annotations: Readonly<{} & { enabled: boolean; index: string; }>; readonly unsafe: Readonly<{} & { alertingExperience: Readonly<{} & { enabled: boolean; }>; }>; }" + "{ readonly enabled: boolean; readonly annotations: Readonly<{} & { enabled: boolean; index: string; }>; readonly unsafe: Readonly<{} & { cases: Readonly<{} & { enabled: boolean; }>; alertingExperience: Readonly<{} & { enabled: boolean; }>; }>; }" ], "source": { "path": "x-pack/plugins/observability/server/index.ts", - "lineNumber": 34 + "lineNumber": 35 }, "deprecated": false, "initialIsOpen": false @@ -3974,7 +3988,15 @@ "Type", "; end: ", "Type", - "; }>, ", + "; status: ", + "UnionC", + "<[", + "LiteralC", + "<\"all\">, ", + "LiteralC", + "<\"open\">, ", + "LiteralC", + "<\"closed\">]>; }>, ", "PartialC", "<{ kuery: ", "StringC", diff --git a/api_docs/presentation_util.json b/api_docs/presentation_util.json index ee045dfd830fb..bde8373e4450e 100644 --- a/api_docs/presentation_util.json +++ b/api_docs/presentation_util.json @@ -528,7 +528,9 @@ "type": "CompoundType", "tags": [], "label": "Component", - "description": [], + "description": [ + "A component deferred by `React.lazy`" + ], "signature": [ "React.ComponentType

    " ], @@ -545,7 +547,9 @@ "type": "CompoundType", "tags": [], "label": "fallback", - "description": [], + "description": [ + "A fallback component to render while things load; default is `EuiLoadingSpinner`" + ], "signature": [ "React.ReactElement React.ReactElement React.Component)> | null) | (new (props: any) => React.Component)> | null" ], diff --git a/api_docs/reporting.json b/api_docs/reporting.json index e8cea57b24902..b2529f510bc2e 100644 --- a/api_docs/reporting.json +++ b/api_docs/reporting.json @@ -911,10 +911,10 @@ "children": [ { "parentPluginId": "reporting", - "id": "def-server.ReportingCore.getStartContract", + "id": "def-server.ReportingCore.getContract", "type": "Function", "tags": [], - "label": "getStartContract", + "label": "getContract", "description": [], "signature": [ "() => ", @@ -1010,7 +1010,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 92 + "lineNumber": 90 }, "deprecated": false, "children": [ @@ -1026,7 +1026,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 92 + "lineNumber": 90 }, "deprecated": false, "isRequired": true @@ -1048,7 +1048,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 106 + "lineNumber": 104 }, "deprecated": false, "children": [ @@ -1064,7 +1064,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 106 + "lineNumber": 104 }, "deprecated": false, "isRequired": true @@ -1084,7 +1084,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 119 + "lineNumber": 117 }, "deprecated": false, "children": [], @@ -1102,7 +1102,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 130 + "lineNumber": 128 }, "deprecated": false, "children": [], @@ -1120,7 +1120,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 137 + "lineNumber": 135 }, "deprecated": false, "children": [], @@ -1146,7 +1146,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 144 + "lineNumber": 142 }, "deprecated": false, "children": [ @@ -1168,7 +1168,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 144 + "lineNumber": 142 }, "deprecated": false, "isRequired": true @@ -1190,7 +1190,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 153 + "lineNumber": 151 }, "deprecated": false, "children": [], @@ -1215,7 +1215,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 187 + "lineNumber": 185 }, "deprecated": false, "children": [], @@ -1233,7 +1233,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 199 + "lineNumber": 197 }, "deprecated": false, "children": [], @@ -1253,7 +1253,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 206 + "lineNumber": 204 }, "deprecated": false, "children": [], @@ -1272,7 +1272,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 214 + "lineNumber": 212 }, "deprecated": false, "children": [], @@ -1302,7 +1302,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 218 + "lineNumber": 216 }, "deprecated": false, "children": [ @@ -1321,7 +1321,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 218 + "lineNumber": 216 }, "deprecated": false, "isRequired": true @@ -1343,7 +1343,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 222 + "lineNumber": 220 }, "deprecated": false, "children": [], @@ -1363,7 +1363,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 226 + "lineNumber": 224 }, "deprecated": false, "children": [], @@ -1383,7 +1383,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 236 + "lineNumber": 234 }, "deprecated": false, "children": [], @@ -1401,7 +1401,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 242 + "lineNumber": 240 }, "deprecated": false, "children": [], @@ -1420,7 +1420,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 250 + "lineNumber": 248 }, "deprecated": false, "children": [], @@ -1454,7 +1454,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 262 + "lineNumber": 260 }, "deprecated": false, "children": [ @@ -1478,7 +1478,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 262 + "lineNumber": 260 }, "deprecated": false, "isRequired": true @@ -1508,7 +1508,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 268 + "lineNumber": 266 }, "deprecated": false, "children": [ @@ -1531,7 +1531,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 268 + "lineNumber": 266 }, "deprecated": false, "isRequired": true @@ -1548,7 +1548,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 268 + "lineNumber": 266 }, "deprecated": false, "isRequired": true @@ -1578,7 +1578,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 282 + "lineNumber": 280 }, "deprecated": false, "children": [ @@ -1594,7 +1594,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 282 + "lineNumber": 280 }, "deprecated": false, "isRequired": true @@ -1611,7 +1611,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 282 + "lineNumber": 280 }, "deprecated": false, "isRequired": false @@ -1628,7 +1628,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 282 + "lineNumber": 280 }, "deprecated": false, "isRequired": true @@ -1666,7 +1666,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 302 + "lineNumber": 300 }, "deprecated": false, "children": [ @@ -1689,7 +1689,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 302 + "lineNumber": 300 }, "deprecated": false, "isRequired": true @@ -1706,7 +1706,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 302 + "lineNumber": 300 }, "deprecated": false, "isRequired": true @@ -1734,7 +1734,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 312 + "lineNumber": 310 }, "deprecated": false, "children": [], @@ -1760,7 +1760,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 317 + "lineNumber": 315 }, "deprecated": false, "children": [], @@ -1778,7 +1778,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 322 + "lineNumber": 320 }, "deprecated": false, "children": [ @@ -1794,7 +1794,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 322 + "lineNumber": 320 }, "deprecated": false, "isRequired": true @@ -1814,7 +1814,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 326 + "lineNumber": 324 }, "deprecated": false, "children": [ @@ -1830,7 +1830,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 326 + "lineNumber": 324 }, "deprecated": false, "isRequired": true @@ -1850,7 +1850,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 330 + "lineNumber": 328 }, "deprecated": false, "children": [], @@ -1918,7 +1918,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/plugin.ts", - "lineNumber": 25 + "lineNumber": 26 }, "deprecated": false, "children": [ @@ -1934,7 +1934,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/plugin.ts", - "lineNumber": 30 + "lineNumber": 31 }, "deprecated": false, "children": [ @@ -1959,7 +1959,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/plugin.ts", - "lineNumber": 30 + "lineNumber": 31 }, "deprecated": false, "isRequired": true @@ -2002,7 +2002,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/plugin.ts", - "lineNumber": 34 + "lineNumber": 35 }, "deprecated": false, "children": [ @@ -2025,7 +2025,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/plugin.ts", - "lineNumber": 34 + "lineNumber": 35 }, "deprecated": false, "isRequired": true @@ -2048,7 +2048,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/plugin.ts", - "lineNumber": 34 + "lineNumber": 35 }, "deprecated": false, "isRequired": true @@ -2091,7 +2091,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/plugin.ts", - "lineNumber": 87 + "lineNumber": 88 }, "deprecated": false, "children": [ @@ -2113,7 +2113,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/plugin.ts", - "lineNumber": 87 + "lineNumber": 88 }, "deprecated": false, "isRequired": true @@ -2136,7 +2136,7 @@ ], "source": { "path": "x-pack/plugins/reporting/server/plugin.ts", - "lineNumber": 87 + "lineNumber": 88 }, "deprecated": false, "isRequired": true diff --git a/api_docs/rule_registry.json b/api_docs/rule_registry.json index 63a50f8fbd42f..cd1f4994c1da6 100644 --- a/api_docs/rule_registry.json +++ b/api_docs/rule_registry.json @@ -695,8 +695,8 @@ "{ readonly enabled: boolean; readonly index: string; readonly write: Readonly<{} & { enabled: boolean; }>; }" ], "source": { - "path": "x-pack/plugins/rule_registry/server/index.ts", - "lineNumber": 28 + "path": "x-pack/plugins/rule_registry/server/config.ts", + "lineNumber": 20 }, "deprecated": false, "initialIsOpen": false @@ -706,18 +706,49 @@ "setup": { "parentPluginId": "ruleRegistry", "id": "def-server.RuleRegistryPluginSetupContract", - "type": "Type", + "type": "Interface", "tags": [], "label": "RuleRegistryPluginSetupContract", "description": [], - "signature": [ - "RuleDataPluginService" - ], "source": { "path": "x-pack/plugins/rule_registry/server/plugin.ts", - "lineNumber": 12 + "lineNumber": 22 }, "deprecated": false, + "children": [ + { + "parentPluginId": "ruleRegistry", + "id": "def-server.RuleRegistryPluginSetupContract.ruleDataService", + "type": "Object", + "tags": [], + "label": "ruleDataService", + "description": [], + "signature": [ + "RuleDataPluginService" + ], + "source": { + "path": "x-pack/plugins/rule_registry/server/plugin.ts", + "lineNumber": 23 + }, + "deprecated": false + }, + { + "parentPluginId": "ruleRegistry", + "id": "def-server.RuleRegistryPluginSetupContract.eventLogService", + "type": "Object", + "tags": [], + "label": "eventLogService", + "description": [], + "signature": [ + "IEventLogService" + ], + "source": { + "path": "x-pack/plugins/rule_registry/server/plugin.ts", + "lineNumber": 24 + }, + "deprecated": false + } + ], "lifecycle": "setup", "initialIsOpen": true }, @@ -733,7 +764,7 @@ ], "source": { "path": "x-pack/plugins/rule_registry/server/plugin.ts", - "lineNumber": 13 + "lineNumber": 27 }, "deprecated": false, "lifecycle": "start", diff --git a/api_docs/spaces.json b/api_docs/spaces.json index 5225e8cebbeb5..2f2d79c2379d5 100644 --- a/api_docs/spaces.json +++ b/api_docs/spaces.json @@ -1210,7 +1210,7 @@ "plugin": "reporting", "link": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 271 + "lineNumber": 269 } }, { @@ -2030,21 +2030,21 @@ "plugin": "reporting", "link": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 269 + "lineNumber": 267 } }, { "plugin": "reporting", "link": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 291 + "lineNumber": 289 } }, { "plugin": "reporting", "link": { "path": "x-pack/plugins/reporting/server/core.ts", - "lineNumber": 303 + "lineNumber": 301 } }, { diff --git a/api_docs/triggers_actions_ui.json b/api_docs/triggers_actions_ui.json index cade40cf39c73..de7a13b3080fe 100644 --- a/api_docs/triggers_actions_ui.json +++ b/api_docs/triggers_actions_ui.json @@ -45,7 +45,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/plugin.ts", - "lineNumber": 77 + "lineNumber": 80 }, "deprecated": false, "children": [ @@ -61,7 +61,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/plugin.ts", - "lineNumber": 88 + "lineNumber": 91 }, "deprecated": false, "children": [], @@ -94,7 +94,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/plugin.ts", - "lineNumber": 93 + "lineNumber": 96 }, "deprecated": false, "children": [ @@ -117,7 +117,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/plugin.ts", - "lineNumber": 93 + "lineNumber": 96 }, "deprecated": false, "isRequired": true @@ -134,7 +134,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/plugin.ts", - "lineNumber": 93 + "lineNumber": 96 }, "deprecated": false, "isRequired": true @@ -161,7 +161,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/plugin.ts", - "lineNumber": 169 + "lineNumber": 172 }, "deprecated": false, "children": [], @@ -179,7 +179,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/plugin.ts", - "lineNumber": 203 + "lineNumber": 206 }, "deprecated": false, "children": [], @@ -228,44 +228,6 @@ ], "initialIsOpen": false }, - { - "parentPluginId": "triggersActionsUi", - "id": "def-public.AlertAdd", - "type": "Function", - "tags": [], - "label": "AlertAdd", - "description": [], - "signature": [ - "(props: ", - "AlertAddProps", - ">) => JSX.Element" - ], - "source": { - "path": "x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/index.tsx", - "lineNumber": 11 - }, - "deprecated": false, - "returnComment": [], - "children": [ - { - "parentPluginId": "triggersActionsUi", - "id": "def-public.props", - "type": "Uncategorized", - "tags": [], - "label": "props", - "description": [], - "signature": [ - "T" - ], - "source": { - "path": "x-pack/plugins/triggers_actions_ui/public/application/lib/suspended_component_with_props.tsx", - "lineNumber": 16 - }, - "deprecated": false - } - ], - "initialIsOpen": false - }, { "parentPluginId": "triggersActionsUi", "id": "def-public.AlertConditions", @@ -346,44 +308,6 @@ ], "initialIsOpen": false }, - { - "parentPluginId": "triggersActionsUi", - "id": "def-public.AlertEdit", - "type": "Function", - "tags": [], - "label": "AlertEdit", - "description": [], - "signature": [ - "(props: ", - "AlertEditProps", - ">) => JSX.Element" - ], - "source": { - "path": "x-pack/plugins/triggers_actions_ui/public/application/sections/index.tsx", - "lineNumber": 17 - }, - "deprecated": false, - "returnComment": [], - "children": [ - { - "parentPluginId": "triggersActionsUi", - "id": "def-public.props", - "type": "Uncategorized", - "tags": [], - "label": "props", - "description": [], - "signature": [ - "T" - ], - "source": { - "path": "x-pack/plugins/triggers_actions_ui/public/application/lib/suspended_component_with_props.tsx", - "lineNumber": 16 - }, - "deprecated": false - } - ], - "initialIsOpen": false - }, { "parentPluginId": "triggersActionsUi", "id": "def-public.ConnectorAddFlyout", @@ -518,7 +442,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/jira.tsx", - "lineNumber": 63 + "lineNumber": 62 }, "deprecated": false, "children": [], @@ -545,7 +469,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/resilient/resilient.tsx", - "lineNumber": 68 + "lineNumber": 67 }, "deprecated": false, "children": [], @@ -752,7 +676,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/servicenow.tsx", - "lineNumber": 64 + "lineNumber": 63 }, "deprecated": false, "children": [], @@ -779,7 +703,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/servicenow.tsx", - "lineNumber": 99 + "lineNumber": 98 }, "deprecated": false, "children": [], @@ -1459,7 +1383,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", - "lineNumber": 234 + "lineNumber": 235 }, "deprecated": false, "children": [ @@ -1472,7 +1396,7 @@ "description": [], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", - "lineNumber": 235 + "lineNumber": 236 }, "deprecated": false }, @@ -1485,7 +1409,7 @@ "description": [], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", - "lineNumber": 236 + "lineNumber": 237 }, "deprecated": false }, @@ -1498,7 +1422,7 @@ "description": [], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", - "lineNumber": 237 + "lineNumber": 238 }, "deprecated": false }, @@ -1522,7 +1446,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", - "lineNumber": 238 + "lineNumber": 239 }, "deprecated": false }, @@ -1545,7 +1469,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", - "lineNumber": 239 + "lineNumber": 240 }, "deprecated": false, "returnComment": [], @@ -1562,7 +1486,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", - "lineNumber": 239 + "lineNumber": 240 }, "deprecated": false } @@ -1588,7 +1512,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", - "lineNumber": 240 + "lineNumber": 241 }, "deprecated": false, "returnComment": [], @@ -1620,7 +1544,7 @@ "description": [], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", - "lineNumber": 243 + "lineNumber": 244 }, "deprecated": false }, @@ -1636,7 +1560,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", - "lineNumber": 244 + "lineNumber": 245 }, "deprecated": false } @@ -1662,7 +1586,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", - "lineNumber": 212 + "lineNumber": 213 }, "deprecated": false, "children": [ @@ -1678,7 +1602,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", - "lineNumber": 217 + "lineNumber": 218 }, "deprecated": false }, @@ -1691,7 +1615,7 @@ "description": [], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", - "lineNumber": 218 + "lineNumber": 219 }, "deprecated": false }, @@ -1704,7 +1628,7 @@ "description": [], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", - "lineNumber": 219 + "lineNumber": 220 }, "deprecated": false }, @@ -1720,7 +1644,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", - "lineNumber": 220 + "lineNumber": 221 }, "deprecated": false }, @@ -1736,7 +1660,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", - "lineNumber": 221 + "lineNumber": 222 }, "deprecated": false, "returnComment": [], @@ -1753,7 +1677,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", - "lineNumber": 221 + "lineNumber": 222 }, "deprecated": false }, @@ -1769,7 +1693,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", - "lineNumber": 221 + "lineNumber": 222 }, "deprecated": false } @@ -1795,7 +1719,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", - "lineNumber": 222 + "lineNumber": 223 }, "deprecated": false, "returnComment": [], @@ -1812,7 +1736,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", - "lineNumber": 223 + "lineNumber": 224 }, "deprecated": false }, @@ -1836,7 +1760,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", - "lineNumber": 224 + "lineNumber": 225 }, "deprecated": false } @@ -1860,7 +1784,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", - "lineNumber": 226 + "lineNumber": 227 }, "deprecated": false }, @@ -1873,7 +1797,7 @@ "description": [], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", - "lineNumber": 227 + "lineNumber": 228 }, "deprecated": false }, @@ -1896,7 +1820,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", - "lineNumber": 228 + "lineNumber": 229 }, "deprecated": false }, @@ -1912,7 +1836,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", - "lineNumber": 229 + "lineNumber": 230 }, "deprecated": false }, @@ -1934,7 +1858,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", - "lineNumber": 230 + "lineNumber": 231 }, "deprecated": false }, @@ -1956,7 +1880,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", - "lineNumber": 231 + "lineNumber": 232 }, "deprecated": false } @@ -2098,7 +2022,7 @@ "description": [], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", - "lineNumber": 247 + "lineNumber": 248 }, "deprecated": false, "children": [ @@ -2114,7 +2038,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", - "lineNumber": 248 + "lineNumber": 249 }, "deprecated": false } @@ -2483,7 +2407,7 @@ "description": [], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", - "lineNumber": 127 + "lineNumber": 128 }, "deprecated": false, "children": [ @@ -2499,7 +2423,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", - "lineNumber": 128 + "lineNumber": 129 }, "deprecated": false } @@ -2531,7 +2455,7 @@ "description": [], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", - "lineNumber": 79 + "lineNumber": 80 }, "deprecated": false, "initialIsOpen": false @@ -2581,7 +2505,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", - "lineNumber": 161 + "lineNumber": 162 }, "deprecated": false, "initialIsOpen": false @@ -2637,7 +2561,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", - "lineNumber": 64 + "lineNumber": 65 }, "deprecated": false, "initialIsOpen": false @@ -2654,7 +2578,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", - "lineNumber": 179 + "lineNumber": 180 }, "deprecated": false, "initialIsOpen": false @@ -2695,7 +2619,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", - "lineNumber": 40 + "lineNumber": 41 }, "deprecated": false, "initialIsOpen": false @@ -2753,7 +2677,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", - "lineNumber": 68 + "lineNumber": 69 }, "deprecated": false, "initialIsOpen": false @@ -3782,7 +3706,7 @@ "description": [], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/plugin.ts", - "lineNumber": 41 + "lineNumber": 44 }, "deprecated": false, "children": [ @@ -3801,7 +3725,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/plugin.ts", - "lineNumber": 42 + "lineNumber": 45 }, "deprecated": false }, @@ -3826,7 +3750,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/plugin.ts", - "lineNumber": 43 + "lineNumber": 46 }, "deprecated": false } @@ -3843,7 +3767,7 @@ "description": [], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/plugin.ts", - "lineNumber": 46 + "lineNumber": 49 }, "deprecated": false, "children": [ @@ -3862,7 +3786,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/plugin.ts", - "lineNumber": 47 + "lineNumber": 50 }, "deprecated": false }, @@ -3887,7 +3811,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/plugin.ts", - "lineNumber": 48 + "lineNumber": 51 }, "deprecated": false }, @@ -3907,7 +3831,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/plugin.ts", - "lineNumber": 49 + "lineNumber": 52 }, "deprecated": false, "returnComment": [], @@ -3948,7 +3872,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/plugin.ts", - "lineNumber": 50 + "lineNumber": 53 }, "deprecated": false } @@ -3970,7 +3894,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/plugin.ts", - "lineNumber": 52 + "lineNumber": 55 }, "deprecated": false, "returnComment": [], @@ -4005,7 +3929,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/plugin.ts", - "lineNumber": 53 + "lineNumber": 56 }, "deprecated": false } @@ -4027,7 +3951,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/plugin.ts", - "lineNumber": 55 + "lineNumber": 58 }, "deprecated": false, "returnComment": [], @@ -4060,7 +3984,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/plugin.ts", - "lineNumber": 56 + "lineNumber": 59 }, "deprecated": false } @@ -4082,7 +4006,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/plugin.ts", - "lineNumber": 58 + "lineNumber": 61 }, "deprecated": false, "returnComment": [], @@ -4115,7 +4039,7 @@ ], "source": { "path": "x-pack/plugins/triggers_actions_ui/public/plugin.ts", - "lineNumber": 59 + "lineNumber": 62 }, "deprecated": false } diff --git a/api_docs/visualizations.json b/api_docs/visualizations.json index bea890f00e0ed..0df428a158a3d 100644 --- a/api_docs/visualizations.json +++ b/api_docs/visualizations.json @@ -85,7 +85,15 @@ "label": "getSupportedTriggers", "description": [], "signature": [ - "(() => string[]) | undefined" + "((params?: ", + { + "pluginId": "visualizations", + "scope": "common", + "docId": "kibVisualizationsPluginApi", + "section": "def-common.VisParams", + "text": "VisParams" + }, + " | undefined) => string[]) | undefined" ], "source": { "path": "src/plugins/visualizations/public/vis_types/base_vis_type.ts", @@ -3327,7 +3335,15 @@ "\nIf given, it will return the supported triggers for this vis." ], "signature": [ - "(() => string[]) | undefined" + "((params?: ", + { + "pluginId": "visualizations", + "scope": "common", + "docId": "kibVisualizationsPluginApi", + "section": "def-common.VisParams", + "text": "VisParams" + }, + " | undefined) => string[]) | undefined" ], "source": { "path": "src/plugins/visualizations/public/vis_types/types.ts", diff --git a/packages/kbn-docs-utils/src/api_docs/build_api_declarations/build_arrow_fn_dec.ts b/packages/kbn-docs-utils/src/api_docs/build_api_declarations/build_arrow_fn_dec.ts index bcbb9cf3e7bbe..c714165a0922c 100644 --- a/packages/kbn-docs-utils/src/api_docs/build_api_declarations/build_arrow_fn_dec.ts +++ b/packages/kbn-docs-utils/src/api_docs/build_api_declarations/build_arrow_fn_dec.ts @@ -19,7 +19,7 @@ import { import { AnchorLink, ApiDeclaration, TypeKind } from '../types'; import { buildApiDecsForParameters } from './build_parameter_decs'; import { getSignature } from './get_signature'; -import { getJSDocReturnTagComment } from './js_doc_utils'; +import { getJSDocReturnTagComment, getJSDocs } from './js_doc_utils'; import { buildBasicApiDeclaration } from './build_basic_api_declaration'; /** @@ -66,7 +66,8 @@ export function getArrowFunctionDec( anchorLink, currentPluginId, log, - captureReferences + captureReferences, + getJSDocs(node) ), // need to override the signature - use the initializer, not the node. signature: getSignature(initializer, plugins, log), diff --git a/packages/kbn-docs-utils/src/api_docs/tests/api_doc_suite.test.ts b/packages/kbn-docs-utils/src/api_docs/tests/api_doc_suite.test.ts index cdf1e5b718cca..ff71b0efc79d1 100644 --- a/packages/kbn-docs-utils/src/api_docs/tests/api_doc_suite.test.ts +++ b/packages/kbn-docs-utils/src/api_docs/tests/api_doc_suite.test.ts @@ -46,6 +46,8 @@ function fnIsCorrect(fn: ApiDeclaration | undefined) { expect(p1!.isRequired).toBe(true); expect(p1!.signature?.length).toBe(1); expect(linkCount(p1!.signature!)).toBe(0); + expect(p1?.description).toBeDefined(); + expect(p1?.description?.length).toBe(1); const p2 = fn?.children!.find((c) => c.label === 'b'); expect(p2).toBeDefined(); @@ -53,12 +55,15 @@ function fnIsCorrect(fn: ApiDeclaration | undefined) { expect(p2!.type).toBe(TypeKind.NumberKind); expect(p2!.signature?.length).toBe(1); expect(linkCount(p2!.signature!)).toBe(0); + expect(p2?.description?.length).toBe(1); const p3 = fn?.children!.find((c) => c.label === 'c'); expect(p3).toBeDefined(); expect(p3!.isRequired).toBe(true); expect(p3!.type).toBe(TypeKind.ArrayKind); expect(linkCount(p3!.signature!)).toBe(1); + expect(p3?.description).toBeDefined(); + expect(p3?.description?.length).toBe(1); const p4 = fn?.children!.find((c) => c.label === 'd'); expect(p4).toBeDefined(); @@ -66,6 +71,7 @@ function fnIsCorrect(fn: ApiDeclaration | undefined) { expect(p4!.type).toBe(TypeKind.CompoundTypeKind); expect(p4!.signature?.length).toBe(1); expect(linkCount(p4!.signature!)).toBe(1); + expect(p4?.description?.length).toBe(1); const p5 = fn?.children!.find((c) => c.label === 'e'); expect(p5).toBeDefined(); @@ -73,6 +79,7 @@ function fnIsCorrect(fn: ApiDeclaration | undefined) { expect(p5!.type).toBe(TypeKind.StringKind); expect(p5!.signature?.length).toBe(1); expect(linkCount(p5!.signature!)).toBe(0); + expect(p5?.description?.length).toBe(1); } beforeAll(() => { diff --git a/packages/kbn-docs-utils/src/api_docs/tests/snapshots/plugin_a.json b/packages/kbn-docs-utils/src/api_docs/tests/snapshots/plugin_a.json index deb40d875b442..7d8a90c3aad77 100644 --- a/packages/kbn-docs-utils/src/api_docs/tests/snapshots/plugin_a.json +++ b/packages/kbn-docs-utils/src/api_docs/tests/snapshots/plugin_a.json @@ -165,7 +165,9 @@ "type": "CompoundType", "tags": [], "label": "a", - "description": [], + "description": [ + "im a string" + ], "signature": [ { "pluginId": "pluginA", @@ -292,7 +294,9 @@ "type": "string", "tags": [], "label": "a", - "description": [], + "description": [ + "The letter A" + ], "signature": [ "string" ], @@ -309,7 +313,9 @@ "type": "number", "tags": [], "label": "b", - "description": [], + "description": [ + "Feed me to the function" + ], "signature": [ "number | undefined" ], @@ -326,7 +332,9 @@ "type": "Array", "tags": [], "label": "c", - "description": [], + "description": [ + "So many params" + ], "signature": [ { "pluginId": "pluginA", @@ -350,7 +358,9 @@ "type": "CompoundType", "tags": [], "label": "d", - "description": [], + "description": [ + "a great param" + ], "signature": [ { "pluginId": "pluginA", @@ -373,7 +383,9 @@ "type": "string", "tags": [], "label": "e", - "description": [], + "description": [ + "Another comment" + ], "signature": [ "string | undefined" ], @@ -586,7 +598,7 @@ "section": "def-public.ImAType", "text": "ImAType" }, - ", e: string | undefined) => ", + ", e?: string | undefined) => ", { "pluginId": "pluginA", "scope": "public", From b4e8cfe0d7c17ca75f5774fd95a2fa4f36fcc958 Mon Sep 17 00:00:00 2001 From: ymao1 Date: Fri, 28 May 2021 11:56:51 -0400 Subject: [PATCH 70/77] [Actions] Taking space id into account when creating email footer link (#100734) * Taking space id into account when creating email footer link * Handling undefined space when spaces is disabled * Handling undefined space when spaces is disabled Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../create_execution_handler.test.ts | 3 +- .../task_runner/create_execution_handler.ts | 3 +- .../task_runner/inject_action_params.test.ts | 60 +++++++++++++++++-- .../task_runner/inject_action_params.ts | 12 ++-- 4 files changed, 68 insertions(+), 10 deletions(-) diff --git a/x-pack/plugins/alerting/server/task_runner/create_execution_handler.test.ts b/x-pack/plugins/alerting/server/task_runner/create_execution_handler.test.ts index 120ab6de296dd..78d74b78c99ba 100644 --- a/x-pack/plugins/alerting/server/task_runner/create_execution_handler.test.ts +++ b/x-pack/plugins/alerting/server/task_runner/create_execution_handler.test.ts @@ -180,7 +180,8 @@ test('enqueues execution per selected action', async () => { `); expect(jest.requireMock('./inject_action_params').injectActionParams).toHaveBeenCalledWith({ - alertId: '1', + ruleId: '1', + spaceId: 'default', actionTypeId: 'test', actionParams: { alertVal: 'My 1 name-of-alert default tag-A,tag-B 2 goes here', diff --git a/x-pack/plugins/alerting/server/task_runner/create_execution_handler.ts b/x-pack/plugins/alerting/server/task_runner/create_execution_handler.ts index 2ecf540485695..93cced2043d5e 100644 --- a/x-pack/plugins/alerting/server/task_runner/create_execution_handler.ts +++ b/x-pack/plugins/alerting/server/task_runner/create_execution_handler.ts @@ -138,7 +138,8 @@ export function createExecutionHandler< .map((action) => ({ ...action, params: injectActionParams({ - alertId, + ruleId: alertId, + spaceId, actionParams: action.params, actionTypeId: action.actionTypeId, }), diff --git a/x-pack/plugins/alerting/server/task_runner/inject_action_params.test.ts b/x-pack/plugins/alerting/server/task_runner/inject_action_params.test.ts index 62d834eb91da0..0416a3c4d1214 100644 --- a/x-pack/plugins/alerting/server/task_runner/inject_action_params.test.ts +++ b/x-pack/plugins/alerting/server/task_runner/inject_action_params.test.ts @@ -14,7 +14,8 @@ describe('injectActionParams', () => { }; const result = injectActionParams({ actionParams, - alertId: '1', + ruleId: '1', + spaceId: 'the-space', actionTypeId: '.server-log', }); expect(result).toMatchInlineSnapshot(` @@ -32,7 +33,8 @@ describe('injectActionParams', () => { }; const result = injectActionParams({ actionParams, - alertId: '1', + ruleId: '1', + spaceId: 'default', actionTypeId: '.email', }); expect(result).toMatchInlineSnapshot(` @@ -41,8 +43,58 @@ describe('injectActionParams', () => { "message": "State: \\"{{state.value}}\\", Context: \\"{{context.value}}\\"", }, "kibanaFooterLink": Object { - "path": "/app/management/insightsAndAlerting/triggersActions/alert/1", - "text": "View alert in Kibana", + "path": "/app/management/insightsAndAlerting/triggersActions/rule/1", + "text": "View rule in Kibana", + }, + } + `); + }); + + test('injects viewInKibanaPath and viewInKibanaText when actionTypeId is .email and spaceId is undefined', () => { + const actionParams = { + body: { + message: 'State: "{{state.value}}", Context: "{{context.value}}"', + }, + }; + const result = injectActionParams({ + actionParams, + ruleId: '1', + spaceId: undefined, + actionTypeId: '.email', + }); + expect(result).toMatchInlineSnapshot(` + Object { + "body": Object { + "message": "State: \\"{{state.value}}\\", Context: \\"{{context.value}}\\"", + }, + "kibanaFooterLink": Object { + "path": "/app/management/insightsAndAlerting/triggersActions/rule/1", + "text": "View rule in Kibana", + }, + } + `); + }); + + test('injects viewInKibanaPath with space ID and viewInKibanaText when actionTypeId is .email', () => { + const actionParams = { + body: { + message: 'State: "{{state.value}}", Context: "{{context.value}}"', + }, + }; + const result = injectActionParams({ + actionParams, + ruleId: '1', + spaceId: 'not-the-default', + actionTypeId: '.email', + }); + expect(result).toMatchInlineSnapshot(` + Object { + "body": Object { + "message": "State: \\"{{state.value}}\\", Context: \\"{{context.value}}\\"", + }, + "kibanaFooterLink": Object { + "path": "/s/not-the-default/app/management/insightsAndAlerting/triggersActions/rule/1", + "text": "View rule in Kibana", }, } `); diff --git a/x-pack/plugins/alerting/server/task_runner/inject_action_params.ts b/x-pack/plugins/alerting/server/task_runner/inject_action_params.ts index 177622867565c..11ac3f92d1071 100644 --- a/x-pack/plugins/alerting/server/task_runner/inject_action_params.ts +++ b/x-pack/plugins/alerting/server/task_runner/inject_action_params.ts @@ -9,25 +9,29 @@ import { i18n } from '@kbn/i18n'; import { AlertActionParams } from '../types'; export interface InjectActionParamsOpts { - alertId: string; + ruleId: string; + spaceId: string | undefined; actionTypeId: string; actionParams: AlertActionParams; } export function injectActionParams({ - alertId, + ruleId, + spaceId, actionTypeId, actionParams, }: InjectActionParamsOpts) { // Inject kibanaFooterLink if action type is email. This is used by the email action type // to inject a "View alert in Kibana" with a URL in the email's footer. if (actionTypeId === '.email') { + const spacePrefix = + spaceId && spaceId.length > 0 && spaceId !== 'default' ? `/s/${spaceId}` : ''; return { ...actionParams, kibanaFooterLink: { - path: `/app/management/insightsAndAlerting/triggersActions/alert/${alertId}`, + path: `${spacePrefix}/app/management/insightsAndAlerting/triggersActions/rule/${ruleId}`, text: i18n.translate('xpack.alerting.injectActionParams.email.kibanaFooterLinkText', { - defaultMessage: 'View alert in Kibana', + defaultMessage: 'View rule in Kibana', }), }, }; From cec62cb7061502da9aea309bfc5fbe9d3da9fc00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20S=C3=A1nchez?= Date: Fri, 28 May 2021 18:07:54 +0200 Subject: [PATCH 71/77] [Security Solution][Endpoint] Add event filters summary card to the fleet endpoint tab (#100668) * Shows event filters card on fleet page * Uses aggs instead of while loop to retrieve summary data * Add request and response types in the lists package * Fixes old import * Removes old i18n keys * Removes more old i18n keys * Use consts for exception lists url and endpoint event filter list id * Uses event filters service to retrieve summary data * Fixes addressed pr comments such as changing the route without underscore, adding aggs type, validating response, and more * Uses useMemo instead of useState to memoize object * Add new e2e test for summart endpoint * Handle api errors on event filters and trusted apps summary api calls * Add api error message to the toast * Fix wrong i18n key * Change span tag by react fragment * Uses styled components instead of modify compontent style directly and small improvements on test -> ts * Adds curls script for summary route Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../src/request/index.ts | 1 + .../index.mock.ts | 17 +++ .../index.test.ts | 126 ++++++++++++++++++ .../summary_exception_list_schema/index.ts | 33 +++++ .../index.mock.ts | 16 +++ .../index.test.ts | 94 +++++++++++++ .../exception_list_summary_schema/index.ts | 21 +++ .../src/response/index.ts | 1 + x-pack/plugins/lists/server/routes/index.ts | 1 + .../lists/server/routes/init_routes.ts | 4 + .../routes/summary_exception_list_route.ts | 76 +++++++++++ .../server/scripts/summary_exception_list.sh | 25 ++++ .../exception_lists/exception_list_client.ts | 12 ++ .../exception_list_client_types.ts | 6 + .../get_exception_list_summary.ts | 93 +++++++++++++ .../server/services/exception_lists/index.ts | 1 + .../common/endpoint/types/index.ts | 10 ++ .../pages/event_filters/service/index.ts | 13 ++ .../event_filters/store/middleware.test.ts | 1 + .../management/pages/event_filters/types.ts | 2 + ...ummary.tsx => exception_items_summary.tsx} | 46 +++---- .../components/fleet_event_filters_card.tsx | 116 ++++++++++++++++ .../components/fleet_trusted_apps_card.tsx | 63 ++++++--- .../components/styled_components.tsx | 24 ++++ .../index.tsx | 4 + .../translations/translations/ja-JP.json | 4 - .../translations/translations/zh-CN.json | 4 - .../security_and_spaces/tests/index.ts | 1 + .../tests/summary_exception_lists.ts | 98 ++++++++++++++ 29 files changed, 857 insertions(+), 56 deletions(-) create mode 100644 packages/kbn-securitysolution-io-ts-list-types/src/request/summary_exception_list_schema/index.mock.ts create mode 100644 packages/kbn-securitysolution-io-ts-list-types/src/request/summary_exception_list_schema/index.test.ts create mode 100644 packages/kbn-securitysolution-io-ts-list-types/src/request/summary_exception_list_schema/index.ts create mode 100644 packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_summary_schema/index.mock.ts create mode 100644 packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_summary_schema/index.test.ts create mode 100644 packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_summary_schema/index.ts create mode 100644 x-pack/plugins/lists/server/routes/summary_exception_list_route.ts create mode 100755 x-pack/plugins/lists/server/scripts/summary_exception_list.sh create mode 100644 x-pack/plugins/lists/server/services/exception_lists/get_exception_list_summary.ts rename x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/{trusted_app_items_summary.tsx => exception_items_summary.tsx} (52%) create mode 100644 x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/fleet_event_filters_card.tsx create mode 100644 x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/styled_components.tsx create mode 100644 x-pack/test/lists_api_integration/security_and_spaces/tests/summary_exception_lists.ts diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/index.ts index 2c71afd9e066e..3d3c41aed5a72 100644 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/index.ts +++ b/packages/kbn-securitysolution-io-ts-list-types/src/request/index.ts @@ -31,6 +31,7 @@ export * from './read_exception_list_item_schema'; export * from './read_exception_list_schema'; export * from './read_list_item_schema'; export * from './read_list_schema'; +export * from './summary_exception_list_schema'; export * from './update_endpoint_list_item_schema'; export * from './update_exception_list_item_schema'; export * from './update_exception_list_item_validation'; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/summary_exception_list_schema/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/summary_exception_list_schema/index.mock.ts new file mode 100644 index 0000000000000..384f093d0884a --- /dev/null +++ b/packages/kbn-securitysolution-io-ts-list-types/src/request/summary_exception_list_schema/index.mock.ts @@ -0,0 +1,17 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { ID, LIST_ID, NAMESPACE_TYPE } from '../../constants/index.mock'; + +import { SummaryExceptionListSchema } from '.'; + +export const getSummaryExceptionListSchemaMock = (): SummaryExceptionListSchema => ({ + id: ID, + list_id: LIST_ID, + namespace_type: NAMESPACE_TYPE, +}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/summary_exception_list_schema/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/summary_exception_list_schema/index.test.ts new file mode 100644 index 0000000000000..ade015b0d26bf --- /dev/null +++ b/packages/kbn-securitysolution-io-ts-list-types/src/request/summary_exception_list_schema/index.test.ts @@ -0,0 +1,126 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { left } from 'fp-ts/lib/Either'; +import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +import { getSummaryExceptionListSchemaMock } from './index.mock'; +import { SummaryExceptionListSchema, summaryExceptionListSchema } from '.'; + +describe('summary_exception_list_schema', () => { + test('it should validate a typical exception list request', () => { + const payload = getSummaryExceptionListSchemaMock(); + const decoded = summaryExceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = foldLeftRight(checked); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should accept an undefined for "id"', () => { + const payload = getSummaryExceptionListSchemaMock(); + delete payload.id; + const decoded = summaryExceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = foldLeftRight(checked); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should accept an undefined for "list_id"', () => { + const payload = getSummaryExceptionListSchemaMock(); + delete payload.list_id; + const decoded = summaryExceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = foldLeftRight(checked); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should accept an undefined for "namespace_type" but default to "single"', () => { + const payload = getSummaryExceptionListSchemaMock(); + delete payload.namespace_type; + const decoded = summaryExceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = foldLeftRight(checked); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(getSummaryExceptionListSchemaMock()); + }); + + test('it should accept an undefined for "id", "list_id", "namespace_type" but default "namespace_type" to "single"', () => { + const payload = getSummaryExceptionListSchemaMock(); + delete payload.id; + delete payload.namespace_type; + delete payload.list_id; + const output = getSummaryExceptionListSchemaMock(); + delete output.id; + delete output.list_id; + const decoded = summaryExceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = foldLeftRight(checked); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(output); + }); + + test('it should accept an undefined for "id", "list_id"', () => { + const payload = getSummaryExceptionListSchemaMock(); + delete payload.id; + delete payload.list_id; + const decoded = summaryExceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = foldLeftRight(checked); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should accept an undefined for "id", "namespace_type" but default "namespace_type" to "single"', () => { + const payload = getSummaryExceptionListSchemaMock(); + delete payload.id; + delete payload.namespace_type; + const output = getSummaryExceptionListSchemaMock(); + delete output.id; + const decoded = summaryExceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = foldLeftRight(checked); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(output); + }); + + test('it should accept an undefined for "list_id", "namespace_type" but default "namespace_type" to "single"', () => { + const payload = getSummaryExceptionListSchemaMock(); + delete payload.namespace_type; + delete payload.list_id; + const output = getSummaryExceptionListSchemaMock(); + delete output.list_id; + const decoded = summaryExceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = foldLeftRight(checked); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(output); + }); + + test('it should not allow an extra key to be sent in', () => { + const payload: SummaryExceptionListSchema & { + extraKey?: string; + } = getSummaryExceptionListSchemaMock(); + payload.extraKey = 'some new value'; + const decoded = summaryExceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = foldLeftRight(checked); + expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); + expect(message.schema).toEqual({}); + }); +}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/summary_exception_list_schema/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/summary_exception_list_schema/index.ts new file mode 100644 index 0000000000000..990091882df7b --- /dev/null +++ b/packages/kbn-securitysolution-io-ts-list-types/src/request/summary_exception_list_schema/index.ts @@ -0,0 +1,33 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import * as t from 'io-ts'; + +import { NamespaceType } from '../../common/default_namespace'; +import { RequiredKeepUndefined } from '../../common/required_keep_undefined'; +import { id } from '../../common/id'; +import { list_id } from '../../common/list_id'; +import { namespace_type } from '../../common/namespace_type'; + +export const summaryExceptionListSchema = t.exact( + t.partial({ + id, + list_id, + namespace_type, // defaults to 'single' if not set during decode + }) +); + +export type SummaryExceptionListSchema = t.OutputOf; + +// This type is used after a decode since some things are defaults after a decode. +export type SummaryExceptionListSchemaDecoded = Omit< + RequiredKeepUndefined>, + 'namespace_type' +> & { + namespace_type: NamespaceType; +}; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_summary_schema/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_summary_schema/index.mock.ts new file mode 100644 index 0000000000000..6b7ce27d07194 --- /dev/null +++ b/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_summary_schema/index.mock.ts @@ -0,0 +1,16 @@ +/* + * 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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { ExceptionListSummarySchema } from '.'; + +export const getListSummaryResponseMock = (): ExceptionListSummarySchema => ({ + windows: 0, + linux: 1, + macos: 2, + total: 3, +}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_summary_schema/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_summary_schema/index.test.ts new file mode 100644 index 0000000000000..ea086f427451d --- /dev/null +++ b/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_summary_schema/index.test.ts @@ -0,0 +1,94 @@ +/* + * 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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { left } from 'fp-ts/lib/Either'; +import { pipe } from 'fp-ts/lib/pipeable'; +import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +import { getListSummaryResponseMock } from './index.mock'; +import { ExceptionListSummarySchema, exceptionListSummarySchema } from '.'; + +describe('list_summary_schema', () => { + test('it should validate a typical list summary response', () => { + const payload = getListSummaryResponseMock(); + const decoded = exceptionListSummarySchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should NOT accept an undefined for "windows"', () => { + const payload = getListSummaryResponseMock(); + // @ts-expect-error + delete payload.windows; + const decoded = exceptionListSummarySchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "windows"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should NOT accept an undefined for "linux"', () => { + const payload = getListSummaryResponseMock(); + // @ts-expect-error + delete payload.linux; + const decoded = exceptionListSummarySchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "linux"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should NOT accept an undefined for "macos"', () => { + const payload = getListSummaryResponseMock(); + // @ts-expect-error + delete payload.macos; + const decoded = exceptionListSummarySchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "macos"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should NOT accept an undefined for "total"', () => { + const payload = getListSummaryResponseMock(); + // @ts-expect-error + delete payload.total; + const decoded = exceptionListSummarySchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "total"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should not allow an extra key to be sent in', () => { + const payload: ExceptionListSummarySchema & { + extraKey?: string; + } = getListSummaryResponseMock(); + payload.extraKey = 'some new value'; + const decoded = exceptionListSummarySchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); + expect(message.schema).toEqual({}); + }); +}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_summary_schema/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_summary_schema/index.ts new file mode 100644 index 0000000000000..4c0cc8301dbf7 --- /dev/null +++ b/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_summary_schema/index.ts @@ -0,0 +1,21 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { PositiveInteger } from '@kbn/securitysolution-io-ts-types'; +import * as t from 'io-ts'; + +export const exceptionListSummarySchema = t.exact( + t.type({ + windows: PositiveInteger, + linux: PositiveInteger, + macos: PositiveInteger, + total: PositiveInteger, + }) +); + +export type ExceptionListSummarySchema = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/response/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/response/index.ts index 005e753ccf1b3..dc29bdf16ab48 100644 --- a/packages/kbn-securitysolution-io-ts-list-types/src/response/index.ts +++ b/packages/kbn-securitysolution-io-ts-list-types/src/response/index.ts @@ -16,5 +16,6 @@ export * from './found_list_item_schema'; export * from './found_list_schema'; export * from './list_item_schema'; export * from './list_schema'; +export * from './exception_list_summary_schema'; export * from './list_item_index_exist_schema'; export * from './search_list_item_schema'; diff --git a/x-pack/plugins/lists/server/routes/index.ts b/x-pack/plugins/lists/server/routes/index.ts index aa6749d179971..f8d4deea344b2 100644 --- a/x-pack/plugins/lists/server/routes/index.ts +++ b/x-pack/plugins/lists/server/routes/index.ts @@ -36,6 +36,7 @@ export * from './read_list_index_route'; export * from './read_list_item_route'; export * from './read_list_route'; export * from './read_privileges_route'; +export * from './summary_exception_list_route'; export * from './update_endpoint_list_item_route'; export * from './update_exception_list_item_route'; export * from './update_exception_list_route'; diff --git a/x-pack/plugins/lists/server/routes/init_routes.ts b/x-pack/plugins/lists/server/routes/init_routes.ts index 430dad953a32f..2511596ca8463 100644 --- a/x-pack/plugins/lists/server/routes/init_routes.ts +++ b/x-pack/plugins/lists/server/routes/init_routes.ts @@ -39,6 +39,7 @@ import { readListItemRoute, readListRoute, readPrivilegesRoute, + summaryExceptionListRoute, updateEndpointListItemRoute, updateExceptionListItemRoute, updateExceptionListRoute, @@ -95,4 +96,7 @@ export const initRoutes = (router: ListsPluginRouter, config: ConfigType): void updateEndpointListItemRoute(router); deleteEndpointListItemRoute(router); findEndpointListItemRoute(router); + + // exception list items summary + summaryExceptionListRoute(router); }; diff --git a/x-pack/plugins/lists/server/routes/summary_exception_list_route.ts b/x-pack/plugins/lists/server/routes/summary_exception_list_route.ts new file mode 100644 index 0000000000000..0db189fb70759 --- /dev/null +++ b/x-pack/plugins/lists/server/routes/summary_exception_list_route.ts @@ -0,0 +1,76 @@ +/* + * 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 { validate } from '@kbn/securitysolution-io-ts-utils'; +import { transformError } from '@kbn/securitysolution-es-utils'; +import { + SummaryExceptionListSchemaDecoded, + exceptionListSummarySchema, + summaryExceptionListSchema, +} from '@kbn/securitysolution-io-ts-list-types'; +import { EXCEPTION_LIST_URL } from '@kbn/securitysolution-list-constants'; + +import type { ListsPluginRouter } from '../types'; + +import { + buildRouteValidation, + buildSiemResponse, + getErrorMessageExceptionList, + getExceptionListClient, +} from './utils'; + +export const summaryExceptionListRoute = (router: ListsPluginRouter): void => { + router.get( + { + options: { + tags: ['access:lists-summary'], + }, + path: `${EXCEPTION_LIST_URL}/summary`, + validate: { + query: buildRouteValidation< + typeof summaryExceptionListSchema, + SummaryExceptionListSchemaDecoded + >(summaryExceptionListSchema), + }, + }, + async (context, request, response) => { + const siemResponse = buildSiemResponse(response); + try { + const { id, list_id: listId, namespace_type: namespaceType } = request.query; + const exceptionLists = getExceptionListClient(context); + if (id != null || listId != null) { + const exceptionListSummary = await exceptionLists.getExceptionListSummary({ + id, + listId, + namespaceType, + }); + if (exceptionListSummary == null) { + return siemResponse.error({ + body: getErrorMessageExceptionList({ id, listId }), + statusCode: 404, + }); + } else { + const [validated, errors] = validate(exceptionListSummary, exceptionListSummarySchema); + if (errors != null) { + return response.ok({ body: exceptionListSummary }); + } else { + return response.ok({ body: validated ?? {} }); + } + } + } else { + return siemResponse.error({ body: 'id or list_id required', statusCode: 400 }); + } + } catch (err) { + const error = transformError(err); + return siemResponse.error({ + body: error.message, + statusCode: error.statusCode, + }); + } + } + ); +}; diff --git a/x-pack/plugins/lists/server/scripts/summary_exception_list.sh b/x-pack/plugins/lists/server/scripts/summary_exception_list.sh new file mode 100755 index 0000000000000..54daeee7cb387 --- /dev/null +++ b/x-pack/plugins/lists/server/scripts/summary_exception_list.sh @@ -0,0 +1,25 @@ +#!/bin/sh + +# +# 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. +# + +set -e +./check_env_variables.sh + + +LIST_ID=${1:-endpoint_list} +NAMESPACE_TYPE=${2-agnostic} + +# First, post a exception list and two list items for the example to work +# ./post_exception_list.sh ./exception_lists/new/exception_list_agnostic.json +# ./post_exception_list_item.sh ./exception_lists/new/exception_list_item_agnostic.json + +# Retrieve exception list stats by os +# Example: ./summary_exception_list.sh endpoint_list agnostic +curl -s -k \ + -u ${ELASTICSEARCH_USERNAME}:${ELASTICSEARCH_PASSWORD} \ + -X GET "${KIBANA_URL}${SPACE_URL}/api/exception_lists/summary?list_id=${LIST_ID}&namespace_type=${NAMESPACE_TYPE}" | jq . diff --git a/x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts b/x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts index 803cd04c1d1b4..4ccff2dd000b9 100644 --- a/x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts +++ b/x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts @@ -9,6 +9,7 @@ import { SavedObjectsClientContract } from 'kibana/server'; import type { ExceptionListItemSchema, ExceptionListSchema, + ExceptionListSummarySchema, FoundExceptionListItemSchema, FoundExceptionListSchema, } from '@kbn/securitysolution-io-ts-list-types'; @@ -31,11 +32,13 @@ import { GetEndpointListItemOptions, GetExceptionListItemOptions, GetExceptionListOptions, + GetExceptionListSummaryOptions, UpdateEndpointListItemOptions, UpdateExceptionListItemOptions, UpdateExceptionListOptions, } from './exception_list_client_types'; import { getExceptionList } from './get_exception_list'; +import { getExceptionListSummary } from './get_exception_list_summary'; import { createExceptionList } from './create_exception_list'; import { getExceptionListItem } from './get_exception_list_item'; import { createExceptionListItem } from './create_exception_list_item'; @@ -72,6 +75,15 @@ export class ExceptionListClient { return getExceptionList({ id, listId, namespaceType, savedObjectsClient }); }; + public getExceptionListSummary = async ({ + listId, + id, + namespaceType, + }: GetExceptionListSummaryOptions): Promise => { + const { savedObjectsClient } = this; + return getExceptionListSummary({ id, listId, namespaceType, savedObjectsClient }); + }; + public getExceptionListItem = async ({ itemId, id, diff --git a/x-pack/plugins/lists/server/services/exception_lists/exception_list_client_types.ts b/x-pack/plugins/lists/server/services/exception_lists/exception_list_client_types.ts index cbbf7f1513444..b734d3a7b1a3b 100644 --- a/x-pack/plugins/lists/server/services/exception_lists/exception_list_client_types.ts +++ b/x-pack/plugins/lists/server/services/exception_lists/exception_list_client_types.ts @@ -56,6 +56,12 @@ export interface GetExceptionListOptions { namespaceType: NamespaceType; } +export interface GetExceptionListSummaryOptions { + listId: ListIdOrUndefined; + id: IdOrUndefined; + namespaceType: NamespaceType; +} + export interface CreateExceptionListOptions { listId: ListId; namespaceType: NamespaceType; diff --git a/x-pack/plugins/lists/server/services/exception_lists/get_exception_list_summary.ts b/x-pack/plugins/lists/server/services/exception_lists/get_exception_list_summary.ts new file mode 100644 index 0000000000000..f5722ea26ccf7 --- /dev/null +++ b/x-pack/plugins/lists/server/services/exception_lists/get_exception_list_summary.ts @@ -0,0 +1,93 @@ +/* + * 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 type { + ExceptionListSummarySchema, + IdOrUndefined, + ListIdOrUndefined, + NamespaceType, +} from '@kbn/securitysolution-io-ts-list-types'; +import { getSavedObjectType } from '@kbn/securitysolution-list-utils'; + +import { + SavedObjectsClientContract, + SavedObjectsErrorHelpers, +} from '../../../../../../src/core/server/'; +import { ExceptionListSoSchema } from '../../schemas/saved_objects'; + +interface GetExceptionListSummaryOptions { + id: IdOrUndefined; + listId: ListIdOrUndefined; + savedObjectsClient: SavedObjectsClientContract; + namespaceType: NamespaceType; +} + +interface ByOsAggBucketType { + key: string; + doc_count: number; +} +interface ByOsAggType { + by_os: { + buckets: ByOsAggBucketType[]; + }; +} + +export const getExceptionListSummary = async ({ + id, + listId, + savedObjectsClient, + namespaceType, +}: GetExceptionListSummaryOptions): Promise => { + const savedObjectType = getSavedObjectType({ namespaceType }); + let finalListId: string = listId ?? ''; + + // If id and no listId, get the list by id to use the list_id for the find below + if (listId === null && id != null) { + try { + const savedObject = await savedObjectsClient.get(savedObjectType, id); + finalListId = savedObject.attributes.list_id; + } catch (err) { + if (SavedObjectsErrorHelpers.isNotFoundError(err)) { + return null; + } else { + throw err; + } + } + } + + const savedObject = await savedObjectsClient.find({ + aggs: { + by_os: { + terms: { + field: `${savedObjectType}.attributes.os_types`, + }, + }, + }, + filter: `${savedObjectType}.attributes.list_type: item`, + perPage: 0, + search: finalListId, + searchFields: ['list_id'], + sortField: 'tie_breaker_id', + sortOrder: 'desc', + type: savedObjectType, + }); + + if (!savedObject.aggregations) { + return null; + } + + const summary: ExceptionListSummarySchema = savedObject.aggregations.by_os.buckets.reduce( + (acc, item: ByOsAggBucketType) => ({ + ...acc, + [item.key]: item.doc_count, + total: acc.total + item.doc_count, + }), + { linux: 0, macos: 0, total: 0, windows: 0 } + ); + + return summary; +}; diff --git a/x-pack/plugins/lists/server/services/exception_lists/index.ts b/x-pack/plugins/lists/server/services/exception_lists/index.ts index 21041b9d5d9bd..e6a6dd7ef8c3c 100644 --- a/x-pack/plugins/lists/server/services/exception_lists/index.ts +++ b/x-pack/plugins/lists/server/services/exception_lists/index.ts @@ -15,5 +15,6 @@ export * from './find_exception_list_item'; export * from './find_exception_list_items'; export * from './get_exception_list'; export * from './get_exception_list_item'; +export * from './get_exception_list_summary'; export * from './update_exception_list'; export * from './update_exception_list_item'; 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 dd0ff540cb4af..c084dd8ca7668 100644 --- a/x-pack/plugins/security_solution/common/endpoint/types/index.ts +++ b/x-pack/plugins/security_solution/common/endpoint/types/index.ts @@ -1095,3 +1095,13 @@ export interface GetAgentSummaryResponse { versions_count: { [key: string]: number }; }; } + +/** + * REST API response for retrieving exception summary + */ +export interface GetExceptionSummaryResponse { + total: number; + windows: number; + macos: number; + linux: number; +} diff --git a/x-pack/plugins/security_solution/public/management/pages/event_filters/service/index.ts b/x-pack/plugins/security_solution/public/management/pages/event_filters/service/index.ts index 8863acaafbf5a..05729c6d1c14d 100644 --- a/x-pack/plugins/security_solution/public/management/pages/event_filters/service/index.ts +++ b/x-pack/plugins/security_solution/public/management/pages/event_filters/service/index.ts @@ -11,6 +11,7 @@ import type { ExceptionListItemSchema, CreateExceptionListItemSchema, UpdateExceptionListItemSchema, + ExceptionListSummarySchema, } from '@kbn/securitysolution-io-ts-list-types'; import { ENDPOINT_EVENT_FILTERS_LIST_ID } from '@kbn/securitysolution-list-constants'; @@ -102,4 +103,16 @@ export class EventFiltersHttpService implements EventFiltersService { }, }); } + + async getSummary(): Promise { + return (await this.httpWrapper()).get( + `${EXCEPTION_LIST_URL}/summary`, + { + query: { + list_id: ENDPOINT_EVENT_FILTERS_LIST_ID, + namespace_type: 'agnostic', + }, + } + ); + } } diff --git a/x-pack/plugins/security_solution/public/management/pages/event_filters/store/middleware.test.ts b/x-pack/plugins/security_solution/public/management/pages/event_filters/store/middleware.test.ts index b55a32a937c45..5229e4078eb0d 100644 --- a/x-pack/plugins/security_solution/public/management/pages/event_filters/store/middleware.test.ts +++ b/x-pack/plugins/security_solution/public/management/pages/event_filters/store/middleware.test.ts @@ -29,6 +29,7 @@ const createEventFiltersServiceMock = (): jest.Mocked => ({ getOne: jest.fn(), updateOne: jest.fn(), deleteOne: jest.fn(), + getSummary: jest.fn(), }); const createStoreSetup = (eventFiltersService: EventFiltersService) => { diff --git a/x-pack/plugins/security_solution/public/management/pages/event_filters/types.ts b/x-pack/plugins/security_solution/public/management/pages/event_filters/types.ts index be6689b7e5b57..3bcf6a3369302 100644 --- a/x-pack/plugins/security_solution/public/management/pages/event_filters/types.ts +++ b/x-pack/plugins/security_solution/public/management/pages/event_filters/types.ts @@ -10,6 +10,7 @@ import type { CreateExceptionListItemSchema, ExceptionListItemSchema, UpdateExceptionListItemSchema, + ExceptionListSummarySchema, } from '@kbn/securitysolution-io-ts-list-types'; import { AsyncResourceState } from '../../state/async_resource_state'; import { Immutable } from '../../../../common/endpoint/types'; @@ -49,6 +50,7 @@ export interface EventFiltersService { getOne(id: string): Promise; updateOne(exception: Immutable): Promise; deleteOne(id: string): Promise; + getSummary(): Promise; } export interface EventFiltersListPageData { diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/trusted_app_items_summary.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/exception_items_summary.tsx similarity index 52% rename from x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/trusted_app_items_summary.tsx rename to x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/exception_items_summary.tsx index fae65def7e2f6..f42304ffb89ae 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/trusted_app_items_summary.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/exception_items_summary.tsx @@ -6,56 +6,45 @@ */ import { EuiBadge, EuiBadgeProps, EuiFlexGroup, EuiFlexItem, EuiText } from '@elastic/eui'; -import React, { FC, memo, useEffect, useState } from 'react'; -import { CoreStart } from 'kibana/public'; +import React, { FC, memo } from 'react'; import { i18n } from '@kbn/i18n'; -import { useKibana } from '../../../../../../../../../../../src/plugins/kibana_react/public'; -import { TrustedAppsHttpService } from '../../../../../trusted_apps/service'; -import { GetTrustedAppsSummaryResponse } from '../../../../../../../../common/endpoint/types'; +import { GetExceptionSummaryResponse } from '../../../../../../../../common/endpoint/types'; -const SUMMARY_KEYS: Readonly> = [ +const SUMMARY_KEYS: Readonly> = [ 'windows', 'macos', 'linux', 'total', ]; -const SUMMARY_LABELS: Readonly<{ [key in keyof GetTrustedAppsSummaryResponse]: string }> = { +const SUMMARY_LABELS: Readonly<{ [key in keyof GetExceptionSummaryResponse]: string }> = { windows: i18n.translate( - 'xpack.securitySolution.endpoint.fleetCustomExtension.trustedAppItemsSummary.windows', + 'xpack.securitySolution.endpoint.fleetCustomExtension.exceptionItemsSummary.windows', { defaultMessage: 'Windows' } ), linux: i18n.translate( - 'xpack.securitySolution.endpoint.fleetCustomExtension.trustedAppItemsSummary.linux', + 'xpack.securitySolution.endpoint.fleetCustomExtension.exceptionItemsSummary.linux', { defaultMessage: 'Linux' } ), macos: i18n.translate( - 'xpack.securitySolution.endpoint.fleetCustomExtension.trustedAppItemsSummary.macos', + 'xpack.securitySolution.endpoint.fleetCustomExtension.exceptionItemsSummary.macos', { defaultMessage: 'Mac' } ), total: i18n.translate( - 'xpack.securitySolution.endpoint.fleetCustomExtension.trustedAppItemsSummary.total', + 'xpack.securitySolution.endpoint.fleetCustomExtension.exceptionItemsSummary.total', { defaultMessage: 'Total' } ), }; const CSS_BOLD: Readonly = { fontWeight: 'bold' }; -export const TrustedAppItemsSummary = memo(() => { - const { - services: { http }, - } = useKibana(); - const [stats, setStats] = useState(); - const [trustedAppsApi] = useState(() => new TrustedAppsHttpService(http)); - - useEffect(() => { - trustedAppsApi.getTrustedAppsSummary().then((response) => { - setStats(response); - }); - }, [trustedAppsApi]); +interface ExceptionItemsSummaryProps { + stats: GetExceptionSummaryResponse | undefined; +} +export const ExceptionItemsSummary = memo(({ stats }) => { return ( - + {SUMMARY_KEYS.map((stat) => { return ( @@ -73,18 +62,13 @@ export const TrustedAppItemsSummary = memo(() => { ); }); -TrustedAppItemsSummary.displayName = 'TrustedAppItemsSummary'; +ExceptionItemsSummary.displayName = 'ExceptionItemsSummary'; const SummaryStat: FC<{ value: number; color?: EuiBadgeProps['color'] }> = memo( ({ children, value, color, ...commonProps }) => { return ( - + {children} diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/fleet_event_filters_card.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/fleet_event_filters_card.tsx new file mode 100644 index 0000000000000..6f368a89eb5f9 --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/fleet_event_filters_card.tsx @@ -0,0 +1,116 @@ +/* + * 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, { memo, useMemo, useState, useEffect } from 'react'; +import { ApplicationStart, CoreStart } from 'kibana/public'; +import { EuiPanel, EuiText } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { + PackageCustomExtensionComponentProps, + pagePathGetters, +} from '../../../../../../../../../fleet/public'; +import { useKibana } from '../../../../../../../../../../../src/plugins/kibana_react/public'; +import { getEventFiltersListPath } from '../../../../../../common/routing'; +import { GetExceptionSummaryResponse } from '../../../../../../../../common/endpoint/types'; +import { PLUGIN_ID as FLEET_PLUGIN_ID } from '../../../../../../../../../fleet/common'; +import { MANAGEMENT_APP_ID } from '../../../../../../common/constants'; +import { useToasts } from '../../../../../../../common/lib/kibana'; +import { LinkWithIcon } from './link_with_icon'; +import { ExceptionItemsSummary } from './exception_items_summary'; +import { EventFiltersHttpService } from '../../../../../event_filters/service'; +import { StyledEuiFlexGridGroup, StyledEuiFlexGridItem } from './styled_components'; + +export const FleetEventFiltersCard = memo(({ pkgkey }) => { + const { + services: { + application: { getUrlForApp }, + http, + }, + } = useKibana(); + const toasts = useToasts(); + const [stats, setStats] = useState(); + const eventFiltersListUrlPath = getEventFiltersListPath(); + const eventFiltersApi = useMemo(() => new EventFiltersHttpService(http), [http]); + + useEffect(() => { + const fetchStats = async () => { + try { + const summary = await eventFiltersApi.getSummary(); + setStats(summary); + } catch (error) { + toasts.addDanger( + i18n.translate( + 'xpack.securitySolution.endpoint.fleetCustomExtension.eventFiltersSummaryError', + { + defaultMessage: 'There was an error trying to fetch event filters stats: "{error}"', + values: { error }, + } + ) + ); + } + }; + fetchStats(); + }, [eventFiltersApi, toasts]); + + const eventFiltersRouteState = useMemo(() => { + const fleetPackageCustomUrlPath = `#${pagePathGetters.integration_details_custom({ pkgkey })}`; + return { + backButtonLabel: i18n.translate( + 'xpack.securitySolution.endpoint.fleetCustomExtension.backButtonLabel', + { defaultMessage: 'Back to Endpoint Integration' } + ), + onBackButtonNavigateTo: [ + FLEET_PLUGIN_ID, + { + path: fleetPackageCustomUrlPath, + }, + ], + backButtonUrl: getUrlForApp(FLEET_PLUGIN_ID, { + path: fleetPackageCustomUrlPath, + }), + }; + }, [getUrlForApp, pkgkey]); + + return ( + + + + +

    + +

    + + + + + + + <> + + + + + + + + ); +}); + +FleetEventFiltersCard.displayName = 'FleetEventFiltersCard'; diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/fleet_trusted_apps_card.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/fleet_trusted_apps_card.tsx index fe6f82e632f73..ec1479643999a 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/fleet_trusted_apps_card.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/fleet_trusted_apps_card.tsx @@ -5,9 +5,9 @@ * 2.0. */ -import React, { memo, useMemo } from 'react'; -import { ApplicationStart } from 'kibana/public'; -import { EuiFlexGroup, EuiFlexItem, EuiPanel, EuiText } from '@elastic/eui'; +import React, { memo, useMemo, useState, useEffect } from 'react'; +import { ApplicationStart, CoreStart } from 'kibana/public'; +import { EuiPanel, EuiText } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import { @@ -16,19 +16,48 @@ import { } from '../../../../../../../../../fleet/public'; import { useKibana } from '../../../../../../../../../../../src/plugins/kibana_react/public'; import { getTrustedAppsListPath } from '../../../../../../common/routing'; -import { TrustedAppsListPageRouteState } from '../../../../../../../../common/endpoint/types'; +import { + TrustedAppsListPageRouteState, + GetExceptionSummaryResponse, +} from '../../../../../../../../common/endpoint/types'; import { PLUGIN_ID as FLEET_PLUGIN_ID } from '../../../../../../../../../fleet/common'; import { MANAGEMENT_APP_ID } from '../../../../../../common/constants'; +import { useToasts } from '../../../../../../../common/lib/kibana'; import { LinkWithIcon } from './link_with_icon'; -import { TrustedAppItemsSummary } from './trusted_app_items_summary'; +import { ExceptionItemsSummary } from './exception_items_summary'; +import { TrustedAppsHttpService } from '../../../../../trusted_apps/service'; +import { StyledEuiFlexGridGroup, StyledEuiFlexGridItem } from './styled_components'; export const FleetTrustedAppsCard = memo(({ pkgkey }) => { const { services: { application: { getUrlForApp }, + http, }, - } = useKibana<{ application: ApplicationStart }>(); + } = useKibana(); + const toasts = useToasts(); + const [stats, setStats] = useState(); + const trustedAppsApi = useMemo(() => new TrustedAppsHttpService(http), [http]); + useEffect(() => { + const fetchStats = async () => { + try { + const response = await trustedAppsApi.getTrustedAppsSummary(); + setStats(response); + } catch (error) { + toasts.addDanger( + i18n.translate( + 'xpack.securitySolution.endpoint.fleetCustomExtension.trustedAppsSummaryError', + { + defaultMessage: 'There was an error trying to fetch trusted apps stats: "{error}"', + values: { error }, + } + ) + ); + } + }; + fetchStats(); + }, [toasts, trustedAppsApi]); const trustedAppsListUrlPath = getTrustedAppsListPath(); const trustedAppRouteState = useMemo(() => { @@ -52,8 +81,8 @@ export const FleetTrustedAppsCard = memo(( return ( - - + +

    (( />

    -
    - - - - - + + + + + + <> (( defaultMessage="Manage trusted applications" /> - - -
    + + +
    ); }); diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/styled_components.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/styled_components.tsx new file mode 100644 index 0000000000000..8791f7fa87283 --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/styled_components.tsx @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import styled from 'styled-components'; +import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; + +export const StyledEuiFlexGridGroup = styled(EuiFlexGroup)` + display: grid; + grid-template-columns: 25% 45% 30%; + grid-template-areas: 'title summary link'; +`; + +export const StyledEuiFlexGridItem = styled(EuiFlexItem)<{ + gridArea: string; + alignItems?: string; +}>` + grid-area: ${({ gridArea }) => gridArea}; + align-items: ${({ alignItems }) => alignItems ?? 'center'}; + margin: 0px; + padding: 12px; +`; diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/index.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/index.tsx index c127a60d84ccf..094f1131d7034 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/index.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/index.tsx @@ -5,15 +5,19 @@ * 2.0. */ +import { EuiSpacer } from '@elastic/eui'; import React, { memo } from 'react'; import { PackageCustomExtensionComponentProps } from '../../../../../../../../fleet/public'; import { FleetTrustedAppsCard } from './components/fleet_trusted_apps_card'; +import { FleetEventFiltersCard } from './components/fleet_event_filters_card'; export const EndpointPackageCustomExtension = memo( (props) => { return (
    + +
    ); } diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 55a38353cba13..fe77b3823ba44 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -20462,10 +20462,6 @@ "xpack.securitySolution.endpoint.details.policyStatusValue": "{policyStatus, select, success {成功} warning {警告} failure {失敗} other {不明}}", "xpack.securitySolution.endpoint.fleetCustomExtension.backButtonLabel": "エンドポイント統合に戻る", "xpack.securitySolution.endpoint.fleetCustomExtension.manageTrustedAppLinkLabel": "信頼できるアプリケーションを管理", - "xpack.securitySolution.endpoint.fleetCustomExtension.trustedAppItemsSummary.linux": "Linux", - "xpack.securitySolution.endpoint.fleetCustomExtension.trustedAppItemsSummary.macos": "Mac", - "xpack.securitySolution.endpoint.fleetCustomExtension.trustedAppItemsSummary.total": "合計", - "xpack.securitySolution.endpoint.fleetCustomExtension.trustedAppItemsSummary.windows": "Windows", "xpack.securitySolution.endpoint.fleetCustomExtension.trustedAppsLabel": "信頼できるアプリケーション", "xpack.securitySolution.endpoint.ingestManager.createPackagePolicy.endpointConfiguration": "推奨のデフォルト値で統合が保存されます。後からこれを変更するには、エージェントポリシー内で Endpoint Security 統合を編集します。", "xpack.securitySolution.endpoint.ingestToastMessage": "Fleetが設定中に失敗しました。", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 972e3ff299b75..9e7996ec09d92 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -20762,10 +20762,6 @@ "xpack.securitySolution.endpoint.details.policyStatusValue": "{policyStatus, select, success {成功} warning {警告} failure {失败} other {未知}}", "xpack.securitySolution.endpoint.fleetCustomExtension.backButtonLabel": "返回至终端集成", "xpack.securitySolution.endpoint.fleetCustomExtension.manageTrustedAppLinkLabel": "管理受信任的应用程序", - "xpack.securitySolution.endpoint.fleetCustomExtension.trustedAppItemsSummary.linux": "Linux", - "xpack.securitySolution.endpoint.fleetCustomExtension.trustedAppItemsSummary.macos": "Mac", - "xpack.securitySolution.endpoint.fleetCustomExtension.trustedAppItemsSummary.total": "合计", - "xpack.securitySolution.endpoint.fleetCustomExtension.trustedAppItemsSummary.windows": "Windows", "xpack.securitySolution.endpoint.fleetCustomExtension.trustedAppsLabel": "受信任的应用程序", "xpack.securitySolution.endpoint.ingestManager.createPackagePolicy.endpointConfiguration": "我们将使用建议的默认值保存您的集成。稍后,您可以通过在代理策略中编辑 Endpoint Security 集成对其进行更改。", "xpack.securitySolution.endpoint.ingestToastMessage": "Fleet 在设置期间失败。", diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/index.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/index.ts index 61ca693936643..89a1183da6790 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/index.ts +++ b/x-pack/test/lists_api_integration/security_and_spaces/tests/index.ts @@ -35,5 +35,6 @@ export default ({ loadTestFile }: FtrProviderContext): void => { loadTestFile(require.resolve('./find_exception_lists')); loadTestFile(require.resolve('./find_exception_list_items')); loadTestFile(require.resolve('./read_list_privileges')); + loadTestFile(require.resolve('./summary_exception_lists')); }); }; diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/summary_exception_lists.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/summary_exception_lists.ts new file mode 100644 index 0000000000000..13ba7da4c7aaa --- /dev/null +++ b/x-pack/test/lists_api_integration/security_and_spaces/tests/summary_exception_lists.ts @@ -0,0 +1,98 @@ +/* + * 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 expect from '@kbn/expect'; + +import { ExceptionListSummarySchema } from '@kbn/securitysolution-io-ts-list-types'; +import { EXCEPTION_LIST_URL, EXCEPTION_LIST_ITEM_URL } from '@kbn/securitysolution-list-constants'; +import { LIST_ID } from '../../../../plugins/lists/common/constants.mock'; +import { FtrProviderContext } from '../../common/ftr_provider_context'; +import { getCreateExceptionListMinimalSchemaMock } from '../../../../plugins/lists/common/schemas/request/create_exception_list_schema.mock'; +import { getCreateExceptionListItemMinimalSchemaMock } from '../../../../plugins/lists/common/schemas/request/create_exception_list_item_schema.mock'; +import { createListsIndex, deleteListsIndex, deleteAllExceptions } from '../../utils'; + +interface SummaryResponseType { + body: ExceptionListSummarySchema; +} +// eslint-disable-next-line import/no-default-export +export default ({ getService }: FtrProviderContext) => { + const supertest = getService('supertest'); + const es = getService('es'); + + describe('summary_exception_lists', () => { + describe('summary exception lists', () => { + beforeEach(async () => { + await createListsIndex(supertest); + }); + afterEach(async () => { + await deleteListsIndex(supertest); + await deleteAllExceptions(es); + }); + + it('should give a validation error if the list_id and the id are not supplied', async () => { + const { body } = await supertest + .get(`${EXCEPTION_LIST_URL}/summary`) + .set('kbn-xsrf', 'true') + .send(getCreateExceptionListMinimalSchemaMock()) + .expect(400); + + expect(body).to.eql({ + message: 'id or list_id required', + status_code: 400, + }); + }); + + it('should return init summary when there are no items created', async () => { + const { body }: SummaryResponseType = await supertest + .get(`${EXCEPTION_LIST_URL}/summary?list_id=${LIST_ID}`) + .set('kbn-xsrf', 'true') + .send() + .expect(200); + + const expected: ExceptionListSummarySchema = { + linux: 0, + macos: 0, + total: 0, + windows: 0, + }; + expect(body).to.eql(expected); + }); + + it('should return right summary when there are items created', async () => { + await supertest + .post(EXCEPTION_LIST_URL) + .set('kbn-xsrf', 'true') + .send(getCreateExceptionListMinimalSchemaMock()) + .expect(200); + + const item = getCreateExceptionListItemMinimalSchemaMock(); + + for (const os of ['windows', 'linux', 'macos']) { + await supertest + .post(EXCEPTION_LIST_ITEM_URL) + .set('kbn-xsrf', 'true') + .send({ ...item, os_types: [os], item_id: `${item.item_id}-${os}` }) + .expect(200); + } + + const { body }: SummaryResponseType = await supertest + .get(`${EXCEPTION_LIST_URL}/summary?list_id=${LIST_ID}`) + .set('kbn-xsrf', 'true') + .send() + .expect(200); + + const expected: ExceptionListSummarySchema = { + linux: 1, + macos: 1, + total: 3, + windows: 1, + }; + expect(body).to.eql(expected); + }); + }); + }); +}; From a00fa5300076e394d0da42e4bbcd5b3ac9cb2aaf Mon Sep 17 00:00:00 2001 From: Nathan L Smith Date: Fri, 28 May 2021 11:10:14 -0500 Subject: [PATCH 72/77] Fix bug with Observability > APM header navigation (#100845) Call `setHeaderActionMenu(undefined)` when the HeaderMenuPortal is unmounted. Found this line in the docs: > Calling the handler with `undefined` will unmount the current mount point. Which we weren't doing before. Previous behavior: * Go to /app/observability/alerts * Click the "View in app" button for an APM alert * Click back * Click the "View in app" button for an APM alert * Get a weird toast error message and the header menu is gone forever Now: * Go to /app/observability/alerts * Click the "View in app" button for an APM alert * Click back * Click the "View in app" button for an APM alert * Get a working header menu Fixes #97140 --- .../shared/header_menu_portal.test.tsx | 26 +++++++++++++++++++ .../components/shared/header_menu_portal.tsx | 7 ++--- .../public/pages/alerts/alerts.stories.tsx | 6 ++++- 3 files changed, 33 insertions(+), 6 deletions(-) create mode 100644 x-pack/plugins/observability/public/components/shared/header_menu_portal.test.tsx diff --git a/x-pack/plugins/observability/public/components/shared/header_menu_portal.test.tsx b/x-pack/plugins/observability/public/components/shared/header_menu_portal.test.tsx new file mode 100644 index 0000000000000..4e9a1ae2c587f --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/header_menu_portal.test.tsx @@ -0,0 +1,26 @@ +/* + * 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 { render } from '@testing-library/react'; +import React from 'react'; +import HeaderMenuPortal from './header_menu_portal'; + +describe('HeaderMenuPortal', () => { + describe('when unmounted', () => { + it('calls setHeaderActionMenu with undefined', () => { + const setHeaderActionMenu = jest.fn(); + + const { unmount } = render( + test + ); + + unmount(); + + expect(setHeaderActionMenu).toHaveBeenCalledWith(undefined); + }); + }); +}); diff --git a/x-pack/plugins/observability/public/components/shared/header_menu_portal.tsx b/x-pack/plugins/observability/public/components/shared/header_menu_portal.tsx index 54949c1d860d8..6c3b558c5e61d 100644 --- a/x-pack/plugins/observability/public/components/shared/header_menu_portal.tsx +++ b/x-pack/plugins/observability/public/components/shared/header_menu_portal.tsx @@ -15,17 +15,14 @@ export default function HeaderMenuPortal({ children, setHeaderActionMenu }: Head const portalNode = useMemo(() => createPortalNode(), []); useEffect(() => { - let unmount = () => {}; - setHeaderActionMenu((element) => { const mount = toMountPoint(); - unmount = mount(element); - return unmount; + return mount(element); }); return () => { portalNode.unmount(); - unmount(); + setHeaderActionMenu(undefined); }; }, [portalNode, setHeaderActionMenu]); diff --git a/x-pack/plugins/observability/public/pages/alerts/alerts.stories.tsx b/x-pack/plugins/observability/public/pages/alerts/alerts.stories.tsx index 0d47f3da89d36..ba714a679f1e5 100644 --- a/x-pack/plugins/observability/public/pages/alerts/alerts.stories.tsx +++ b/x-pack/plugins/observability/public/pages/alerts/alerts.stories.tsx @@ -11,7 +11,10 @@ import { IntlProvider } from 'react-intl'; import { MemoryRouter } from 'react-router-dom'; import { AlertsPage } from '.'; import { HttpSetup } from '../../../../../../src/core/public'; -import { KibanaContextProvider } from '../../../../../../src/plugins/kibana_react/public'; +import { + KibanaContextProvider, + KibanaPageTemplate, +} from '../../../../../../src/plugins/kibana_react/public'; import { PluginContext, PluginContextValue } from '../../context/plugin_context'; import { createObservabilityRuleTypeRegistryMock } from '../../rules/observability_rule_type_registry_mock'; import { createCallObservabilityApi } from '../../services/call_observability_api'; @@ -63,6 +66,7 @@ export default { http: { basePath: { prepend: (_: string) => '' } }, }, observabilityRuleTypeRegistry: createObservabilityRuleTypeRegistryMock(), + ObservabilityPageTemplate: KibanaPageTemplate, } as unknown) as PluginContextValue } > From 692806aed82a35fc922a5f6817cf71d9da6f4bc5 Mon Sep 17 00:00:00 2001 From: Jonathan Buttner <56361221+jonathan-buttner@users.noreply.github.com> Date: Fri, 28 May 2021 12:21:34 -0400 Subject: [PATCH 73/77] Fixing ES archive mapping failure (#100835) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../es_archives/endpoint/resolver/signals/mappings.json | 9 +-------- .../endpoint/resolver/winlogbeat/mappings.json | 9 +-------- .../apis/resolver/entity.ts | 3 +-- 3 files changed, 3 insertions(+), 18 deletions(-) diff --git a/x-pack/test/functional/es_archives/endpoint/resolver/signals/mappings.json b/x-pack/test/functional/es_archives/endpoint/resolver/signals/mappings.json index 3c6042e8efd24..cb846a489bd70 100644 --- a/x-pack/test/functional/es_archives/endpoint/resolver/signals/mappings.json +++ b/x-pack/test/functional/es_archives/endpoint/resolver/signals/mappings.json @@ -3235,14 +3235,7 @@ } }, "number_of_replicas": "1", - "number_of_shards": "1", - "routing": { - "allocation": { - "include": { - "_tier": "data_hot" - } - } - } + "number_of_shards": "1" } } } diff --git a/x-pack/test/functional/es_archives/endpoint/resolver/winlogbeat/mappings.json b/x-pack/test/functional/es_archives/endpoint/resolver/winlogbeat/mappings.json index a8673d85c3061..e4c02e0acd6e3 100644 --- a/x-pack/test/functional/es_archives/endpoint/resolver/winlogbeat/mappings.json +++ b/x-pack/test/functional/es_archives/endpoint/resolver/winlogbeat/mappings.json @@ -2920,14 +2920,7 @@ } }, "number_of_replicas": "1", - "number_of_shards": "1", - "routing": { - "allocation": { - "include": { - "_tier": "data_hot" - } - } - } + "number_of_shards": "1" } } } diff --git a/x-pack/test/security_solution_endpoint_api_int/apis/resolver/entity.ts b/x-pack/test/security_solution_endpoint_api_int/apis/resolver/entity.ts index 534cb12c3fc65..3cca9213b4554 100644 --- a/x-pack/test/security_solution_endpoint_api_int/apis/resolver/entity.ts +++ b/x-pack/test/security_solution_endpoint_api_int/apis/resolver/entity.ts @@ -14,8 +14,7 @@ export default function ({ getService }: FtrProviderContext) { const supertest = getService('supertest'); const esArchiver = getService('esArchiver'); - // FAILING ES PROMOTION: https://github.com/elastic/kibana/issues/100697 - describe.skip('Resolver tests for the entity route', () => { + describe('Resolver tests for the entity route', () => { describe('winlogbeat tests', () => { before(async () => { await esArchiver.load('endpoint/resolver/winlogbeat'); From 5dbec05289320bd40eb269a69af0e1d407b034a3 Mon Sep 17 00:00:00 2001 From: Pete Harverson Date: Fri, 28 May 2021 17:43:44 +0100 Subject: [PATCH 74/77] [ML] Fix categorization job view examples link when datafeed uses multiple indices (#100789) * [ML] Fix categorization job view examples link when datafeed uses multiple indices * [ML] Fix operator in index pattern check Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../components/anomalies_table/links_menu.js | 3 ++- .../jobs/components/custom_url_editor/utils.js | 16 +++++----------- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/x-pack/plugins/ml/public/application/components/anomalies_table/links_menu.js b/x-pack/plugins/ml/public/application/components/anomalies_table/links_menu.js index 7339b50d4ab34..262daae9d6469 100644 --- a/x-pack/plugins/ml/public/application/components/anomalies_table/links_menu.js +++ b/x-pack/plugins/ml/public/application/components/anomalies_table/links_menu.js @@ -232,6 +232,7 @@ class LinksMenuUI extends Component { } const categorizationFieldName = job.analysis_config.categorization_field_name; const datafeedIndices = job.datafeed_config.indices; + // Find the type of the categorization field i.e. text (preferred) or keyword. // Uses the first matching field found in the list of indices in the datafeed_config. // attempt to load the field type using each index. we have to do it this way as _field_caps @@ -349,7 +350,7 @@ class LinksMenuUI extends Component { getFieldTypeFromMapping(index, categorizationFieldName) .then((resp) => { if (resp !== '') { - createAndOpenUrl(index, resp); + createAndOpenUrl(datafeedIndices.join(), resp); } else { i++; if (i < datafeedIndices.length) { diff --git a/x-pack/plugins/ml/public/application/jobs/components/custom_url_editor/utils.js b/x-pack/plugins/ml/public/application/jobs/components/custom_url_editor/utils.js index 75bc93c8dc65e..9da97f40f5ec6 100644 --- a/x-pack/plugins/ml/public/application/jobs/components/custom_url_editor/utils.js +++ b/x-pack/plugins/ml/public/application/jobs/components/custom_url_editor/utils.js @@ -15,6 +15,7 @@ import { DASHBOARD_APP_URL_GENERATOR } from '../../../../../../../../src/plugins import { getPartitioningFieldNames } from '../../../../../common/util/job_utils'; import { parseInterval } from '../../../../../common/util/parse_interval'; import { replaceTokensInUrlValue, isValidLabel } from '../../../util/custom_url_utils'; +import { getIndexPatternIdFromName } from '../../../util/index_utils'; import { ml } from '../../../services/ml_api_service'; import { mlJobService } from '../../../services/job_service'; import { escapeForElasticsearchQuery } from '../../../util/string_utils'; @@ -38,7 +39,7 @@ export function getNewCustomUrlDefaults(job, dashboards, indexPatterns) { } // For the Discover option, set the default index pattern to that - // which matches the (first) index configured in the job datafeed. + // which matches the indices configured in the job datafeed. const datafeedConfig = job.datafeed_config; if ( indexPatterns !== undefined && @@ -47,16 +48,9 @@ export function getNewCustomUrlDefaults(job, dashboards, indexPatterns) { datafeedConfig.indices !== undefined && datafeedConfig.indices.length > 0 ) { - const datafeedIndex = datafeedConfig.indices[0]; - let defaultIndexPattern = indexPatterns.find((indexPattern) => { - return indexPattern.title === datafeedIndex; - }); - - if (defaultIndexPattern === undefined) { - defaultIndexPattern = indexPatterns[0]; - } - - kibanaSettings.discoverIndexPatternId = defaultIndexPattern.id; + const defaultIndexPatternId = + getIndexPatternIdFromName(datafeedConfig.indices.join()) ?? indexPatterns[0].id; + kibanaSettings.discoverIndexPatternId = defaultIndexPatternId; } return { From 4989ec266b6f914acc4435dea7c728b2b576d7e1 Mon Sep 17 00:00:00 2001 From: Bhavya RM Date: Fri, 28 May 2021 13:04:59 -0400 Subject: [PATCH 75/77] updating the saved objects test to include more saved object types (#100828) --- .../exports/_7.12_import_saved_objects.ndjson | 34 --------- .../exports/_7.13_import_saved_objects.ndjson | 72 +++++++++++++++++++ .../import_saved_objects_between_versions.ts | 10 +-- 3 files changed, 77 insertions(+), 39 deletions(-) delete mode 100644 x-pack/test/functional/apps/saved_objects_management/exports/_7.12_import_saved_objects.ndjson create mode 100644 x-pack/test/functional/apps/saved_objects_management/exports/_7.13_import_saved_objects.ndjson diff --git a/x-pack/test/functional/apps/saved_objects_management/exports/_7.12_import_saved_objects.ndjson b/x-pack/test/functional/apps/saved_objects_management/exports/_7.12_import_saved_objects.ndjson deleted file mode 100644 index 5fe0c303668db..0000000000000 --- a/x-pack/test/functional/apps/saved_objects_management/exports/_7.12_import_saved_objects.ndjson +++ /dev/null @@ -1,34 +0,0 @@ -{"attributes":{"fieldAttrs":"{\"machine.os\":{\"count\":1},\"spaces\":{\"count\":1},\"type\":{\"count\":1},\"bytes_scripted\":{\"count\":1}}","fields":"[{\"count\":1,\"script\":\"doc['bytes'].value*1024\",\"lang\":\"painless\",\"name\":\"bytes_scripted\",\"type\":\"number\",\"scripted\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false}]","runtimeFieldMap":"{}","timeFieldName":"@timestamp","title":"logstash-*"},"coreMigrationVersion":"7.12.1","id":"56b34100-619d-11eb-aebf-c306684b328d","migrationVersion":{"index-pattern":"7.11.0"},"references":[],"sort":[1617218924557,0],"type":"index-pattern","updated_at":"2021-03-31T19:28:44.557Z","version":"WzksMV0="} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"title":"logstash_scriptedfieldviz","uiStateJSON":"{\"vis\":{\"defaultColors\":{\"0 - 100\":\"rgb(0,104,55)\"}}}","version":1,"visState":"{\"title\":\"logstash_scriptedfieldviz\",\"type\":\"goal\",\"params\":{\"addTooltip\":true,\"addLegend\":false,\"isDisplayWarning\":false,\"type\":\"gauge\",\"gauge\":{\"verticalSplit\":false,\"autoExtend\":false,\"percentageMode\":true,\"gaugeType\":\"Arc\",\"gaugeStyle\":\"Full\",\"backStyle\":\"Full\",\"orientation\":\"vertical\",\"useRanges\":false,\"colorSchema\":\"Green to Red\",\"gaugeColorMode\":\"None\",\"colorsRange\":[{\"from\":0,\"to\":10000}],\"invertColors\":false,\"labels\":{\"show\":true,\"color\":\"black\"},\"scale\":{\"show\":false,\"labels\":false,\"color\":\"#333\",\"width\":2},\"type\":\"meter\",\"style\":{\"bgFill\":\"#000\",\"bgColor\":false,\"labelColor\":false,\"subText\":\"\",\"fontSize\":60}}},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"enabled\":true,\"type\":\"range\",\"schema\":\"group\",\"params\":{\"field\":\"bytes_scripted\",\"ranges\":[{\"from\":0,\"to\":40000},{\"from\":40001,\"to\":20000000}]}}]}"},"coreMigrationVersion":"7.12.1","id":"0a274320-61cc-11eb-aebf-c306684b328d","migrationVersion":{"visualization":"7.12.0"},"references":[{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"sort":[1617218952314,184],"type":"visualization","updated_at":"2021-03-31T19:29:12.314Z","version":"WzY3LDFd"} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"title":"logstash_datatable","uiStateJSON":"{\"vis\":{\"params\":{\"sort\":{\"columnIndex\":null,\"direction\":null}}}}","version":1,"visState":"{\"title\":\"logstash_datatable\",\"type\":\"table\",\"params\":{\"perPage\":10,\"showPartialRows\":false,\"showMetricsAtAllLevels\":false,\"sort\":{\"columnIndex\":null,\"direction\":null},\"showTotal\":true,\"totalFunc\":\"sum\",\"showToolbar\":true},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"enabled\":true,\"type\":\"date_histogram\",\"schema\":\"bucket\",\"params\":{\"field\":\"@timestamp\",\"timeRange\":{\"from\":\"2015-07-24T08:58:14.175Z\",\"to\":\"2015-11-11T13:28:17.223Z\",\"mode\":\"absolute\"},\"useNormalizedEsInterval\":true,\"interval\":\"auto\",\"drop_partials\":false,\"min_doc_count\":1,\"extended_bounds\":{}}},{\"id\":\"3\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"bucket\",\"params\":{\"field\":\"response.raw\",\"size\":10,\"order\":\"desc\",\"orderBy\":\"1\",\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\"}}]}"},"coreMigrationVersion":"7.12.1","id":"0d8a8860-623a-11eb-aebf-c306684b328d","migrationVersion":{"visualization":"7.12.0"},"references":[{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"sort":[1617218938927,33],"type":"visualization","updated_at":"2021-03-31T19:28:58.927Z","version":"WzM5LDFd"} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"title":"logstash_area_chart","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"logstash_area_chart\",\"type\":\"area\",\"params\":{\"type\":\"area\",\"grid\":{\"categoryLines\":false,\"style\":{\"color\":\"#eee\"}},\"categoryAxes\":[{\"id\":\"CategoryAxis-1\",\"type\":\"category\",\"position\":\"bottom\",\"show\":true,\"style\":{},\"scale\":{\"type\":\"linear\"},\"labels\":{\"show\":true,\"truncate\":100,\"filter\":true},\"title\":{}}],\"valueAxes\":[{\"id\":\"ValueAxis-1\",\"name\":\"LeftAxis-1\",\"type\":\"value\",\"position\":\"left\",\"show\":true,\"style\":{},\"scale\":{\"type\":\"linear\",\"mode\":\"normal\"},\"labels\":{\"show\":true,\"rotate\":0,\"filter\":false,\"truncate\":100},\"title\":{\"text\":\"Count\"}}],\"seriesParams\":[{\"show\":\"true\",\"type\":\"area\",\"mode\":\"stacked\",\"data\":{\"label\":\"Count\",\"id\":\"1\"},\"drawLinesBetweenPoints\":true,\"showCircles\":true,\"interpolate\":\"linear\",\"valueAxis\":\"ValueAxis-1\"}],\"addTooltip\":true,\"addLegend\":true,\"legendPosition\":\"right\",\"times\":[],\"addTimeMarker\":false,\"palette\":{\"type\":\"palette\",\"name\":\"kibana_palette\"},\"isVislibVis\":true,\"detailedTooltip\":true,\"fittingFunction\":\"zero\"},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"enabled\":true,\"type\":\"date_histogram\",\"schema\":\"segment\",\"params\":{\"field\":\"@timestamp\",\"timeRange\":{\"from\":\"2010-01-28T19:25:55.242Z\",\"to\":\"2021-01-28T19:40:55.242Z\",\"mode\":\"absolute\"},\"useNormalizedEsInterval\":true,\"interval\":\"auto\",\"drop_partials\":false,\"min_doc_count\":1,\"extended_bounds\":{}}},{\"id\":\"3\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"group\",\"params\":{\"field\":\"machine.os.raw\",\"size\":5,\"order\":\"desc\",\"orderBy\":\"1\",\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"customLabel\":\"machine OS\"}}]}"},"coreMigrationVersion":"7.12.1","id":"36b91810-6239-11eb-aebf-c306684b328d","migrationVersion":{"visualization":"7.12.0"},"references":[{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"sort":[1617218930707,21],"type":"visualization","updated_at":"2021-03-31T19:28:50.707Z","version":"WzIzLDFd"} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"title":"logstash_horizontal","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"logstash_horizontal\",\"type\":\"horizontal_bar\",\"params\":{\"type\":\"histogram\",\"grid\":{\"categoryLines\":false,\"style\":{\"color\":\"#eee\"}},\"categoryAxes\":[{\"id\":\"CategoryAxis-1\",\"type\":\"category\",\"position\":\"left\",\"show\":true,\"style\":{},\"scale\":{\"type\":\"linear\"},\"labels\":{\"show\":true,\"rotate\":0,\"filter\":false,\"truncate\":200},\"title\":{}}],\"valueAxes\":[{\"id\":\"ValueAxis-1\",\"name\":\"LeftAxis-1\",\"type\":\"value\",\"position\":\"bottom\",\"show\":true,\"style\":{},\"scale\":{\"type\":\"linear\",\"mode\":\"normal\"},\"labels\":{\"show\":true,\"rotate\":75,\"filter\":true,\"truncate\":100},\"title\":{\"text\":\"no of documents\"}}],\"seriesParams\":[{\"show\":true,\"type\":\"histogram\",\"mode\":\"normal\",\"data\":{\"label\":\"no of documents\",\"id\":\"1\"},\"valueAxis\":\"ValueAxis-1\",\"drawLinesBetweenPoints\":true,\"showCircles\":true}],\"addTooltip\":true,\"addLegend\":true,\"legendPosition\":\"right\",\"times\":[],\"addTimeMarker\":true,\"palette\":{\"type\":\"palette\",\"name\":\"kibana_palette\"},\"isVislibVis\":true,\"detailedTooltip\":true},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{\"customLabel\":\"no of documents\"}},{\"id\":\"2\",\"enabled\":true,\"type\":\"date_histogram\",\"schema\":\"segment\",\"params\":{\"field\":\"@timestamp\",\"timeRange\":{\"from\":\"2015-07-24T08:58:14.175Z\",\"to\":\"2015-11-11T13:28:17.223Z\",\"mode\":\"absolute\"},\"useNormalizedEsInterval\":true,\"interval\":\"auto\",\"drop_partials\":false,\"min_doc_count\":1,\"extended_bounds\":{}}},{\"id\":\"3\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"group\",\"params\":{\"field\":\"agent.raw\",\"size\":5,\"order\":\"desc\",\"orderBy\":\"1\",\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\"}},{\"id\":\"4\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"group\",\"params\":{\"field\":\"extension.raw\",\"size\":5,\"order\":\"desc\",\"orderBy\":\"1\",\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\"}}]}"},"coreMigrationVersion":"7.12.1","id":"e4aef350-623d-11eb-aebf-c306684b328d","migrationVersion":{"visualization":"7.12.0"},"references":[{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"sort":[1617218932758,19],"type":"visualization","updated_at":"2021-03-31T19:28:52.758Z","version":"WzI3LDFd"} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"title":"logstash_linechart","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"logstash_linechart\",\"type\":\"line\",\"params\":{\"type\":\"line\",\"grid\":{\"categoryLines\":false,\"style\":{\"color\":\"#eee\"}},\"categoryAxes\":[{\"id\":\"CategoryAxis-1\",\"type\":\"category\",\"position\":\"bottom\",\"show\":true,\"style\":{},\"scale\":{\"type\":\"linear\"},\"labels\":{\"show\":true,\"truncate\":100,\"filter\":true},\"title\":{}}],\"valueAxes\":[{\"id\":\"ValueAxis-1\",\"name\":\"LeftAxis-1\",\"type\":\"value\",\"position\":\"left\",\"show\":true,\"style\":{},\"scale\":{\"type\":\"linear\",\"mode\":\"normal\"},\"labels\":{\"show\":true,\"rotate\":0,\"filter\":false,\"truncate\":100},\"title\":{\"text\":\"Count\"}}],\"seriesParams\":[{\"show\":\"true\",\"type\":\"line\",\"mode\":\"normal\",\"data\":{\"label\":\"Count\",\"id\":\"1\"},\"valueAxis\":\"ValueAxis-1\",\"drawLinesBetweenPoints\":true,\"showCircles\":true}],\"addTooltip\":true,\"addLegend\":true,\"legendPosition\":\"right\",\"times\":[],\"addTimeMarker\":false,\"radiusRatio\":51,\"palette\":{\"type\":\"palette\",\"name\":\"kibana_palette\"},\"isVislibVis\":true,\"detailedTooltip\":true,\"fittingFunction\":\"zero\"},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"enabled\":true,\"type\":\"date_histogram\",\"schema\":\"segment\",\"params\":{\"field\":\"@timestamp\",\"timeRange\":{\"from\":\"2015-09-18T06:38:43.311Z\",\"to\":\"2015-09-26T04:02:51.104Z\",\"mode\":\"absolute\"},\"useNormalizedEsInterval\":true,\"interval\":\"auto\",\"drop_partials\":false,\"min_doc_count\":1,\"extended_bounds\":{}}},{\"id\":\"3\",\"enabled\":true,\"type\":\"sum\",\"schema\":\"radius\",\"params\":{\"field\":\"bytes\",\"customLabel\":\"bubbles\"}},{\"id\":\"4\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"group\",\"params\":{\"field\":\"machine.os.raw\",\"size\":5,\"order\":\"desc\",\"orderBy\":\"1\",\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\"}}]}"},"coreMigrationVersion":"7.12.1","id":"f92e5630-623e-11eb-aebf-c306684b328d","migrationVersion":{"visualization":"7.12.0"},"references":[{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"sort":[1617218933787,95],"type":"visualization","updated_at":"2021-03-31T19:28:53.787Z","version":"WzI5LDFd"} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"title":"logstash_heatmap","uiStateJSON":"{\"vis\":{\"defaultColors\":{\"0% - 25%\":\"rgb(255,255,204)\",\"25% - 50%\":\"rgb(254,217,118)\",\"50% - 75%\":\"rgb(253,141,60)\",\"75% - 100%\":\"rgb(227,27,28)\"}}}","version":1,"visState":"{\"title\":\"logstash_heatmap\",\"type\":\"heatmap\",\"params\":{\"type\":\"heatmap\",\"addTooltip\":true,\"addLegend\":true,\"enableHover\":false,\"legendPosition\":\"right\",\"times\":[],\"colorsNumber\":4,\"colorSchema\":\"Yellow to Red\",\"setColorRange\":false,\"colorsRange\":[],\"invertColors\":false,\"percentageMode\":true,\"valueAxes\":[{\"show\":false,\"id\":\"ValueAxis-1\",\"type\":\"value\",\"scale\":{\"type\":\"linear\",\"defaultYExtents\":false},\"labels\":{\"show\":false,\"rotate\":0,\"overwriteColor\":false,\"color\":\"#555\"}}],\"row\":true},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"enabled\":true,\"type\":\"date_histogram\",\"schema\":\"segment\",\"params\":{\"field\":\"@timestamp\",\"timeRange\":{\"from\":\"2015-07-24T08:58:14.175Z\",\"to\":\"2015-11-11T13:28:17.223Z\",\"mode\":\"absolute\"},\"useNormalizedEsInterval\":true,\"interval\":\"auto\",\"drop_partials\":false,\"min_doc_count\":1,\"extended_bounds\":{}}},{\"id\":\"3\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"group\",\"params\":{\"field\":\"machine.os.raw\",\"size\":5,\"order\":\"desc\",\"orderBy\":\"1\",\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\"}},{\"id\":\"4\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"split\",\"params\":{\"field\":\"response.raw\",\"size\":5,\"order\":\"desc\",\"orderBy\":\"1\",\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\"}}]}"},"coreMigrationVersion":"7.12.1","id":"9853d4d0-623d-11eb-aebf-c306684b328d","migrationVersion":{"visualization":"7.12.0"},"references":[{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"sort":[1617218934821,97],"type":"visualization","updated_at":"2021-03-31T19:28:54.821Z","version":"WzMxLDFd"} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"title":"logstash_goalchart","uiStateJSON":"{\"vis\":{\"defaultColors\":{\"0 - 33\":\"rgb(0,104,55)\",\"33 - 67\":\"rgb(255,255,190)\",\"67 - 100\":\"rgb(165,0,38)\"}}}","version":1,"visState":"{\"title\":\"logstash_goalchart\",\"type\":\"goal\",\"params\":{\"addTooltip\":true,\"addLegend\":false,\"isDisplayWarning\":false,\"type\":\"gauge\",\"gauge\":{\"verticalSplit\":false,\"autoExtend\":false,\"percentageMode\":true,\"gaugeType\":\"Circle\",\"gaugeStyle\":\"Full\",\"backStyle\":\"Full\",\"orientation\":\"vertical\",\"useRanges\":false,\"colorSchema\":\"Green to Red\",\"gaugeColorMode\":\"None\",\"colorsRange\":[{\"from\":0,\"to\":10000},{\"from\":10001,\"to\":20000},{\"from\":20001,\"to\":30000}],\"invertColors\":false,\"labels\":{\"show\":true,\"color\":\"black\"},\"scale\":{\"show\":false,\"labels\":false,\"color\":\"#333\",\"width\":2},\"type\":\"meter\",\"style\":{\"bgFill\":\"#000\",\"bgColor\":false,\"labelColor\":false,\"subText\":\"\",\"fontSize\":60},\"minAngle\":0,\"maxAngle\":6.283185307179586}},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"enabled\":true,\"type\":\"date_histogram\",\"schema\":\"group\",\"params\":{\"field\":\"@timestamp\",\"timeRange\":{\"from\":\"2015-07-24T08:58:14.175Z\",\"to\":\"2015-11-11T13:28:17.223Z\",\"mode\":\"absolute\"},\"useNormalizedEsInterval\":true,\"interval\":\"auto\",\"drop_partials\":false,\"min_doc_count\":1,\"extended_bounds\":{}}}]}"},"coreMigrationVersion":"7.12.1","id":"6ecb33b0-623d-11eb-aebf-c306684b328d","migrationVersion":{"visualization":"7.12.0"},"references":[{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"sort":[1617218935846,99],"type":"visualization","updated_at":"2021-03-31T19:28:55.846Z","version":"WzMzLDFd"} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"title":"logstash_gauge","uiStateJSON":"{\"vis\":{\"defaultColors\":{\"0 - 50\":\"rgb(0,104,55)\",\"50 - 75\":\"rgb(255,255,190)\",\"75 - 100\":\"rgb(165,0,38)\"}}}","version":1,"visState":"{\"title\":\"logstash_gauge\",\"type\":\"gauge\",\"params\":{\"type\":\"gauge\",\"addTooltip\":true,\"addLegend\":true,\"isDisplayWarning\":false,\"gauge\":{\"extendRange\":true,\"percentageMode\":false,\"gaugeType\":\"Arc\",\"gaugeStyle\":\"Full\",\"backStyle\":\"Full\",\"orientation\":\"vertical\",\"colorSchema\":\"Green to Red\",\"gaugeColorMode\":\"Labels\",\"colorsRange\":[{\"from\":0,\"to\":50},{\"from\":50,\"to\":75},{\"from\":75,\"to\":100}],\"invertColors\":false,\"labels\":{\"show\":true,\"color\":\"black\"},\"scale\":{\"show\":true,\"labels\":false,\"color\":\"#333\"},\"type\":\"meter\",\"style\":{\"bgWidth\":0.9,\"width\":0.9,\"mask\":false,\"bgMask\":false,\"maskBars\":50,\"bgFill\":\"#eee\",\"bgColor\":false,\"subText\":\"\",\"fontSize\":60,\"labelColor\":true},\"alignment\":\"horizontal\"}},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"enabled\":true,\"type\":\"range\",\"schema\":\"group\",\"params\":{\"field\":\"bytes\",\"ranges\":[{\"from\":0,\"to\":10001},{\"from\":10002,\"to\":1000000}],\"json\":\"\"}}]}"},"coreMigrationVersion":"7.12.1","id":"b8e35c80-623c-11eb-aebf-c306684b328d","migrationVersion":{"visualization":"7.12.0"},"references":[{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"sort":[1617218936874,101],"type":"visualization","updated_at":"2021-03-31T19:28:56.874Z","version":"WzM1LDFd"} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"title":"logstash_coordinatemaps","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"logstash_coordinatemaps\",\"type\":\"tile_map\",\"params\":{\"colorSchema\":\"Yellow to Red\",\"mapType\":\"Scaled Circle Markers\",\"isDesaturated\":false,\"addTooltip\":true,\"heatClusterSize\":1.5,\"legendPosition\":\"bottomright\",\"mapZoom\":2,\"mapCenter\":[0,0],\"wms\":{\"enabled\":false,\"options\":{\"format\":\"image/png\",\"transparent\":true},\"selectedTmsLayer\":{\"origin\":\"elastic_maps_service\",\"id\":\"road_map\",\"minZoom\":0,\"maxZoom\":18,\"attribution\":\"

    © OpenStreetMap contributors|OpenMapTiles|Elastic Maps Service

    \"}}},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"enabled\":true,\"type\":\"geohash_grid\",\"schema\":\"segment\",\"params\":{\"field\":\"geo.coordinates\",\"autoPrecision\":true,\"isFilteredByCollar\":true,\"useGeocentroid\":true,\"mapZoom\":2,\"mapCenter\":[0,0],\"precision\":2,\"customLabel\":\"logstash src/dest\"}}]}"},"coreMigrationVersion":"7.12.1","id":"f1bc75d0-6239-11eb-aebf-c306684b328d","migrationVersion":{"visualization":"7.12.0"},"references":[{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"sort":[1617218937901,31],"type":"visualization","updated_at":"2021-03-31T19:28:57.901Z","version":"WzM3LDFd"} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"title":"logstash_inputcontrols","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"logstash_inputcontrols\",\"type\":\"input_control_vis\",\"params\":{\"controls\":[{\"id\":\"1611928563867\",\"fieldName\":\"machine.ram\",\"parent\":\"\",\"label\":\"Logstash RAM\",\"type\":\"range\",\"options\":{\"decimalPlaces\":0,\"step\":1024},\"indexPatternRefName\":\"control_0_index_pattern\"},{\"id\":\"1611928586274\",\"fieldName\":\"machine.os.raw\",\"parent\":\"\",\"label\":\"Logstash OS\",\"type\":\"list\",\"options\":{\"type\":\"terms\",\"multiselect\":true,\"dynamicOptions\":true,\"size\":5,\"order\":\"desc\"},\"indexPatternRefName\":\"control_1_index_pattern\"}],\"updateFiltersOnChange\":false,\"useTimeFilter\":false,\"pinFilters\":false},\"aggs\":[]}"},"coreMigrationVersion":"7.12.1","id":"d79fe3d0-6239-11eb-aebf-c306684b328d","migrationVersion":{"visualization":"7.12.0"},"references":[{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"control_0_index_pattern","type":"index-pattern"},{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"control_1_index_pattern","type":"index-pattern"}],"sort":[1617218939955,36],"type":"visualization","updated_at":"2021-03-31T19:28:59.955Z","version":"WzQxLDFd"} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"title":"logstash_markdown","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"logstash_markdown\",\"type\":\"markdown\",\"params\":{\"fontSize\":12,\"openLinksInNewTab\":true,\"markdown\":\"Kibana is built with JS https://www.javascript.com/\"},\"aggs\":[]}"},"coreMigrationVersion":"7.12.1","id":"318375a0-6240-11eb-aebf-c306684b328d","migrationVersion":{"visualization":"7.12.0"},"references":[],"sort":[1617218940976,37],"type":"visualization","updated_at":"2021-03-31T19:29:00.976Z","version":"WzQzLDFd"} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"title":"logstash_vegaviz","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"logstash_vegaviz\",\"type\":\"vega\",\"params\":{\"spec\":\"{\\n/*\\n\\nWelcome to Vega visualizations. Here you can design your own dataviz from scratch using a declarative language called Vega, or its simpler form Vega-Lite. In Vega, you have the full control of what data is loaded, even from multiple sources, how that data is transformed, and what visual elements are used to show it. Use help icon to view Vega examples, tutorials, and other docs. Use the wrench icon to reformat this text, or to remove comments.\\n\\nThis example graph shows the document count in all indexes in the current time range. You might need to adjust the time filter in the upper right corner.\\n*/\\n\\n $schema: https://vega.github.io/schema/vega-lite/v2.json\\n title: Event counts from all indexes\\n\\n // Define the data source\\n data: {\\n url: {\\n/*\\nAn object instead of a string for the \\\"url\\\" param is treated as an Elasticsearch query. Anything inside this object is not part of the Vega language, but only understood by Kibana and Elasticsearch server. This query counts the number of documents per time interval, assuming you have a @timestamp field in your data.\\n\\nKibana has a special handling for the fields surrounded by \\\"%\\\". They are processed before the the query is sent to Elasticsearch. This way the query becomes context aware, and can use the time range and the dashboard filters.\\n*/\\n\\n // Apply dashboard context filters when set\\n %context%: true\\n // Filter the time picker (upper right corner) with this field\\n %timefield%: @timestamp\\n\\n/*\\nSee .search() documentation for : https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/api-reference.html#api-search\\n*/\\n\\n // Which index to search\\n index: logstash-*\\n // Aggregate data by the time field into time buckets, counting the number of documents in each bucket.\\n body: {\\n aggs: {\\n time_buckets: {\\n date_histogram: {\\n // Use date histogram aggregation on @timestamp field\\n field: @timestamp\\n // The interval value will depend on the daterange picker (true), or use an integer to set an approximate bucket count\\n interval: {%autointerval%: true}\\n // Make sure we get an entire range, even if it has no data\\n extended_bounds: {\\n // Use the current time range's start and end\\n min: {%timefilter%: \\\"min\\\"}\\n max: {%timefilter%: \\\"max\\\"}\\n }\\n // Use this for linear (e.g. line, area) graphs. Without it, empty buckets will not show up\\n min_doc_count: 13\\n }\\n }\\n }\\n // Speed up the response by only including aggregation results\\n size: 0\\n }\\n }\\n/*\\nElasticsearch will return results in this format:\\n\\naggregations: {\\n time_buckets: {\\n buckets: [\\n {\\n key_as_string: 2015-11-30T22:00:00.000Z\\n key: 1448920800000\\n doc_count: 0\\n },\\n {\\n key_as_string: 2015-11-30T23:00:00.000Z\\n key: 1448924400000\\n doc_count: 0\\n }\\n ...\\n ]\\n }\\n}\\n\\nFor our graph, we only need the list of bucket values. Use the format.property to discard everything else.\\n*/\\n format: {property: \\\"aggregations.time_buckets.buckets\\\"}\\n }\\n\\n // \\\"mark\\\" is the graphics element used to show our data. Other mark values are: area, bar, circle, line, point, rect, rule, square, text, and tick. See https://vega.github.io/vega-lite/docs/mark.html\\n mark: line\\n\\n // \\\"encoding\\\" tells the \\\"mark\\\" what data to use and in what way. See https://vega.github.io/vega-lite/docs/encoding.html\\n encoding: {\\n x: {\\n // The \\\"key\\\" value is the timestamp in milliseconds. Use it for X axis.\\n field: key\\n type: temporal\\n axis: {title: false} // Customize X axis format\\n }\\n y: {\\n // The \\\"doc_count\\\" is the count per bucket. Use it for Y axis.\\n field: doc_count\\n type: quantitative\\n axis: {title: \\\"Document count\\\"}\\n }\\n }\\n}\\n\"},\"aggs\":[]}"},"coreMigrationVersion":"7.12.1","id":"e461eb20-6245-11eb-aebf-c306684b328d","migrationVersion":{"visualization":"7.12.0"},"references":[],"sort":[1617218942061,29],"type":"visualization","updated_at":"2021-03-31T19:29:02.061Z","version":"WzQ1LDFd"} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"language\":\"kuery\",\"query\":\"\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"title":"logstash_regionmap","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"logstash_regionmap\",\"type\":\"region_map\",\"params\":{\"addTooltip\":true,\"colorSchema\":\"Yellow to Red\",\"emsHotLink\":\"https://maps.elastic.co/v6.7?locale=en#file/world_countries\",\"isDisplayWarning\":true,\"legendPosition\":\"bottomright\",\"mapCenter\":[0,0],\"mapZoom\":2,\"outlineWeight\":1,\"selectedJoinField\":{\"type\":\"id\",\"name\":\"iso2\",\"description\":\"ISO 3166-1 alpha-2 code\"},\"showAllShapes\":true,\"wms\":{\"enabled\":false,\"options\":{\"format\":\"image/png\",\"transparent\":true},\"selectedTmsLayer\":{\"origin\":\"elastic_maps_service\",\"id\":\"road_map\",\"minZoom\":0,\"maxZoom\":18,\"attribution\":\"

    © OpenStreetMap contributors|OpenMapTiles|Elastic Maps Service

    \"}},\"selectedLayer\":{\"name\":\"World Countries\",\"origin\":\"elastic_maps_service\",\"id\":\"world_countries\",\"created_at\":\"2017-04-26T17:12:15.978370\",\"attribution\":\"Made with NaturalEarth | Elastic Maps Service\",\"fields\":[{\"type\":\"id\",\"name\":\"iso2\",\"description\":\"ISO 3166-1 alpha-2 code\"},{\"type\":\"id\",\"name\":\"iso3\",\"description\":\"ISO 3166-1 alpha-3 code\"},{\"type\":\"property\",\"name\":\"name\",\"description\":\"name\"}],\"format\":{\"type\":\"geojson\"},\"layerId\":\"elastic_maps_service.World Countries\",\"isEMS\":true}},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"segment\",\"params\":{\"field\":\"geo.dest\",\"size\":5,\"order\":\"desc\",\"orderBy\":\"1\",\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\"}}]}"},"coreMigrationVersion":"7.12.1","id":"25bdc750-6242-11eb-aebf-c306684b328d","migrationVersion":{"visualization":"7.12.0"},"references":[{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"sort":[1617218943039,44],"type":"visualization","updated_at":"2021-03-31T19:29:03.039Z","version":"WzQ3LDFd"} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"title":"logstash_verticalbarchart","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"logstash_verticalbarchart\",\"type\":\"histogram\",\"params\":{\"type\":\"histogram\",\"grid\":{\"categoryLines\":false,\"style\":{\"color\":\"#eee\"}},\"categoryAxes\":[{\"id\":\"CategoryAxis-1\",\"type\":\"category\",\"position\":\"bottom\",\"show\":true,\"style\":{},\"scale\":{\"type\":\"linear\"},\"labels\":{\"show\":true,\"truncate\":100,\"filter\":true},\"title\":{}}],\"valueAxes\":[{\"id\":\"ValueAxis-1\",\"name\":\"LeftAxis-1\",\"type\":\"value\",\"position\":\"left\",\"show\":true,\"style\":{},\"scale\":{\"type\":\"linear\",\"mode\":\"normal\",\"defaultYExtents\":true},\"labels\":{\"show\":true,\"rotate\":0,\"filter\":false,\"truncate\":100},\"title\":{\"text\":\"Count\"}}],\"seriesParams\":[{\"show\":\"true\",\"type\":\"histogram\",\"mode\":\"stacked\",\"data\":{\"label\":\"Count\",\"id\":\"1\"},\"valueAxis\":\"ValueAxis-1\",\"drawLinesBetweenPoints\":true,\"showCircles\":true}],\"addTooltip\":true,\"addLegend\":true,\"legendPosition\":\"right\",\"times\":[],\"addTimeMarker\":true,\"row\":true,\"palette\":{\"type\":\"palette\",\"name\":\"kibana_palette\"},\"isVislibVis\":true,\"detailedTooltip\":true},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"enabled\":true,\"type\":\"date_histogram\",\"schema\":\"segment\",\"params\":{\"field\":\"@timestamp\",\"timeRange\":{\"from\":\"2015-09-18T06:38:43.311Z\",\"to\":\"2015-09-26T04:02:51.104Z\",\"mode\":\"absolute\"},\"useNormalizedEsInterval\":true,\"interval\":\"h\",\"drop_partials\":false,\"min_doc_count\":1,\"extended_bounds\":{},\"scaleMetricValues\":true}},{\"id\":\"3\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"split\",\"params\":{\"field\":\"response.raw\",\"size\":5,\"order\":\"desc\",\"orderBy\":\"1\",\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"customLabel\":\"Response code\"}}]}"},"coreMigrationVersion":"7.12.1","id":"71dd7bc0-6248-11eb-aebf-c306684b328d","migrationVersion":{"visualization":"7.12.0"},"references":[{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"sort":[1617218944094,47],"type":"visualization","updated_at":"2021-03-31T19:29:04.094Z","version":"WzUxLDFd"} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"title":"logstash_metricviz","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"logstash_metricviz\",\"type\":\"metric\",\"params\":{\"addTooltip\":true,\"addLegend\":false,\"type\":\"metric\",\"metric\":{\"percentageMode\":false,\"useRanges\":false,\"colorSchema\":\"Green to Red\",\"metricColorMode\":\"None\",\"colorsRange\":[{\"from\":0,\"to\":10000}],\"labels\":{\"show\":true},\"invertColors\":false,\"style\":{\"bgFill\":\"#000\",\"bgColor\":false,\"labelColor\":false,\"subText\":\"\",\"fontSize\":60}}},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"enabled\":true,\"type\":\"range\",\"schema\":\"group\",\"params\":{\"field\":\"bytes_scripted\",\"ranges\":[{\"from\":0,\"to\":10000},{\"from\":10001,\"to\":300000}]}}]}"},"coreMigrationVersion":"7.12.1","id":"6aea48a0-6240-11eb-aebf-c306684b328d","migrationVersion":{"visualization":"7.12.0"},"references":[{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"sort":[1617218946147,51],"type":"visualization","updated_at":"2021-03-31T19:29:06.147Z","version":"WzU1LDFd"} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"title":"logstash_piechart","uiStateJSON":"{}","version":1,"visState":"{\"aggs\":[{\"enabled\":true,\"id\":\"1\",\"params\":{},\"schema\":\"metric\",\"type\":\"count\"},{\"enabled\":true,\"id\":\"2\",\"params\":{\"field\":\"machine.os.raw\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"order\":\"desc\",\"orderBy\":\"1\",\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"size\":5},\"schema\":\"segment\",\"type\":\"terms\"}],\"params\":{\"addLegend\":true,\"addTooltip\":true,\"isDonut\":true,\"labels\":{\"last_level\":true,\"show\":false,\"truncate\":100,\"values\":true},\"legendPosition\":\"right\",\"type\":\"pie\"},\"title\":\"logstash_piechart\",\"type\":\"pie\"}"},"coreMigrationVersion":"7.12.1","id":"32b681f0-6241-11eb-aebf-c306684b328d","migrationVersion":{"visualization":"7.12.0"},"references":[{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"sort":[1617218947175,107],"type":"visualization","updated_at":"2021-03-31T19:29:07.175Z","version":"WzU3LDFd"} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"title":"logstash_tagcloud","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"logstash_tagcloud\",\"type\":\"tagcloud\",\"params\":{\"scale\":\"log\",\"orientation\":\"single\",\"minFontSize\":18,\"maxFontSize\":72,\"showLabel\":true},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"segment\",\"params\":{\"field\":\"geo.srcdest\",\"size\":23,\"order\":\"desc\",\"orderBy\":\"1\",\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\"}}]}"},"coreMigrationVersion":"7.12.1","id":"ccca99e0-6244-11eb-aebf-c306684b328d","migrationVersion":{"visualization":"7.12.0"},"references":[{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"sort":[1617218948213,111],"type":"visualization","updated_at":"2021-03-31T19:29:08.213Z","version":"WzU5LDFd"} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"language\":\"kuery\",\"query\":\"\"},\"filter\":[]}"},"title":"logstash_timelion","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"logstash_timelion\",\"type\":\"timelion\",\"params\":{\"expression\":\".es(q='machine.os.raw:win xp' , index=logstash-*)\",\"interval\":\"auto\"},\"aggs\":[]}"},"coreMigrationVersion":"7.12.1","id":"a4d7be80-6245-11eb-aebf-c306684b328d","migrationVersion":{"visualization":"7.12.0"},"references":[],"sort":[1617218949236,113],"type":"visualization","updated_at":"2021-03-31T19:29:09.236Z","version":"WzYxLDFd"} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{}"},"title":"logstash_tsvb","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"logstash_tsvb\",\"type\":\"metrics\",\"params\":{\"id\":\"61ca57f0-469d-11e7-af02-69e470af7417\",\"type\":\"timeseries\",\"series\":[{\"id\":\"61ca57f1-469d-11e7-af02-69e470af7417\",\"color\":\"#68BC00\",\"split_mode\":\"everything\",\"metrics\":[{\"id\":\"61ca57f2-469d-11e7-af02-69e470af7417\",\"type\":\"count\"}],\"separate_axis\":0,\"axis_position\":\"right\",\"formatter\":\"number\",\"chart_type\":\"line\",\"line_width\":1,\"point_size\":1,\"fill\":0.5,\"stacked\":\"none\",\"split_color_mode\":\"gradient\"}],\"time_field\":\"@timestamp\",\"index_pattern\":\"\",\"interval\":\"auto\",\"axis_position\":\"left\",\"axis_formatter\":\"number\",\"axis_scale\":\"normal\",\"show_legend\":1,\"show_grid\":1,\"default_index_pattern\":\"logstash-*\",\"annotations\":[{\"fields\":\"machine.os.raw\",\"template\":\"{{machine.os.raw}}\",\"index_pattern\":\"logstash-*\",\"query_string\":{\"query\":\"machine.os.raw :\\\"win xp\\\" \",\"language\":\"lucene\"},\"id\":\"aa43ceb0-6248-11eb-9a82-ef1c6e6c0265\",\"color\":\"#F00\",\"time_field\":\"@timestamp\",\"icon\":\"fa-tag\",\"ignore_global_filters\":1,\"ignore_panel_filters\":1}]},\"aggs\":[]}"},"coreMigrationVersion":"7.12.1","id":"c94d8440-6248-11eb-aebf-c306684b328d","migrationVersion":{"visualization":"7.12.0"},"references":[],"sort":[1617218951289,112],"type":"visualization","updated_at":"2021-03-31T19:29:11.289Z","version":"WzY1LDFd"} -{"attributes":{"columns":["bytes_scripted"],"description":"","hits":0,"kibanaSavedObjectMeta":{"searchSourceJSON":"{\"highlightAll\":true,\"version\":true,\"query\":{\"query\":\"machine.os.raw :\\\"win xp\\\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"sort":[["@timestamp","desc"]],"title":"logstash_scripted_saved_search","version":1},"coreMigrationVersion":"7.12.1","id":"db6226f0-61c0-11eb-aebf-c306684b328d","migrationVersion":{"search":"7.9.3"},"references":[{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"sort":[1617218928794,16],"type":"search","updated_at":"2021-03-31T19:28:48.794Z","version":"WzE5LDFd"} -{"attributes":{"description":"","hits":0,"kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"language\":\"lucene\",\"query\":\"\"},\"filter\":[]}"},"optionsJSON":"{\"darkTheme\":false,\"hidePanelTitles\":false,\"useMargins\":true}","panelsJSON":"[{\"version\":\"7.3.0\",\"gridData\":{\"h\":15,\"i\":\"1\",\"w\":24,\"x\":0,\"y\":0},\"panelIndex\":\"1\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_0\"},{\"version\":\"7.3.0\",\"gridData\":{\"h\":15,\"i\":\"2\",\"w\":24,\"x\":24,\"y\":0},\"panelIndex\":\"2\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_1\"},{\"version\":\"7.3.0\",\"gridData\":{\"h\":15,\"i\":\"3\",\"w\":24,\"x\":0,\"y\":15},\"panelIndex\":\"3\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_2\"},{\"version\":\"7.3.0\",\"gridData\":{\"h\":15,\"i\":\"4\",\"w\":24,\"x\":24,\"y\":15},\"panelIndex\":\"4\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_3\"},{\"version\":\"7.3.0\",\"gridData\":{\"h\":15,\"i\":\"5\",\"w\":24,\"x\":0,\"y\":30},\"panelIndex\":\"5\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_4\"},{\"version\":\"7.3.0\",\"gridData\":{\"h\":15,\"i\":\"6\",\"w\":24,\"x\":24,\"y\":30},\"panelIndex\":\"6\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_5\"},{\"version\":\"7.3.0\",\"gridData\":{\"h\":15,\"i\":\"7\",\"w\":24,\"x\":0,\"y\":45},\"panelIndex\":\"7\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_6\"},{\"version\":\"7.3.0\",\"gridData\":{\"h\":15,\"i\":\"8\",\"w\":24,\"x\":24,\"y\":45},\"panelIndex\":\"8\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_7\"},{\"version\":\"7.3.0\",\"gridData\":{\"h\":15,\"i\":\"9\",\"w\":24,\"x\":0,\"y\":60},\"panelIndex\":\"9\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_8\"},{\"version\":\"7.3.0\",\"gridData\":{\"h\":15,\"i\":\"10\",\"w\":24,\"x\":24,\"y\":60},\"panelIndex\":\"10\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_9\"},{\"version\":\"7.3.0\",\"gridData\":{\"h\":15,\"i\":\"11\",\"w\":24,\"x\":0,\"y\":75},\"panelIndex\":\"11\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_10\"},{\"version\":\"7.3.0\",\"gridData\":{\"h\":15,\"i\":\"12\",\"w\":24,\"x\":24,\"y\":75},\"panelIndex\":\"12\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_11\"},{\"version\":\"7.3.0\",\"gridData\":{\"h\":15,\"i\":\"13\",\"w\":24,\"x\":0,\"y\":90},\"panelIndex\":\"13\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_12\"},{\"version\":\"7.3.0\",\"gridData\":{\"h\":15,\"i\":\"14\",\"w\":24,\"x\":24,\"y\":90},\"panelIndex\":\"14\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_13\"},{\"version\":\"7.3.0\",\"gridData\":{\"h\":15,\"i\":\"15\",\"w\":24,\"x\":0,\"y\":105},\"panelIndex\":\"15\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_14\"},{\"version\":\"7.3.0\",\"gridData\":{\"h\":15,\"i\":\"16\",\"w\":24,\"x\":24,\"y\":105},\"panelIndex\":\"16\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_15\"},{\"version\":\"7.3.0\",\"gridData\":{\"h\":15,\"i\":\"17\",\"w\":24,\"x\":0,\"y\":120},\"panelIndex\":\"17\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_16\"},{\"version\":\"7.3.0\",\"gridData\":{\"h\":15,\"i\":\"18\",\"w\":24,\"x\":24,\"y\":120},\"panelIndex\":\"18\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_17\"},{\"version\":\"7.3.0\",\"gridData\":{\"h\":15,\"i\":\"19\",\"w\":24,\"x\":0,\"y\":135},\"panelIndex\":\"19\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_18\"},{\"version\":\"7.3.0\",\"gridData\":{\"h\":15,\"i\":\"20\",\"w\":24,\"x\":24,\"y\":135},\"panelIndex\":\"20\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_19\"}]","timeRestore":false,"title":"logstash_dashboardwithtime","version":1},"coreMigrationVersion":"7.12.1","id":"154944b0-6249-11eb-aebf-c306684b328d","migrationVersion":{"dashboard":"7.11.0"},"references":[{"id":"36b91810-6239-11eb-aebf-c306684b328d","name":"panel_0","type":"visualization"},{"id":"0a274320-61cc-11eb-aebf-c306684b328d","name":"panel_1","type":"visualization"},{"id":"e4aef350-623d-11eb-aebf-c306684b328d","name":"panel_2","type":"visualization"},{"id":"f92e5630-623e-11eb-aebf-c306684b328d","name":"panel_3","type":"visualization"},{"id":"9853d4d0-623d-11eb-aebf-c306684b328d","name":"panel_4","type":"visualization"},{"id":"6ecb33b0-623d-11eb-aebf-c306684b328d","name":"panel_5","type":"visualization"},{"id":"b8e35c80-623c-11eb-aebf-c306684b328d","name":"panel_6","type":"visualization"},{"id":"f1bc75d0-6239-11eb-aebf-c306684b328d","name":"panel_7","type":"visualization"},{"id":"0d8a8860-623a-11eb-aebf-c306684b328d","name":"panel_8","type":"visualization"},{"id":"d79fe3d0-6239-11eb-aebf-c306684b328d","name":"panel_9","type":"visualization"},{"id":"318375a0-6240-11eb-aebf-c306684b328d","name":"panel_10","type":"visualization"},{"id":"e461eb20-6245-11eb-aebf-c306684b328d","name":"panel_11","type":"visualization"},{"id":"25bdc750-6242-11eb-aebf-c306684b328d","name":"panel_12","type":"visualization"},{"id":"71dd7bc0-6248-11eb-aebf-c306684b328d","name":"panel_13","type":"visualization"},{"id":"6aea48a0-6240-11eb-aebf-c306684b328d","name":"panel_14","type":"visualization"},{"id":"32b681f0-6241-11eb-aebf-c306684b328d","name":"panel_15","type":"visualization"},{"id":"ccca99e0-6244-11eb-aebf-c306684b328d","name":"panel_16","type":"visualization"},{"id":"a4d7be80-6245-11eb-aebf-c306684b328d","name":"panel_17","type":"visualization"},{"id":"c94d8440-6248-11eb-aebf-c306684b328d","name":"panel_18","type":"visualization"},{"id":"db6226f0-61c0-11eb-aebf-c306684b328d","name":"panel_19","type":"search"}],"sort":[1617218953348,182],"type":"dashboard","updated_at":"2021-03-31T19:29:13.348Z","version":"WzY5LDFd"} -{"attributes":{"fieldAttrs":"{\"speaker\":{\"count\":1},\"text_entry\":{\"count\":6},\"type\":{\"count\":3}}","fields":"[]","runtimeFieldMap":"{}","title":"shakespeare"},"coreMigrationVersion":"7.12.1","id":"4e937b20-619d-11eb-aebf-c306684b328d","migrationVersion":{"index-pattern":"7.11.0"},"references":[],"sort":[1617218924067,3],"type":"index-pattern","updated_at":"2021-03-31T19:28:44.067Z","version":"WzcsMV0="} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"title":"shakespeare_areachart","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"shakespeare_areachart\",\"type\":\"histogram\",\"params\":{\"type\":\"histogram\",\"grid\":{\"categoryLines\":false,\"style\":{\"color\":\"#eee\"}},\"categoryAxes\":[{\"id\":\"CategoryAxis-1\",\"type\":\"category\",\"position\":\"bottom\",\"show\":true,\"style\":{},\"scale\":{\"type\":\"linear\"},\"labels\":{\"show\":true,\"truncate\":100,\"filter\":true},\"title\":{}}],\"valueAxes\":[{\"id\":\"ValueAxis-1\",\"name\":\"LeftAxis-1\",\"type\":\"value\",\"position\":\"left\",\"show\":true,\"style\":{},\"scale\":{\"type\":\"linear\",\"mode\":\"normal\"},\"labels\":{\"show\":true,\"rotate\":0,\"filter\":false,\"truncate\":100},\"title\":{\"text\":\"Count\"}}],\"seriesParams\":[{\"show\":true,\"mode\":\"stacked\",\"type\":\"histogram\",\"drawLinesBetweenPoints\":true,\"showCircles\":true,\"data\":{\"id\":\"2\",\"label\":\"Count\"},\"valueAxis\":\"ValueAxis-1\"}],\"addTooltip\":true,\"addLegend\":true,\"legendPosition\":\"right\",\"times\":[],\"addTimeMarker\":false,\"palette\":{\"type\":\"palette\",\"name\":\"kibana_palette\"},\"isVislibVis\":true,\"detailedTooltip\":true},\"aggs\":[{\"id\":\"2\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"3\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"segment\",\"params\":{\"field\":\"play_name\",\"size\":20,\"order\":\"desc\",\"orderBy\":\"2\",\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\"}},{\"id\":\"4\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"group\",\"params\":{\"field\":\"play_name\",\"size\":5,\"order\":\"desc\",\"orderBy\":\"2\",\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\"}}]}"},"coreMigrationVersion":"7.12.1","id":"185283c0-619e-11eb-aebf-c306684b328d","migrationVersion":{"visualization":"7.12.0"},"references":[{"id":"4e937b20-619d-11eb-aebf-c306684b328d","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"sort":[1617218945128,49],"type":"visualization","updated_at":"2021-03-31T19:29:05.128Z","version":"WzUzLDFd"} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"title":"shakespeare_piechart","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"shakespeare_piechart\",\"type\":\"pie\",\"params\":{\"type\":\"pie\",\"addTooltip\":true,\"addLegend\":true,\"legendPosition\":\"right\",\"isDonut\":false,\"labels\":{\"show\":true,\"values\":true,\"last_level\":true,\"truncate\":100}},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"segment\",\"params\":{\"field\":\"play_name\",\"size\":15,\"order\":\"desc\",\"orderBy\":\"1\",\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\"}}]}"},"coreMigrationVersion":"7.12.1","id":"33736660-619e-11eb-aebf-c306684b328d","migrationVersion":{"visualization":"7.12.0"},"references":[{"id":"4e937b20-619d-11eb-aebf-c306684b328d","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"sort":[1617218950263,109],"type":"visualization","updated_at":"2021-03-31T19:29:10.263Z","version":"WzYzLDFd"} -{"attributes":{"description":"","hits":0,"kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"language\":\"lucene\",\"query\":\"\"},\"filter\":[]}"},"optionsJSON":"{\"darkTheme\":false,\"hidePanelTitles\":false,\"useMargins\":true}","panelsJSON":"[{\"version\":\"7.3.0\",\"gridData\":{\"h\":15,\"i\":\"1\",\"w\":24,\"x\":0,\"y\":0},\"panelIndex\":\"1\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_0\"},{\"version\":\"7.3.0\",\"gridData\":{\"h\":15,\"i\":\"2\",\"w\":24,\"x\":24,\"y\":0},\"panelIndex\":\"2\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_1\"},{\"version\":\"7.3.0\",\"gridData\":{\"h\":15,\"i\":\"3\",\"w\":24,\"x\":0,\"y\":15},\"panelIndex\":\"3\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_2\"},{\"version\":\"7.3.0\",\"gridData\":{\"h\":15,\"i\":\"4\",\"w\":24,\"x\":24,\"y\":15},\"panelIndex\":\"4\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_3\"},{\"version\":\"7.3.0\",\"gridData\":{\"h\":15,\"i\":\"5\",\"w\":24,\"x\":0,\"y\":30},\"panelIndex\":\"5\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_4\"},{\"version\":\"7.3.0\",\"gridData\":{\"h\":15,\"i\":\"6\",\"w\":24,\"x\":24,\"y\":30},\"panelIndex\":\"6\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_5\"},{\"version\":\"7.3.0\",\"gridData\":{\"h\":15,\"i\":\"7\",\"w\":24,\"x\":0,\"y\":45},\"panelIndex\":\"7\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_6\"},{\"version\":\"7.3.0\",\"gridData\":{\"h\":15,\"i\":\"8\",\"w\":24,\"x\":24,\"y\":45},\"panelIndex\":\"8\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_7\"},{\"version\":\"7.3.0\",\"gridData\":{\"h\":15,\"i\":\"9\",\"w\":24,\"x\":0,\"y\":60},\"panelIndex\":\"9\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_8\"},{\"version\":\"7.3.0\",\"gridData\":{\"h\":15,\"i\":\"10\",\"w\":24,\"x\":24,\"y\":60},\"panelIndex\":\"10\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_9\"},{\"version\":\"7.3.0\",\"gridData\":{\"h\":15,\"i\":\"11\",\"w\":24,\"x\":0,\"y\":75},\"panelIndex\":\"11\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_10\"},{\"version\":\"7.3.0\",\"gridData\":{\"h\":15,\"i\":\"12\",\"w\":24,\"x\":24,\"y\":75},\"panelIndex\":\"12\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_11\"},{\"version\":\"7.3.0\",\"gridData\":{\"h\":15,\"i\":\"13\",\"w\":24,\"x\":0,\"y\":90},\"panelIndex\":\"13\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_12\"},{\"version\":\"7.3.0\",\"gridData\":{\"h\":15,\"i\":\"14\",\"w\":24,\"x\":24,\"y\":90},\"panelIndex\":\"14\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_13\"},{\"version\":\"7.3.0\",\"gridData\":{\"h\":15,\"i\":\"15\",\"w\":24,\"x\":0,\"y\":105},\"panelIndex\":\"15\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_14\"},{\"version\":\"7.3.0\",\"gridData\":{\"h\":15,\"i\":\"16\",\"w\":24,\"x\":24,\"y\":105},\"panelIndex\":\"16\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_15\"},{\"version\":\"7.3.0\",\"gridData\":{\"h\":15,\"i\":\"17\",\"w\":24,\"x\":0,\"y\":120},\"panelIndex\":\"17\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_16\"},{\"version\":\"7.3.0\",\"gridData\":{\"h\":15,\"i\":\"18\",\"w\":24,\"x\":24,\"y\":120},\"panelIndex\":\"18\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_17\"},{\"version\":\"7.3.0\",\"gridData\":{\"h\":15,\"i\":\"19\",\"w\":24,\"x\":0,\"y\":135},\"panelIndex\":\"19\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_18\"},{\"version\":\"7.3.0\",\"gridData\":{\"h\":15,\"i\":\"20\",\"w\":24,\"x\":24,\"y\":135},\"panelIndex\":\"20\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_19\"}]","timeRestore":false,"title":"logstash_dashboard_withouttime","version":1},"coreMigrationVersion":"7.12.1","id":"5d3410c0-6249-11eb-aebf-c306684b328d","migrationVersion":{"dashboard":"7.11.0"},"references":[{"id":"36b91810-6239-11eb-aebf-c306684b328d","name":"panel_0","type":"visualization"},{"id":"0a274320-61cc-11eb-aebf-c306684b328d","name":"panel_1","type":"visualization"},{"id":"e4aef350-623d-11eb-aebf-c306684b328d","name":"panel_2","type":"visualization"},{"id":"f92e5630-623e-11eb-aebf-c306684b328d","name":"panel_3","type":"visualization"},{"id":"9853d4d0-623d-11eb-aebf-c306684b328d","name":"panel_4","type":"visualization"},{"id":"6ecb33b0-623d-11eb-aebf-c306684b328d","name":"panel_5","type":"visualization"},{"id":"b8e35c80-623c-11eb-aebf-c306684b328d","name":"panel_6","type":"visualization"},{"id":"f1bc75d0-6239-11eb-aebf-c306684b328d","name":"panel_7","type":"visualization"},{"id":"0d8a8860-623a-11eb-aebf-c306684b328d","name":"panel_8","type":"visualization"},{"id":"d79fe3d0-6239-11eb-aebf-c306684b328d","name":"panel_9","type":"visualization"},{"id":"318375a0-6240-11eb-aebf-c306684b328d","name":"panel_10","type":"visualization"},{"id":"e461eb20-6245-11eb-aebf-c306684b328d","name":"panel_11","type":"visualization"},{"id":"25bdc750-6242-11eb-aebf-c306684b328d","name":"panel_12","type":"visualization"},{"id":"71dd7bc0-6248-11eb-aebf-c306684b328d","name":"panel_13","type":"visualization"},{"id":"6aea48a0-6240-11eb-aebf-c306684b328d","name":"panel_14","type":"visualization"},{"id":"32b681f0-6241-11eb-aebf-c306684b328d","name":"panel_15","type":"visualization"},{"id":"ccca99e0-6244-11eb-aebf-c306684b328d","name":"panel_16","type":"visualization"},{"id":"a4d7be80-6245-11eb-aebf-c306684b328d","name":"panel_17","type":"visualization"},{"id":"c94d8440-6248-11eb-aebf-c306684b328d","name":"panel_18","type":"visualization"},{"id":"db6226f0-61c0-11eb-aebf-c306684b328d","name":"panel_19","type":"search"}],"sort":[1617218954375,161],"type":"dashboard","updated_at":"2021-03-31T19:29:14.375Z","version":"WzcxLDFd"} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"title":"shakespeare_tag_cloud","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"shakespeare_tag_cloud\",\"type\":\"tagcloud\",\"params\":{\"scale\":\"linear\",\"orientation\":\"multiple\",\"minFontSize\":59,\"maxFontSize\":100,\"showLabel\":true},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"segment\",\"params\":{\"field\":\"type.keyword\",\"size\":5,\"order\":\"desc\",\"orderBy\":\"1\",\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\"}}]}"},"coreMigrationVersion":"7.12.1","id":"622ac7f0-619e-11eb-aebf-c306684b328d","migrationVersion":{"visualization":"7.12.0"},"references":[{"id":"4e937b20-619d-11eb-aebf-c306684b328d","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"sort":[1617218929689,13],"type":"visualization","updated_at":"2021-03-31T19:28:49.689Z","version":"WzIyLDFd"} -{"attributes":{"buildNum":9007199254740991,"defaultIndex":"56b34100-619d-11eb-aebf-c306684b328d"},"coreMigrationVersion":"7.12.1","id":"7.12.1","migrationVersion":{"config":"7.12.0"},"references":[],"sort":[1617218966119,191],"type":"config","updated_at":"2021-03-31T19:29:26.119Z","version":"Wzc3LDFd"} -{"attributes":{"columns":["_source"],"description":"","hits":0,"kibanaSavedObjectMeta":{"searchSourceJSON":"{\"highlightAll\":true,\"version\":true,\"query\":{\"query\":\"\",\"language\":\"lucene\"},\"filter\":[{\"meta\":{\"negate\":false,\"type\":\"phrase\",\"key\":\"text_entry\",\"value\":\"Christendom.\",\"params\":{\"query\":\"Christendom.\",\"type\":\"phrase\"},\"disabled\":false,\"alias\":null,\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index\"},\"query\":{\"match\":{\"text_entry\":{\"query\":\"Christendom.\",\"type\":\"phrase\"}}},\"$state\":{\"store\":\"appState\"}}],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"sort":[["_score","desc"]],"title":"shakespeare_saved_search","version":1},"coreMigrationVersion":"7.12.1","id":"712ebbe0-619d-11eb-aebf-c306684b328d","migrationVersion":{"search":"7.9.3"},"references":[{"id":"4e937b20-619d-11eb-aebf-c306684b328d","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"},{"id":"4e937b20-619d-11eb-aebf-c306684b328d","name":"kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index","type":"index-pattern"}],"sort":[1617218925706,93],"type":"search","updated_at":"2021-03-31T19:28:45.706Z","version":"WzEzLDFd"} -{"attributes":{"columns":["play_name","speaker"],"description":"","hits":0,"kibanaSavedObjectMeta":{"searchSourceJSON":"{\"highlightAll\":true,\"version\":true,\"query\":{\"query\":\"speaker:\\\"GLOUCESTER\\\"\",\"language\":\"lucene\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"sort":[["_score","desc"]],"title":"shakespeare_saved_lucene_search","version":1},"coreMigrationVersion":"7.12.1","id":"ddacc820-619d-11eb-aebf-c306684b328d","migrationVersion":{"search":"7.9.3"},"references":[{"id":"4e937b20-619d-11eb-aebf-c306684b328d","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"sort":[1617218927635,25],"type":"search","updated_at":"2021-03-31T19:28:47.635Z","version":"WzE2LDFd"} -{"attributes":{"columns":["_source"],"description":"","hits":0,"kibanaSavedObjectMeta":{"searchSourceJSON":"{\"highlightAll\":true,\"version\":true,\"query\":{\"query\":\"text_entry :\\\"MORDAKE THE EARL OF FIFE, AND ELDEST SON\\\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"sort":[["_score","desc"]],"title":"shakespeare_saved_kql_search","version":1},"coreMigrationVersion":"7.12.1","id":"f852d570-619d-11eb-aebf-c306684b328d","migrationVersion":{"search":"7.9.3"},"references":[{"id":"4e937b20-619d-11eb-aebf-c306684b328d","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"sort":[1617218926603,23],"type":"search","updated_at":"2021-03-31T19:28:46.603Z","version":"WzE0LDFd"} -{"attributes":{"description":"","hits":0,"kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"language\":\"kuery\",\"query\":\"\"},\"filter\":[]}"},"optionsJSON":"{\"darkTheme\":false,\"hidePanelTitles\":false,\"useMargins\":true}","panelsJSON":"[{\"version\":\"7.3.0\",\"gridData\":{\"h\":15,\"i\":\"1\",\"w\":24,\"x\":0,\"y\":0},\"panelIndex\":\"1\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_0\"},{\"version\":\"7.3.0\",\"gridData\":{\"h\":15,\"i\":\"2\",\"w\":24,\"x\":24,\"y\":0},\"panelIndex\":\"2\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_1\"},{\"version\":\"7.3.0\",\"gridData\":{\"h\":15,\"i\":\"3\",\"w\":24,\"x\":0,\"y\":15},\"panelIndex\":\"3\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_2\"},{\"version\":\"7.3.0\",\"gridData\":{\"h\":15,\"i\":\"4\",\"w\":24,\"x\":24,\"y\":15},\"panelIndex\":\"4\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_3\"},{\"version\":\"7.3.0\",\"gridData\":{\"h\":15,\"i\":\"5\",\"w\":24,\"x\":0,\"y\":30},\"panelIndex\":\"5\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_4\"},{\"version\":\"7.3.0\",\"gridData\":{\"h\":15,\"i\":\"6\",\"w\":24,\"x\":24,\"y\":30},\"panelIndex\":\"6\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_5\"}]","timeRestore":false,"title":"shakespeare_dashboard","version":1},"coreMigrationVersion":"7.12.1","id":"73398a90-619e-11eb-aebf-c306684b328d","migrationVersion":{"dashboard":"7.11.0"},"references":[{"id":"185283c0-619e-11eb-aebf-c306684b328d","name":"panel_0","type":"visualization"},{"id":"33736660-619e-11eb-aebf-c306684b328d","name":"panel_1","type":"visualization"},{"id":"622ac7f0-619e-11eb-aebf-c306684b328d","name":"panel_2","type":"visualization"},{"id":"712ebbe0-619d-11eb-aebf-c306684b328d","name":"panel_3","type":"search"},{"id":"ddacc820-619d-11eb-aebf-c306684b328d","name":"panel_4","type":"search"},{"id":"f852d570-619d-11eb-aebf-c306684b328d","name":"panel_5","type":"search"}],"sort":[1617218931742,88],"type":"dashboard","updated_at":"2021-03-31T19:28:51.742Z","version":"WzI2LDFd"} -{"attributes":{"description":"","hits":0,"kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"language\":\"lucene\",\"query\":\"\"},\"filter\":[{\"meta\":{\"negate\":false,\"disabled\":false,\"alias\":null,\"type\":\"phrase\",\"key\":\"geo.srcdest\",\"value\":\"IN:US\",\"params\":{\"query\":\"IN:US\",\"type\":\"phrase\"},\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index\"},\"query\":{\"match\":{\"geo.srcdest\":{\"query\":\"IN:US\",\"type\":\"phrase\"}}},\"$state\":{\"store\":\"appState\"}}]}"},"optionsJSON":"{\"darkTheme\":false,\"hidePanelTitles\":false,\"useMargins\":true}","panelsJSON":"[{\"version\":\"7.3.0\",\"gridData\":{\"h\":15,\"i\":\"1\",\"w\":24,\"x\":0,\"y\":0},\"panelIndex\":\"1\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_0\"},{\"version\":\"7.3.0\",\"gridData\":{\"h\":15,\"i\":\"2\",\"w\":24,\"x\":24,\"y\":0},\"panelIndex\":\"2\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_1\"},{\"version\":\"7.3.0\",\"gridData\":{\"h\":15,\"i\":\"3\",\"w\":24,\"x\":0,\"y\":15},\"panelIndex\":\"3\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_2\"},{\"version\":\"7.3.0\",\"gridData\":{\"h\":15,\"i\":\"4\",\"w\":24,\"x\":24,\"y\":15},\"panelIndex\":\"4\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_3\"},{\"version\":\"7.3.0\",\"gridData\":{\"h\":15,\"i\":\"5\",\"w\":24,\"x\":0,\"y\":30},\"panelIndex\":\"5\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_4\"},{\"version\":\"7.3.0\",\"gridData\":{\"h\":15,\"i\":\"6\",\"w\":24,\"x\":24,\"y\":30},\"panelIndex\":\"6\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_5\"},{\"version\":\"7.3.0\",\"gridData\":{\"h\":15,\"i\":\"7\",\"w\":24,\"x\":0,\"y\":45},\"panelIndex\":\"7\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_6\"},{\"version\":\"7.3.0\",\"gridData\":{\"h\":15,\"i\":\"8\",\"w\":24,\"x\":24,\"y\":45},\"panelIndex\":\"8\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_7\"},{\"version\":\"7.3.0\",\"gridData\":{\"h\":15,\"i\":\"9\",\"w\":24,\"x\":0,\"y\":60},\"panelIndex\":\"9\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_8\"},{\"version\":\"7.3.0\",\"gridData\":{\"h\":15,\"i\":\"10\",\"w\":24,\"x\":24,\"y\":60},\"panelIndex\":\"10\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_9\"},{\"version\":\"7.3.0\",\"gridData\":{\"h\":15,\"i\":\"11\",\"w\":24,\"x\":0,\"y\":75},\"panelIndex\":\"11\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_10\"},{\"version\":\"7.3.0\",\"gridData\":{\"h\":15,\"i\":\"12\",\"w\":24,\"x\":24,\"y\":75},\"panelIndex\":\"12\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_11\"},{\"version\":\"7.3.0\",\"gridData\":{\"h\":15,\"i\":\"13\",\"w\":24,\"x\":0,\"y\":90},\"panelIndex\":\"13\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_12\"},{\"version\":\"7.3.0\",\"gridData\":{\"h\":15,\"i\":\"14\",\"w\":24,\"x\":24,\"y\":90},\"panelIndex\":\"14\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_13\"},{\"version\":\"7.3.0\",\"gridData\":{\"h\":15,\"i\":\"15\",\"w\":24,\"x\":0,\"y\":105},\"panelIndex\":\"15\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_14\"},{\"version\":\"7.3.0\",\"gridData\":{\"h\":15,\"i\":\"16\",\"w\":24,\"x\":24,\"y\":105},\"panelIndex\":\"16\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_15\"},{\"version\":\"7.3.0\",\"gridData\":{\"h\":15,\"i\":\"17\",\"w\":24,\"x\":0,\"y\":120},\"panelIndex\":\"17\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_16\"},{\"version\":\"7.3.0\",\"gridData\":{\"h\":15,\"i\":\"18\",\"w\":24,\"x\":24,\"y\":120},\"panelIndex\":\"18\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_17\"},{\"version\":\"7.3.0\",\"gridData\":{\"h\":15,\"i\":\"19\",\"w\":24,\"x\":0,\"y\":135},\"panelIndex\":\"19\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_18\"},{\"version\":\"7.3.0\",\"gridData\":{\"h\":15,\"i\":\"20\",\"w\":24,\"x\":24,\"y\":135},\"panelIndex\":\"20\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_19\"}]","timeRestore":false,"title":"logstash_dashboardwithfilters","version":1},"coreMigrationVersion":"7.12.1","id":"79794f20-6249-11eb-aebf-c306684b328d","migrationVersion":{"dashboard":"7.11.0"},"references":[{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index","type":"index-pattern"},{"id":"36b91810-6239-11eb-aebf-c306684b328d","name":"panel_0","type":"visualization"},{"id":"0a274320-61cc-11eb-aebf-c306684b328d","name":"panel_1","type":"visualization"},{"id":"e4aef350-623d-11eb-aebf-c306684b328d","name":"panel_2","type":"visualization"},{"id":"f92e5630-623e-11eb-aebf-c306684b328d","name":"panel_3","type":"visualization"},{"id":"9853d4d0-623d-11eb-aebf-c306684b328d","name":"panel_4","type":"visualization"},{"id":"6ecb33b0-623d-11eb-aebf-c306684b328d","name":"panel_5","type":"visualization"},{"id":"b8e35c80-623c-11eb-aebf-c306684b328d","name":"panel_6","type":"visualization"},{"id":"f1bc75d0-6239-11eb-aebf-c306684b328d","name":"panel_7","type":"visualization"},{"id":"0d8a8860-623a-11eb-aebf-c306684b328d","name":"panel_8","type":"visualization"},{"id":"d79fe3d0-6239-11eb-aebf-c306684b328d","name":"panel_9","type":"visualization"},{"id":"318375a0-6240-11eb-aebf-c306684b328d","name":"panel_10","type":"visualization"},{"id":"e461eb20-6245-11eb-aebf-c306684b328d","name":"panel_11","type":"visualization"},{"id":"25bdc750-6242-11eb-aebf-c306684b328d","name":"panel_12","type":"visualization"},{"id":"71dd7bc0-6248-11eb-aebf-c306684b328d","name":"panel_13","type":"visualization"},{"id":"6aea48a0-6240-11eb-aebf-c306684b328d","name":"panel_14","type":"visualization"},{"id":"32b681f0-6241-11eb-aebf-c306684b328d","name":"panel_15","type":"visualization"},{"id":"ccca99e0-6244-11eb-aebf-c306684b328d","name":"panel_16","type":"visualization"},{"id":"a4d7be80-6245-11eb-aebf-c306684b328d","name":"panel_17","type":"visualization"},{"id":"c94d8440-6248-11eb-aebf-c306684b328d","name":"panel_18","type":"visualization"},{"id":"db6226f0-61c0-11eb-aebf-c306684b328d","name":"panel_19","type":"search"}],"sort":[1617218955401,140],"type":"dashboard","updated_at":"2021-03-31T19:29:15.401Z","version":"WzczLDFd"} -{"exportedCount":33,"missingRefCount":0,"missingReferences":[]} \ No newline at end of file diff --git a/x-pack/test/functional/apps/saved_objects_management/exports/_7.13_import_saved_objects.ndjson b/x-pack/test/functional/apps/saved_objects_management/exports/_7.13_import_saved_objects.ndjson new file mode 100644 index 0000000000000..5b2a4748d2eee --- /dev/null +++ b/x-pack/test/functional/apps/saved_objects_management/exports/_7.13_import_saved_objects.ndjson @@ -0,0 +1,72 @@ +{"attributes":{"accessCount":0,"accessDate":1621977234367,"createDate":1621977234367,"url":"/app/dashboards#/view/154944b0-6249-11eb-aebf-c306684b328d?embed=true&_g=(filters:!(),refreshInterval:(pause:!t,value:0),time:(from:now-15y,to:now))&_a=(description:%27%27,filters:!(),fullScreenMode:!f,options:(darkTheme:!f,hidePanelTitles:!f,useMargins:!t),panels:!((embeddableConfig:(enhancements:()),gridData:(h:15,i:%271%27,w:24,x:0,y:0),id:%2736b91810-6239-11eb-aebf-c306684b328d%27,panelIndex:%271%27,type:visualization,version:%277.13.1%27),(embeddableConfig:(enhancements:(),vis:!n),gridData:(h:15,i:%272%27,w:24,x:24,y:0),id:%270a274320-61cc-11eb-aebf-c306684b328d%27,panelIndex:%272%27,type:visualization,version:%277.13.1%27),(embeddableConfig:(enhancements:()),gridData:(h:15,i:%273%27,w:24,x:0,y:15),id:e4aef350-623d-11eb-aebf-c306684b328d,panelIndex:%273%27,type:visualization,version:%277.13.1%27),(embeddableConfig:(enhancements:()),gridData:(h:15,i:%274%27,w:24,x:24,y:15),id:f92e5630-623e-11eb-aebf-c306684b328d,panelIndex:%274%27,type:visualization,version:%277.13.1%27),(embeddableConfig:(enhancements:(),vis:!n),gridData:(h:15,i:%275%27,w:24,x:0,y:30),id:%279853d4d0-623d-11eb-aebf-c306684b328d%27,panelIndex:%275%27,type:visualization,version:%277.13.1%27),(embeddableConfig:(enhancements:(),vis:!n),gridData:(h:15,i:%276%27,w:24,x:24,y:30),id:%276ecb33b0-623d-11eb-aebf-c306684b328d%27,panelIndex:%276%27,type:visualization,version:%277.13.1%27),(embeddableConfig:(enhancements:(),vis:!n),gridData:(h:15,i:%277%27,w:24,x:0,y:45),id:b8e35c80-623c-11eb-aebf-c306684b328d,panelIndex:%277%27,type:visualization,version:%277.13.1%27),(embeddableConfig:(enhancements:()),gridData:(h:15,i:%278%27,w:24,x:24,y:45),id:f1bc75d0-6239-11eb-aebf-c306684b328d,panelIndex:%278%27,type:visualization,version:%277.13.1%27),(embeddableConfig:(enhancements:()),gridData:(h:15,i:%279%27,w:24,x:0,y:60),id:%270d8a8860-623a-11eb-aebf-c306684b328d%27,panelIndex:%279%27,type:visualization,version:%277.13.1%27),(embeddableConfig:(enhancements:()),gridData:(h:15,i:%2710%27,w:24,x:24,y:60),id:d79fe3d0-6239-11eb-aebf-c306684b328d,panelIndex:%2710%27,type:visualization,version:%277.13.1%27),(embeddableConfig:(enhancements:()),gridData:(h:15,i:%2711%27,w:24,x:0,y:75),id:%27318375a0-6240-11eb-aebf-c306684b328d%27,panelIndex:%2711%27,type:visualization,version:%277.13.1%27),(embeddableConfig:(enhancements:()),gridData:(h:15,i:%2712%27,w:24,x:24,y:75),id:e461eb20-6245-11eb-aebf-c306684b328d,panelIndex:%2712%27,type:visualization,version:%277.13.1%27),(embeddableConfig:(enhancements:()),gridData:(h:15,i:%2713%27,w:24,x:0,y:90),id:%2725bdc750-6242-11eb-aebf-c306684b328d%27,panelIndex:%2713%27,type:visualization,version:%277.13.1%27),(embeddableConfig:(enhancements:()),gridData:(h:15,i:%2714%27,w:24,x:24,y:90),id:%2771dd7bc0-6248-11eb-aebf-c306684b328d%27,panelIndex:%2714%27,type:visualization,version:%277.13.1%27),(embeddableConfig:(enhancements:()),gridData:(h:15,i:%2715%27,w:24,x:0,y:105),id:%276aea48a0-6240-11eb-aebf-c306684b328d%27,panelIndex:%2715%27,type:visualization,version:%277.13.1%27),(embeddableConfig:(enhancements:()),gridData:(h:15,i:%2716%27,w:24,x:24,y:105),id:%2732b681f0-6241-11eb-aebf-c306684b328d%27,panelIndex:%2716%27,type:visualization,version:%277.13.1%27),(embeddableConfig:(enhancements:()),gridData:(h:15,i:%2717%27,w:24,x:0,y:120),id:ccca99e0-6244-11eb-aebf-c306684b328d,panelIndex:%2717%27,type:visualization,version:%277.13.1%27),(embeddableConfig:(enhancements:()),gridData:(h:15,i:%2718%27,w:24,x:24,y:120),id:a4d7be80-6245-11eb-aebf-c306684b328d,panelIndex:%2718%27,type:visualization,version:%277.13.1%27),(embeddableConfig:(enhancements:()),gridData:(h:15,i:%2719%27,w:24,x:0,y:135),id:c94d8440-6248-11eb-aebf-c306684b328d,panelIndex:%2719%27,type:visualization,version:%277.13.1%27),(embeddableConfig:(enhancements:()),gridData:(h:15,i:%2720%27,w:24,x:24,y:135),id:db6226f0-61c0-11eb-aebf-c306684b328d,panelIndex:%2720%27,type:search,version:%277.13.1%27)),query:(language:lucene,query:%27%27),tags:!(),timeRestore:!f,title:logstash_dashboardwithtime,viewMode:view)"},"coreMigrationVersion":"7.13.1","id":"058bc10f0578013fc41ddedc9a1dcd1e","references":[],"sort":[1621977234371,155],"type":"url","updated_at":"2021-05-25T21:13:54.371Z","version":"Wzk3LDJd"} +{"attributes":{"fieldAttrs":"{\"machine.os\":{\"count\":1},\"spaces\":{\"count\":1},\"type\":{\"count\":1},\"bytes_scripted\":{\"count\":1}}","fields":"[{\"count\":1,\"script\":\"doc['bytes'].value*1024\",\"lang\":\"painless\",\"name\":\"bytes_scripted\",\"type\":\"number\",\"scripted\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false}]","runtimeFieldMap":"{}","timeFieldName":"@timestamp","title":"logstash-*"},"coreMigrationVersion":"7.13.1","id":"56b34100-619d-11eb-aebf-c306684b328d","migrationVersion":{"index-pattern":"7.11.0"},"references":[],"sort":[1621974324983,81],"type":"index-pattern","updated_at":"2021-05-25T20:25:24.983Z","version":"WzEyLDJd"} +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"title":"logstash_scriptedfieldviz","uiStateJSON":"{\"vis\":{\"defaultColors\":{\"0 - 100\":\"rgb(0,104,55)\"}}}","version":1,"visState":"{\"title\":\"logstash_scriptedfieldviz\",\"type\":\"goal\",\"params\":{\"addTooltip\":true,\"addLegend\":false,\"isDisplayWarning\":false,\"type\":\"gauge\",\"gauge\":{\"verticalSplit\":false,\"autoExtend\":false,\"percentageMode\":true,\"gaugeType\":\"Arc\",\"gaugeStyle\":\"Full\",\"backStyle\":\"Full\",\"orientation\":\"vertical\",\"useRanges\":false,\"colorSchema\":\"Green to Red\",\"gaugeColorMode\":\"None\",\"colorsRange\":[{\"from\":0,\"to\":10000}],\"invertColors\":false,\"labels\":{\"show\":true,\"color\":\"black\"},\"scale\":{\"show\":false,\"labels\":false,\"color\":\"#333\",\"width\":2},\"type\":\"meter\",\"style\":{\"bgFill\":\"#000\",\"bgColor\":false,\"labelColor\":false,\"subText\":\"\",\"fontSize\":60}}},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"enabled\":true,\"type\":\"range\",\"schema\":\"group\",\"params\":{\"field\":\"bytes_scripted\",\"ranges\":[{\"from\":0,\"to\":40000},{\"from\":40001,\"to\":20000000}]}}]}"},"coreMigrationVersion":"7.13.1","id":"0a274320-61cc-11eb-aebf-c306684b328d","migrationVersion":{"visualization":"7.13.0"},"references":[{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"sort":[1621974352673,78],"type":"visualization","updated_at":"2021-05-25T20:25:52.673Z","version":"WzY4LDJd"} +{"attributes":{"color":"#81a93f","description":"","name":"logstash_tag"},"coreMigrationVersion":"7.13.1","id":"e6994960-bd9e-11eb-9520-1b4c3ca6a781","references":[],"sort":[1621977573626,178],"type":"tag","updated_at":"2021-05-25T21:19:33.626Z","version":"WzE1MSwyXQ=="} +{"attributes":{"description":"","layerListJSON":"[{\"sourceDescriptor\":{\"type\":\"EMS_TMS\",\"isAutoSelect\":true},\"id\":\"4c2394ca-a6a2-4f8d-9631-259eb3a9627f\",\"label\":null,\"minZoom\":0,\"maxZoom\":24,\"alpha\":1,\"visible\":true,\"style\":{\"type\":\"TILE\"},\"type\":\"VECTOR_TILE\"},{\"sourceDescriptor\":{\"geoField\":\"geo.coordinates\",\"filterByMapBounds\":true,\"scalingType\":\"CLUSTERS\",\"id\":\"7555324e-e793-4b7d-a9d2-cd63e6b7fe3d\",\"type\":\"ES_SEARCH\",\"applyGlobalQuery\":true,\"applyGlobalTime\":true,\"tooltipProperties\":[\"geo.srcdest\",\"machine.os\",\"type\"],\"sortField\":\"bytes_scripted\",\"sortOrder\":\"desc\",\"topHitsSplitField\":\"\",\"topHitsSize\":1,\"indexPatternRefName\":\"layer_1_source_index_pattern\"},\"id\":\"6a493d8b-a220-46bc-8906-a1a7569799e0\",\"label\":null,\"minZoom\":0,\"maxZoom\":24,\"alpha\":0.75,\"visible\":true,\"style\":{\"type\":\"VECTOR\",\"properties\":{\"icon\":{\"type\":\"STATIC\",\"options\":{\"value\":\"marker\"}},\"fillColor\":{\"type\":\"DYNAMIC\",\"options\":{\"color\":\"Blues\",\"colorCategory\":\"palette_0\",\"field\":{\"name\":\"extension.raw\",\"origin\":\"source\"},\"fieldMetaOptions\":{\"isEnabled\":true,\"sigma\":3},\"type\":\"CATEGORICAL\"}},\"lineColor\":{\"type\":\"DYNAMIC\",\"options\":{\"color\":\"Blues\",\"colorCategory\":\"palette_0\",\"field\":{\"name\":\"machine.os.raw\",\"origin\":\"source\"},\"fieldMetaOptions\":{\"isEnabled\":true,\"sigma\":3},\"type\":\"CATEGORICAL\"}},\"lineWidth\":{\"type\":\"STATIC\",\"options\":{\"size\":1}},\"iconSize\":{\"type\":\"STATIC\",\"options\":{\"size\":6}},\"iconOrientation\":{\"type\":\"STATIC\",\"options\":{\"orientation\":0}},\"labelText\":{\"type\":\"STATIC\",\"options\":{\"value\":\"\"}},\"labelColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#000000\"}},\"labelSize\":{\"type\":\"STATIC\",\"options\":{\"size\":14}},\"labelBorderColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#FFFFFF\"}},\"symbolizeAs\":{\"options\":{\"value\":\"circle\"}},\"labelBorderSize\":{\"options\":{\"size\":\"SMALL\"}}},\"isTimeAware\":true},\"type\":\"BLENDED_VECTOR\",\"joins\":[]}]","mapStateJSON":"{\"zoom\":1.56,\"center\":{\"lon\":0,\"lat\":19.94277},\"timeFilters\":{\"from\":\"now-15y\",\"to\":\"now\"},\"refreshConfig\":{\"isPaused\":true,\"interval\":0},\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filters\":[],\"settings\":{\"autoFitToDataBounds\":false,\"backgroundColor\":\"#ffffff\",\"disableInteractive\":false,\"disableTooltipControl\":false,\"hideToolbarOverlay\":false,\"hideLayerControl\":false,\"hideViewControl\":false,\"initialLocation\":\"LAST_SAVED_LOCATION\",\"fixedLocation\":{\"lat\":0,\"lon\":0,\"zoom\":2},\"browserLocation\":{\"zoom\":2},\"maxZoom\":24,\"minZoom\":0,\"showScaleControl\":false,\"showSpatialFilters\":true,\"spatialFiltersAlpa\":0.3,\"spatialFiltersFillColor\":\"#DA8B45\",\"spatialFiltersLineColor\":\"#DA8B45\"}}","title":"logstash_maps","uiStateJSON":"{\"isLayerTOCOpen\":true,\"openTOCDetails\":[]}"},"coreMigrationVersion":"7.13.1","id":"0c5974f0-be5c-11eb-9520-1b4c3ca6a781","migrationVersion":{"map":"7.12.0"},"references":[{"id":"e6994960-bd9e-11eb-9520-1b4c3ca6a781","name":"tag-ref-e6994960-bd9e-11eb-9520-1b4c3ca6a781","type":"tag"},{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"layer_1_source_index_pattern","type":"index-pattern"}],"sort":[1622058811844,517],"type":"map","updated_at":"2021-05-26T19:53:31.844Z","version":"WzExODAsMl0="} +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"title":"logstash_datatable","uiStateJSON":"{\"vis\":{\"params\":{\"sort\":{\"columnIndex\":null,\"direction\":null}}}}","version":1,"visState":"{\"title\":\"logstash_datatable\",\"type\":\"table\",\"params\":{\"perPage\":10,\"showPartialRows\":false,\"showMetricsAtAllLevels\":false,\"sort\":{\"columnIndex\":null,\"direction\":null},\"showTotal\":true,\"totalFunc\":\"sum\",\"showToolbar\":true},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"enabled\":true,\"type\":\"date_histogram\",\"schema\":\"bucket\",\"params\":{\"field\":\"@timestamp\",\"timeRange\":{\"from\":\"2015-07-24T08:58:14.175Z\",\"to\":\"2015-11-11T13:28:17.223Z\",\"mode\":\"absolute\"},\"useNormalizedEsInterval\":true,\"interval\":\"auto\",\"drop_partials\":false,\"min_doc_count\":1,\"extended_bounds\":{}}},{\"id\":\"3\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"bucket\",\"params\":{\"field\":\"response.raw\",\"size\":10,\"order\":\"desc\",\"orderBy\":\"1\",\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\"}}]}"},"coreMigrationVersion":"7.13.1","id":"0d8a8860-623a-11eb-aebf-c306684b328d","migrationVersion":{"visualization":"7.13.0"},"references":[{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"sort":[1621974339308,101],"type":"visualization","updated_at":"2021-05-25T20:25:39.308Z","version":"WzQyLDJd"} +{"attributes":{"description":null,"state":{"datasourceStates":{"indexpattern":{"layers":{"35fd070e-5bbc-4906-bf69-8548a213d7a0":{"columnOrder":["2bf7969f-0371-4df2-a398-0a191e428ce5","aab812d6-609b-444d-9990-1e67f85fd85d","e9829e8a-c484-4c9d-b489-f1eb3fb138d2","4fc9fb3b-29a5-4679-ab3c-90d5daaf0661"],"columns":{"2bf7969f-0371-4df2-a398-0a191e428ce5":{"dataType":"date","isBucketed":true,"label":"@timestamp","operationType":"date_histogram","params":{"interval":"auto"},"scale":"interval","sourceField":"@timestamp"},"4fc9fb3b-29a5-4679-ab3c-90d5daaf0661":{"dataType":"number","isBucketed":false,"label":"Moving average of Median of bytes","operationType":"moving_average","params":{"window":5},"references":["e9829e8a-c484-4c9d-b489-f1eb3fb138d2"],"scale":"ratio"},"aab812d6-609b-444d-9990-1e67f85fd85d":{"dataType":"number","isBucketed":false,"label":"Average of bytes","operationType":"average","scale":"ratio","sourceField":"bytes"},"e9829e8a-c484-4c9d-b489-f1eb3fb138d2":{"dataType":"number","isBucketed":false,"label":"Median of bytes","operationType":"median","scale":"ratio","sourceField":"bytes"}},"incompleteColumns":{}}}}},"filters":[],"query":{"language":"kuery","query":""},"visualization":{"axisTitlesVisibilitySettings":{"x":true,"yLeft":true,"yRight":true},"fittingFunction":"None","gridlinesVisibilitySettings":{"x":true,"yLeft":true,"yRight":true},"layers":[{"accessors":["aab812d6-609b-444d-9990-1e67f85fd85d","4fc9fb3b-29a5-4679-ab3c-90d5daaf0661"],"layerId":"35fd070e-5bbc-4906-bf69-8548a213d7a0","position":"top","seriesType":"bar_stacked","showGridlines":false,"xAccessor":"2bf7969f-0371-4df2-a398-0a191e428ce5"}],"legend":{"isVisible":true,"position":"right"},"preferredSeriesType":"bar_stacked","tickLabelsVisibilitySettings":{"x":true,"yLeft":true,"yRight":true},"valueLabels":"hide"}},"title":"lens_barvertical_stacked_average","visualizationType":"lnsXY"},"coreMigrationVersion":"7.13.1","id":"0dbbf8b0-be3c-11eb-9520-1b4c3ca6a781","migrationVersion":{"lens":"7.13.0"},"references":[{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"indexpattern-datasource-current-indexpattern","type":"index-pattern"},{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"indexpattern-datasource-layer-35fd070e-5bbc-4906-bf69-8548a213d7a0","type":"index-pattern"},{"id":"e6994960-bd9e-11eb-9520-1b4c3ca6a781","name":"tag-ref-e6994960-bd9e-11eb-9520-1b4c3ca6a781","type":"tag"}],"sort":[1622144050677,978],"type":"lens","updated_at":"2021-05-27T19:34:10.677Z","version":"WzE5OTQsMl0="} +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"title":"logstash_area_chart","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"logstash_area_chart\",\"type\":\"area\",\"params\":{\"type\":\"area\",\"grid\":{\"categoryLines\":false,\"style\":{\"color\":\"#eee\"}},\"categoryAxes\":[{\"id\":\"CategoryAxis-1\",\"type\":\"category\",\"position\":\"bottom\",\"show\":true,\"style\":{},\"scale\":{\"type\":\"linear\"},\"labels\":{\"show\":true,\"truncate\":100,\"filter\":true},\"title\":{}}],\"valueAxes\":[{\"id\":\"ValueAxis-1\",\"name\":\"LeftAxis-1\",\"type\":\"value\",\"position\":\"left\",\"show\":true,\"style\":{},\"scale\":{\"type\":\"linear\",\"mode\":\"normal\"},\"labels\":{\"show\":true,\"rotate\":0,\"filter\":false,\"truncate\":100},\"title\":{\"text\":\"Count\"}}],\"seriesParams\":[{\"show\":\"true\",\"type\":\"area\",\"mode\":\"stacked\",\"data\":{\"label\":\"Count\",\"id\":\"1\"},\"drawLinesBetweenPoints\":true,\"showCircles\":true,\"interpolate\":\"linear\",\"valueAxis\":\"ValueAxis-1\"}],\"addTooltip\":true,\"addLegend\":true,\"legendPosition\":\"right\",\"times\":[],\"addTimeMarker\":false,\"palette\":{\"type\":\"palette\",\"name\":\"kibana_palette\"},\"isVislibVis\":true,\"detailedTooltip\":true,\"fittingFunction\":\"zero\"},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"enabled\":true,\"type\":\"date_histogram\",\"schema\":\"segment\",\"params\":{\"field\":\"@timestamp\",\"timeRange\":{\"from\":\"2010-01-28T19:25:55.242Z\",\"to\":\"2021-01-28T19:40:55.242Z\",\"mode\":\"absolute\"},\"useNormalizedEsInterval\":true,\"interval\":\"auto\",\"drop_partials\":false,\"min_doc_count\":1,\"extended_bounds\":{}}},{\"id\":\"3\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"group\",\"params\":{\"field\":\"machine.os.raw\",\"size\":5,\"order\":\"desc\",\"orderBy\":\"1\",\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"customLabel\":\"machine OS\"}}]}"},"coreMigrationVersion":"7.13.1","id":"36b91810-6239-11eb-aebf-c306684b328d","migrationVersion":{"visualization":"7.13.0"},"references":[{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"sort":[1621974331088,14],"type":"visualization","updated_at":"2021-05-25T20:25:31.088Z","version":"WzI2LDJd"} +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"title":"logstash_horizontal","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"logstash_horizontal\",\"type\":\"horizontal_bar\",\"params\":{\"type\":\"histogram\",\"grid\":{\"categoryLines\":false,\"style\":{\"color\":\"#eee\"}},\"categoryAxes\":[{\"id\":\"CategoryAxis-1\",\"type\":\"category\",\"position\":\"left\",\"show\":true,\"style\":{},\"scale\":{\"type\":\"linear\"},\"labels\":{\"show\":true,\"rotate\":0,\"filter\":false,\"truncate\":200},\"title\":{}}],\"valueAxes\":[{\"id\":\"ValueAxis-1\",\"name\":\"LeftAxis-1\",\"type\":\"value\",\"position\":\"bottom\",\"show\":true,\"style\":{},\"scale\":{\"type\":\"linear\",\"mode\":\"normal\"},\"labels\":{\"show\":true,\"rotate\":75,\"filter\":true,\"truncate\":100},\"title\":{\"text\":\"no of documents\"}}],\"seriesParams\":[{\"show\":true,\"type\":\"histogram\",\"mode\":\"normal\",\"data\":{\"label\":\"no of documents\",\"id\":\"1\"},\"valueAxis\":\"ValueAxis-1\",\"drawLinesBetweenPoints\":true,\"showCircles\":true}],\"addTooltip\":true,\"addLegend\":true,\"legendPosition\":\"right\",\"times\":[],\"addTimeMarker\":true,\"palette\":{\"type\":\"palette\",\"name\":\"kibana_palette\"},\"isVislibVis\":true,\"detailedTooltip\":true},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{\"customLabel\":\"no of documents\"}},{\"id\":\"2\",\"enabled\":true,\"type\":\"date_histogram\",\"schema\":\"segment\",\"params\":{\"field\":\"@timestamp\",\"timeRange\":{\"from\":\"2015-07-24T08:58:14.175Z\",\"to\":\"2015-11-11T13:28:17.223Z\",\"mode\":\"absolute\"},\"useNormalizedEsInterval\":true,\"interval\":\"auto\",\"drop_partials\":false,\"min_doc_count\":1,\"extended_bounds\":{}}},{\"id\":\"3\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"group\",\"params\":{\"field\":\"agent.raw\",\"size\":5,\"order\":\"desc\",\"orderBy\":\"1\",\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\"}},{\"id\":\"4\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"group\",\"params\":{\"field\":\"extension.raw\",\"size\":5,\"order\":\"desc\",\"orderBy\":\"1\",\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\"}}]}"},"coreMigrationVersion":"7.13.1","id":"e4aef350-623d-11eb-aebf-c306684b328d","migrationVersion":{"visualization":"7.13.0"},"references":[{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"sort":[1621974333130,10],"type":"visualization","updated_at":"2021-05-25T20:25:33.130Z","version":"WzMwLDJd"} +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"title":"logstash_linechart","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"logstash_linechart\",\"type\":\"line\",\"params\":{\"type\":\"line\",\"grid\":{\"categoryLines\":false,\"style\":{\"color\":\"#eee\"}},\"categoryAxes\":[{\"id\":\"CategoryAxis-1\",\"type\":\"category\",\"position\":\"bottom\",\"show\":true,\"style\":{},\"scale\":{\"type\":\"linear\"},\"labels\":{\"show\":true,\"truncate\":100,\"filter\":true},\"title\":{}}],\"valueAxes\":[{\"id\":\"ValueAxis-1\",\"name\":\"LeftAxis-1\",\"type\":\"value\",\"position\":\"left\",\"show\":true,\"style\":{},\"scale\":{\"type\":\"linear\",\"mode\":\"normal\"},\"labels\":{\"show\":true,\"rotate\":0,\"filter\":false,\"truncate\":100},\"title\":{\"text\":\"Count\"}}],\"seriesParams\":[{\"show\":\"true\",\"type\":\"line\",\"mode\":\"normal\",\"data\":{\"label\":\"Count\",\"id\":\"1\"},\"valueAxis\":\"ValueAxis-1\",\"drawLinesBetweenPoints\":true,\"showCircles\":true}],\"addTooltip\":true,\"addLegend\":true,\"legendPosition\":\"right\",\"times\":[],\"addTimeMarker\":false,\"radiusRatio\":51,\"palette\":{\"type\":\"palette\",\"name\":\"kibana_palette\"},\"isVislibVis\":true,\"detailedTooltip\":true,\"fittingFunction\":\"zero\"},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"enabled\":true,\"type\":\"date_histogram\",\"schema\":\"segment\",\"params\":{\"field\":\"@timestamp\",\"timeRange\":{\"from\":\"2015-09-18T06:38:43.311Z\",\"to\":\"2015-09-26T04:02:51.104Z\",\"mode\":\"absolute\"},\"useNormalizedEsInterval\":true,\"interval\":\"auto\",\"drop_partials\":false,\"min_doc_count\":1,\"extended_bounds\":{}}},{\"id\":\"3\",\"enabled\":true,\"type\":\"sum\",\"schema\":\"radius\",\"params\":{\"field\":\"bytes\",\"customLabel\":\"bubbles\"}},{\"id\":\"4\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"group\",\"params\":{\"field\":\"machine.os.raw\",\"size\":5,\"order\":\"desc\",\"orderBy\":\"1\",\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\"}}]}"},"coreMigrationVersion":"7.13.1","id":"f92e5630-623e-11eb-aebf-c306684b328d","migrationVersion":{"visualization":"7.13.0"},"references":[{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"sort":[1621974334172,12],"type":"visualization","updated_at":"2021-05-25T20:25:34.172Z","version":"WzMyLDJd"} +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"title":"logstash_heatmap","uiStateJSON":"{\"vis\":{\"defaultColors\":{\"0% - 25%\":\"rgb(255,255,204)\",\"25% - 50%\":\"rgb(254,217,118)\",\"50% - 75%\":\"rgb(253,141,60)\",\"75% - 100%\":\"rgb(227,27,28)\"}}}","version":1,"visState":"{\"title\":\"logstash_heatmap\",\"type\":\"heatmap\",\"params\":{\"type\":\"heatmap\",\"addTooltip\":true,\"addLegend\":true,\"enableHover\":false,\"legendPosition\":\"right\",\"times\":[],\"colorsNumber\":4,\"colorSchema\":\"Yellow to Red\",\"setColorRange\":false,\"colorsRange\":[],\"invertColors\":false,\"percentageMode\":true,\"valueAxes\":[{\"show\":false,\"id\":\"ValueAxis-1\",\"type\":\"value\",\"scale\":{\"type\":\"linear\",\"defaultYExtents\":false},\"labels\":{\"show\":false,\"rotate\":0,\"overwriteColor\":false,\"color\":\"#555\"}}],\"row\":true},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"enabled\":true,\"type\":\"date_histogram\",\"schema\":\"segment\",\"params\":{\"field\":\"@timestamp\",\"timeRange\":{\"from\":\"2015-07-24T08:58:14.175Z\",\"to\":\"2015-11-11T13:28:17.223Z\",\"mode\":\"absolute\"},\"useNormalizedEsInterval\":true,\"interval\":\"auto\",\"drop_partials\":false,\"min_doc_count\":1,\"extended_bounds\":{}}},{\"id\":\"3\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"group\",\"params\":{\"field\":\"machine.os.raw\",\"size\":5,\"order\":\"desc\",\"orderBy\":\"1\",\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\"}},{\"id\":\"4\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"split\",\"params\":{\"field\":\"response.raw\",\"size\":5,\"order\":\"desc\",\"orderBy\":\"1\",\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\"}}]}"},"coreMigrationVersion":"7.13.1","id":"9853d4d0-623d-11eb-aebf-c306684b328d","migrationVersion":{"visualization":"7.13.0"},"references":[{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"sort":[1621974335202,93],"type":"visualization","updated_at":"2021-05-25T20:25:35.202Z","version":"WzM0LDJd"} +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"title":"logstash_goalchart","uiStateJSON":"{\"vis\":{\"defaultColors\":{\"0 - 33\":\"rgb(0,104,55)\",\"33 - 67\":\"rgb(255,255,190)\",\"67 - 100\":\"rgb(165,0,38)\"}}}","version":1,"visState":"{\"title\":\"logstash_goalchart\",\"type\":\"goal\",\"params\":{\"addTooltip\":true,\"addLegend\":false,\"isDisplayWarning\":false,\"type\":\"gauge\",\"gauge\":{\"verticalSplit\":false,\"autoExtend\":false,\"percentageMode\":true,\"gaugeType\":\"Circle\",\"gaugeStyle\":\"Full\",\"backStyle\":\"Full\",\"orientation\":\"vertical\",\"useRanges\":false,\"colorSchema\":\"Green to Red\",\"gaugeColorMode\":\"None\",\"colorsRange\":[{\"from\":0,\"to\":10000},{\"from\":10001,\"to\":20000},{\"from\":20001,\"to\":30000}],\"invertColors\":false,\"labels\":{\"show\":true,\"color\":\"black\"},\"scale\":{\"show\":false,\"labels\":false,\"color\":\"#333\",\"width\":2},\"type\":\"meter\",\"style\":{\"bgFill\":\"#000\",\"bgColor\":false,\"labelColor\":false,\"subText\":\"\",\"fontSize\":60},\"minAngle\":0,\"maxAngle\":6.283185307179586}},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"enabled\":true,\"type\":\"date_histogram\",\"schema\":\"group\",\"params\":{\"field\":\"@timestamp\",\"timeRange\":{\"from\":\"2015-07-24T08:58:14.175Z\",\"to\":\"2015-11-11T13:28:17.223Z\",\"mode\":\"absolute\"},\"useNormalizedEsInterval\":true,\"interval\":\"auto\",\"drop_partials\":false,\"min_doc_count\":1,\"extended_bounds\":{}}}]}"},"coreMigrationVersion":"7.13.1","id":"6ecb33b0-623d-11eb-aebf-c306684b328d","migrationVersion":{"visualization":"7.13.0"},"references":[{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"sort":[1621974336232,97],"type":"visualization","updated_at":"2021-05-25T20:25:36.232Z","version":"WzM2LDJd"} +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"title":"logstash_gauge","uiStateJSON":"{\"vis\":{\"defaultColors\":{\"0 - 50\":\"rgb(0,104,55)\",\"50 - 75\":\"rgb(255,255,190)\",\"75 - 100\":\"rgb(165,0,38)\"}}}","version":1,"visState":"{\"title\":\"logstash_gauge\",\"type\":\"gauge\",\"params\":{\"type\":\"gauge\",\"addTooltip\":true,\"addLegend\":true,\"isDisplayWarning\":false,\"gauge\":{\"extendRange\":true,\"percentageMode\":false,\"gaugeType\":\"Arc\",\"gaugeStyle\":\"Full\",\"backStyle\":\"Full\",\"orientation\":\"vertical\",\"colorSchema\":\"Green to Red\",\"gaugeColorMode\":\"Labels\",\"colorsRange\":[{\"from\":0,\"to\":50},{\"from\":50,\"to\":75},{\"from\":75,\"to\":100}],\"invertColors\":false,\"labels\":{\"show\":true,\"color\":\"black\"},\"scale\":{\"show\":true,\"labels\":false,\"color\":\"#333\"},\"type\":\"meter\",\"style\":{\"bgWidth\":0.9,\"width\":0.9,\"mask\":false,\"bgMask\":false,\"maskBars\":50,\"bgFill\":\"#eee\",\"bgColor\":false,\"subText\":\"\",\"fontSize\":60,\"labelColor\":true},\"alignment\":\"horizontal\"}},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"enabled\":true,\"type\":\"range\",\"schema\":\"group\",\"params\":{\"field\":\"bytes\",\"ranges\":[{\"from\":0,\"to\":10001},{\"from\":10002,\"to\":1000000}],\"json\":\"\"}}]}"},"coreMigrationVersion":"7.13.1","id":"b8e35c80-623c-11eb-aebf-c306684b328d","migrationVersion":{"visualization":"7.13.0"},"references":[{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"sort":[1621974337263,95],"type":"visualization","updated_at":"2021-05-25T20:25:37.263Z","version":"WzM4LDJd"} +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"title":"logstash_coordinatemaps","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"logstash_coordinatemaps\",\"type\":\"tile_map\",\"params\":{\"colorSchema\":\"Yellow to Red\",\"mapType\":\"Scaled Circle Markers\",\"isDesaturated\":false,\"addTooltip\":true,\"heatClusterSize\":1.5,\"legendPosition\":\"bottomright\",\"mapZoom\":2,\"mapCenter\":[0,0],\"wms\":{\"enabled\":false,\"options\":{\"format\":\"image/png\",\"transparent\":true},\"selectedTmsLayer\":{\"origin\":\"elastic_maps_service\",\"id\":\"road_map\",\"minZoom\":0,\"maxZoom\":18,\"attribution\":\"

    © OpenStreetMap contributors|OpenMapTiles|Elastic Maps Service

    \"}}},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"enabled\":true,\"type\":\"geohash_grid\",\"schema\":\"segment\",\"params\":{\"field\":\"geo.coordinates\",\"autoPrecision\":true,\"isFilteredByCollar\":true,\"useGeocentroid\":true,\"mapZoom\":2,\"mapCenter\":[0,0],\"precision\":2,\"customLabel\":\"logstash src/dest\"}}]}"},"coreMigrationVersion":"7.13.1","id":"f1bc75d0-6239-11eb-aebf-c306684b328d","migrationVersion":{"visualization":"7.13.0"},"references":[{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"sort":[1621974338282,99],"type":"visualization","updated_at":"2021-05-25T20:25:38.282Z","version":"WzQwLDJd"} +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"title":"logstash_inputcontrols","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"logstash_inputcontrols\",\"type\":\"input_control_vis\",\"params\":{\"controls\":[{\"id\":\"1611928563867\",\"fieldName\":\"machine.ram\",\"parent\":\"\",\"label\":\"Logstash RAM\",\"type\":\"range\",\"options\":{\"decimalPlaces\":0,\"step\":1024},\"indexPatternRefName\":\"control_0_index_pattern\"},{\"id\":\"1611928586274\",\"fieldName\":\"machine.os.raw\",\"parent\":\"\",\"label\":\"Logstash OS\",\"type\":\"list\",\"options\":{\"type\":\"terms\",\"multiselect\":true,\"dynamicOptions\":true,\"size\":5,\"order\":\"desc\"},\"indexPatternRefName\":\"control_1_index_pattern\"}],\"updateFiltersOnChange\":false,\"useTimeFilter\":false,\"pinFilters\":false},\"aggs\":[]}"},"coreMigrationVersion":"7.13.1","id":"d79fe3d0-6239-11eb-aebf-c306684b328d","migrationVersion":{"visualization":"7.13.0"},"references":[{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"control_0_index_pattern","type":"index-pattern"},{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"control_1_index_pattern","type":"index-pattern"}],"sort":[1621974340341,25],"type":"visualization","updated_at":"2021-05-25T20:25:40.341Z","version":"WzQ0LDJd"} +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"title":"logstash_markdown","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"logstash_markdown\",\"type\":\"markdown\",\"params\":{\"fontSize\":12,\"openLinksInNewTab\":true,\"markdown\":\"Kibana is built with JS https://www.javascript.com/\"},\"aggs\":[]}"},"coreMigrationVersion":"7.13.1","id":"318375a0-6240-11eb-aebf-c306684b328d","migrationVersion":{"visualization":"7.13.0"},"references":[],"sort":[1621974341379,22],"type":"visualization","updated_at":"2021-05-25T20:25:41.379Z","version":"WzQ2LDJd"} +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"title":"logstash_vegaviz","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"logstash_vegaviz\",\"type\":\"vega\",\"params\":{\"spec\":\"{\\n/*\\n\\nWelcome to Vega visualizations. Here you can design your own dataviz from scratch using a declarative language called Vega, or its simpler form Vega-Lite. In Vega, you have the full control of what data is loaded, even from multiple sources, how that data is transformed, and what visual elements are used to show it. Use help icon to view Vega examples, tutorials, and other docs. Use the wrench icon to reformat this text, or to remove comments.\\n\\nThis example graph shows the document count in all indexes in the current time range. You might need to adjust the time filter in the upper right corner.\\n*/\\n\\n $schema: https://vega.github.io/schema/vega-lite/v2.json\\n title: Event counts from all indexes\\n\\n // Define the data source\\n data: {\\n url: {\\n/*\\nAn object instead of a string for the \\\"url\\\" param is treated as an Elasticsearch query. Anything inside this object is not part of the Vega language, but only understood by Kibana and Elasticsearch server. This query counts the number of documents per time interval, assuming you have a @timestamp field in your data.\\n\\nKibana has a special handling for the fields surrounded by \\\"%\\\". They are processed before the the query is sent to Elasticsearch. This way the query becomes context aware, and can use the time range and the dashboard filters.\\n*/\\n\\n // Apply dashboard context filters when set\\n %context%: true\\n // Filter the time picker (upper right corner) with this field\\n %timefield%: @timestamp\\n\\n/*\\nSee .search() documentation for : https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/api-reference.html#api-search\\n*/\\n\\n // Which index to search\\n index: logstash-*\\n // Aggregate data by the time field into time buckets, counting the number of documents in each bucket.\\n body: {\\n aggs: {\\n time_buckets: {\\n date_histogram: {\\n // Use date histogram aggregation on @timestamp field\\n field: @timestamp\\n // The interval value will depend on the daterange picker (true), or use an integer to set an approximate bucket count\\n interval: {%autointerval%: true}\\n // Make sure we get an entire range, even if it has no data\\n extended_bounds: {\\n // Use the current time range's start and end\\n min: {%timefilter%: \\\"min\\\"}\\n max: {%timefilter%: \\\"max\\\"}\\n }\\n // Use this for linear (e.g. line, area) graphs. Without it, empty buckets will not show up\\n min_doc_count: 13\\n }\\n }\\n }\\n // Speed up the response by only including aggregation results\\n size: 0\\n }\\n }\\n/*\\nElasticsearch will return results in this format:\\n\\naggregations: {\\n time_buckets: {\\n buckets: [\\n {\\n key_as_string: 2015-11-30T22:00:00.000Z\\n key: 1448920800000\\n doc_count: 0\\n },\\n {\\n key_as_string: 2015-11-30T23:00:00.000Z\\n key: 1448924400000\\n doc_count: 0\\n }\\n ...\\n ]\\n }\\n}\\n\\nFor our graph, we only need the list of bucket values. Use the format.property to discard everything else.\\n*/\\n format: {property: \\\"aggregations.time_buckets.buckets\\\"}\\n }\\n\\n // \\\"mark\\\" is the graphics element used to show our data. Other mark values are: area, bar, circle, line, point, rect, rule, square, text, and tick. See https://vega.github.io/vega-lite/docs/mark.html\\n mark: line\\n\\n // \\\"encoding\\\" tells the \\\"mark\\\" what data to use and in what way. See https://vega.github.io/vega-lite/docs/encoding.html\\n encoding: {\\n x: {\\n // The \\\"key\\\" value is the timestamp in milliseconds. Use it for X axis.\\n field: key\\n type: temporal\\n axis: {title: false} // Customize X axis format\\n }\\n y: {\\n // The \\\"doc_count\\\" is the count per bucket. Use it for Y axis.\\n field: doc_count\\n type: quantitative\\n axis: {title: \\\"Document count\\\"}\\n }\\n }\\n}\\n\"},\"aggs\":[]}"},"coreMigrationVersion":"7.13.1","id":"e461eb20-6245-11eb-aebf-c306684b328d","migrationVersion":{"visualization":"7.13.0"},"references":[],"sort":[1621974342396,17],"type":"visualization","updated_at":"2021-05-25T20:25:42.396Z","version":"WzQ4LDJd"} +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"language\":\"kuery\",\"query\":\"\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"title":"logstash_regionmap","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"logstash_regionmap\",\"type\":\"region_map\",\"params\":{\"addTooltip\":true,\"colorSchema\":\"Yellow to Red\",\"emsHotLink\":\"https://maps.elastic.co/v6.7?locale=en#file/world_countries\",\"isDisplayWarning\":true,\"legendPosition\":\"bottomright\",\"mapCenter\":[0,0],\"mapZoom\":2,\"outlineWeight\":1,\"selectedJoinField\":{\"type\":\"id\",\"name\":\"iso2\",\"description\":\"ISO 3166-1 alpha-2 code\"},\"showAllShapes\":true,\"wms\":{\"enabled\":false,\"options\":{\"format\":\"image/png\",\"transparent\":true},\"selectedTmsLayer\":{\"origin\":\"elastic_maps_service\",\"id\":\"road_map\",\"minZoom\":0,\"maxZoom\":18,\"attribution\":\"

    © OpenStreetMap contributors|OpenMapTiles|Elastic Maps Service

    \"}},\"selectedLayer\":{\"name\":\"World Countries\",\"origin\":\"elastic_maps_service\",\"id\":\"world_countries\",\"created_at\":\"2017-04-26T17:12:15.978370\",\"attribution\":\"Made with NaturalEarth | Elastic Maps Service\",\"fields\":[{\"type\":\"id\",\"name\":\"iso2\",\"description\":\"ISO 3166-1 alpha-2 code\"},{\"type\":\"id\",\"name\":\"iso3\",\"description\":\"ISO 3166-1 alpha-3 code\"},{\"type\":\"property\",\"name\":\"name\",\"description\":\"name\"}],\"format\":{\"type\":\"geojson\"},\"layerId\":\"elastic_maps_service.World Countries\",\"isEMS\":true}},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"segment\",\"params\":{\"field\":\"geo.dest\",\"size\":5,\"order\":\"desc\",\"orderBy\":\"1\",\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\"}}]}"},"coreMigrationVersion":"7.13.1","id":"25bdc750-6242-11eb-aebf-c306684b328d","migrationVersion":{"visualization":"7.13.0"},"references":[{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"sort":[1621974343416,19],"type":"visualization","updated_at":"2021-05-25T20:25:43.416Z","version":"WzUwLDJd"} +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"title":"logstash_verticalbarchart","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"logstash_verticalbarchart\",\"type\":\"histogram\",\"params\":{\"type\":\"histogram\",\"grid\":{\"categoryLines\":false,\"style\":{\"color\":\"#eee\"}},\"categoryAxes\":[{\"id\":\"CategoryAxis-1\",\"type\":\"category\",\"position\":\"bottom\",\"show\":true,\"style\":{},\"scale\":{\"type\":\"linear\"},\"labels\":{\"show\":true,\"truncate\":100,\"filter\":true},\"title\":{}}],\"valueAxes\":[{\"id\":\"ValueAxis-1\",\"name\":\"LeftAxis-1\",\"type\":\"value\",\"position\":\"left\",\"show\":true,\"style\":{},\"scale\":{\"type\":\"linear\",\"mode\":\"normal\",\"defaultYExtents\":true},\"labels\":{\"show\":true,\"rotate\":0,\"filter\":false,\"truncate\":100},\"title\":{\"text\":\"Count\"}}],\"seriesParams\":[{\"show\":\"true\",\"type\":\"histogram\",\"mode\":\"stacked\",\"data\":{\"label\":\"Count\",\"id\":\"1\"},\"valueAxis\":\"ValueAxis-1\",\"drawLinesBetweenPoints\":true,\"showCircles\":true}],\"addTooltip\":true,\"addLegend\":true,\"legendPosition\":\"right\",\"times\":[],\"addTimeMarker\":true,\"row\":true,\"palette\":{\"type\":\"palette\",\"name\":\"kibana_palette\"},\"isVislibVis\":true,\"detailedTooltip\":true},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"enabled\":true,\"type\":\"date_histogram\",\"schema\":\"segment\",\"params\":{\"field\":\"@timestamp\",\"timeRange\":{\"from\":\"2015-09-18T06:38:43.311Z\",\"to\":\"2015-09-26T04:02:51.104Z\",\"mode\":\"absolute\"},\"useNormalizedEsInterval\":true,\"interval\":\"h\",\"drop_partials\":false,\"min_doc_count\":1,\"extended_bounds\":{},\"scaleMetricValues\":true}},{\"id\":\"3\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"split\",\"params\":{\"field\":\"response.raw\",\"size\":5,\"order\":\"desc\",\"orderBy\":\"1\",\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"customLabel\":\"Response code\"}}]}"},"coreMigrationVersion":"7.13.1","id":"71dd7bc0-6248-11eb-aebf-c306684b328d","migrationVersion":{"visualization":"7.13.0"},"references":[{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"sort":[1621974344441,16],"type":"visualization","updated_at":"2021-05-25T20:25:44.441Z","version":"WzUyLDJd"} +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"title":"logstash_metricviz","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"logstash_metricviz\",\"type\":\"metric\",\"params\":{\"addTooltip\":true,\"addLegend\":false,\"type\":\"metric\",\"metric\":{\"percentageMode\":false,\"useRanges\":false,\"colorSchema\":\"Green to Red\",\"metricColorMode\":\"None\",\"colorsRange\":[{\"from\":0,\"to\":10000}],\"labels\":{\"show\":true},\"invertColors\":false,\"style\":{\"bgFill\":\"#000\",\"bgColor\":false,\"labelColor\":false,\"subText\":\"\",\"fontSize\":60}}},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"enabled\":true,\"type\":\"range\",\"schema\":\"group\",\"params\":{\"field\":\"bytes_scripted\",\"ranges\":[{\"from\":0,\"to\":10000},{\"from\":10001,\"to\":300000}]}}]}"},"coreMigrationVersion":"7.13.1","id":"6aea48a0-6240-11eb-aebf-c306684b328d","migrationVersion":{"visualization":"7.13.0"},"references":[{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"sort":[1621974346488,27],"type":"visualization","updated_at":"2021-05-25T20:25:46.488Z","version":"WzU2LDJd"} +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"title":"logstash_piechart","uiStateJSON":"{}","version":1,"visState":"{\"aggs\":[{\"enabled\":true,\"id\":\"1\",\"params\":{},\"schema\":\"metric\",\"type\":\"count\"},{\"enabled\":true,\"id\":\"2\",\"params\":{\"field\":\"machine.os.raw\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"order\":\"desc\",\"orderBy\":\"1\",\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"size\":5},\"schema\":\"segment\",\"type\":\"terms\"}],\"params\":{\"addLegend\":true,\"addTooltip\":true,\"isDonut\":true,\"labels\":{\"last_level\":true,\"show\":false,\"truncate\":100,\"values\":true},\"legendPosition\":\"right\",\"type\":\"pie\"},\"title\":\"logstash_piechart\",\"type\":\"pie\"}"},"coreMigrationVersion":"7.13.1","id":"32b681f0-6241-11eb-aebf-c306684b328d","migrationVersion":{"visualization":"7.13.0"},"references":[{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"sort":[1621974347523,29],"type":"visualization","updated_at":"2021-05-25T20:25:47.523Z","version":"WzU4LDJd"} +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"title":"logstash_tagcloud","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"logstash_tagcloud\",\"type\":\"tagcloud\",\"params\":{\"scale\":\"log\",\"orientation\":\"single\",\"minFontSize\":18,\"maxFontSize\":72,\"showLabel\":true},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"segment\",\"params\":{\"field\":\"geo.srcdest\",\"size\":23,\"order\":\"desc\",\"orderBy\":\"1\",\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\"}}]}"},"coreMigrationVersion":"7.13.1","id":"ccca99e0-6244-11eb-aebf-c306684b328d","migrationVersion":{"visualization":"7.13.0"},"references":[{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"sort":[1621974348553,33],"type":"visualization","updated_at":"2021-05-25T20:25:48.553Z","version":"WzYwLDJd"} +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"language\":\"kuery\",\"query\":\"\"},\"filter\":[]}"},"title":"logstash_timelion","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"logstash_timelion\",\"type\":\"timelion\",\"params\":{\"expression\":\".es(q='machine.os.raw:win xp' , index=logstash-*)\",\"interval\":\"auto\"},\"aggs\":[]}"},"coreMigrationVersion":"7.13.1","id":"a4d7be80-6245-11eb-aebf-c306684b328d","migrationVersion":{"visualization":"7.13.0"},"references":[],"sort":[1621974349582,34],"type":"visualization","updated_at":"2021-05-25T20:25:49.582Z","version":"WzYyLDJd"} +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{}"},"title":"logstash_tsvb","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"logstash_tsvb\",\"type\":\"metrics\",\"params\":{\"id\":\"61ca57f0-469d-11e7-af02-69e470af7417\",\"type\":\"timeseries\",\"series\":[{\"id\":\"61ca57f1-469d-11e7-af02-69e470af7417\",\"color\":\"#68BC00\",\"split_mode\":\"everything\",\"metrics\":[{\"id\":\"61ca57f2-469d-11e7-af02-69e470af7417\",\"type\":\"count\"}],\"separate_axis\":0,\"axis_position\":\"right\",\"formatter\":\"number\",\"chart_type\":\"line\",\"line_width\":1,\"point_size\":1,\"fill\":0.5,\"stacked\":\"none\",\"split_color_mode\":\"gradient\"}],\"time_field\":\"@timestamp\",\"index_pattern\":\"\",\"interval\":\"auto\",\"axis_position\":\"left\",\"axis_formatter\":\"number\",\"axis_scale\":\"normal\",\"show_legend\":1,\"show_grid\":1,\"annotations\":[{\"fields\":\"machine.os.raw\",\"template\":\"{{machine.os.raw}}\",\"index_pattern\":\"logstash-*\",\"query_string\":{\"query\":\"machine.os.raw :\\\"win xp\\\" \",\"language\":\"lucene\"},\"id\":\"aa43ceb0-6248-11eb-9a82-ef1c6e6c0265\",\"color\":\"#F00\",\"time_field\":\"@timestamp\",\"icon\":\"fa-tag\",\"ignore_global_filters\":1,\"ignore_panel_filters\":1}],\"use_kibana_indexes\":false},\"aggs\":[]}"},"coreMigrationVersion":"7.13.1","id":"c94d8440-6248-11eb-aebf-c306684b328d","migrationVersion":{"visualization":"7.13.0"},"references":[],"sort":[1621974351638,79],"type":"visualization","updated_at":"2021-05-25T20:25:51.638Z","version":"WzY2LDJd"} +{"attributes":{"columns":["bytes_scripted"],"description":"","hits":0,"kibanaSavedObjectMeta":{"searchSourceJSON":"{\"highlightAll\":true,\"version\":true,\"query\":{\"query\":\"machine.os.raw :\\\"win xp\\\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"sort":[["@timestamp","desc"]],"title":"logstash_scripted_saved_search","version":1},"coreMigrationVersion":"7.13.1","id":"db6226f0-61c0-11eb-aebf-c306684b328d","migrationVersion":{"search":"7.9.3"},"references":[{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"sort":[1621974329204,4],"type":"search","updated_at":"2021-05-25T20:25:29.204Z","version":"WzIyLDJd"} +{"attributes":{"description":"","hits":0,"kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"language\":\"lucene\",\"query\":\"\"},\"filter\":[]}"},"optionsJSON":"{\"darkTheme\":false,\"hidePanelTitles\":false,\"useMargins\":true}","panelsJSON":"[{\"version\":\"7.3.0\",\"type\":\"visualization\",\"gridData\":{\"h\":15,\"i\":\"1\",\"w\":24,\"x\":0,\"y\":0},\"panelIndex\":\"1\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_1\"},{\"version\":\"7.3.0\",\"type\":\"visualization\",\"gridData\":{\"h\":15,\"i\":\"2\",\"w\":24,\"x\":24,\"y\":0},\"panelIndex\":\"2\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_2\"},{\"version\":\"7.3.0\",\"type\":\"visualization\",\"gridData\":{\"h\":15,\"i\":\"3\",\"w\":24,\"x\":0,\"y\":15},\"panelIndex\":\"3\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_3\"},{\"version\":\"7.3.0\",\"type\":\"visualization\",\"gridData\":{\"h\":15,\"i\":\"4\",\"w\":24,\"x\":24,\"y\":15},\"panelIndex\":\"4\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_4\"},{\"version\":\"7.3.0\",\"type\":\"visualization\",\"gridData\":{\"h\":15,\"i\":\"5\",\"w\":24,\"x\":0,\"y\":30},\"panelIndex\":\"5\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_5\"},{\"version\":\"7.3.0\",\"type\":\"visualization\",\"gridData\":{\"h\":15,\"i\":\"6\",\"w\":24,\"x\":24,\"y\":30},\"panelIndex\":\"6\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_6\"},{\"version\":\"7.3.0\",\"type\":\"visualization\",\"gridData\":{\"h\":15,\"i\":\"7\",\"w\":24,\"x\":0,\"y\":45},\"panelIndex\":\"7\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_7\"},{\"version\":\"7.3.0\",\"type\":\"visualization\",\"gridData\":{\"h\":15,\"i\":\"8\",\"w\":24,\"x\":24,\"y\":45},\"panelIndex\":\"8\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_8\"},{\"version\":\"7.3.0\",\"type\":\"visualization\",\"gridData\":{\"h\":15,\"i\":\"9\",\"w\":24,\"x\":0,\"y\":60},\"panelIndex\":\"9\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_9\"},{\"version\":\"7.3.0\",\"type\":\"visualization\",\"gridData\":{\"h\":15,\"i\":\"10\",\"w\":24,\"x\":24,\"y\":60},\"panelIndex\":\"10\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_10\"},{\"version\":\"7.3.0\",\"type\":\"visualization\",\"gridData\":{\"h\":15,\"i\":\"11\",\"w\":24,\"x\":0,\"y\":75},\"panelIndex\":\"11\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_11\"},{\"version\":\"7.3.0\",\"type\":\"visualization\",\"gridData\":{\"h\":15,\"i\":\"12\",\"w\":24,\"x\":24,\"y\":75},\"panelIndex\":\"12\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_12\"},{\"version\":\"7.3.0\",\"type\":\"visualization\",\"gridData\":{\"h\":15,\"i\":\"13\",\"w\":24,\"x\":0,\"y\":90},\"panelIndex\":\"13\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_13\"},{\"version\":\"7.3.0\",\"type\":\"visualization\",\"gridData\":{\"h\":15,\"i\":\"14\",\"w\":24,\"x\":24,\"y\":90},\"panelIndex\":\"14\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_14\"},{\"version\":\"7.3.0\",\"type\":\"visualization\",\"gridData\":{\"h\":15,\"i\":\"15\",\"w\":24,\"x\":0,\"y\":105},\"panelIndex\":\"15\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_15\"},{\"version\":\"7.3.0\",\"type\":\"visualization\",\"gridData\":{\"h\":15,\"i\":\"16\",\"w\":24,\"x\":24,\"y\":105},\"panelIndex\":\"16\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_16\"},{\"version\":\"7.3.0\",\"type\":\"visualization\",\"gridData\":{\"h\":15,\"i\":\"17\",\"w\":24,\"x\":0,\"y\":120},\"panelIndex\":\"17\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_17\"},{\"version\":\"7.3.0\",\"type\":\"visualization\",\"gridData\":{\"h\":15,\"i\":\"18\",\"w\":24,\"x\":24,\"y\":120},\"panelIndex\":\"18\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_18\"},{\"version\":\"7.3.0\",\"type\":\"visualization\",\"gridData\":{\"h\":15,\"i\":\"19\",\"w\":24,\"x\":0,\"y\":135},\"panelIndex\":\"19\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_19\"},{\"version\":\"7.3.0\",\"type\":\"search\",\"gridData\":{\"h\":15,\"i\":\"20\",\"w\":24,\"x\":24,\"y\":135},\"panelIndex\":\"20\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_20\"}]","timeRestore":false,"title":"logstash_dashboardwithtime","version":1},"coreMigrationVersion":"7.13.1","id":"154944b0-6249-11eb-aebf-c306684b328d","migrationVersion":{"dashboard":"7.11.0"},"references":[{"id":"36b91810-6239-11eb-aebf-c306684b328d","name":"1:panel_1","type":"visualization"},{"id":"0a274320-61cc-11eb-aebf-c306684b328d","name":"2:panel_2","type":"visualization"},{"id":"e4aef350-623d-11eb-aebf-c306684b328d","name":"3:panel_3","type":"visualization"},{"id":"f92e5630-623e-11eb-aebf-c306684b328d","name":"4:panel_4","type":"visualization"},{"id":"9853d4d0-623d-11eb-aebf-c306684b328d","name":"5:panel_5","type":"visualization"},{"id":"6ecb33b0-623d-11eb-aebf-c306684b328d","name":"6:panel_6","type":"visualization"},{"id":"b8e35c80-623c-11eb-aebf-c306684b328d","name":"7:panel_7","type":"visualization"},{"id":"f1bc75d0-6239-11eb-aebf-c306684b328d","name":"8:panel_8","type":"visualization"},{"id":"0d8a8860-623a-11eb-aebf-c306684b328d","name":"9:panel_9","type":"visualization"},{"id":"d79fe3d0-6239-11eb-aebf-c306684b328d","name":"10:panel_10","type":"visualization"},{"id":"318375a0-6240-11eb-aebf-c306684b328d","name":"11:panel_11","type":"visualization"},{"id":"e461eb20-6245-11eb-aebf-c306684b328d","name":"12:panel_12","type":"visualization"},{"id":"25bdc750-6242-11eb-aebf-c306684b328d","name":"13:panel_13","type":"visualization"},{"id":"71dd7bc0-6248-11eb-aebf-c306684b328d","name":"14:panel_14","type":"visualization"},{"id":"6aea48a0-6240-11eb-aebf-c306684b328d","name":"15:panel_15","type":"visualization"},{"id":"32b681f0-6241-11eb-aebf-c306684b328d","name":"16:panel_16","type":"visualization"},{"id":"ccca99e0-6244-11eb-aebf-c306684b328d","name":"17:panel_17","type":"visualization"},{"id":"a4d7be80-6245-11eb-aebf-c306684b328d","name":"18:panel_18","type":"visualization"},{"id":"c94d8440-6248-11eb-aebf-c306684b328d","name":"19:panel_19","type":"visualization"},{"id":"db6226f0-61c0-11eb-aebf-c306684b328d","name":"20:panel_20","type":"search"}],"sort":[1621974353701,76],"type":"dashboard","updated_at":"2021-05-25T20:25:53.701Z","version":"WzcwLDJd"} +{"attributes":{"description":"","state":{"datasourceStates":{"indexpattern":{"layers":{"26e2cf99-d931-4320-9e15-9dbc148f3534":{"columnOrder":["6adde1a2-4c6f-47eb-95cc-5c6a9d863a6e","beb72af1-239c-46d8-823b-b00d1e2ace43"],"columns":{"6adde1a2-4c6f-47eb-95cc-5c6a9d863a6e":{"dataType":"string","isBucketed":true,"label":"Top values of url.raw","operationType":"terms","params":{"missingBucket":false,"orderBy":{"columnId":"beb72af1-239c-46d8-823b-b00d1e2ace43","type":"column"},"orderDirection":"desc","otherBucket":true,"size":20},"scale":"ordinal","sourceField":"url.raw"},"beb72af1-239c-46d8-823b-b00d1e2ace43":{"dataType":"number","isBucketed":false,"label":"Unique count of geo.srcdest","operationType":"unique_count","scale":"ratio","sourceField":"geo.srcdest"}},"incompleteColumns":{}}}}},"filters":[],"query":{"language":"kuery","query":""},"visualization":{"layers":[{"categoryDisplay":"default","groups":["6adde1a2-4c6f-47eb-95cc-5c6a9d863a6e","6adde1a2-4c6f-47eb-95cc-5c6a9d863a6e","6adde1a2-4c6f-47eb-95cc-5c6a9d863a6e"],"layerId":"26e2cf99-d931-4320-9e15-9dbc148f3534","legendDisplay":"default","metric":"beb72af1-239c-46d8-823b-b00d1e2ace43","nestedLegend":false,"numberDisplay":"percent"}],"shape":"donut"}},"title":"lens_pie_chart","visualizationType":"lnsPie"},"coreMigrationVersion":"7.13.1","id":"21905950-bd9f-11eb-9520-1b4c3ca6a781","migrationVersion":{"lens":"7.13.0"},"references":[{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"indexpattern-datasource-current-indexpattern","type":"index-pattern"},{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"indexpattern-datasource-layer-26e2cf99-d931-4320-9e15-9dbc148f3534","type":"index-pattern"},{"id":"e6994960-bd9e-11eb-9520-1b4c3ca6a781","name":"tag-ref-e6994960-bd9e-11eb-9520-1b4c3ca6a781","type":"tag"}],"sort":[1621977672552,193],"type":"lens","updated_at":"2021-05-25T21:21:12.552Z","version":"WzIxNCwyXQ=="} +{"attributes":{"description":null,"state":{"datasourceStates":{"indexpattern":{"layers":{"a3ac0e3d-63ec-49b2-882a-b34680a967ba":{"columnOrder":["352a2c02-aa6f-4a35-b776-45c3715a6c5e","8ef68cbb-e039-49d6-b15e-be81559f4b55","14fad6b1-6a7c-4ae8-ae4b-d9569e31e04a"],"columns":{"14fad6b1-6a7c-4ae8-ae4b-d9569e31e04a":{"dataType":"number","isBucketed":false,"label":"Count of records","operationType":"count","scale":"ratio","sourceField":"Records"},"352a2c02-aa6f-4a35-b776-45c3715a6c5e":{"dataType":"string","isBucketed":true,"label":"Top values of geo.srcdest","operationType":"terms","params":{"missingBucket":false,"orderBy":{"columnId":"14fad6b1-6a7c-4ae8-ae4b-d9569e31e04a","type":"column"},"orderDirection":"desc","otherBucket":true,"size":67},"scale":"ordinal","sourceField":"geo.srcdest"},"8ef68cbb-e039-49d6-b15e-be81559f4b55":{"dataType":"date","isBucketed":true,"label":"@timestamp","operationType":"date_histogram","params":{"interval":"auto"},"scale":"interval","sourceField":"@timestamp"}},"incompleteColumns":{}}}}},"filters":[],"query":{"language":"kuery","query":""},"visualization":{"axisTitlesVisibilitySettings":{"x":true,"yLeft":true,"yRight":true},"fittingFunction":"None","gridlinesVisibilitySettings":{"x":true,"yLeft":true,"yRight":true},"layers":[{"accessors":["14fad6b1-6a7c-4ae8-ae4b-d9569e31e04a"],"layerId":"a3ac0e3d-63ec-49b2-882a-b34680a967ba","position":"top","seriesType":"bar_percentage_stacked","showGridlines":false,"splitAccessor":"352a2c02-aa6f-4a35-b776-45c3715a6c5e","xAccessor":"8ef68cbb-e039-49d6-b15e-be81559f4b55"}],"legend":{"isVisible":true,"position":"top","showSingleSeries":true},"preferredSeriesType":"bar_percentage_stacked","tickLabelsVisibilitySettings":{"x":true,"yLeft":true,"yRight":true},"valueLabels":"hide"}},"title":"lens_bar_verticalpercentage","visualizationType":"lnsXY"},"coreMigrationVersion":"7.13.1","id":"aa4b8da0-bd9f-11eb-9520-1b4c3ca6a781","migrationVersion":{"lens":"7.13.0"},"references":[{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"indexpattern-datasource-current-indexpattern","type":"index-pattern"},{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"indexpattern-datasource-layer-a3ac0e3d-63ec-49b2-882a-b34680a967ba","type":"index-pattern"},{"id":"e6994960-bd9e-11eb-9520-1b4c3ca6a781","name":"tag-ref-e6994960-bd9e-11eb-9520-1b4c3ca6a781","type":"tag"}],"sort":[1622143924918,560],"type":"lens","updated_at":"2021-05-27T19:32:04.918Z","version":"WzE5NzEsMl0="} +{"attributes":{"description":"","state":{"datasourceStates":{"indexpattern":{"layers":{"037b7937-790b-4d2d-94a5-7f5837a6ef05":{"columnOrder":["b3d46616-75e0-419e-97ea-91148961ef94","025a0fb3-dc44-4f5c-b517-2d71d3f26f14","c476db14-0cc1-40ec-863e-d2779256a407"],"columns":{"025a0fb3-dc44-4f5c-b517-2d71d3f26f14":{"dataType":"date","isBucketed":true,"label":"@timestamp","operationType":"date_histogram","params":{"interval":"auto"},"scale":"interval","sourceField":"@timestamp"},"b3d46616-75e0-419e-97ea-91148961ef94":{"dataType":"string","isBucketed":true,"label":"Top values of geo.srcdest","operationType":"terms","params":{"missingBucket":false,"orderBy":{"columnId":"c476db14-0cc1-40ec-863e-d2779256a407","type":"column"},"orderDirection":"desc","otherBucket":true,"size":3},"scale":"ordinal","sourceField":"geo.srcdest"},"c476db14-0cc1-40ec-863e-d2779256a407":{"dataType":"number","isBucketed":false,"label":"Count of records","operationType":"count","scale":"ratio","sourceField":"Records"}},"incompleteColumns":{}}}}},"filters":[],"query":{"language":"lucene","query":""},"visualization":{"axisTitlesVisibilitySettings":{"x":true,"yLeft":true,"yRight":true},"fittingFunction":"None","gridlinesVisibilitySettings":{"x":true,"yLeft":true,"yRight":true},"layers":[{"accessors":["c476db14-0cc1-40ec-863e-d2779256a407"],"layerId":"037b7937-790b-4d2d-94a5-7f5837a6ef05","position":"top","seriesType":"bar_stacked","showGridlines":false,"splitAccessor":"b3d46616-75e0-419e-97ea-91148961ef94","xAccessor":"025a0fb3-dc44-4f5c-b517-2d71d3f26f14"}],"legend":{"isVisible":true,"position":"right"},"preferredSeriesType":"bar_stacked","tickLabelsVisibilitySettings":{"x":true,"yLeft":true,"yRight":true},"valueLabels":"hide"}},"title":"lens_barchart_vertical","visualizationType":"lnsXY"},"coreMigrationVersion":"7.13.1","id":"2d3f1250-bd9f-11eb-9520-1b4c3ca6a781","migrationVersion":{"lens":"7.13.0"},"references":[{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"indexpattern-datasource-current-indexpattern","type":"index-pattern"},{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"indexpattern-datasource-layer-037b7937-790b-4d2d-94a5-7f5837a6ef05","type":"index-pattern"},{"id":"e6994960-bd9e-11eb-9520-1b4c3ca6a781","name":"tag-ref-e6994960-bd9e-11eb-9520-1b4c3ca6a781","type":"tag"}],"sort":[1621977692152,134],"type":"lens","updated_at":"2021-05-25T21:21:32.152Z","version":"WzIyNywyXQ=="} +{"attributes":{"description":null,"state":{"datasourceStates":{"indexpattern":{"layers":{"212688dc-e7d7-4875-a221-09e6191bdcf7":{"columnOrder":["05410186-83c4-460a-82bf-dd7e9d998c9f","e8659feb-1db4-4706-9147-ac1fd513a1ba","c9a32fd0-a465-44fb-8adc-b957fb72cad5"],"columns":{"05410186-83c4-460a-82bf-dd7e9d998c9f":{"dataType":"string","isBucketed":true,"label":"Top values of extension.raw","operationType":"terms","params":{"missingBucket":false,"orderBy":{"columnId":"c9a32fd0-a465-44fb-8adc-b957fb72cad5","type":"column"},"orderDirection":"desc","otherBucket":true,"size":3},"scale":"ordinal","sourceField":"extension.raw"},"c9a32fd0-a465-44fb-8adc-b957fb72cad5":{"dataType":"number","isBucketed":false,"label":"Average of bytes","operationType":"average","scale":"ratio","sourceField":"bytes"},"e8659feb-1db4-4706-9147-ac1fd513a1ba":{"dataType":"date","isBucketed":true,"label":"@timestamp","operationType":"date_histogram","params":{"interval":"auto"},"scale":"interval","sourceField":"@timestamp"}},"incompleteColumns":{}}}}},"filters":[],"query":{"language":"kuery","query":""},"visualization":{"axisTitlesVisibilitySettings":{"x":true,"yLeft":true,"yRight":true},"fittingFunction":"None","gridlinesVisibilitySettings":{"x":true,"yLeft":true,"yRight":true},"layers":[{"accessors":["c9a32fd0-a465-44fb-8adc-b957fb72cad5"],"layerId":"212688dc-e7d7-4875-a221-09e6191bdcf7","position":"top","seriesType":"bar_horizontal_stacked","showGridlines":false,"splitAccessor":"05410186-83c4-460a-82bf-dd7e9d998c9f","xAccessor":"e8659feb-1db4-4706-9147-ac1fd513a1ba"}],"legend":{"isVisible":true,"position":"right"},"preferredSeriesType":"bar_horizontal_stacked","tickLabelsVisibilitySettings":{"x":true,"yLeft":true,"yRight":true},"valueLabels":"hide"}},"title":"lens_barhorizontal_stacked","visualizationType":"lnsXY"},"coreMigrationVersion":"7.13.1","id":"edd5a560-bda4-11eb-9520-1b4c3ca6a781","migrationVersion":{"lens":"7.13.0"},"references":[{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"indexpattern-datasource-current-indexpattern","type":"index-pattern"},{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"indexpattern-datasource-layer-212688dc-e7d7-4875-a221-09e6191bdcf7","type":"index-pattern"},{"id":"e6994960-bd9e-11eb-9520-1b4c3ca6a781","name":"tag-ref-e6994960-bd9e-11eb-9520-1b4c3ca6a781","type":"tag"}],"sort":[1622055636010,504],"type":"lens","updated_at":"2021-05-26T19:00:36.010Z","version":"WzExMzQsMl0="} +{"attributes":{"description":"","state":{"datasourceStates":{"indexpattern":{"layers":{"7ab04fd4-04da-4023-8899-d94620193607":{"columnOrder":["0ab2d5f8-11f0-4b25-b8bb-3127a3b8d4c7","9eb851dd-31f6-481a-84d1-9ecce53a6ad2","f6b271a7-509b-4c37-b7b6-ac5be4bcb49a"],"columns":{"0ab2d5f8-11f0-4b25-b8bb-3127a3b8d4c7":{"dataType":"string","isBucketed":true,"label":"Top values of request.raw","operationType":"terms","params":{"missingBucket":false,"orderBy":{"columnId":"f6b271a7-509b-4c37-b7b6-ac5be4bcb49a","type":"column"},"orderDirection":"desc","otherBucket":true,"size":3},"scale":"ordinal","sourceField":"request.raw"},"9eb851dd-31f6-481a-84d1-9ecce53a6ad2":{"dataType":"date","isBucketed":true,"label":"@timestamp","operationType":"date_histogram","params":{"interval":"auto"},"scale":"interval","sourceField":"@timestamp"},"f6b271a7-509b-4c37-b7b6-ac5be4bcb49a":{"dataType":"number","isBucketed":false,"label":"Count of records","operationType":"count","scale":"ratio","sourceField":"Records"}},"incompleteColumns":{}}}}},"filters":[],"query":{"language":"kuery","query":""},"visualization":{"axisTitlesVisibilitySettings":{"x":true,"yLeft":true,"yRight":true},"fittingFunction":"None","gridlinesVisibilitySettings":{"x":true,"yLeft":true,"yRight":true},"layers":[{"accessors":["f6b271a7-509b-4c37-b7b6-ac5be4bcb49a"],"layerId":"7ab04fd4-04da-4023-8899-d94620193607","position":"top","seriesType":"bar_horizontal_percentage_stacked","showGridlines":false,"splitAccessor":"0ab2d5f8-11f0-4b25-b8bb-3127a3b8d4c7","xAccessor":"9eb851dd-31f6-481a-84d1-9ecce53a6ad2"}],"legend":{"isVisible":true,"position":"right"},"preferredSeriesType":"bar_horizontal_percentage_stacked","tickLabelsVisibilitySettings":{"x":true,"yLeft":true,"yRight":true},"valueLabels":"hide"}},"title":"lens_barhorizontalpercentage","visualizationType":"lnsXY"},"coreMigrationVersion":"7.13.1","id":"2c25a450-bda5-11eb-9520-1b4c3ca6a781","migrationVersion":{"lens":"7.13.0"},"references":[{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"indexpattern-datasource-current-indexpattern","type":"index-pattern"},{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"indexpattern-datasource-layer-7ab04fd4-04da-4023-8899-d94620193607","type":"index-pattern"},{"id":"e6994960-bd9e-11eb-9520-1b4c3ca6a781","name":"tag-ref-e6994960-bd9e-11eb-9520-1b4c3ca6a781","type":"tag"}],"sort":[1621980267288,251],"type":"lens","updated_at":"2021-05-25T22:04:27.288Z","version":"WzQxNiwyXQ=="} +{"attributes":{"description":"","state":{"datasourceStates":{"indexpattern":{"layers":{"037b7937-790b-4d2d-94a5-7f5837a6ef05":{"columnOrder":["b3d46616-75e0-419e-97ea-91148961ef94","025a0fb3-dc44-4f5c-b517-2d71d3f26f14","c476db14-0cc1-40ec-863e-d2779256a407"],"columns":{"025a0fb3-dc44-4f5c-b517-2d71d3f26f14":{"dataType":"date","isBucketed":true,"label":"@timestamp","operationType":"date_histogram","params":{"interval":"auto"},"scale":"interval","sourceField":"@timestamp"},"b3d46616-75e0-419e-97ea-91148961ef94":{"dataType":"string","isBucketed":true,"label":"Top values of geo.srcdest","operationType":"terms","params":{"missingBucket":false,"orderBy":{"columnId":"c476db14-0cc1-40ec-863e-d2779256a407","type":"column"},"orderDirection":"desc","otherBucket":true,"size":3},"scale":"ordinal","sourceField":"geo.srcdest"},"c476db14-0cc1-40ec-863e-d2779256a407":{"dataType":"number","isBucketed":false,"label":"Count of records","operationType":"count","scale":"ratio","sourceField":"Records"}},"incompleteColumns":{}}}}},"filters":[],"query":{"language":"lucene","query":""},"visualization":{"axisTitlesVisibilitySettings":{"x":true,"yLeft":true,"yRight":true},"fittingFunction":"None","gridlinesVisibilitySettings":{"x":true,"yLeft":true,"yRight":true},"layers":[{"accessors":["c476db14-0cc1-40ec-863e-d2779256a407"],"layerId":"037b7937-790b-4d2d-94a5-7f5837a6ef05","position":"top","seriesType":"bar_stacked","showGridlines":false,"splitAccessor":"b3d46616-75e0-419e-97ea-91148961ef94","xAccessor":"025a0fb3-dc44-4f5c-b517-2d71d3f26f14"}],"legend":{"isVisible":true,"position":"right"},"preferredSeriesType":"bar_stacked","tickLabelsVisibilitySettings":{"x":true,"yLeft":true,"yRight":true},"valueLabels":"hide"}},"title":"lens_dashboard_logstash","visualizationType":"lnsXY"},"coreMigrationVersion":"7.13.1","id":"e79116e0-bd9e-11eb-9520-1b4c3ca6a781","migrationVersion":{"lens":"7.13.0"},"references":[{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"indexpattern-datasource-current-indexpattern","type":"index-pattern"},{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"indexpattern-datasource-layer-037b7937-790b-4d2d-94a5-7f5837a6ef05","type":"index-pattern"},{"id":"e6994960-bd9e-11eb-9520-1b4c3ca6a781","name":"tag-ref-e6994960-bd9e-11eb-9520-1b4c3ca6a781","type":"tag"}],"sort":[1621977575250,175],"type":"lens","updated_at":"2021-05-25T21:19:35.250Z","version":"WzE1NCwyXQ=="} +{"attributes":{"description":"","state":{"datasourceStates":{"indexpattern":{"layers":{"72783e5f-aa7b-4b8a-b26c-a3e4d051340e":{"columnOrder":["0f619652-9ff1-453b-ae1f-7371baa82f55"],"columns":{"0f619652-9ff1-453b-ae1f-7371baa82f55":{"dataType":"number","isBucketed":false,"label":"Average of phpmemory","operationType":"average","params":{"format":{"id":"percent","params":{"decimals":10}}},"scale":"ratio","sourceField":"phpmemory"}},"incompleteColumns":{}}}}},"filters":[],"query":{"language":"kuery","query":""},"visualization":{"accessor":"0f619652-9ff1-453b-ae1f-7371baa82f55","layerId":"72783e5f-aa7b-4b8a-b26c-a3e4d051340e"}},"title":"lens_metric","visualizationType":"lnsMetric"},"coreMigrationVersion":"7.13.1","id":"974fb950-bda5-11eb-9520-1b4c3ca6a781","migrationVersion":{"lens":"7.13.0"},"references":[{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"indexpattern-datasource-current-indexpattern","type":"index-pattern"},{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"indexpattern-datasource-layer-72783e5f-aa7b-4b8a-b26c-a3e4d051340e","type":"index-pattern"},{"id":"e6994960-bd9e-11eb-9520-1b4c3ca6a781","name":"tag-ref-e6994960-bd9e-11eb-9520-1b4c3ca6a781","type":"tag"}],"sort":[1621980447079,289],"type":"lens","updated_at":"2021-05-25T22:07:27.079Z","version":"WzUyMSwyXQ=="} +{"attributes":{"description":null,"state":{"datasourceStates":{"indexpattern":{"layers":{"bb478774-f9e8-4380-bf3a-f4a89a4d79b5":{"columnOrder":["4573ae8f-8f9d-4918-b496-c08f7102c6e1","cebdc6c5-3587-4f57-879c-dd63ea99cf03"],"columns":{"4573ae8f-8f9d-4918-b496-c08f7102c6e1":{"dataType":"string","isBucketed":true,"label":"Top values of machine.os.raw","operationType":"terms","params":{"missingBucket":false,"orderBy":{"columnId":"cebdc6c5-3587-4f57-879c-dd63ea99cf03","type":"column"},"orderDirection":"desc","otherBucket":true,"size":5},"scale":"ordinal","sourceField":"machine.os.raw"},"cebdc6c5-3587-4f57-879c-dd63ea99cf03":{"dataType":"number","isBucketed":false,"label":"Count of records","operationType":"count","scale":"ratio","sourceField":"Records"}},"incompleteColumns":{}}}}},"filters":[],"query":{"language":"kuery","query":""},"visualization":{"layers":[{"categoryDisplay":"default","groups":["4573ae8f-8f9d-4918-b496-c08f7102c6e1"],"layerId":"bb478774-f9e8-4380-bf3a-f4a89a4d79b5","legendDisplay":"default","metric":"cebdc6c5-3587-4f57-879c-dd63ea99cf03","nestedLegend":false,"numberDisplay":"percent"}],"shape":"pie"}},"title":"lens_piechart","visualizationType":"lnsPie"},"coreMigrationVersion":"7.13.1","id":"51b63040-bda5-11eb-9520-1b4c3ca6a781","migrationVersion":{"lens":"7.13.0"},"references":[{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"indexpattern-datasource-current-indexpattern","type":"index-pattern"},{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"indexpattern-datasource-layer-bb478774-f9e8-4380-bf3a-f4a89a4d79b5","type":"index-pattern"},{"id":"e6994960-bd9e-11eb-9520-1b4c3ca6a781","name":"tag-ref-e6994960-bd9e-11eb-9520-1b4c3ca6a781","type":"tag"}],"sort":[1621980390953,279],"type":"lens","updated_at":"2021-05-25T22:06:30.953Z","version":"WzQ5NCwyXQ=="} +{"attributes":{"description":"","state":{"datasourceStates":{"indexpattern":{"layers":{"a1b85651-db29-441f-8f08-cf1b9b6f7bf1":{"columnOrder":["2b3bdc32-0be0-49dc-993d-4630b0bd1185","b85cc0a7-0b18-4b08-b7f0-c617f80cf903","03203126-8286-444d-b5b3-4f399eaf2c26","44305317-61e8-4600-9f3c-ac4070e0c529"],"columns":{"03203126-8286-444d-b5b3-4f399eaf2c26":{"dataType":"date","isBucketed":true,"label":"@timestamp","operationType":"date_histogram","params":{"interval":"auto"},"scale":"interval","sourceField":"@timestamp"},"2b3bdc32-0be0-49dc-993d-4630b0bd1185":{"dataType":"string","isBucketed":true,"label":"Top values of extension.raw","operationType":"terms","params":{"missingBucket":false,"orderBy":{"columnId":"44305317-61e8-4600-9f3c-ac4070e0c529","type":"column"},"orderDirection":"desc","otherBucket":true,"size":3},"scale":"ordinal","sourceField":"extension.raw"},"44305317-61e8-4600-9f3c-ac4070e0c529":{"dataType":"number","isBucketed":false,"label":"Count of records","operationType":"count","scale":"ratio","sourceField":"Records"},"b85cc0a7-0b18-4b08-b7f0-c617f80cf903":{"dataType":"string","isBucketed":true,"label":"Top values of machine.os.raw","operationType":"terms","params":{"missingBucket":false,"orderBy":{"columnId":"44305317-61e8-4600-9f3c-ac4070e0c529","type":"column"},"orderDirection":"desc","otherBucket":true,"size":3},"scale":"ordinal","sourceField":"machine.os.raw"}},"incompleteColumns":{}}}}},"filters":[],"query":{"language":"kuery","query":""},"visualization":{"columns":[{"columnId":"2b3bdc32-0be0-49dc-993d-4630b0bd1185","isTransposed":false},{"columnId":"b85cc0a7-0b18-4b08-b7f0-c617f80cf903","isTransposed":false},{"columnId":"03203126-8286-444d-b5b3-4f399eaf2c26","isTransposed":false},{"columnId":"44305317-61e8-4600-9f3c-ac4070e0c529","isTransposed":false}],"layerId":"a1b85651-db29-441f-8f08-cf1b9b6f7bf1"}},"title":"lens_table","visualizationType":"lnsDatatable"},"coreMigrationVersion":"7.13.1","id":"b00679c0-bda5-11eb-9520-1b4c3ca6a781","migrationVersion":{"lens":"7.13.0"},"references":[{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"indexpattern-datasource-current-indexpattern","type":"index-pattern"},{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"indexpattern-datasource-layer-a1b85651-db29-441f-8f08-cf1b9b6f7bf1","type":"index-pattern"},{"id":"e6994960-bd9e-11eb-9520-1b4c3ca6a781","name":"tag-ref-e6994960-bd9e-11eb-9520-1b4c3ca6a781","type":"tag"}],"sort":[1621980488543,306],"type":"lens","updated_at":"2021-05-25T22:08:08.543Z","version":"WzU1NiwyXQ=="} +{"attributes":{"description":"","state":{"datasourceStates":{"indexpattern":{"layers":{"4fbb51e9-1f99-4b5e-b59d-60fcb547b1d9":{"columnOrder":["08a1af05-743d-480e-9056-3405b1bdda7d","bae35990-75c2-487f-94eb-d8e03d2eda33"],"columns":{"08a1af05-743d-480e-9056-3405b1bdda7d":{"dataType":"string","isBucketed":true,"label":"Top values of geo.srcdest","operationType":"terms","params":{"missingBucket":false,"orderBy":{"columnId":"bae35990-75c2-487f-94eb-d8e03d2eda33","type":"column"},"orderDirection":"desc","otherBucket":true,"size":25},"scale":"ordinal","sourceField":"geo.srcdest"},"bae35990-75c2-487f-94eb-d8e03d2eda33":{"dataType":"number","isBucketed":false,"label":"Count of records","operationType":"count","scale":"ratio","sourceField":"Records"}},"incompleteColumns":{}}}}},"filters":[],"query":{"language":"kuery","query":""},"visualization":{"layers":[{"categoryDisplay":"default","groups":["08a1af05-743d-480e-9056-3405b1bdda7d","08a1af05-743d-480e-9056-3405b1bdda7d","08a1af05-743d-480e-9056-3405b1bdda7d"],"layerId":"4fbb51e9-1f99-4b5e-b59d-60fcb547b1d9","legendDisplay":"default","metric":"bae35990-75c2-487f-94eb-d8e03d2eda33","nestedLegend":false,"numberDisplay":"percent"}],"shape":"treemap"}},"title":"lens_treemap","visualizationType":"lnsPie"},"coreMigrationVersion":"7.13.1","id":"652ade10-bd9f-11eb-9520-1b4c3ca6a781","migrationVersion":{"lens":"7.13.0"},"references":[{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"indexpattern-datasource-current-indexpattern","type":"index-pattern"},{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"indexpattern-datasource-layer-4fbb51e9-1f99-4b5e-b59d-60fcb547b1d9","type":"index-pattern"},{"id":"e6994960-bd9e-11eb-9520-1b4c3ca6a781","name":"tag-ref-e6994960-bd9e-11eb-9520-1b4c3ca6a781","type":"tag"}],"sort":[1621977785972,208],"type":"lens","updated_at":"2021-05-25T21:23:05.972Z","version":"WzI3MywyXQ=="} +{"attributes":{"description":"","state":{"datasourceStates":{"indexpattern":{"layers":{"e84503c1-4dbd-4ac6-9ac9-ad938654680f":{"columnOrder":["38c73fd4-6330-4162-8a7b-1a059f005da8","e8d4dad2-ac30-4741-aca0-904eb1fc8455","70433aa7-3c2c-4e6c-b8cf-4218c995cff5"],"columns":{"38c73fd4-6330-4162-8a7b-1a059f005da8":{"dataType":"string","isBucketed":true,"label":"Top values of url.raw","operationType":"terms","params":{"missingBucket":false,"orderBy":{"columnId":"70433aa7-3c2c-4e6c-b8cf-4218c995cff5","type":"column"},"orderDirection":"desc","otherBucket":true,"size":3},"scale":"ordinal","sourceField":"url.raw"},"70433aa7-3c2c-4e6c-b8cf-4218c995cff5":{"dataType":"number","isBucketed":false,"label":"Count of records","operationType":"count","scale":"ratio","sourceField":"Records"},"e8d4dad2-ac30-4741-aca0-904eb1fc8455":{"dataType":"date","isBucketed":true,"label":"@timestamp","operationType":"date_histogram","params":{"interval":"auto"},"scale":"interval","sourceField":"@timestamp"}},"incompleteColumns":{}}}}},"filters":[],"query":{"language":"kuery","query":""},"visualization":{"axisTitlesVisibilitySettings":{"x":true,"yLeft":true,"yRight":true},"fittingFunction":"None","gridlinesVisibilitySettings":{"x":true,"yLeft":true,"yRight":true},"layers":[{"accessors":["70433aa7-3c2c-4e6c-b8cf-4218c995cff5"],"layerId":"e84503c1-4dbd-4ac6-9ac9-ad938654680f","position":"top","seriesType":"line","showGridlines":false,"splitAccessor":"38c73fd4-6330-4162-8a7b-1a059f005da8","xAccessor":"e8d4dad2-ac30-4741-aca0-904eb1fc8455"}],"legend":{"isVisible":true,"position":"right"},"preferredSeriesType":"line","tickLabelsVisibilitySettings":{"x":true,"yLeft":true,"yRight":true},"valueLabels":"hide"}},"title":"lens_line_chart","visualizationType":"lnsXY"},"coreMigrationVersion":"7.13.1","id":"7f3b5fb0-be2f-11eb-9520-1b4c3ca6a781","migrationVersion":{"lens":"7.13.0"},"references":[{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"indexpattern-datasource-current-indexpattern","type":"index-pattern"},{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"indexpattern-datasource-layer-e84503c1-4dbd-4ac6-9ac9-ad938654680f","type":"index-pattern"},{"id":"e6994960-bd9e-11eb-9520-1b4c3ca6a781","name":"tag-ref-e6994960-bd9e-11eb-9520-1b4c3ca6a781","type":"tag"}],"sort":[1622039677230,345],"type":"lens","updated_at":"2021-05-26T14:34:37.230Z","version":"WzY1OSwyXQ=="} +{"attributes":{"fieldAttrs":"{\"speaker\":{\"count\":1},\"text_entry\":{\"count\":6},\"type\":{\"count\":3}}","fields":"[]","runtimeFieldMap":"{}","title":"shakespeare"},"coreMigrationVersion":"7.13.1","id":"4e937b20-619d-11eb-aebf-c306684b328d","migrationVersion":{"index-pattern":"7.11.0"},"references":[],"sort":[1621974324538,82],"type":"index-pattern","updated_at":"2021-05-25T20:25:24.538Z","version":"WzksMl0="} +{"attributes":{"description":"","state":{"datasourceStates":{"indexpattern":{"layers":{"d35680ce-c285-4fae-89d6-1245671bbc78":{"columnOrder":["2bcbffbe-c24d-4e74-8a03-9a6da7db70c0","6b00fde6-bfaa-4da1-beeb-bfd85a4cb2ff","8319857d-a03b-4158-bdf1-2a788e510445"],"columns":{"2bcbffbe-c24d-4e74-8a03-9a6da7db70c0":{"dataType":"date","isBucketed":true,"label":"@timestamp","operationType":"date_histogram","params":{"interval":"auto"},"scale":"interval","sourceField":"@timestamp"},"6b00fde6-bfaa-4da1-beeb-bfd85a4cb2ff":{"dataType":"number","isBucketed":false,"label":"Average of bytes","operationType":"average","scale":"ratio","sourceField":"bytes"},"8319857d-a03b-4158-bdf1-2a788e510445":{"dataType":"number","isBucketed":false,"label":"Sum of bytes_scripted","operationType":"sum","params":{"format":{"id":"number","params":{"decimals":2}}},"scale":"ratio","sourceField":"bytes_scripted"}},"incompleteColumns":{}}}}},"filters":[],"query":{"language":"kuery","query":""},"visualization":{"axisTitlesVisibilitySettings":{"x":true,"yLeft":true,"yRight":true},"fittingFunction":"None","gridlinesVisibilitySettings":{"x":true,"yLeft":true,"yRight":true},"layers":[{"accessors":["6b00fde6-bfaa-4da1-beeb-bfd85a4cb2ff","8319857d-a03b-4158-bdf1-2a788e510445"],"layerId":"d35680ce-c285-4fae-89d6-1245671bbc78","position":"top","seriesType":"area","showGridlines":false,"xAccessor":"2bcbffbe-c24d-4e74-8a03-9a6da7db70c0","yConfig":[{"axisMode":"auto","forAccessor":"8319857d-a03b-4158-bdf1-2a788e510445"}]}],"legend":{"isVisible":true,"position":"right"},"preferredSeriesType":"area","tickLabelsVisibilitySettings":{"x":true,"yLeft":true,"yRight":true},"valueLabels":"hide"}},"title":"lens_area_chart","visualizationType":"lnsXY"},"coreMigrationVersion":"7.13.1","id":"bb9e5bb0-be2f-11eb-9520-1b4c3ca6a781","migrationVersion":{"lens":"7.13.0"},"references":[{"id":"4e937b20-619d-11eb-aebf-c306684b328d","name":"indexpattern-datasource-current-indexpattern","type":"index-pattern"},{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"indexpattern-datasource-layer-d35680ce-c285-4fae-89d6-1245671bbc78","type":"index-pattern"},{"id":"e6994960-bd9e-11eb-9520-1b4c3ca6a781","name":"tag-ref-e6994960-bd9e-11eb-9520-1b4c3ca6a781","type":"tag"}],"sort":[1622039778542,361],"type":"lens","updated_at":"2021-05-26T14:36:18.542Z","version":"WzcwNCwyXQ=="} +{"attributes":{"description":"","state":{"datasourceStates":{"indexpattern":{"layers":{"70bd567e-8e67-4696-a406-313b06344fa9":{"columnOrder":["96ddedfb-043b-479e-a746-600e72ab546e","d325b7da-4266-4035-9b13-5f853615149a","2fc1391b-17d1-4c49-9ddc-06ff307e3520","1cc6f19c-cbcb-4abd-b56d-1a2f9deae5f3"],"columns":{"1cc6f19c-cbcb-4abd-b56d-1a2f9deae5f3":{"dataType":"number","isBucketed":false,"label":"Average of machine.ram","operationType":"average","scale":"ratio","sourceField":"machine.ram"},"2fc1391b-17d1-4c49-9ddc-06ff307e3520":{"dataType":"number","isBucketed":false,"label":"Count of records","operationType":"count","scale":"ratio","sourceField":"Records"},"96ddedfb-043b-479e-a746-600e72ab546e":{"dataType":"string","isBucketed":true,"label":"Top values of machine.os.raw","operationType":"terms","params":{"missingBucket":false,"orderBy":{"columnId":"2fc1391b-17d1-4c49-9ddc-06ff307e3520","type":"column"},"orderDirection":"desc","otherBucket":true,"size":3},"scale":"ordinal","sourceField":"machine.os.raw"},"d325b7da-4266-4035-9b13-5f853615149a":{"dataType":"date","isBucketed":true,"label":"@timestamp","operationType":"date_histogram","params":{"interval":"auto"},"scale":"interval","sourceField":"@timestamp"}},"incompleteColumns":{}}}}},"filters":[],"query":{"language":"kuery","query":""},"visualization":{"axisTitlesVisibilitySettings":{"x":true,"yLeft":true,"yRight":true},"fittingFunction":"None","gridlinesVisibilitySettings":{"x":true,"yLeft":true,"yRight":true},"layers":[{"accessors":["2fc1391b-17d1-4c49-9ddc-06ff307e3520","1cc6f19c-cbcb-4abd-b56d-1a2f9deae5f3"],"layerId":"70bd567e-8e67-4696-a406-313b06344fa9","position":"top","seriesType":"area_stacked","showGridlines":false,"splitAccessor":"96ddedfb-043b-479e-a746-600e72ab546e","xAccessor":"d325b7da-4266-4035-9b13-5f853615149a"}],"legend":{"isVisible":true,"position":"right"},"preferredSeriesType":"area_stacked","tickLabelsVisibilitySettings":{"x":true,"yLeft":true,"yRight":true},"valueLabels":"hide"}},"title":"lens_area_stacked","visualizationType":"lnsXY"},"coreMigrationVersion":"7.13.1","id":"dd315430-be2f-11eb-9520-1b4c3ca6a781","migrationVersion":{"lens":"7.13.0"},"references":[{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"indexpattern-datasource-current-indexpattern","type":"index-pattern"},{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"indexpattern-datasource-layer-70bd567e-8e67-4696-a406-313b06344fa9","type":"index-pattern"},{"id":"e6994960-bd9e-11eb-9520-1b4c3ca6a781","name":"tag-ref-e6994960-bd9e-11eb-9520-1b4c3ca6a781","type":"tag"}],"sort":[1622039834870,378],"type":"lens","updated_at":"2021-05-26T14:37:14.870Z","version":"WzczOCwyXQ=="} +{"attributes":{"description":"","hits":0,"kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"language\":\"kuery\",\"query\":\"\"},\"filter\":[]}"},"optionsJSON":"{\"hidePanelTitles\":false,\"useMargins\":true}","panelsJSON":"[{\"version\":\"7.13.1\",\"type\":\"lens\",\"gridData\":{\"x\":24,\"y\":0,\"w\":24,\"h\":15,\"i\":\"2e80716f-c1b6-46f2-be2b-35db744b5031\"},\"panelIndex\":\"2e80716f-c1b6-46f2-be2b-35db744b5031\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"type\":\"lens\",\"visualizationType\":\"lnsPie\",\"state\":{\"datasourceStates\":{\"indexpattern\":{\"layers\":{\"26e2cf99-d931-4320-9e15-9dbc148f3534\":{\"columns\":{\"6adde1a2-4c6f-47eb-95cc-5c6a9d863a6e\":{\"label\":\"Top values of url.raw\",\"dataType\":\"string\",\"operationType\":\"terms\",\"scale\":\"ordinal\",\"sourceField\":\"url.raw\",\"isBucketed\":true,\"params\":{\"size\":20,\"orderBy\":{\"type\":\"column\",\"columnId\":\"beb72af1-239c-46d8-823b-b00d1e2ace43\"},\"orderDirection\":\"desc\",\"otherBucket\":true,\"missingBucket\":false}},\"beb72af1-239c-46d8-823b-b00d1e2ace43\":{\"label\":\"Unique count of geo.srcdest\",\"dataType\":\"number\",\"operationType\":\"unique_count\",\"scale\":\"ratio\",\"sourceField\":\"geo.srcdest\",\"isBucketed\":false}},\"columnOrder\":[\"6adde1a2-4c6f-47eb-95cc-5c6a9d863a6e\",\"beb72af1-239c-46d8-823b-b00d1e2ace43\"],\"incompleteColumns\":{}}}}},\"visualization\":{\"shape\":\"donut\",\"layers\":[{\"layerId\":\"26e2cf99-d931-4320-9e15-9dbc148f3534\",\"groups\":[\"6adde1a2-4c6f-47eb-95cc-5c6a9d863a6e\",\"6adde1a2-4c6f-47eb-95cc-5c6a9d863a6e\",\"6adde1a2-4c6f-47eb-95cc-5c6a9d863a6e\"],\"metric\":\"beb72af1-239c-46d8-823b-b00d1e2ace43\",\"numberDisplay\":\"percent\",\"categoryDisplay\":\"default\",\"legendDisplay\":\"default\",\"nestedLegend\":false}]},\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filters\":[]},\"references\":[{\"type\":\"index-pattern\",\"id\":\"56b34100-619d-11eb-aebf-c306684b328d\",\"name\":\"indexpattern-datasource-current-indexpattern\"},{\"type\":\"index-pattern\",\"id\":\"56b34100-619d-11eb-aebf-c306684b328d\",\"name\":\"indexpattern-datasource-layer-26e2cf99-d931-4320-9e15-9dbc148f3534\"}]},\"enhancements\":{}},\"panelRefName\":\"panel_2e80716f-c1b6-46f2-be2b-35db744b5031\"},{\"version\":\"7.13.1\",\"type\":\"lens\",\"gridData\":{\"x\":0,\"y\":0,\"w\":24,\"h\":15,\"i\":\"da8843e0-6789-4aae-bcd0-81f270538719\"},\"panelIndex\":\"da8843e0-6789-4aae-bcd0-81f270538719\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_da8843e0-6789-4aae-bcd0-81f270538719\"},{\"version\":\"7.13.1\",\"type\":\"lens\",\"gridData\":{\"x\":24,\"y\":15,\"w\":24,\"h\":15,\"i\":\"adcd4418-7299-4efa-b369-5f71a7b4ebe0\"},\"panelIndex\":\"adcd4418-7299-4efa-b369-5f71a7b4ebe0\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_adcd4418-7299-4efa-b369-5f71a7b4ebe0\"},{\"version\":\"7.13.1\",\"type\":\"lens\",\"gridData\":{\"x\":0,\"y\":15,\"w\":24,\"h\":15,\"i\":\"869754a7-edf0-478f-a7f1-80374f63108a\"},\"panelIndex\":\"869754a7-edf0-478f-a7f1-80374f63108a\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_869754a7-edf0-478f-a7f1-80374f63108a\"},{\"version\":\"7.13.1\",\"type\":\"lens\",\"gridData\":{\"x\":24,\"y\":30,\"w\":24,\"h\":15,\"i\":\"67111cf4-338e-453f-8621-e8dea64082d1\"},\"panelIndex\":\"67111cf4-338e-453f-8621-e8dea64082d1\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_67111cf4-338e-453f-8621-e8dea64082d1\"},{\"version\":\"7.13.1\",\"type\":\"lens\",\"gridData\":{\"x\":0,\"y\":30,\"w\":24,\"h\":15,\"i\":\"13f21ad2-9b2d-4aa2-a908-b62e1bdedc1d\"},\"panelIndex\":\"13f21ad2-9b2d-4aa2-a908-b62e1bdedc1d\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_13f21ad2-9b2d-4aa2-a908-b62e1bdedc1d\"},{\"version\":\"7.13.1\",\"type\":\"lens\",\"gridData\":{\"x\":24,\"y\":45,\"w\":24,\"h\":15,\"i\":\"88847944-ae1b-45fd-b102-3b45f9bea04b\"},\"panelIndex\":\"88847944-ae1b-45fd-b102-3b45f9bea04b\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_88847944-ae1b-45fd-b102-3b45f9bea04b\"},{\"version\":\"7.13.1\",\"type\":\"lens\",\"gridData\":{\"x\":0,\"y\":45,\"w\":24,\"h\":15,\"i\":\"5a7924c7-eac0-4573-9199-fecec5b82e9e\"},\"panelIndex\":\"5a7924c7-eac0-4573-9199-fecec5b82e9e\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_5a7924c7-eac0-4573-9199-fecec5b82e9e\"},{\"version\":\"7.13.1\",\"type\":\"lens\",\"gridData\":{\"x\":24,\"y\":60,\"w\":24,\"h\":15,\"i\":\"f8f49591-f071-4a96-b1ed-cd65daff5648\"},\"panelIndex\":\"f8f49591-f071-4a96-b1ed-cd65daff5648\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_f8f49591-f071-4a96-b1ed-cd65daff5648\"},{\"version\":\"7.13.1\",\"type\":\"lens\",\"gridData\":{\"x\":0,\"y\":60,\"w\":24,\"h\":15,\"i\":\"9f357f47-c2a0-421f-a456-9583c40837ab\"},\"panelIndex\":\"9f357f47-c2a0-421f-a456-9583c40837ab\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_9f357f47-c2a0-421f-a456-9583c40837ab\"},{\"version\":\"7.13.1\",\"type\":\"lens\",\"gridData\":{\"x\":24,\"y\":75,\"w\":24,\"h\":15,\"i\":\"6cb383e9-1e80-44f9-80d5-7b8c585668db\"},\"panelIndex\":\"6cb383e9-1e80-44f9-80d5-7b8c585668db\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_6cb383e9-1e80-44f9-80d5-7b8c585668db\"},{\"version\":\"7.13.1\",\"type\":\"lens\",\"gridData\":{\"x\":0,\"y\":75,\"w\":24,\"h\":15,\"i\":\"57f5f0bf-6610-4599-aad4-37484640b5e2\"},\"panelIndex\":\"57f5f0bf-6610-4599-aad4-37484640b5e2\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_57f5f0bf-6610-4599-aad4-37484640b5e2\"},{\"version\":\"7.13.1\",\"type\":\"lens\",\"gridData\":{\"x\":0,\"y\":90,\"w\":24,\"h\":15,\"i\":\"32d3ab66-52e1-44e3-8c1f-1dccff3c5692\"},\"panelIndex\":\"32d3ab66-52e1-44e3-8c1f-1dccff3c5692\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_32d3ab66-52e1-44e3-8c1f-1dccff3c5692\"},{\"version\":\"7.13.1\",\"type\":\"lens\",\"gridData\":{\"x\":24,\"y\":90,\"w\":24,\"h\":15,\"i\":\"dd1718fd-74ee-4032-851b-db97e893825d\"},\"panelIndex\":\"dd1718fd-74ee-4032-851b-db97e893825d\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_dd1718fd-74ee-4032-851b-db97e893825d\"},{\"version\":\"7.13.1\",\"type\":\"lens\",\"gridData\":{\"x\":0,\"y\":105,\"w\":24,\"h\":15,\"i\":\"98a556ee-078b-4e03-93a8-29996133cdcb\"},\"panelIndex\":\"98a556ee-078b-4e03-93a8-29996133cdcb\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"type\":\"lens\",\"visualizationType\":\"lnsXY\",\"state\":{\"datasourceStates\":{\"indexpattern\":{\"layers\":{\"999a2d60-cb2a-451c-8d71-80d7e92e70fd\":{\"columns\":{\"ce9117a2-773c-474c-8fb1-18940cf58b38\":{\"label\":\"Top values of type\",\"dataType\":\"string\",\"operationType\":\"terms\",\"scale\":\"ordinal\",\"sourceField\":\"type\",\"isBucketed\":true,\"params\":{\"size\":5,\"orderBy\":{\"type\":\"column\",\"columnId\":\"cf07d1f1-d3fd-41f7-812c-d8587ec75959\"},\"orderDirection\":\"asc\",\"otherBucket\":true,\"missingBucket\":false}},\"a3d10552-e352-40d0-a156-e86112c0501a\":{\"label\":\"Top values of _type\",\"dataType\":\"string\",\"operationType\":\"terms\",\"scale\":\"ordinal\",\"sourceField\":\"_type\",\"isBucketed\":true,\"params\":{\"size\":3,\"orderBy\":{\"type\":\"column\",\"columnId\":\"cf07d1f1-d3fd-41f7-812c-d8587ec75959\"},\"orderDirection\":\"desc\",\"otherBucket\":true,\"missingBucket\":false}},\"cf07d1f1-d3fd-41f7-812c-d8587ec75959\":{\"label\":\"Count of records\",\"dataType\":\"number\",\"operationType\":\"count\",\"isBucketed\":false,\"scale\":\"ratio\",\"sourceField\":\"Records\"},\"9c5db2f3-9eb0-4667-9a74-3318301de251\":{\"label\":\"Sum of bytes\",\"dataType\":\"number\",\"operationType\":\"sum\",\"sourceField\":\"bytes\",\"isBucketed\":false,\"scale\":\"ratio\"}},\"columnOrder\":[\"ce9117a2-773c-474c-8fb1-18940cf58b38\",\"a3d10552-e352-40d0-a156-e86112c0501a\",\"cf07d1f1-d3fd-41f7-812c-d8587ec75959\",\"9c5db2f3-9eb0-4667-9a74-3318301de251\"],\"incompleteColumns\":{}}}}},\"visualization\":{\"legend\":{\"isVisible\":true,\"position\":\"right\"},\"valueLabels\":\"hide\",\"fittingFunction\":\"None\",\"axisTitlesVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"tickLabelsVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"gridlinesVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"preferredSeriesType\":\"bar_stacked\",\"layers\":[{\"layerId\":\"999a2d60-cb2a-451c-8d71-80d7e92e70fd\",\"accessors\":[\"cf07d1f1-d3fd-41f7-812c-d8587ec75959\",\"9c5db2f3-9eb0-4667-9a74-3318301de251\"],\"position\":\"top\",\"seriesType\":\"bar_stacked\",\"showGridlines\":false,\"xAccessor\":\"ce9117a2-773c-474c-8fb1-18940cf58b38\",\"splitAccessor\":\"a3d10552-e352-40d0-a156-e86112c0501a\"}]},\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filters\":[]},\"references\":[{\"type\":\"index-pattern\",\"id\":\"56b34100-619d-11eb-aebf-c306684b328d\",\"name\":\"indexpattern-datasource-current-indexpattern\"},{\"type\":\"index-pattern\",\"id\":\"56b34100-619d-11eb-aebf-c306684b328d\",\"name\":\"indexpattern-datasource-layer-999a2d60-cb2a-451c-8d71-80d7e92e70fd\"}]},\"enhancements\":{}}},{\"version\":\"7.13.1\",\"type\":\"lens\",\"gridData\":{\"x\":24,\"y\":105,\"w\":24,\"h\":15,\"i\":\"62a0f0b0-3589-4cef-807b-b1b4258b7a9b\"},\"panelIndex\":\"62a0f0b0-3589-4cef-807b-b1b4258b7a9b\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_62a0f0b0-3589-4cef-807b-b1b4258b7a9b\"},{\"version\":\"7.13.1\",\"type\":\"map\",\"gridData\":{\"x\":0,\"y\":120,\"w\":24,\"h\":15,\"i\":\"dcc0defa-3376-465c-9b5b-2ba69528848c\"},\"panelIndex\":\"dcc0defa-3376-465c-9b5b-2ba69528848c\",\"embeddableConfig\":{\"mapCenter\":{\"lat\":19.94277,\"lon\":0,\"zoom\":1.56},\"mapBuffer\":{\"minLon\":-210.32666,\"minLat\":-64.8435,\"maxLon\":210.32666,\"maxLat\":95.13806},\"isLayerTOCOpen\":true,\"openTOCDetails\":[],\"hiddenLayers\":[],\"enhancements\":{}},\"panelRefName\":\"panel_dcc0defa-3376-465c-9b5b-2ba69528848c\"}]","refreshInterval":{"pause":true,"value":0},"timeFrom":"2015-09-20T01:56:56.132Z","timeRestore":true,"timeTo":"2015-09-21T11:18:20.471Z","title":"lens_maps_dashboard_logstash","version":1},"coreMigrationVersion":"7.13.1","id":"16d86080-be5c-11eb-9520-1b4c3ca6a781","migrationVersion":{"dashboard":"7.11.0"},"references":[{"id":"21905950-bd9f-11eb-9520-1b4c3ca6a781","name":"2e80716f-c1b6-46f2-be2b-35db744b5031:panel_2e80716f-c1b6-46f2-be2b-35db744b5031","type":"lens"},{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"2e80716f-c1b6-46f2-be2b-35db744b5031:indexpattern-datasource-current-indexpattern","type":"index-pattern"},{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"2e80716f-c1b6-46f2-be2b-35db744b5031:indexpattern-datasource-layer-26e2cf99-d931-4320-9e15-9dbc148f3534","type":"index-pattern"},{"id":"aa4b8da0-bd9f-11eb-9520-1b4c3ca6a781","name":"da8843e0-6789-4aae-bcd0-81f270538719:panel_da8843e0-6789-4aae-bcd0-81f270538719","type":"lens"},{"id":"2d3f1250-bd9f-11eb-9520-1b4c3ca6a781","name":"adcd4418-7299-4efa-b369-5f71a7b4ebe0:panel_adcd4418-7299-4efa-b369-5f71a7b4ebe0","type":"lens"},{"id":"edd5a560-bda4-11eb-9520-1b4c3ca6a781","name":"869754a7-edf0-478f-a7f1-80374f63108a:panel_869754a7-edf0-478f-a7f1-80374f63108a","type":"lens"},{"id":"2c25a450-bda5-11eb-9520-1b4c3ca6a781","name":"67111cf4-338e-453f-8621-e8dea64082d1:panel_67111cf4-338e-453f-8621-e8dea64082d1","type":"lens"},{"id":"e79116e0-bd9e-11eb-9520-1b4c3ca6a781","name":"13f21ad2-9b2d-4aa2-a908-b62e1bdedc1d:panel_13f21ad2-9b2d-4aa2-a908-b62e1bdedc1d","type":"lens"},{"id":"974fb950-bda5-11eb-9520-1b4c3ca6a781","name":"88847944-ae1b-45fd-b102-3b45f9bea04b:panel_88847944-ae1b-45fd-b102-3b45f9bea04b","type":"lens"},{"id":"21905950-bd9f-11eb-9520-1b4c3ca6a781","name":"5a7924c7-eac0-4573-9199-fecec5b82e9e:panel_5a7924c7-eac0-4573-9199-fecec5b82e9e","type":"lens"},{"id":"51b63040-bda5-11eb-9520-1b4c3ca6a781","name":"f8f49591-f071-4a96-b1ed-cd65daff5648:panel_f8f49591-f071-4a96-b1ed-cd65daff5648","type":"lens"},{"id":"b00679c0-bda5-11eb-9520-1b4c3ca6a781","name":"9f357f47-c2a0-421f-a456-9583c40837ab:panel_9f357f47-c2a0-421f-a456-9583c40837ab","type":"lens"},{"id":"652ade10-bd9f-11eb-9520-1b4c3ca6a781","name":"6cb383e9-1e80-44f9-80d5-7b8c585668db:panel_6cb383e9-1e80-44f9-80d5-7b8c585668db","type":"lens"},{"id":"7f3b5fb0-be2f-11eb-9520-1b4c3ca6a781","name":"57f5f0bf-6610-4599-aad4-37484640b5e2:panel_57f5f0bf-6610-4599-aad4-37484640b5e2","type":"lens"},{"id":"bb9e5bb0-be2f-11eb-9520-1b4c3ca6a781","name":"32d3ab66-52e1-44e3-8c1f-1dccff3c5692:panel_32d3ab66-52e1-44e3-8c1f-1dccff3c5692","type":"lens"},{"id":"dd315430-be2f-11eb-9520-1b4c3ca6a781","name":"dd1718fd-74ee-4032-851b-db97e893825d:panel_dd1718fd-74ee-4032-851b-db97e893825d","type":"lens"},{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"98a556ee-078b-4e03-93a8-29996133cdcb:indexpattern-datasource-current-indexpattern","type":"index-pattern"},{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"98a556ee-078b-4e03-93a8-29996133cdcb:indexpattern-datasource-layer-999a2d60-cb2a-451c-8d71-80d7e92e70fd","type":"index-pattern"},{"id":"0dbbf8b0-be3c-11eb-9520-1b4c3ca6a781","name":"62a0f0b0-3589-4cef-807b-b1b4258b7a9b:panel_62a0f0b0-3589-4cef-807b-b1b4258b7a9b","type":"lens"},{"id":"0c5974f0-be5c-11eb-9520-1b4c3ca6a781","name":"dcc0defa-3376-465c-9b5b-2ba69528848c:panel_dcc0defa-3376-465c-9b5b-2ba69528848c","type":"map"},{"id":"e6994960-bd9e-11eb-9520-1b4c3ca6a781","name":"tag-e6994960-bd9e-11eb-9520-1b4c3ca6a781","type":"tag"}],"sort":[1622058829451,686],"type":"dashboard","updated_at":"2021-05-26T19:53:49.451Z","version":"WzExOTEsMl0="} +{"attributes":{"fieldAttrs":"{}","fields":"[]","runtimeFieldMap":"{}","title":".kibana"},"coreMigrationVersion":"7.13.1","id":"1773aa90-be66-11eb-9520-1b4c3ca6a781","migrationVersion":{"index-pattern":"7.11.0"},"references":[],"sort":[1622063125441,526],"type":"index-pattern","updated_at":"2021-05-26T21:05:25.441Z","version":"WzE2NzUsMl0="} +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"title":"shakespeare_areachart","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"shakespeare_areachart\",\"type\":\"histogram\",\"params\":{\"type\":\"histogram\",\"grid\":{\"categoryLines\":false,\"style\":{\"color\":\"#eee\"}},\"categoryAxes\":[{\"id\":\"CategoryAxis-1\",\"type\":\"category\",\"position\":\"bottom\",\"show\":true,\"style\":{},\"scale\":{\"type\":\"linear\"},\"labels\":{\"show\":true,\"truncate\":100,\"filter\":true},\"title\":{}}],\"valueAxes\":[{\"id\":\"ValueAxis-1\",\"name\":\"LeftAxis-1\",\"type\":\"value\",\"position\":\"left\",\"show\":true,\"style\":{},\"scale\":{\"type\":\"linear\",\"mode\":\"normal\"},\"labels\":{\"show\":true,\"rotate\":0,\"filter\":false,\"truncate\":100},\"title\":{\"text\":\"Count\"}}],\"seriesParams\":[{\"show\":true,\"mode\":\"stacked\",\"type\":\"histogram\",\"drawLinesBetweenPoints\":true,\"showCircles\":true,\"data\":{\"id\":\"2\",\"label\":\"Count\"},\"valueAxis\":\"ValueAxis-1\"}],\"addTooltip\":true,\"addLegend\":true,\"legendPosition\":\"right\",\"times\":[],\"addTimeMarker\":false,\"palette\":{\"type\":\"palette\",\"name\":\"kibana_palette\"},\"isVislibVis\":true,\"detailedTooltip\":true},\"aggs\":[{\"id\":\"2\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"3\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"segment\",\"params\":{\"field\":\"play_name\",\"size\":20,\"order\":\"desc\",\"orderBy\":\"2\",\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\"}},{\"id\":\"4\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"group\",\"params\":{\"field\":\"play_name\",\"size\":5,\"order\":\"desc\",\"orderBy\":\"2\",\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\"}}]}"},"coreMigrationVersion":"7.13.1","id":"185283c0-619e-11eb-aebf-c306684b328d","migrationVersion":{"visualization":"7.13.0"},"references":[{"id":"4e937b20-619d-11eb-aebf-c306684b328d","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"sort":[1621974345456,21],"type":"visualization","updated_at":"2021-05-25T20:25:45.456Z","version":"WzU0LDJd"} +{"attributes":{"color":"#f44fcf","description":"","name":"shakespeare"},"coreMigrationVersion":"7.13.1","id":"42b4cec0-be32-11eb-9520-1b4c3ca6a781","references":[],"sort":[1622040864176,414],"type":"tag","updated_at":"2021-05-26T14:54:24.176Z","version":"Wzg0NCwyXQ=="} +{"attributes":{"description":"","state":{"datasourceStates":{"indexpattern":{"layers":{"3338dd55-4007-4be5-908d-25722b6174cb":{"columnOrder":["6c83b0c2-5834-4619-888c-9e8a08e47d42","b25e7497-c188-4c25-b002-1fd5bd69e76d"],"columns":{"6c83b0c2-5834-4619-888c-9e8a08e47d42":{"dataType":"string","isBucketed":true,"label":"Top values of speaker","operationType":"terms","params":{"missingBucket":false,"orderBy":{"columnId":"b25e7497-c188-4c25-b002-1fd5bd69e76d","type":"column"},"orderDirection":"desc","otherBucket":false,"size":90},"scale":"ordinal","sourceField":"speaker"},"b25e7497-c188-4c25-b002-1fd5bd69e76d":{"dataType":"number","isBucketed":false,"label":"Count of records","operationType":"count","scale":"ratio","sourceField":"Records"}},"incompleteColumns":{}}}}},"filters":[],"query":{"language":"kuery","query":""},"visualization":{"layers":[{"categoryDisplay":"default","groups":["6c83b0c2-5834-4619-888c-9e8a08e47d42","6c83b0c2-5834-4619-888c-9e8a08e47d42","6c83b0c2-5834-4619-888c-9e8a08e47d42"],"layerId":"3338dd55-4007-4be5-908d-25722b6174cb","legendDisplay":"default","metric":"b25e7497-c188-4c25-b002-1fd5bd69e76d","nestedLegend":false,"numberDisplay":"percent"}],"palette":{"name":"complimentary","type":"palette"},"shape":"treemap"}},"title":"lens_shakespeare_treemap","visualizationType":"lnsPie"},"coreMigrationVersion":"7.13.1","id":"31e9f2f0-be32-11eb-9520-1b4c3ca6a781","migrationVersion":{"lens":"7.13.0"},"references":[{"id":"4e937b20-619d-11eb-aebf-c306684b328d","name":"indexpattern-datasource-current-indexpattern","type":"index-pattern"},{"id":"4e937b20-619d-11eb-aebf-c306684b328d","name":"indexpattern-datasource-layer-3338dd55-4007-4be5-908d-25722b6174cb","type":"index-pattern"},{"id":"42b4cec0-be32-11eb-9520-1b4c3ca6a781","name":"tag-ref-42b4cec0-be32-11eb-9520-1b4c3ca6a781","type":"tag"}],"sort":[1622040944080,421],"type":"lens","updated_at":"2021-05-26T14:55:44.080Z","version":"Wzg3OSwyXQ=="} +{"attributes":{"accessCount":0,"accessDate":1622059178542,"createDate":1622059178542,"url":"/app/dashboards#/view/73398a90-619e-11eb-aebf-c306684b328d?embed=true&_g=(filters:!(),refreshInterval:(pause:!t,value:0),time:(from:%272015-09-20T01:56:56.132Z%27,to:%272015-09-21T11:18:20.471Z%27))&_a=(description:%27%27,filters:!(),fullScreenMode:!f,options:(darkTheme:!f,hidePanelTitles:!f,useMargins:!t),panels:!((embeddableConfig:(enhancements:()),gridData:(h:15,i:%271%27,w:24,x:0,y:0),id:%27185283c0-619e-11eb-aebf-c306684b328d%27,panelIndex:%271%27,type:visualization,version:%277.13.1%27),(embeddableConfig:(enhancements:()),gridData:(h:15,i:%272%27,w:24,x:24,y:0),id:%2733736660-619e-11eb-aebf-c306684b328d%27,panelIndex:%272%27,type:visualization,version:%277.13.1%27),(embeddableConfig:(enhancements:()),gridData:(h:15,i:%273%27,w:24,x:0,y:15),id:%27622ac7f0-619e-11eb-aebf-c306684b328d%27,panelIndex:%273%27,type:visualization,version:%277.13.1%27),(embeddableConfig:(enhancements:()),gridData:(h:15,i:%274%27,w:24,x:24,y:15),id:%27712ebbe0-619d-11eb-aebf-c306684b328d%27,panelIndex:%274%27,type:search,version:%277.13.1%27),(embeddableConfig:(enhancements:()),gridData:(h:15,i:%275%27,w:24,x:0,y:30),id:ddacc820-619d-11eb-aebf-c306684b328d,panelIndex:%275%27,type:search,version:%277.13.1%27),(embeddableConfig:(enhancements:()),gridData:(h:15,i:%276%27,w:24,x:24,y:30),id:f852d570-619d-11eb-aebf-c306684b328d,panelIndex:%276%27,type:search,version:%277.13.1%27)),query:(language:kuery,query:%27%27),tags:!(),timeRestore:!f,title:shakespeare_dashboard,viewMode:view)"},"coreMigrationVersion":"7.13.1","id":"32a03249ec3a048108d4b5a427a37fc8","references":[],"sort":[1622059178544,731],"type":"url","updated_at":"2021-05-26T19:59:38.544Z","version":"WzEyODYsMl0="} +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"title":"shakespeare_piechart","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"shakespeare_piechart\",\"type\":\"pie\",\"params\":{\"type\":\"pie\",\"addTooltip\":true,\"addLegend\":true,\"legendPosition\":\"right\",\"isDonut\":false,\"labels\":{\"show\":true,\"values\":true,\"last_level\":true,\"truncate\":100}},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"segment\",\"params\":{\"field\":\"play_name\",\"size\":15,\"order\":\"desc\",\"orderBy\":\"1\",\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\"}}]}"},"coreMigrationVersion":"7.13.1","id":"33736660-619e-11eb-aebf-c306684b328d","migrationVersion":{"visualization":"7.13.0"},"references":[{"id":"4e937b20-619d-11eb-aebf-c306684b328d","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"sort":[1621974350604,31],"type":"visualization","updated_at":"2021-05-25T20:25:50.604Z","version":"WzY0LDJd"} +{"attributes":{"description":"","state":{"datasourceStates":{"indexpattern":{"layers":{"a7a8f2fb-066e-4023-9755-821e84560b4a":{"columnOrder":["ee46f645-0af0-4b5d-8ed3-2557c98c9c12","91859a54-9b88-4478-8c80-0779fe165fba","62a4dea1-fab9-45ff-93e0-b99cfff719d5"],"columns":{"62a4dea1-fab9-45ff-93e0-b99cfff719d5":{"dataType":"number","isBucketed":false,"label":"Count of records","operationType":"count","scale":"ratio","sourceField":"Records"},"91859a54-9b88-4478-8c80-0779fe165fba":{"dataType":"string","isBucketed":true,"label":"Top values of play_name","operationType":"terms","params":{"missingBucket":false,"orderBy":{"columnId":"62a4dea1-fab9-45ff-93e0-b99cfff719d5","type":"column"},"orderDirection":"desc","otherBucket":true,"size":3},"scale":"ordinal","sourceField":"play_name"},"ee46f645-0af0-4b5d-8ed3-2557c98c9c12":{"dataType":"string","isBucketed":true,"label":"Top values of speaker","operationType":"terms","params":{"missingBucket":false,"orderBy":{"columnId":"62a4dea1-fab9-45ff-93e0-b99cfff719d5","type":"column"},"orderDirection":"desc","otherBucket":true,"size":25},"scale":"ordinal","sourceField":"speaker"}},"incompleteColumns":{}}}}},"filters":[],"query":{"language":"kuery","query":""},"visualization":{"layers":[{"categoryDisplay":"default","groups":["ee46f645-0af0-4b5d-8ed3-2557c98c9c12","ee46f645-0af0-4b5d-8ed3-2557c98c9c12","ee46f645-0af0-4b5d-8ed3-2557c98c9c12","ee46f645-0af0-4b5d-8ed3-2557c98c9c12","91859a54-9b88-4478-8c80-0779fe165fba"],"layerId":"a7a8f2fb-066e-4023-9755-821e84560b4a","legendDisplay":"default","metric":"62a4dea1-fab9-45ff-93e0-b99cfff719d5","nestedLegend":false,"numberDisplay":"percent"}],"palette":{"name":"kibana_palette","type":"palette"},"shape":"pie"}},"title":"lens_shakespeare_piechart","visualizationType":"lnsPie"},"coreMigrationVersion":"7.13.1","id":"b5bd5050-be31-11eb-9520-1b4c3ca6a781","migrationVersion":{"lens":"7.13.0"},"references":[{"id":"4e937b20-619d-11eb-aebf-c306684b328d","name":"indexpattern-datasource-current-indexpattern","type":"index-pattern"},{"id":"4e937b20-619d-11eb-aebf-c306684b328d","name":"indexpattern-datasource-layer-a7a8f2fb-066e-4023-9755-821e84560b4a","type":"index-pattern"},{"id":"42b4cec0-be32-11eb-9520-1b4c3ca6a781","name":"tag-ref-42b4cec0-be32-11eb-9520-1b4c3ca6a781","type":"tag"}],"sort":[1622040892536,425],"type":"lens","updated_at":"2021-05-26T14:54:52.536Z","version":"Wzg2NSwyXQ=="} +{"attributes":{"description":"","hits":0,"kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"language\":\"kuery\",\"query\":\"\"},\"filter\":[]}"},"optionsJSON":"{\"hidePanelTitles\":false,\"useMargins\":true}","panelsJSON":"[{\"version\":\"7.13.1\",\"type\":\"lens\",\"gridData\":{\"x\":0,\"y\":0,\"w\":24,\"h\":15,\"i\":\"c4b1daae-a3af-4136-969e-8485d4ba53f9\"},\"panelIndex\":\"c4b1daae-a3af-4136-969e-8485d4ba53f9\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_c4b1daae-a3af-4136-969e-8485d4ba53f9\"},{\"version\":\"7.13.1\",\"type\":\"lens\",\"gridData\":{\"x\":24,\"y\":0,\"w\":24,\"h\":15,\"i\":\"f092b002-182e-49b8-bcc4-58f5233e041b\"},\"panelIndex\":\"f092b002-182e-49b8-bcc4-58f5233e041b\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_f092b002-182e-49b8-bcc4-58f5233e041b\"}]","refreshInterval":{"pause":true,"value":0},"timeFrom":"2015-09-20T01:56:56.132Z","timeRestore":true,"timeTo":"2015-09-21T11:18:20.471Z","title":"lens_shakespeare_dashboard","version":1},"coreMigrationVersion":"7.13.1","id":"43fae350-be32-11eb-9520-1b4c3ca6a781","migrationVersion":{"dashboard":"7.11.0"},"references":[{"id":"b5bd5050-be31-11eb-9520-1b4c3ca6a781","name":"c4b1daae-a3af-4136-969e-8485d4ba53f9:panel_c4b1daae-a3af-4136-969e-8485d4ba53f9","type":"lens"},{"id":"31e9f2f0-be32-11eb-9520-1b4c3ca6a781","name":"f092b002-182e-49b8-bcc4-58f5233e041b:panel_f092b002-182e-49b8-bcc4-58f5233e041b","type":"lens"},{"id":"42b4cec0-be32-11eb-9520-1b4c3ca6a781","name":"tag-42b4cec0-be32-11eb-9520-1b4c3ca6a781","type":"tag"}],"sort":[1622040866315,411],"type":"dashboard","updated_at":"2021-05-26T14:54:26.315Z","version":"Wzg0NywyXQ=="} +{"attributes":{"description":"","hits":0,"kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"language\":\"lucene\",\"query\":\"\"},\"filter\":[]}"},"optionsJSON":"{\"darkTheme\":false,\"hidePanelTitles\":false,\"useMargins\":true}","panelsJSON":"[{\"version\":\"7.3.0\",\"type\":\"visualization\",\"gridData\":{\"h\":15,\"i\":\"1\",\"w\":24,\"x\":0,\"y\":0},\"panelIndex\":\"1\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_1\"},{\"version\":\"7.3.0\",\"type\":\"visualization\",\"gridData\":{\"h\":15,\"i\":\"2\",\"w\":24,\"x\":24,\"y\":0},\"panelIndex\":\"2\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_2\"},{\"version\":\"7.3.0\",\"type\":\"visualization\",\"gridData\":{\"h\":15,\"i\":\"3\",\"w\":24,\"x\":0,\"y\":15},\"panelIndex\":\"3\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_3\"},{\"version\":\"7.3.0\",\"type\":\"visualization\",\"gridData\":{\"h\":15,\"i\":\"4\",\"w\":24,\"x\":24,\"y\":15},\"panelIndex\":\"4\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_4\"},{\"version\":\"7.3.0\",\"type\":\"visualization\",\"gridData\":{\"h\":15,\"i\":\"5\",\"w\":24,\"x\":0,\"y\":30},\"panelIndex\":\"5\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_5\"},{\"version\":\"7.3.0\",\"type\":\"visualization\",\"gridData\":{\"h\":15,\"i\":\"6\",\"w\":24,\"x\":24,\"y\":30},\"panelIndex\":\"6\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_6\"},{\"version\":\"7.3.0\",\"type\":\"visualization\",\"gridData\":{\"h\":15,\"i\":\"7\",\"w\":24,\"x\":0,\"y\":45},\"panelIndex\":\"7\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_7\"},{\"version\":\"7.3.0\",\"type\":\"visualization\",\"gridData\":{\"h\":15,\"i\":\"8\",\"w\":24,\"x\":24,\"y\":45},\"panelIndex\":\"8\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_8\"},{\"version\":\"7.3.0\",\"type\":\"visualization\",\"gridData\":{\"h\":15,\"i\":\"9\",\"w\":24,\"x\":0,\"y\":60},\"panelIndex\":\"9\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_9\"},{\"version\":\"7.3.0\",\"type\":\"visualization\",\"gridData\":{\"h\":15,\"i\":\"10\",\"w\":24,\"x\":24,\"y\":60},\"panelIndex\":\"10\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_10\"},{\"version\":\"7.3.0\",\"type\":\"visualization\",\"gridData\":{\"h\":15,\"i\":\"11\",\"w\":24,\"x\":0,\"y\":75},\"panelIndex\":\"11\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_11\"},{\"version\":\"7.3.0\",\"type\":\"visualization\",\"gridData\":{\"h\":15,\"i\":\"12\",\"w\":24,\"x\":24,\"y\":75},\"panelIndex\":\"12\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_12\"},{\"version\":\"7.3.0\",\"type\":\"visualization\",\"gridData\":{\"h\":15,\"i\":\"13\",\"w\":24,\"x\":0,\"y\":90},\"panelIndex\":\"13\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_13\"},{\"version\":\"7.3.0\",\"type\":\"visualization\",\"gridData\":{\"h\":15,\"i\":\"14\",\"w\":24,\"x\":24,\"y\":90},\"panelIndex\":\"14\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_14\"},{\"version\":\"7.3.0\",\"type\":\"visualization\",\"gridData\":{\"h\":15,\"i\":\"15\",\"w\":24,\"x\":0,\"y\":105},\"panelIndex\":\"15\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_15\"},{\"version\":\"7.3.0\",\"type\":\"visualization\",\"gridData\":{\"h\":15,\"i\":\"16\",\"w\":24,\"x\":24,\"y\":105},\"panelIndex\":\"16\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_16\"},{\"version\":\"7.3.0\",\"type\":\"visualization\",\"gridData\":{\"h\":15,\"i\":\"17\",\"w\":24,\"x\":0,\"y\":120},\"panelIndex\":\"17\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_17\"},{\"version\":\"7.3.0\",\"type\":\"visualization\",\"gridData\":{\"h\":15,\"i\":\"18\",\"w\":24,\"x\":24,\"y\":120},\"panelIndex\":\"18\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_18\"},{\"version\":\"7.3.0\",\"type\":\"visualization\",\"gridData\":{\"h\":15,\"i\":\"19\",\"w\":24,\"x\":0,\"y\":135},\"panelIndex\":\"19\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_19\"},{\"version\":\"7.3.0\",\"type\":\"search\",\"gridData\":{\"h\":15,\"i\":\"20\",\"w\":24,\"x\":24,\"y\":135},\"panelIndex\":\"20\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_20\"}]","timeRestore":false,"title":"logstash_dashboard_withouttime","version":1},"coreMigrationVersion":"7.13.1","id":"5d3410c0-6249-11eb-aebf-c306684b328d","migrationVersion":{"dashboard":"7.11.0"},"references":[{"id":"36b91810-6239-11eb-aebf-c306684b328d","name":"1:panel_1","type":"visualization"},{"id":"0a274320-61cc-11eb-aebf-c306684b328d","name":"2:panel_2","type":"visualization"},{"id":"e4aef350-623d-11eb-aebf-c306684b328d","name":"3:panel_3","type":"visualization"},{"id":"f92e5630-623e-11eb-aebf-c306684b328d","name":"4:panel_4","type":"visualization"},{"id":"9853d4d0-623d-11eb-aebf-c306684b328d","name":"5:panel_5","type":"visualization"},{"id":"6ecb33b0-623d-11eb-aebf-c306684b328d","name":"6:panel_6","type":"visualization"},{"id":"b8e35c80-623c-11eb-aebf-c306684b328d","name":"7:panel_7","type":"visualization"},{"id":"f1bc75d0-6239-11eb-aebf-c306684b328d","name":"8:panel_8","type":"visualization"},{"id":"0d8a8860-623a-11eb-aebf-c306684b328d","name":"9:panel_9","type":"visualization"},{"id":"d79fe3d0-6239-11eb-aebf-c306684b328d","name":"10:panel_10","type":"visualization"},{"id":"318375a0-6240-11eb-aebf-c306684b328d","name":"11:panel_11","type":"visualization"},{"id":"e461eb20-6245-11eb-aebf-c306684b328d","name":"12:panel_12","type":"visualization"},{"id":"25bdc750-6242-11eb-aebf-c306684b328d","name":"13:panel_13","type":"visualization"},{"id":"71dd7bc0-6248-11eb-aebf-c306684b328d","name":"14:panel_14","type":"visualization"},{"id":"6aea48a0-6240-11eb-aebf-c306684b328d","name":"15:panel_15","type":"visualization"},{"id":"32b681f0-6241-11eb-aebf-c306684b328d","name":"16:panel_16","type":"visualization"},{"id":"ccca99e0-6244-11eb-aebf-c306684b328d","name":"17:panel_17","type":"visualization"},{"id":"a4d7be80-6245-11eb-aebf-c306684b328d","name":"18:panel_18","type":"visualization"},{"id":"c94d8440-6248-11eb-aebf-c306684b328d","name":"19:panel_19","type":"visualization"},{"id":"db6226f0-61c0-11eb-aebf-c306684b328d","name":"20:panel_20","type":"search"}],"sort":[1621974354739,55],"type":"dashboard","updated_at":"2021-05-25T20:25:54.739Z","version":"WzcyLDJd"} +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"title":"shakespeare_tag_cloud","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"shakespeare_tag_cloud\",\"type\":\"tagcloud\",\"params\":{\"scale\":\"linear\",\"orientation\":\"multiple\",\"minFontSize\":59,\"maxFontSize\":100,\"showLabel\":true},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"segment\",\"params\":{\"field\":\"type.keyword\",\"size\":5,\"order\":\"desc\",\"orderBy\":\"1\",\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\"}}]}"},"coreMigrationVersion":"7.13.1","id":"622ac7f0-619e-11eb-aebf-c306684b328d","migrationVersion":{"visualization":"7.13.0"},"references":[{"id":"4e937b20-619d-11eb-aebf-c306684b328d","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"sort":[1621974330073,6],"type":"visualization","updated_at":"2021-05-25T20:25:30.073Z","version":"WzI0LDJd"} +{"attributes":{"numLinks":4,"numVertices":5,"title":"logstash_graph","version":1,"wsState":"\"{\\\"selectedFields\\\":[{\\\"name\\\":\\\"machine.os.raw\\\",\\\"hopSize\\\":5,\\\"lastValidHopSize\\\":5,\\\"color\\\":\\\"#B9A888\\\",\\\"selected\\\":true,\\\"iconClass\\\":\\\"fa-folder-open-o\\\"},{\\\"name\\\":\\\"response.raw\\\",\\\"hopSize\\\":5,\\\"lastValidHopSize\\\":5,\\\"color\\\":\\\"#D6BF57\\\",\\\"selected\\\":true,\\\"iconClass\\\":\\\"fa-folder-open-o\\\"}],\\\"blocklist\\\":[],\\\"vertices\\\":[{\\\"x\\\":461.96184642905024,\\\"y\\\":284.02313214227325,\\\"label\\\":\\\"osx\\\",\\\"color\\\":\\\"#B9A888\\\",\\\"field\\\":\\\"machine.os.raw\\\",\\\"term\\\":\\\"osx\\\",\\\"parent\\\":null,\\\"size\\\":15},{\\\"x\\\":383.946159835112,\\\"y\\\":375.6063135315976,\\\"label\\\":\\\"503\\\",\\\"color\\\":\\\"#D6BF57\\\",\\\"field\\\":\\\"response.raw\\\",\\\"term\\\":\\\"503\\\",\\\"parent\\\":null,\\\"size\\\":15},{\\\"x\\\":287.104700756828,\\\"y\\\":324.1245253249895,\\\"label\\\":\\\"win 7\\\",\\\"color\\\":\\\"#B9A888\\\",\\\"field\\\":\\\"machine.os.raw\\\",\\\"term\\\":\\\"win 7\\\",\\\"parent\\\":null,\\\"size\\\":15},{\\\"x\\\":487.9986107998273,\\\"y\\\":407.07546535764254,\\\"label\\\":\\\"ios\\\",\\\"color\\\":\\\"#B9A888\\\",\\\"field\\\":\\\"machine.os.raw\\\",\\\"term\\\":\\\"ios\\\",\\\"parent\\\":null,\\\"size\\\":15},{\\\"x\\\":302.35059551806023,\\\"y\\\":211.66825720913607,\\\"label\\\":\\\"200\\\",\\\"color\\\":\\\"#D6BF57\\\",\\\"field\\\":\\\"response.raw\\\",\\\"term\\\":\\\"200\\\",\\\"parent\\\":null,\\\"size\\\":15}],\\\"links\\\":[{\\\"weight\\\":0.000881324009872165,\\\"width\\\":7.983523640193488,\\\"source\\\":4,\\\"target\\\":2},{\\\"weight\\\":0.000023386835221992895,\\\"width\\\":2,\\\"source\\\":1,\\\"target\\\":0},{\\\"weight\\\":0.0011039286029480653,\\\"width\\\":2,\\\"source\\\":1,\\\"target\\\":2},{\\\"weight\\\":0.000045596928960694605,\\\"width\\\":2,\\\"source\\\":1,\\\"target\\\":3}],\\\"urlTemplates\\\":[{\\\"url\\\":\\\"/app/discover#/?_a=(columns%3A!(_source)%2Cindex%3A%2756b34100-619d-11eb-aebf-c306684b328d%27%2Cinterval%3Aauto%2Cquery%3A(language%3Akuery%2Cquery%3A{{gquery}})%2Csort%3A!(_score%2Cdesc))\\\",\\\"description\\\":\\\"Machine OS win 7\\\",\\\"isDefault\\\":false,\\\"encoderID\\\":\\\"kql\\\",\\\"iconClass\\\":\\\"fa-share-alt\\\"}],\\\"exploreControls\\\":{\\\"useSignificance\\\":true,\\\"sampleSize\\\":2000,\\\"timeoutMillis\\\":5000,\\\"maxValuesPerDoc\\\":1,\\\"minDocCount\\\":3},\\\"indexPatternRefName\\\":\\\"indexPattern_0\\\"}\""},"coreMigrationVersion":"7.13.1","id":"6afc4b40-be5c-11eb-9520-1b4c3ca6a781","migrationVersion":{"graph-workspace":"7.11.0"},"references":[{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"indexPattern_0","type":"index-pattern"}],"sort":[1622058970616,690],"type":"graph-workspace","updated_at":"2021-05-26T19:56:10.616Z","version":"WzEyMTUsMl0="} +{"attributes":{"accessibility:disableAnimations":true,"buildNum":null,"dateFormat:tz":"UTC","defaultIndex":"56b34100-619d-11eb-aebf-c306684b328d","visualization:visualize:legacyChartsLibrary":true},"coreMigrationVersion":"7.13.1","id":"7.13.1","migrationVersion":{"config":"7.13.0"},"references":[],"sort":[1621977169980,125],"type":"config","updated_at":"2021-05-25T21:12:49.980Z","version":"Wzg2LDJd"} +{"attributes":{"columns":["_source"],"description":"","hits":0,"kibanaSavedObjectMeta":{"searchSourceJSON":"{\"highlightAll\":true,\"version\":true,\"query\":{\"query\":\"\",\"language\":\"lucene\"},\"filter\":[{\"meta\":{\"negate\":false,\"type\":\"phrase\",\"key\":\"text_entry\",\"value\":\"Christendom.\",\"params\":{\"query\":\"Christendom.\",\"type\":\"phrase\"},\"disabled\":false,\"alias\":null,\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index\"},\"query\":{\"match\":{\"text_entry\":{\"query\":\"Christendom.\",\"type\":\"phrase\"}}},\"$state\":{\"store\":\"appState\"}}],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"sort":[["_score","desc"]],"title":"shakespeare_saved_search","version":1},"coreMigrationVersion":"7.13.1","id":"712ebbe0-619d-11eb-aebf-c306684b328d","migrationVersion":{"search":"7.9.3"},"references":[{"id":"4e937b20-619d-11eb-aebf-c306684b328d","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"},{"id":"4e937b20-619d-11eb-aebf-c306684b328d","name":"kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index","type":"index-pattern"}],"sort":[1621974326135,2],"type":"search","updated_at":"2021-05-25T20:25:26.135Z","version":"WzE1LDJd"} +{"attributes":{"columns":["play_name","speaker"],"description":"","hits":0,"kibanaSavedObjectMeta":{"searchSourceJSON":"{\"highlightAll\":true,\"version\":true,\"query\":{\"query\":\"speaker:\\\"GLOUCESTER\\\"\",\"language\":\"lucene\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"sort":[["_score","desc"]],"title":"shakespeare_saved_lucene_search","version":1},"coreMigrationVersion":"7.13.1","id":"ddacc820-619d-11eb-aebf-c306684b328d","migrationVersion":{"search":"7.9.3"},"references":[{"id":"4e937b20-619d-11eb-aebf-c306684b328d","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"sort":[1621974328029,8],"type":"search","updated_at":"2021-05-25T20:25:28.029Z","version":"WzE5LDJd"} +{"attributes":{"columns":["_source"],"description":"","hits":0,"kibanaSavedObjectMeta":{"searchSourceJSON":"{\"highlightAll\":true,\"version\":true,\"query\":{\"query\":\"text_entry :\\\"MORDAKE THE EARL OF FIFE, AND ELDEST SON\\\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"sort":[["_score","desc"]],"title":"shakespeare_saved_kql_search","version":1},"coreMigrationVersion":"7.13.1","id":"f852d570-619d-11eb-aebf-c306684b328d","migrationVersion":{"search":"7.9.3"},"references":[{"id":"4e937b20-619d-11eb-aebf-c306684b328d","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"sort":[1621974327007,84],"type":"search","updated_at":"2021-05-25T20:25:27.007Z","version":"WzE3LDJd"} +{"attributes":{"description":"","hits":0,"kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"language\":\"kuery\",\"query\":\"\"},\"filter\":[]}"},"optionsJSON":"{\"darkTheme\":false,\"hidePanelTitles\":false,\"useMargins\":true}","panelsJSON":"[{\"version\":\"7.3.0\",\"type\":\"visualization\",\"gridData\":{\"h\":15,\"i\":\"1\",\"w\":24,\"x\":0,\"y\":0},\"panelIndex\":\"1\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_1\"},{\"version\":\"7.3.0\",\"type\":\"visualization\",\"gridData\":{\"h\":15,\"i\":\"2\",\"w\":24,\"x\":24,\"y\":0},\"panelIndex\":\"2\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_2\"},{\"version\":\"7.3.0\",\"type\":\"visualization\",\"gridData\":{\"h\":15,\"i\":\"3\",\"w\":24,\"x\":0,\"y\":15},\"panelIndex\":\"3\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_3\"},{\"version\":\"7.3.0\",\"type\":\"search\",\"gridData\":{\"h\":15,\"i\":\"4\",\"w\":24,\"x\":24,\"y\":15},\"panelIndex\":\"4\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_4\"},{\"version\":\"7.3.0\",\"type\":\"search\",\"gridData\":{\"h\":15,\"i\":\"5\",\"w\":24,\"x\":0,\"y\":30},\"panelIndex\":\"5\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_5\"},{\"version\":\"7.3.0\",\"type\":\"search\",\"gridData\":{\"h\":15,\"i\":\"6\",\"w\":24,\"x\":24,\"y\":30},\"panelIndex\":\"6\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_6\"}]","timeRestore":false,"title":"shakespeare_dashboard","version":1},"coreMigrationVersion":"7.13.1","id":"73398a90-619e-11eb-aebf-c306684b328d","migrationVersion":{"dashboard":"7.11.0"},"references":[{"id":"185283c0-619e-11eb-aebf-c306684b328d","name":"1:panel_1","type":"visualization"},{"id":"33736660-619e-11eb-aebf-c306684b328d","name":"2:panel_2","type":"visualization"},{"id":"622ac7f0-619e-11eb-aebf-c306684b328d","name":"3:panel_3","type":"visualization"},{"id":"712ebbe0-619d-11eb-aebf-c306684b328d","name":"4:panel_4","type":"search"},{"id":"ddacc820-619d-11eb-aebf-c306684b328d","name":"5:panel_5","type":"search"},{"id":"f852d570-619d-11eb-aebf-c306684b328d","name":"6:panel_6","type":"search"}],"sort":[1621974332122,91],"type":"dashboard","updated_at":"2021-05-25T20:25:32.122Z","version":"WzI4LDJd"} +{"attributes":{"description":"","hits":0,"kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"language\":\"lucene\",\"query\":\"\"},\"filter\":[{\"meta\":{\"negate\":false,\"disabled\":false,\"alias\":null,\"type\":\"phrase\",\"key\":\"geo.srcdest\",\"value\":\"IN:US\",\"params\":{\"query\":\"IN:US\",\"type\":\"phrase\"},\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index\"},\"query\":{\"match\":{\"geo.srcdest\":{\"query\":\"IN:US\",\"type\":\"phrase\"}}},\"$state\":{\"store\":\"appState\"}}]}"},"optionsJSON":"{\"darkTheme\":false,\"hidePanelTitles\":false,\"useMargins\":true}","panelsJSON":"[{\"version\":\"7.3.0\",\"type\":\"visualization\",\"gridData\":{\"h\":15,\"i\":\"1\",\"w\":24,\"x\":0,\"y\":0},\"panelIndex\":\"1\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_1\"},{\"version\":\"7.3.0\",\"type\":\"visualization\",\"gridData\":{\"h\":15,\"i\":\"2\",\"w\":24,\"x\":24,\"y\":0},\"panelIndex\":\"2\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_2\"},{\"version\":\"7.3.0\",\"type\":\"visualization\",\"gridData\":{\"h\":15,\"i\":\"3\",\"w\":24,\"x\":0,\"y\":15},\"panelIndex\":\"3\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_3\"},{\"version\":\"7.3.0\",\"type\":\"visualization\",\"gridData\":{\"h\":15,\"i\":\"4\",\"w\":24,\"x\":24,\"y\":15},\"panelIndex\":\"4\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_4\"},{\"version\":\"7.3.0\",\"type\":\"visualization\",\"gridData\":{\"h\":15,\"i\":\"5\",\"w\":24,\"x\":0,\"y\":30},\"panelIndex\":\"5\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_5\"},{\"version\":\"7.3.0\",\"type\":\"visualization\",\"gridData\":{\"h\":15,\"i\":\"6\",\"w\":24,\"x\":24,\"y\":30},\"panelIndex\":\"6\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_6\"},{\"version\":\"7.3.0\",\"type\":\"visualization\",\"gridData\":{\"h\":15,\"i\":\"7\",\"w\":24,\"x\":0,\"y\":45},\"panelIndex\":\"7\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_7\"},{\"version\":\"7.3.0\",\"type\":\"visualization\",\"gridData\":{\"h\":15,\"i\":\"8\",\"w\":24,\"x\":24,\"y\":45},\"panelIndex\":\"8\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_8\"},{\"version\":\"7.3.0\",\"type\":\"visualization\",\"gridData\":{\"h\":15,\"i\":\"9\",\"w\":24,\"x\":0,\"y\":60},\"panelIndex\":\"9\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_9\"},{\"version\":\"7.3.0\",\"type\":\"visualization\",\"gridData\":{\"h\":15,\"i\":\"10\",\"w\":24,\"x\":24,\"y\":60},\"panelIndex\":\"10\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_10\"},{\"version\":\"7.3.0\",\"type\":\"visualization\",\"gridData\":{\"h\":15,\"i\":\"11\",\"w\":24,\"x\":0,\"y\":75},\"panelIndex\":\"11\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_11\"},{\"version\":\"7.3.0\",\"type\":\"visualization\",\"gridData\":{\"h\":15,\"i\":\"12\",\"w\":24,\"x\":24,\"y\":75},\"panelIndex\":\"12\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_12\"},{\"version\":\"7.3.0\",\"type\":\"visualization\",\"gridData\":{\"h\":15,\"i\":\"13\",\"w\":24,\"x\":0,\"y\":90},\"panelIndex\":\"13\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_13\"},{\"version\":\"7.3.0\",\"type\":\"visualization\",\"gridData\":{\"h\":15,\"i\":\"14\",\"w\":24,\"x\":24,\"y\":90},\"panelIndex\":\"14\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_14\"},{\"version\":\"7.3.0\",\"type\":\"visualization\",\"gridData\":{\"h\":15,\"i\":\"15\",\"w\":24,\"x\":0,\"y\":105},\"panelIndex\":\"15\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_15\"},{\"version\":\"7.3.0\",\"type\":\"visualization\",\"gridData\":{\"h\":15,\"i\":\"16\",\"w\":24,\"x\":24,\"y\":105},\"panelIndex\":\"16\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_16\"},{\"version\":\"7.3.0\",\"type\":\"visualization\",\"gridData\":{\"h\":15,\"i\":\"17\",\"w\":24,\"x\":0,\"y\":120},\"panelIndex\":\"17\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_17\"},{\"version\":\"7.3.0\",\"type\":\"visualization\",\"gridData\":{\"h\":15,\"i\":\"18\",\"w\":24,\"x\":24,\"y\":120},\"panelIndex\":\"18\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_18\"},{\"version\":\"7.3.0\",\"type\":\"visualization\",\"gridData\":{\"h\":15,\"i\":\"19\",\"w\":24,\"x\":0,\"y\":135},\"panelIndex\":\"19\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_19\"},{\"version\":\"7.3.0\",\"type\":\"search\",\"gridData\":{\"h\":15,\"i\":\"20\",\"w\":24,\"x\":24,\"y\":135},\"panelIndex\":\"20\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_20\"}]","timeRestore":false,"title":"logstash_dashboardwithfilters","version":1},"coreMigrationVersion":"7.13.1","id":"79794f20-6249-11eb-aebf-c306684b328d","migrationVersion":{"dashboard":"7.11.0"},"references":[{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index","type":"index-pattern"},{"id":"36b91810-6239-11eb-aebf-c306684b328d","name":"1:panel_1","type":"visualization"},{"id":"0a274320-61cc-11eb-aebf-c306684b328d","name":"2:panel_2","type":"visualization"},{"id":"e4aef350-623d-11eb-aebf-c306684b328d","name":"3:panel_3","type":"visualization"},{"id":"f92e5630-623e-11eb-aebf-c306684b328d","name":"4:panel_4","type":"visualization"},{"id":"9853d4d0-623d-11eb-aebf-c306684b328d","name":"5:panel_5","type":"visualization"},{"id":"6ecb33b0-623d-11eb-aebf-c306684b328d","name":"6:panel_6","type":"visualization"},{"id":"b8e35c80-623c-11eb-aebf-c306684b328d","name":"7:panel_7","type":"visualization"},{"id":"f1bc75d0-6239-11eb-aebf-c306684b328d","name":"8:panel_8","type":"visualization"},{"id":"0d8a8860-623a-11eb-aebf-c306684b328d","name":"9:panel_9","type":"visualization"},{"id":"d79fe3d0-6239-11eb-aebf-c306684b328d","name":"10:panel_10","type":"visualization"},{"id":"318375a0-6240-11eb-aebf-c306684b328d","name":"11:panel_11","type":"visualization"},{"id":"e461eb20-6245-11eb-aebf-c306684b328d","name":"12:panel_12","type":"visualization"},{"id":"25bdc750-6242-11eb-aebf-c306684b328d","name":"13:panel_13","type":"visualization"},{"id":"71dd7bc0-6248-11eb-aebf-c306684b328d","name":"14:panel_14","type":"visualization"},{"id":"6aea48a0-6240-11eb-aebf-c306684b328d","name":"15:panel_15","type":"visualization"},{"id":"32b681f0-6241-11eb-aebf-c306684b328d","name":"16:panel_16","type":"visualization"},{"id":"ccca99e0-6244-11eb-aebf-c306684b328d","name":"17:panel_17","type":"visualization"},{"id":"a4d7be80-6245-11eb-aebf-c306684b328d","name":"18:panel_18","type":"visualization"},{"id":"c94d8440-6248-11eb-aebf-c306684b328d","name":"19:panel_19","type":"visualization"},{"id":"db6226f0-61c0-11eb-aebf-c306684b328d","name":"20:panel_20","type":"search"}],"sort":[1621974355768,123],"type":"dashboard","updated_at":"2021-05-25T20:25:55.768Z","version":"Wzc0LDJd"} +{"attributes":{"description":"","state":{"datasourceStates":{"indexpattern":{"layers":{"037b7937-790b-4d2d-94a5-7f5837a6ef05":{"columnOrder":["b3d46616-75e0-419e-97ea-91148961ef94","025a0fb3-dc44-4f5c-b517-2d71d3f26f14","c476db14-0cc1-40ec-863e-d2779256a407"],"columns":{"025a0fb3-dc44-4f5c-b517-2d71d3f26f14":{"dataType":"date","isBucketed":true,"label":"@timestamp","operationType":"date_histogram","params":{"interval":"auto"},"scale":"interval","sourceField":"@timestamp"},"b3d46616-75e0-419e-97ea-91148961ef94":{"dataType":"string","isBucketed":true,"label":"Top values of geo.srcdest","operationType":"terms","params":{"missingBucket":false,"orderBy":{"columnId":"c476db14-0cc1-40ec-863e-d2779256a407","type":"column"},"orderDirection":"desc","otherBucket":true,"size":3},"scale":"ordinal","sourceField":"geo.srcdest"},"c476db14-0cc1-40ec-863e-d2779256a407":{"dataType":"number","isBucketed":false,"label":"Count of records","operationType":"count","scale":"ratio","sourceField":"Records"}},"incompleteColumns":{}}}}},"filters":[],"query":{"language":"lucene","query":""},"visualization":{"axisTitlesVisibilitySettings":{"x":true,"yLeft":true,"yRight":true},"fittingFunction":"None","gridlinesVisibilitySettings":{"x":true,"yLeft":true,"yRight":true},"layers":[{"accessors":["c476db14-0cc1-40ec-863e-d2779256a407"],"layerId":"037b7937-790b-4d2d-94a5-7f5837a6ef05","position":"top","seriesType":"bar_stacked","showGridlines":false,"splitAccessor":"b3d46616-75e0-419e-97ea-91148961ef94","xAccessor":"025a0fb3-dc44-4f5c-b517-2d71d3f26f14"}],"legend":{"isVisible":true,"position":"right"},"preferredSeriesType":"bar_stacked","tickLabelsVisibilitySettings":{"x":true,"yLeft":true,"yRight":true},"valueLabels":"hide"}},"title":"lens_verticalstacked","visualizationType":"lnsXY"},"coreMigrationVersion":"7.13.1","id":"8dc19b50-be32-11eb-9520-1b4c3ca6a781","migrationVersion":{"lens":"7.13.0"},"references":[{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"indexpattern-datasource-current-indexpattern","type":"index-pattern"},{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"indexpattern-datasource-layer-037b7937-790b-4d2d-94a5-7f5837a6ef05","type":"index-pattern"},{"id":"e6994960-bd9e-11eb-9520-1b4c3ca6a781","name":"tag-ref-e6994960-bd9e-11eb-9520-1b4c3ca6a781","type":"tag"}],"sort":[1622040990089,435],"type":"lens","updated_at":"2021-05-26T14:56:30.089Z","version":"WzkwMywyXQ=="} +{"attributes":{"description":"","hits":0,"timelion_chart_height":275,"timelion_columns":2,"timelion_interval":"auto","timelion_rows":2,"timelion_sheet":[".es(index=logstash-*, \"sum:bytes\")"],"title":"logstash_timelionsheet","version":1},"coreMigrationVersion":"7.13.1","id":"a8961990-be5c-11eb-9520-1b4c3ca6a781","references":[],"sort":[1622059073967,700],"type":"timelion-sheet","updated_at":"2021-05-26T19:57:53.967Z","version":"WzEyMjksMl0="} +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{}"},"title":"logstash_timelion_panel","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"logstash_timelion_panel\",\"type\":\"timelion\",\"aggs\":[],\"params\":{\"expression\":\".es(index=logstash-*, \\\"sum:bytes\\\")\",\"interval\":\"auto\"}}"},"coreMigrationVersion":"7.13.1","id":"b3a44cd0-be5c-11eb-9520-1b4c3ca6a781","migrationVersion":{"visualization":"7.13.0"},"references":[],"sort":[1622059092512,699],"type":"visualization","updated_at":"2021-05-26T19:58:12.512Z","version":"WzEyMzUsMl0="} +{"attributes":{"color":"#9170B8","description":"","name":"alltogether"},"coreMigrationVersion":"7.13.1","id":"be808cb0-be32-11eb-9520-1b4c3ca6a781","references":[],"sort":[1622041071870,449],"type":"tag","updated_at":"2021-05-26T14:57:51.870Z","version":"WzkzMCwyXQ=="} +{"attributes":{"description":"","hits":0,"kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"language\":\"kuery\",\"query\":\"\"},\"filter\":[]}"},"optionsJSON":"{\"hidePanelTitles\":false,\"useMargins\":true}","panelsJSON":"[{\"version\":\"7.13.1\",\"type\":\"lens\",\"gridData\":{\"x\":24,\"y\":0,\"w\":24,\"h\":15,\"i\":\"4d9e9a01-cdb8-4aef-afcb-50db52247bb1\"},\"panelIndex\":\"4d9e9a01-cdb8-4aef-afcb-50db52247bb1\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_4d9e9a01-cdb8-4aef-afcb-50db52247bb1\"},{\"version\":\"7.13.1\",\"type\":\"lens\",\"gridData\":{\"x\":0,\"y\":0,\"w\":24,\"h\":15,\"i\":\"d9cab9c8-667e-4d34-821b-cbb070891956\"},\"panelIndex\":\"d9cab9c8-667e-4d34-821b-cbb070891956\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_d9cab9c8-667e-4d34-821b-cbb070891956\"}]","refreshInterval":{"pause":true,"value":0},"timeFrom":"2015-09-20T01:56:56.132Z","timeRestore":true,"timeTo":"2015-09-21T11:18:20.471Z","title":"lens_combined_dashboard","version":1},"coreMigrationVersion":"7.13.1","id":"bfb3dc90-be32-11eb-9520-1b4c3ca6a781","migrationVersion":{"dashboard":"7.11.0"},"references":[{"id":"8dc19b50-be32-11eb-9520-1b4c3ca6a781","name":"4d9e9a01-cdb8-4aef-afcb-50db52247bb1:panel_4d9e9a01-cdb8-4aef-afcb-50db52247bb1","type":"lens"},{"id":"b5bd5050-be31-11eb-9520-1b4c3ca6a781","name":"d9cab9c8-667e-4d34-821b-cbb070891956:panel_d9cab9c8-667e-4d34-821b-cbb070891956","type":"lens"},{"id":"be808cb0-be32-11eb-9520-1b4c3ca6a781","name":"tag-be808cb0-be32-11eb-9520-1b4c3ca6a781","type":"tag"}],"sort":[1622041081330,447],"type":"dashboard","updated_at":"2021-05-26T14:58:01.330Z","version":"WzkzOSwyXQ=="} +{"attributes":{"description":"","hits":0,"kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"language\":\"kuery\",\"query\":\"\"},\"filter\":[]}"},"optionsJSON":"{\"hidePanelTitles\":false,\"useMargins\":true}","panelsJSON":"[{\"version\":\"7.13.1\",\"type\":\"lens\",\"gridData\":{\"x\":24,\"y\":0,\"w\":24,\"h\":15,\"i\":\"2e80716f-c1b6-46f2-be2b-35db744b5031\"},\"panelIndex\":\"2e80716f-c1b6-46f2-be2b-35db744b5031\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"type\":\"lens\",\"visualizationType\":\"lnsPie\",\"state\":{\"datasourceStates\":{\"indexpattern\":{\"layers\":{\"26e2cf99-d931-4320-9e15-9dbc148f3534\":{\"columns\":{\"6adde1a2-4c6f-47eb-95cc-5c6a9d863a6e\":{\"label\":\"Top values of url.raw\",\"dataType\":\"string\",\"operationType\":\"terms\",\"scale\":\"ordinal\",\"sourceField\":\"url.raw\",\"isBucketed\":true,\"params\":{\"size\":20,\"orderBy\":{\"type\":\"column\",\"columnId\":\"beb72af1-239c-46d8-823b-b00d1e2ace43\"},\"orderDirection\":\"desc\",\"otherBucket\":true,\"missingBucket\":false}},\"beb72af1-239c-46d8-823b-b00d1e2ace43\":{\"label\":\"Unique count of geo.srcdest\",\"dataType\":\"number\",\"operationType\":\"unique_count\",\"scale\":\"ratio\",\"sourceField\":\"geo.srcdest\",\"isBucketed\":false}},\"columnOrder\":[\"6adde1a2-4c6f-47eb-95cc-5c6a9d863a6e\",\"beb72af1-239c-46d8-823b-b00d1e2ace43\"],\"incompleteColumns\":{}}}}},\"visualization\":{\"shape\":\"donut\",\"layers\":[{\"layerId\":\"26e2cf99-d931-4320-9e15-9dbc148f3534\",\"groups\":[\"6adde1a2-4c6f-47eb-95cc-5c6a9d863a6e\",\"6adde1a2-4c6f-47eb-95cc-5c6a9d863a6e\",\"6adde1a2-4c6f-47eb-95cc-5c6a9d863a6e\"],\"metric\":\"beb72af1-239c-46d8-823b-b00d1e2ace43\",\"numberDisplay\":\"percent\",\"categoryDisplay\":\"default\",\"legendDisplay\":\"default\",\"nestedLegend\":false}]},\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filters\":[]},\"references\":[{\"type\":\"index-pattern\",\"id\":\"56b34100-619d-11eb-aebf-c306684b328d\",\"name\":\"indexpattern-datasource-current-indexpattern\"},{\"type\":\"index-pattern\",\"id\":\"56b34100-619d-11eb-aebf-c306684b328d\",\"name\":\"indexpattern-datasource-layer-26e2cf99-d931-4320-9e15-9dbc148f3534\"}]},\"enhancements\":{}},\"panelRefName\":\"panel_2e80716f-c1b6-46f2-be2b-35db744b5031\"},{\"version\":\"7.13.1\",\"type\":\"lens\",\"gridData\":{\"x\":0,\"y\":0,\"w\":24,\"h\":15,\"i\":\"da8843e0-6789-4aae-bcd0-81f270538719\"},\"panelIndex\":\"da8843e0-6789-4aae-bcd0-81f270538719\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_da8843e0-6789-4aae-bcd0-81f270538719\"},{\"version\":\"7.13.1\",\"type\":\"lens\",\"gridData\":{\"x\":24,\"y\":15,\"w\":24,\"h\":15,\"i\":\"adcd4418-7299-4efa-b369-5f71a7b4ebe0\"},\"panelIndex\":\"adcd4418-7299-4efa-b369-5f71a7b4ebe0\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_adcd4418-7299-4efa-b369-5f71a7b4ebe0\"},{\"version\":\"7.13.1\",\"type\":\"lens\",\"gridData\":{\"x\":0,\"y\":15,\"w\":24,\"h\":15,\"i\":\"869754a7-edf0-478f-a7f1-80374f63108a\"},\"panelIndex\":\"869754a7-edf0-478f-a7f1-80374f63108a\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_869754a7-edf0-478f-a7f1-80374f63108a\"},{\"version\":\"7.13.1\",\"type\":\"lens\",\"gridData\":{\"x\":24,\"y\":30,\"w\":24,\"h\":15,\"i\":\"67111cf4-338e-453f-8621-e8dea64082d1\"},\"panelIndex\":\"67111cf4-338e-453f-8621-e8dea64082d1\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_67111cf4-338e-453f-8621-e8dea64082d1\"},{\"version\":\"7.13.1\",\"type\":\"lens\",\"gridData\":{\"x\":0,\"y\":30,\"w\":24,\"h\":15,\"i\":\"13f21ad2-9b2d-4aa2-a908-b62e1bdedc1d\"},\"panelIndex\":\"13f21ad2-9b2d-4aa2-a908-b62e1bdedc1d\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_13f21ad2-9b2d-4aa2-a908-b62e1bdedc1d\"},{\"version\":\"7.13.1\",\"type\":\"lens\",\"gridData\":{\"x\":24,\"y\":45,\"w\":24,\"h\":15,\"i\":\"88847944-ae1b-45fd-b102-3b45f9bea04b\"},\"panelIndex\":\"88847944-ae1b-45fd-b102-3b45f9bea04b\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_88847944-ae1b-45fd-b102-3b45f9bea04b\"},{\"version\":\"7.13.1\",\"type\":\"lens\",\"gridData\":{\"x\":0,\"y\":45,\"w\":24,\"h\":15,\"i\":\"5a7924c7-eac0-4573-9199-fecec5b82e9e\"},\"panelIndex\":\"5a7924c7-eac0-4573-9199-fecec5b82e9e\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_5a7924c7-eac0-4573-9199-fecec5b82e9e\"},{\"version\":\"7.13.1\",\"type\":\"lens\",\"gridData\":{\"x\":24,\"y\":60,\"w\":24,\"h\":15,\"i\":\"f8f49591-f071-4a96-b1ed-cd65daff5648\"},\"panelIndex\":\"f8f49591-f071-4a96-b1ed-cd65daff5648\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_f8f49591-f071-4a96-b1ed-cd65daff5648\"},{\"version\":\"7.13.1\",\"type\":\"lens\",\"gridData\":{\"x\":0,\"y\":60,\"w\":24,\"h\":15,\"i\":\"9f357f47-c2a0-421f-a456-9583c40837ab\"},\"panelIndex\":\"9f357f47-c2a0-421f-a456-9583c40837ab\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_9f357f47-c2a0-421f-a456-9583c40837ab\"},{\"version\":\"7.13.1\",\"type\":\"lens\",\"gridData\":{\"x\":24,\"y\":75,\"w\":24,\"h\":15,\"i\":\"6cb383e9-1e80-44f9-80d5-7b8c585668db\"},\"panelIndex\":\"6cb383e9-1e80-44f9-80d5-7b8c585668db\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_6cb383e9-1e80-44f9-80d5-7b8c585668db\"},{\"version\":\"7.13.1\",\"type\":\"lens\",\"gridData\":{\"x\":0,\"y\":75,\"w\":24,\"h\":15,\"i\":\"57f5f0bf-6610-4599-aad4-37484640b5e2\"},\"panelIndex\":\"57f5f0bf-6610-4599-aad4-37484640b5e2\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_57f5f0bf-6610-4599-aad4-37484640b5e2\"},{\"version\":\"7.13.1\",\"type\":\"lens\",\"gridData\":{\"x\":0,\"y\":90,\"w\":24,\"h\":15,\"i\":\"32d3ab66-52e1-44e3-8c1f-1dccff3c5692\"},\"panelIndex\":\"32d3ab66-52e1-44e3-8c1f-1dccff3c5692\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_32d3ab66-52e1-44e3-8c1f-1dccff3c5692\"},{\"version\":\"7.13.1\",\"type\":\"lens\",\"gridData\":{\"x\":24,\"y\":90,\"w\":24,\"h\":15,\"i\":\"dd1718fd-74ee-4032-851b-db97e893825d\"},\"panelIndex\":\"dd1718fd-74ee-4032-851b-db97e893825d\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_dd1718fd-74ee-4032-851b-db97e893825d\"},{\"version\":\"7.13.1\",\"type\":\"lens\",\"gridData\":{\"x\":0,\"y\":105,\"w\":24,\"h\":15,\"i\":\"98a556ee-078b-4e03-93a8-29996133cdcb\"},\"panelIndex\":\"98a556ee-078b-4e03-93a8-29996133cdcb\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"type\":\"lens\",\"visualizationType\":\"lnsXY\",\"state\":{\"datasourceStates\":{\"indexpattern\":{\"layers\":{\"999a2d60-cb2a-451c-8d71-80d7e92e70fd\":{\"columns\":{\"ce9117a2-773c-474c-8fb1-18940cf58b38\":{\"label\":\"Top values of type\",\"dataType\":\"string\",\"operationType\":\"terms\",\"scale\":\"ordinal\",\"sourceField\":\"type\",\"isBucketed\":true,\"params\":{\"size\":5,\"orderBy\":{\"type\":\"column\",\"columnId\":\"cf07d1f1-d3fd-41f7-812c-d8587ec75959\"},\"orderDirection\":\"asc\",\"otherBucket\":true,\"missingBucket\":false}},\"a3d10552-e352-40d0-a156-e86112c0501a\":{\"label\":\"Top values of _type\",\"dataType\":\"string\",\"operationType\":\"terms\",\"scale\":\"ordinal\",\"sourceField\":\"_type\",\"isBucketed\":true,\"params\":{\"size\":3,\"orderBy\":{\"type\":\"column\",\"columnId\":\"cf07d1f1-d3fd-41f7-812c-d8587ec75959\"},\"orderDirection\":\"desc\",\"otherBucket\":true,\"missingBucket\":false}},\"cf07d1f1-d3fd-41f7-812c-d8587ec75959\":{\"label\":\"Count of records\",\"dataType\":\"number\",\"operationType\":\"count\",\"isBucketed\":false,\"scale\":\"ratio\",\"sourceField\":\"Records\"},\"9c5db2f3-9eb0-4667-9a74-3318301de251\":{\"label\":\"Sum of bytes\",\"dataType\":\"number\",\"operationType\":\"sum\",\"sourceField\":\"bytes\",\"isBucketed\":false,\"scale\":\"ratio\"}},\"columnOrder\":[\"ce9117a2-773c-474c-8fb1-18940cf58b38\",\"a3d10552-e352-40d0-a156-e86112c0501a\",\"cf07d1f1-d3fd-41f7-812c-d8587ec75959\",\"9c5db2f3-9eb0-4667-9a74-3318301de251\"],\"incompleteColumns\":{}}}}},\"visualization\":{\"legend\":{\"isVisible\":true,\"position\":\"right\"},\"valueLabels\":\"hide\",\"fittingFunction\":\"None\",\"axisTitlesVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"tickLabelsVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"gridlinesVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"preferredSeriesType\":\"bar_stacked\",\"layers\":[{\"layerId\":\"999a2d60-cb2a-451c-8d71-80d7e92e70fd\",\"accessors\":[\"cf07d1f1-d3fd-41f7-812c-d8587ec75959\",\"9c5db2f3-9eb0-4667-9a74-3318301de251\"],\"position\":\"top\",\"seriesType\":\"bar_stacked\",\"showGridlines\":false,\"xAccessor\":\"ce9117a2-773c-474c-8fb1-18940cf58b38\",\"splitAccessor\":\"a3d10552-e352-40d0-a156-e86112c0501a\"}]},\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filters\":[]},\"references\":[{\"type\":\"index-pattern\",\"id\":\"56b34100-619d-11eb-aebf-c306684b328d\",\"name\":\"indexpattern-datasource-current-indexpattern\"},{\"type\":\"index-pattern\",\"id\":\"56b34100-619d-11eb-aebf-c306684b328d\",\"name\":\"indexpattern-datasource-layer-999a2d60-cb2a-451c-8d71-80d7e92e70fd\"}]},\"enhancements\":{}}},{\"version\":\"7.13.1\",\"type\":\"lens\",\"gridData\":{\"x\":24,\"y\":105,\"w\":24,\"h\":15,\"i\":\"62a0f0b0-3589-4cef-807b-b1b4258b7a9b\"},\"panelIndex\":\"62a0f0b0-3589-4cef-807b-b1b4258b7a9b\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_62a0f0b0-3589-4cef-807b-b1b4258b7a9b\"},{\"version\":\"7.13.1\",\"type\":\"map\",\"gridData\":{\"x\":0,\"y\":120,\"w\":24,\"h\":15,\"i\":\"dcc0defa-3376-465c-9b5b-2ba69528848c\"},\"panelIndex\":\"dcc0defa-3376-465c-9b5b-2ba69528848c\",\"embeddableConfig\":{\"mapCenter\":{\"lat\":19.94277,\"lon\":0,\"zoom\":1.56},\"mapBuffer\":{\"minLon\":-210.32666,\"minLat\":-64.8435,\"maxLon\":210.32666,\"maxLat\":95.13806},\"isLayerTOCOpen\":true,\"openTOCDetails\":[],\"hiddenLayers\":[],\"enhancements\":{}},\"panelRefName\":\"panel_dcc0defa-3376-465c-9b5b-2ba69528848c\"},{\"version\":\"7.13.1\",\"type\":\"visualization\",\"gridData\":{\"x\":24,\"y\":120,\"w\":24,\"h\":15,\"i\":\"dd21a674-ae3a-40f6-9d68-4e01361ea5e2\"},\"panelIndex\":\"dd21a674-ae3a-40f6-9d68-4e01361ea5e2\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_dd21a674-ae3a-40f6-9d68-4e01361ea5e2\"}]","refreshInterval":{"pause":true,"value":0},"timeFrom":"2015-09-20T01:56:56.132Z","timeRestore":true,"timeTo":"2015-09-21T11:18:20.471Z","title":"timelion_lens_maps_dashboard_logstash","version":1},"coreMigrationVersion":"7.13.1","id":"c4ab2030-be5c-11eb-9520-1b4c3ca6a781","migrationVersion":{"dashboard":"7.11.0"},"references":[{"id":"21905950-bd9f-11eb-9520-1b4c3ca6a781","name":"2e80716f-c1b6-46f2-be2b-35db744b5031:panel_2e80716f-c1b6-46f2-be2b-35db744b5031","type":"lens"},{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"2e80716f-c1b6-46f2-be2b-35db744b5031:indexpattern-datasource-current-indexpattern","type":"index-pattern"},{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"2e80716f-c1b6-46f2-be2b-35db744b5031:indexpattern-datasource-layer-26e2cf99-d931-4320-9e15-9dbc148f3534","type":"index-pattern"},{"id":"aa4b8da0-bd9f-11eb-9520-1b4c3ca6a781","name":"da8843e0-6789-4aae-bcd0-81f270538719:panel_da8843e0-6789-4aae-bcd0-81f270538719","type":"lens"},{"id":"2d3f1250-bd9f-11eb-9520-1b4c3ca6a781","name":"adcd4418-7299-4efa-b369-5f71a7b4ebe0:panel_adcd4418-7299-4efa-b369-5f71a7b4ebe0","type":"lens"},{"id":"edd5a560-bda4-11eb-9520-1b4c3ca6a781","name":"869754a7-edf0-478f-a7f1-80374f63108a:panel_869754a7-edf0-478f-a7f1-80374f63108a","type":"lens"},{"id":"2c25a450-bda5-11eb-9520-1b4c3ca6a781","name":"67111cf4-338e-453f-8621-e8dea64082d1:panel_67111cf4-338e-453f-8621-e8dea64082d1","type":"lens"},{"id":"e79116e0-bd9e-11eb-9520-1b4c3ca6a781","name":"13f21ad2-9b2d-4aa2-a908-b62e1bdedc1d:panel_13f21ad2-9b2d-4aa2-a908-b62e1bdedc1d","type":"lens"},{"id":"974fb950-bda5-11eb-9520-1b4c3ca6a781","name":"88847944-ae1b-45fd-b102-3b45f9bea04b:panel_88847944-ae1b-45fd-b102-3b45f9bea04b","type":"lens"},{"id":"21905950-bd9f-11eb-9520-1b4c3ca6a781","name":"5a7924c7-eac0-4573-9199-fecec5b82e9e:panel_5a7924c7-eac0-4573-9199-fecec5b82e9e","type":"lens"},{"id":"51b63040-bda5-11eb-9520-1b4c3ca6a781","name":"f8f49591-f071-4a96-b1ed-cd65daff5648:panel_f8f49591-f071-4a96-b1ed-cd65daff5648","type":"lens"},{"id":"b00679c0-bda5-11eb-9520-1b4c3ca6a781","name":"9f357f47-c2a0-421f-a456-9583c40837ab:panel_9f357f47-c2a0-421f-a456-9583c40837ab","type":"lens"},{"id":"652ade10-bd9f-11eb-9520-1b4c3ca6a781","name":"6cb383e9-1e80-44f9-80d5-7b8c585668db:panel_6cb383e9-1e80-44f9-80d5-7b8c585668db","type":"lens"},{"id":"7f3b5fb0-be2f-11eb-9520-1b4c3ca6a781","name":"57f5f0bf-6610-4599-aad4-37484640b5e2:panel_57f5f0bf-6610-4599-aad4-37484640b5e2","type":"lens"},{"id":"bb9e5bb0-be2f-11eb-9520-1b4c3ca6a781","name":"32d3ab66-52e1-44e3-8c1f-1dccff3c5692:panel_32d3ab66-52e1-44e3-8c1f-1dccff3c5692","type":"lens"},{"id":"dd315430-be2f-11eb-9520-1b4c3ca6a781","name":"dd1718fd-74ee-4032-851b-db97e893825d:panel_dd1718fd-74ee-4032-851b-db97e893825d","type":"lens"},{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"98a556ee-078b-4e03-93a8-29996133cdcb:indexpattern-datasource-current-indexpattern","type":"index-pattern"},{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"98a556ee-078b-4e03-93a8-29996133cdcb:indexpattern-datasource-layer-999a2d60-cb2a-451c-8d71-80d7e92e70fd","type":"index-pattern"},{"id":"0dbbf8b0-be3c-11eb-9520-1b4c3ca6a781","name":"62a0f0b0-3589-4cef-807b-b1b4258b7a9b:panel_62a0f0b0-3589-4cef-807b-b1b4258b7a9b","type":"lens"},{"id":"0c5974f0-be5c-11eb-9520-1b4c3ca6a781","name":"dcc0defa-3376-465c-9b5b-2ba69528848c:panel_dcc0defa-3376-465c-9b5b-2ba69528848c","type":"map"},{"id":"a4d7be80-6245-11eb-aebf-c306684b328d","name":"dd21a674-ae3a-40f6-9d68-4e01361ea5e2:panel_dd21a674-ae3a-40f6-9d68-4e01361ea5e2","type":"visualization"},{"id":"e6994960-bd9e-11eb-9520-1b4c3ca6a781","name":"tag-e6994960-bd9e-11eb-9520-1b4c3ca6a781","type":"tag"}],"sort":[1622059147790,728],"type":"dashboard","updated_at":"2021-05-26T19:59:07.790Z","version":"WzEyNzAsMl0="} +{"attributes":{"@created":"2021-05-27T19:45:29.712Z","@timestamp":"2021-05-27T19:45:29.712Z","content":"{\"selectedNodes\":[{\"id\":\"element-56d2ba72-f227-4d04-9478-a1d6f0c7e601\",\"position\":{\"left\":20,\"top\":20,\"width\":500,\"height\":300,\"angle\":0,\"parent\":\"group-499b5982-25f4-4894-9540-1874a27d78e7\",\"type\":\"element\"},\"expression\":\"savedLens id=\\\"bb9e5bb0-be2f-11eb-9520-1b4c3ca6a781\\\" timerange={timerange from=\\\"now-15y\\\" to=\\\"now\\\"}\\n| render\",\"filter\":null,\"ast\":{\"type\":\"expression\",\"chain\":[{\"type\":\"function\",\"function\":\"savedLens\",\"arguments\":{\"id\":[\"bb9e5bb0-be2f-11eb-9520-1b4c3ca6a781\"],\"timerange\":[{\"type\":\"expression\",\"chain\":[{\"type\":\"function\",\"function\":\"timerange\",\"arguments\":{\"from\":[\"now-15y\"],\"to\":[\"now\"]}}]}]}},{\"type\":\"function\",\"function\":\"render\",\"arguments\":{}}]}},{\"id\":\"element-afbaa26e-10e7-47d4-bb41-b061dfdced2b\",\"position\":{\"left\":527,\"top\":20,\"width\":500,\"height\":300,\"angle\":0,\"parent\":\"group-499b5982-25f4-4894-9540-1874a27d78e7\",\"type\":\"element\"},\"expression\":\"savedVisualization id=\\\"0d8a8860-623a-11eb-aebf-c306684b328d\\\" timerange={timerange from=\\\"now-15y\\\" to=\\\"now\\\"}\\n| render\",\"filter\":null,\"ast\":{\"type\":\"expression\",\"chain\":[{\"type\":\"function\",\"function\":\"savedVisualization\",\"arguments\":{\"id\":[\"0d8a8860-623a-11eb-aebf-c306684b328d\"],\"timerange\":[{\"type\":\"expression\",\"chain\":[{\"type\":\"function\",\"function\":\"timerange\",\"arguments\":{\"from\":[\"now-15y\"],\"to\":[\"now\"]}}]}]}},{\"type\":\"function\",\"function\":\"render\",\"arguments\":{}}]}}]}","displayName":"element_canvas","help":"","image":"","name":"elementCanvas"},"coreMigrationVersion":"7.13.1","id":"custom-element-3bc52277-ee01-4cdc-8d2d-f2db6ade1512","references":[],"sort":[1622144729716,605],"type":"canvas-element","updated_at":"2021-05-27T19:45:29.716Z","version":"WzIwMjUsMl0="} +{"attributes":{"description":"","hits":0,"kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"language\":\"kuery\",\"query\":\"\"},\"filter\":[]}"},"optionsJSON":"{\"hidePanelTitles\":false,\"useMargins\":true}","panelsJSON":"[{\"version\":\"7.13.1\",\"type\":\"lens\",\"gridData\":{\"x\":24,\"y\":0,\"w\":24,\"h\":15,\"i\":\"2e80716f-c1b6-46f2-be2b-35db744b5031\"},\"panelIndex\":\"2e80716f-c1b6-46f2-be2b-35db744b5031\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"type\":\"lens\",\"visualizationType\":\"lnsPie\",\"state\":{\"datasourceStates\":{\"indexpattern\":{\"layers\":{\"26e2cf99-d931-4320-9e15-9dbc148f3534\":{\"columns\":{\"6adde1a2-4c6f-47eb-95cc-5c6a9d863a6e\":{\"label\":\"Top values of url.raw\",\"dataType\":\"string\",\"operationType\":\"terms\",\"scale\":\"ordinal\",\"sourceField\":\"url.raw\",\"isBucketed\":true,\"params\":{\"size\":20,\"orderBy\":{\"type\":\"column\",\"columnId\":\"beb72af1-239c-46d8-823b-b00d1e2ace43\"},\"orderDirection\":\"desc\",\"otherBucket\":true,\"missingBucket\":false}},\"beb72af1-239c-46d8-823b-b00d1e2ace43\":{\"label\":\"Unique count of geo.srcdest\",\"dataType\":\"number\",\"operationType\":\"unique_count\",\"scale\":\"ratio\",\"sourceField\":\"geo.srcdest\",\"isBucketed\":false}},\"columnOrder\":[\"6adde1a2-4c6f-47eb-95cc-5c6a9d863a6e\",\"beb72af1-239c-46d8-823b-b00d1e2ace43\"],\"incompleteColumns\":{}}}}},\"visualization\":{\"shape\":\"donut\",\"layers\":[{\"layerId\":\"26e2cf99-d931-4320-9e15-9dbc148f3534\",\"groups\":[\"6adde1a2-4c6f-47eb-95cc-5c6a9d863a6e\",\"6adde1a2-4c6f-47eb-95cc-5c6a9d863a6e\",\"6adde1a2-4c6f-47eb-95cc-5c6a9d863a6e\"],\"metric\":\"beb72af1-239c-46d8-823b-b00d1e2ace43\",\"numberDisplay\":\"percent\",\"categoryDisplay\":\"default\",\"legendDisplay\":\"default\",\"nestedLegend\":false}]},\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filters\":[]},\"references\":[{\"type\":\"index-pattern\",\"id\":\"56b34100-619d-11eb-aebf-c306684b328d\",\"name\":\"indexpattern-datasource-current-indexpattern\"},{\"type\":\"index-pattern\",\"id\":\"56b34100-619d-11eb-aebf-c306684b328d\",\"name\":\"indexpattern-datasource-layer-26e2cf99-d931-4320-9e15-9dbc148f3534\"}]},\"enhancements\":{}},\"panelRefName\":\"panel_2e80716f-c1b6-46f2-be2b-35db744b5031\"},{\"version\":\"7.13.1\",\"type\":\"lens\",\"gridData\":{\"x\":0,\"y\":0,\"w\":24,\"h\":15,\"i\":\"da8843e0-6789-4aae-bcd0-81f270538719\"},\"panelIndex\":\"da8843e0-6789-4aae-bcd0-81f270538719\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_da8843e0-6789-4aae-bcd0-81f270538719\"},{\"version\":\"7.13.1\",\"type\":\"lens\",\"gridData\":{\"x\":24,\"y\":15,\"w\":24,\"h\":15,\"i\":\"adcd4418-7299-4efa-b369-5f71a7b4ebe0\"},\"panelIndex\":\"adcd4418-7299-4efa-b369-5f71a7b4ebe0\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_adcd4418-7299-4efa-b369-5f71a7b4ebe0\"},{\"version\":\"7.13.1\",\"type\":\"lens\",\"gridData\":{\"x\":0,\"y\":15,\"w\":24,\"h\":15,\"i\":\"869754a7-edf0-478f-a7f1-80374f63108a\"},\"panelIndex\":\"869754a7-edf0-478f-a7f1-80374f63108a\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_869754a7-edf0-478f-a7f1-80374f63108a\"},{\"version\":\"7.13.1\",\"type\":\"lens\",\"gridData\":{\"x\":24,\"y\":30,\"w\":24,\"h\":15,\"i\":\"67111cf4-338e-453f-8621-e8dea64082d1\"},\"panelIndex\":\"67111cf4-338e-453f-8621-e8dea64082d1\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_67111cf4-338e-453f-8621-e8dea64082d1\"},{\"version\":\"7.13.1\",\"type\":\"lens\",\"gridData\":{\"x\":0,\"y\":30,\"w\":24,\"h\":15,\"i\":\"13f21ad2-9b2d-4aa2-a908-b62e1bdedc1d\"},\"panelIndex\":\"13f21ad2-9b2d-4aa2-a908-b62e1bdedc1d\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_13f21ad2-9b2d-4aa2-a908-b62e1bdedc1d\"},{\"version\":\"7.13.1\",\"type\":\"lens\",\"gridData\":{\"x\":24,\"y\":45,\"w\":24,\"h\":15,\"i\":\"88847944-ae1b-45fd-b102-3b45f9bea04b\"},\"panelIndex\":\"88847944-ae1b-45fd-b102-3b45f9bea04b\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_88847944-ae1b-45fd-b102-3b45f9bea04b\"},{\"version\":\"7.13.1\",\"type\":\"lens\",\"gridData\":{\"x\":0,\"y\":45,\"w\":24,\"h\":15,\"i\":\"5a7924c7-eac0-4573-9199-fecec5b82e9e\"},\"panelIndex\":\"5a7924c7-eac0-4573-9199-fecec5b82e9e\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_5a7924c7-eac0-4573-9199-fecec5b82e9e\"},{\"version\":\"7.13.1\",\"type\":\"lens\",\"gridData\":{\"x\":24,\"y\":60,\"w\":24,\"h\":15,\"i\":\"f8f49591-f071-4a96-b1ed-cd65daff5648\"},\"panelIndex\":\"f8f49591-f071-4a96-b1ed-cd65daff5648\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_f8f49591-f071-4a96-b1ed-cd65daff5648\"},{\"version\":\"7.13.1\",\"type\":\"lens\",\"gridData\":{\"x\":0,\"y\":60,\"w\":24,\"h\":15,\"i\":\"9f357f47-c2a0-421f-a456-9583c40837ab\"},\"panelIndex\":\"9f357f47-c2a0-421f-a456-9583c40837ab\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_9f357f47-c2a0-421f-a456-9583c40837ab\"},{\"version\":\"7.13.1\",\"type\":\"lens\",\"gridData\":{\"x\":24,\"y\":75,\"w\":24,\"h\":15,\"i\":\"6cb383e9-1e80-44f9-80d5-7b8c585668db\"},\"panelIndex\":\"6cb383e9-1e80-44f9-80d5-7b8c585668db\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_6cb383e9-1e80-44f9-80d5-7b8c585668db\"},{\"version\":\"7.13.1\",\"type\":\"lens\",\"gridData\":{\"x\":0,\"y\":75,\"w\":24,\"h\":15,\"i\":\"57f5f0bf-6610-4599-aad4-37484640b5e2\"},\"panelIndex\":\"57f5f0bf-6610-4599-aad4-37484640b5e2\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_57f5f0bf-6610-4599-aad4-37484640b5e2\"},{\"version\":\"7.13.1\",\"type\":\"lens\",\"gridData\":{\"x\":0,\"y\":90,\"w\":24,\"h\":15,\"i\":\"32d3ab66-52e1-44e3-8c1f-1dccff3c5692\"},\"panelIndex\":\"32d3ab66-52e1-44e3-8c1f-1dccff3c5692\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_32d3ab66-52e1-44e3-8c1f-1dccff3c5692\"},{\"version\":\"7.13.1\",\"type\":\"lens\",\"gridData\":{\"x\":24,\"y\":90,\"w\":24,\"h\":15,\"i\":\"dd1718fd-74ee-4032-851b-db97e893825d\"},\"panelIndex\":\"dd1718fd-74ee-4032-851b-db97e893825d\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_dd1718fd-74ee-4032-851b-db97e893825d\"},{\"version\":\"7.13.1\",\"type\":\"lens\",\"gridData\":{\"x\":0,\"y\":105,\"w\":24,\"h\":15,\"i\":\"98a556ee-078b-4e03-93a8-29996133cdcb\"},\"panelIndex\":\"98a556ee-078b-4e03-93a8-29996133cdcb\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"type\":\"lens\",\"visualizationType\":\"lnsXY\",\"state\":{\"datasourceStates\":{\"indexpattern\":{\"layers\":{\"999a2d60-cb2a-451c-8d71-80d7e92e70fd\":{\"columns\":{\"ce9117a2-773c-474c-8fb1-18940cf58b38\":{\"label\":\"Top values of type\",\"dataType\":\"string\",\"operationType\":\"terms\",\"scale\":\"ordinal\",\"sourceField\":\"type\",\"isBucketed\":true,\"params\":{\"size\":5,\"orderBy\":{\"type\":\"column\",\"columnId\":\"cf07d1f1-d3fd-41f7-812c-d8587ec75959\"},\"orderDirection\":\"asc\",\"otherBucket\":true,\"missingBucket\":false}},\"a3d10552-e352-40d0-a156-e86112c0501a\":{\"label\":\"Top values of _type\",\"dataType\":\"string\",\"operationType\":\"terms\",\"scale\":\"ordinal\",\"sourceField\":\"_type\",\"isBucketed\":true,\"params\":{\"size\":3,\"orderBy\":{\"type\":\"column\",\"columnId\":\"cf07d1f1-d3fd-41f7-812c-d8587ec75959\"},\"orderDirection\":\"desc\",\"otherBucket\":true,\"missingBucket\":false}},\"cf07d1f1-d3fd-41f7-812c-d8587ec75959\":{\"label\":\"Count of records\",\"dataType\":\"number\",\"operationType\":\"count\",\"isBucketed\":false,\"scale\":\"ratio\",\"sourceField\":\"Records\"},\"9c5db2f3-9eb0-4667-9a74-3318301de251\":{\"label\":\"Sum of bytes\",\"dataType\":\"number\",\"operationType\":\"sum\",\"sourceField\":\"bytes\",\"isBucketed\":false,\"scale\":\"ratio\"}},\"columnOrder\":[\"ce9117a2-773c-474c-8fb1-18940cf58b38\",\"a3d10552-e352-40d0-a156-e86112c0501a\",\"cf07d1f1-d3fd-41f7-812c-d8587ec75959\",\"9c5db2f3-9eb0-4667-9a74-3318301de251\"],\"incompleteColumns\":{}}}}},\"visualization\":{\"legend\":{\"isVisible\":true,\"position\":\"right\"},\"valueLabels\":\"hide\",\"fittingFunction\":\"None\",\"axisTitlesVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"tickLabelsVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"gridlinesVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"preferredSeriesType\":\"bar_stacked\",\"layers\":[{\"layerId\":\"999a2d60-cb2a-451c-8d71-80d7e92e70fd\",\"accessors\":[\"cf07d1f1-d3fd-41f7-812c-d8587ec75959\",\"9c5db2f3-9eb0-4667-9a74-3318301de251\"],\"position\":\"top\",\"seriesType\":\"bar_stacked\",\"showGridlines\":false,\"xAccessor\":\"ce9117a2-773c-474c-8fb1-18940cf58b38\",\"splitAccessor\":\"a3d10552-e352-40d0-a156-e86112c0501a\"}]},\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filters\":[]},\"references\":[{\"type\":\"index-pattern\",\"id\":\"56b34100-619d-11eb-aebf-c306684b328d\",\"name\":\"indexpattern-datasource-current-indexpattern\"},{\"type\":\"index-pattern\",\"id\":\"56b34100-619d-11eb-aebf-c306684b328d\",\"name\":\"indexpattern-datasource-layer-999a2d60-cb2a-451c-8d71-80d7e92e70fd\"}]},\"enhancements\":{}}},{\"version\":\"7.13.1\",\"type\":\"lens\",\"gridData\":{\"x\":24,\"y\":105,\"w\":24,\"h\":15,\"i\":\"62a0f0b0-3589-4cef-807b-b1b4258b7a9b\"},\"panelIndex\":\"62a0f0b0-3589-4cef-807b-b1b4258b7a9b\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_62a0f0b0-3589-4cef-807b-b1b4258b7a9b\"}]","refreshInterval":{"pause":true,"value":0},"timeFrom":"2015-09-20T01:56:56.132Z","timeRestore":true,"timeTo":"2015-09-21T11:18:20.471Z","title":"lens_dashboard_logstash","version":1},"coreMigrationVersion":"7.13.1","id":"f458b9f0-bd9e-11eb-9520-1b4c3ca6a781","migrationVersion":{"dashboard":"7.11.0"},"references":[{"id":"21905950-bd9f-11eb-9520-1b4c3ca6a781","name":"2e80716f-c1b6-46f2-be2b-35db744b5031:panel_2e80716f-c1b6-46f2-be2b-35db744b5031","type":"lens"},{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"2e80716f-c1b6-46f2-be2b-35db744b5031:indexpattern-datasource-current-indexpattern","type":"index-pattern"},{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"2e80716f-c1b6-46f2-be2b-35db744b5031:indexpattern-datasource-layer-26e2cf99-d931-4320-9e15-9dbc148f3534","type":"index-pattern"},{"id":"aa4b8da0-bd9f-11eb-9520-1b4c3ca6a781","name":"da8843e0-6789-4aae-bcd0-81f270538719:panel_da8843e0-6789-4aae-bcd0-81f270538719","type":"lens"},{"id":"2d3f1250-bd9f-11eb-9520-1b4c3ca6a781","name":"adcd4418-7299-4efa-b369-5f71a7b4ebe0:panel_adcd4418-7299-4efa-b369-5f71a7b4ebe0","type":"lens"},{"id":"edd5a560-bda4-11eb-9520-1b4c3ca6a781","name":"869754a7-edf0-478f-a7f1-80374f63108a:panel_869754a7-edf0-478f-a7f1-80374f63108a","type":"lens"},{"id":"2c25a450-bda5-11eb-9520-1b4c3ca6a781","name":"67111cf4-338e-453f-8621-e8dea64082d1:panel_67111cf4-338e-453f-8621-e8dea64082d1","type":"lens"},{"id":"e79116e0-bd9e-11eb-9520-1b4c3ca6a781","name":"13f21ad2-9b2d-4aa2-a908-b62e1bdedc1d:panel_13f21ad2-9b2d-4aa2-a908-b62e1bdedc1d","type":"lens"},{"id":"974fb950-bda5-11eb-9520-1b4c3ca6a781","name":"88847944-ae1b-45fd-b102-3b45f9bea04b:panel_88847944-ae1b-45fd-b102-3b45f9bea04b","type":"lens"},{"id":"21905950-bd9f-11eb-9520-1b4c3ca6a781","name":"5a7924c7-eac0-4573-9199-fecec5b82e9e:panel_5a7924c7-eac0-4573-9199-fecec5b82e9e","type":"lens"},{"id":"51b63040-bda5-11eb-9520-1b4c3ca6a781","name":"f8f49591-f071-4a96-b1ed-cd65daff5648:panel_f8f49591-f071-4a96-b1ed-cd65daff5648","type":"lens"},{"id":"b00679c0-bda5-11eb-9520-1b4c3ca6a781","name":"9f357f47-c2a0-421f-a456-9583c40837ab:panel_9f357f47-c2a0-421f-a456-9583c40837ab","type":"lens"},{"id":"652ade10-bd9f-11eb-9520-1b4c3ca6a781","name":"6cb383e9-1e80-44f9-80d5-7b8c585668db:panel_6cb383e9-1e80-44f9-80d5-7b8c585668db","type":"lens"},{"id":"7f3b5fb0-be2f-11eb-9520-1b4c3ca6a781","name":"57f5f0bf-6610-4599-aad4-37484640b5e2:panel_57f5f0bf-6610-4599-aad4-37484640b5e2","type":"lens"},{"id":"bb9e5bb0-be2f-11eb-9520-1b4c3ca6a781","name":"32d3ab66-52e1-44e3-8c1f-1dccff3c5692:panel_32d3ab66-52e1-44e3-8c1f-1dccff3c5692","type":"lens"},{"id":"dd315430-be2f-11eb-9520-1b4c3ca6a781","name":"dd1718fd-74ee-4032-851b-db97e893825d:panel_dd1718fd-74ee-4032-851b-db97e893825d","type":"lens"},{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"98a556ee-078b-4e03-93a8-29996133cdcb:indexpattern-datasource-current-indexpattern","type":"index-pattern"},{"id":"56b34100-619d-11eb-aebf-c306684b328d","name":"98a556ee-078b-4e03-93a8-29996133cdcb:indexpattern-datasource-layer-999a2d60-cb2a-451c-8d71-80d7e92e70fd","type":"index-pattern"},{"id":"0dbbf8b0-be3c-11eb-9520-1b4c3ca6a781","name":"62a0f0b0-3589-4cef-807b-b1b4258b7a9b:panel_62a0f0b0-3589-4cef-807b-b1b4258b7a9b","type":"lens"},{"id":"e6994960-bd9e-11eb-9520-1b4c3ca6a781","name":"tag-e6994960-bd9e-11eb-9520-1b4c3ca6a781","type":"tag"}],"sort":[1622045107288,482],"type":"dashboard","updated_at":"2021-05-26T16:05:07.288Z","version":"WzEwNTcsMl0="} +{"attributes":{"allowNoIndex":true,"fieldFormatMap":"{\"Target.process.parent.pgid\":{\"id\":\"string\"},\"Target.process.parent.pid\":{\"id\":\"string\"},\"Target.process.parent.ppid\":{\"id\":\"string\"},\"Target.process.parent.thread.id\":{\"id\":\"string\"},\"Target.process.pgid\":{\"id\":\"string\"},\"Target.process.pid\":{\"id\":\"string\"},\"Target.process.ppid\":{\"id\":\"string\"},\"Target.process.thread.id\":{\"id\":\"string\"},\"event.sequence\":{\"id\":\"string\"},\"event.severity\":{\"id\":\"string\"},\"process.parent.pgid\":{\"id\":\"string\"},\"process.parent.pid\":{\"id\":\"string\"},\"process.parent.ppid\":{\"id\":\"string\"},\"process.parent.thread.id\":{\"id\":\"string\"},\"process.pgid\":{\"id\":\"string\"},\"process.pid\":{\"id\":\"string\"},\"process.ppid\":{\"id\":\"string\"},\"process.thread.id\":{\"id\":\"string\"},\"destination.bytes\":{\"id\":\"bytes\"},\"destination.port\":{\"id\":\"string\"},\"http.request.body.bytes\":{\"id\":\"bytes\"},\"http.request.bytes\":{\"id\":\"bytes\"},\"http.response.body.bytes\":{\"id\":\"bytes\"},\"http.response.bytes\":{\"id\":\"bytes\"},\"http.response.status_code\":{\"id\":\"string\"},\"network.bytes\":{\"id\":\"bytes\"},\"source.bytes\":{\"id\":\"bytes\"},\"source.port\":{\"id\":\"string\"}}","fields":"[{\"name\":\"@timestamp\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"message\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":true},{\"name\":\"Endpoint.policy\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Endpoint.policy.applied\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Endpoint.policy.applied.artifacts\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"searchable\":false,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"Endpoint.policy.applied.artifacts.global\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Endpoint.policy.applied.artifacts.global.identifiers\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Endpoint.policy.applied.artifacts.global.identifiers.name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Endpoint.policy.applied.artifacts.global.identifiers.sha256\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Endpoint.policy.applied.artifacts.global.version\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Endpoint.policy.applied.artifacts.user\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Endpoint.policy.applied.artifacts.user.identifiers\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Endpoint.policy.applied.artifacts.user.identifiers.name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Endpoint.policy.applied.artifacts.user.identifiers.sha256\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Endpoint.policy.applied.artifacts.user.version\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Endpoint.policy.applied.id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Endpoint.policy.applied.name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Endpoint.policy.applied.status\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Endpoint.policy.applied.version\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Memory_protection.cross_session\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Memory_protection.feature\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Memory_protection.parent_to_child\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Memory_protection.self_injection\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Memory_protection.thread_count\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Memory_protection.unique_key_v1\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Ransomware.child_pids\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Ransomware.feature\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Ransomware.files\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Ransomware.files.data\",\"type\":\"binary\",\"count\":0,\"scripted\":false,\"indexed\":false,\"searchable\":false,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"Ransomware.files.entropy\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Ransomware.files.extension\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Ransomware.files.metrics\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Ransomware.files.operation\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Ransomware.files.original.extension\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Ransomware.files.original.path\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Ransomware.files.path\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Ransomware.files.score\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Ransomware.score\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Ransomware.version\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.dll.Ext\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.dll.Ext.code_signature\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.dll.Ext.code_signature.exists\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.dll.Ext.code_signature.status\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.dll.Ext.code_signature.subject_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.dll.Ext.code_signature.trusted\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.dll.Ext.code_signature.valid\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.dll.Ext.compile_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.dll.Ext.malware_classification.features\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"searchable\":false,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"Target.dll.Ext.malware_classification.features.data.buffer\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.dll.Ext.malware_classification.features.data.decompressed_size\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.dll.Ext.malware_classification.features.data.encoding\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.dll.Ext.malware_classification.identifier\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.dll.Ext.malware_classification.score\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.dll.Ext.malware_classification.threshold\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.dll.Ext.malware_classification.upx_packed\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.dll.Ext.malware_classification.version\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.dll.Ext.mapped_address\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.dll.Ext.mapped_size\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.dll.hash.md5\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.dll.hash.sha1\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.dll.hash.sha256\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.dll.hash.sha512\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.dll.name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.dll.path\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.dll.pe.company\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.dll.pe.description\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.dll.pe.file_version\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.dll.pe.imphash\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.dll.pe.original_file_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.dll.pe.product\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.Ext\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.Ext.ancestry\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.Ext.architecture\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.Ext.authentication_id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.Ext.code_signature\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.Ext.code_signature.exists\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.Ext.code_signature.status\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.Ext.code_signature.subject_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.Ext.code_signature.trusted\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.Ext.code_signature.valid\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.Ext.dll.Ext\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.Ext.dll.Ext.code_signature\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.Ext.dll.Ext.code_signature.exists\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.Ext.dll.Ext.code_signature.status\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.Ext.dll.Ext.code_signature.subject_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.Ext.dll.Ext.code_signature.trusted\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.Ext.dll.Ext.code_signature.valid\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.Ext.dll.Ext.compile_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.Ext.dll.Ext.mapped_address\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.Ext.dll.Ext.mapped_size\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.Ext.dll.hash.md5\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.Ext.dll.hash.sha1\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.Ext.dll.hash.sha256\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.Ext.dll.hash.sha512\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.Ext.dll.name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.Ext.dll.path\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.Ext.dll.pe.company\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.Ext.dll.pe.description\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.Ext.dll.pe.file_version\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.Ext.dll.pe.imphash\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.Ext.dll.pe.original_file_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.Ext.dll.pe.product\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.Ext.malware_classification.features\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"searchable\":false,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"Target.process.Ext.malware_classification.features.data.buffer\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.Ext.malware_classification.features.data.decompressed_size\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.Ext.malware_classification.features.data.encoding\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.Ext.malware_classification.identifier\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.Ext.malware_classification.score\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.Ext.malware_classification.threshold\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.Ext.malware_classification.upx_packed\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.Ext.malware_classification.version\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.Ext.services\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.Ext.session\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.Ext.token.domain\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.Ext.token.elevation\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.Ext.token.elevation_type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.Ext.token.impersonation_level\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.Ext.token.integrity_level\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.Ext.token.integrity_level_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.Ext.token.is_appcontainer\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.Ext.token.privileges\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.Ext.token.privileges.description\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.Ext.token.privileges.enabled\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.Ext.token.privileges.name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.Ext.token.sid\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.Ext.token.type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.Ext.token.user\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.Ext.user\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.args\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.args_count\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.command_line\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.command_line.caseless\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.command_line.text\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":true},{\"name\":\"Target.process.entity_id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.executable\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.executable.caseless\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.executable.text\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":true},{\"name\":\"Target.process.exit_code\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.hash.md5\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.hash.sha1\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.hash.sha256\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.hash.sha512\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.name.caseless\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.name.text\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.Ext\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.Ext.architecture\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.Ext.code_signature\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.Ext.code_signature.exists\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.Ext.code_signature.status\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.Ext.code_signature.subject_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.Ext.code_signature.trusted\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.Ext.code_signature.valid\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.Ext.dll.Ext\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.Ext.dll.Ext.code_signature\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.Ext.dll.Ext.code_signature.exists\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.Ext.dll.Ext.code_signature.status\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.Ext.dll.Ext.code_signature.subject_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.Ext.dll.Ext.code_signature.trusted\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.Ext.dll.Ext.code_signature.valid\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.Ext.dll.Ext.compile_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.Ext.dll.Ext.mapped_address\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.Ext.dll.Ext.mapped_size\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.Ext.dll.hash.md5\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.Ext.dll.hash.sha1\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.Ext.dll.hash.sha256\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.Ext.dll.hash.sha512\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.Ext.dll.name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.Ext.dll.path\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.Ext.dll.pe.company\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.Ext.dll.pe.description\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.Ext.dll.pe.file_version\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.Ext.dll.pe.imphash\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.Ext.dll.pe.original_file_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.Ext.dll.pe.product\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.Ext.real\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.Ext.real.pid\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.Ext.token.domain\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.Ext.token.elevation\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.Ext.token.elevation_type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.Ext.token.impersonation_level\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.Ext.token.integrity_level\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.Ext.token.integrity_level_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.Ext.token.is_appcontainer\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.Ext.token.privileges\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.Ext.token.privileges.description\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.Ext.token.privileges.enabled\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.Ext.token.privileges.name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.Ext.token.sid\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.Ext.token.type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.Ext.token.user\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.Ext.user\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.args\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.args_count\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.command_line\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.command_line.caseless\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.command_line.text\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.entity_id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.executable\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.executable.caseless\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.executable.text\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.exit_code\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.hash.md5\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.hash.sha1\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.hash.sha256\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.hash.sha512\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.name.caseless\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.name.text\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.pe.company\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.pe.description\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.pe.file_version\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.pe.imphash\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.pe.original_file_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.pe.product\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.pgid\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.pid\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.ppid\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.start\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.thread.id\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.thread.name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.title\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.title.text\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.uptime\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.working_directory\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.working_directory.caseless\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.parent.working_directory.text\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":true},{\"name\":\"Target.process.pe.company\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.pe.description\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.pe.file_version\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.pe.imphash\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.pe.original_file_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.pe.product\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.pgid\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.pid\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.ppid\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.start\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.thread.Ext\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.thread.Ext.call_stack.instruction_pointer\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.thread.Ext.call_stack.memory_section.address\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.thread.Ext.call_stack.memory_section.protection\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.thread.Ext.call_stack.memory_section.size\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.thread.Ext.call_stack.module_path\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.thread.Ext.call_stack.rva\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.thread.Ext.call_stack.symbol_info\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.thread.Ext.parameter\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.thread.Ext.parameter_bytes_compressed\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.thread.Ext.parameter_bytes_compressed_present\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.thread.Ext.service\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.thread.Ext.start\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.thread.Ext.start_address\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.thread.Ext.start_address_allocation_offset\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.thread.Ext.start_address_bytes\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.thread.Ext.start_address_bytes_disasm\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.thread.Ext.start_address_bytes_disasm_hash\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.thread.Ext.start_address_details.allocation_base\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.thread.Ext.start_address_details.allocation_protection\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.thread.Ext.start_address_details.allocation_size\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.thread.Ext.start_address_details.allocation_type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.thread.Ext.start_address_details.bytes_address\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.thread.Ext.start_address_details.bytes_allocation_offset\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.thread.Ext.start_address_details.bytes_compressed\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.thread.Ext.start_address_details.bytes_compressed_present\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.thread.Ext.start_address_details.mapped_pe.company\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.thread.Ext.start_address_details.mapped_pe.description\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.thread.Ext.start_address_details.mapped_pe.file_version\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.thread.Ext.start_address_details.mapped_pe.imphash\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.thread.Ext.start_address_details.mapped_pe.original_file_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.thread.Ext.start_address_details.mapped_pe.product\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.thread.Ext.start_address_details.mapped_pe_detected\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.thread.Ext.start_address_details.memory_pe.company\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.thread.Ext.start_address_details.memory_pe.description\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.thread.Ext.start_address_details.memory_pe.file_version\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.thread.Ext.start_address_details.memory_pe.imphash\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.thread.Ext.start_address_details.memory_pe.original_file_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.thread.Ext.start_address_details.memory_pe.product\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.thread.Ext.start_address_details.memory_pe_detected\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.thread.Ext.start_address_details.region_base\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.thread.Ext.start_address_details.region_protection\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.thread.Ext.start_address_details.region_size\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.thread.Ext.start_address_details.region_state\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.thread.Ext.start_address_details.strings\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.thread.Ext.start_address_module\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.thread.Ext.token.domain\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.thread.Ext.token.elevation\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.thread.Ext.token.elevation_type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.thread.Ext.token.impersonation_level\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.thread.Ext.token.integrity_level\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.thread.Ext.token.integrity_level_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.thread.Ext.token.is_appcontainer\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.thread.Ext.token.privileges\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.thread.Ext.token.privileges.description\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.thread.Ext.token.privileges.enabled\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.thread.Ext.token.privileges.name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.thread.Ext.token.sid\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.thread.Ext.token.type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.thread.Ext.token.user\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.thread.Ext.uptime\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.thread.id\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.thread.name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.title\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.title.text\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":true},{\"name\":\"Target.process.uptime\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.working_directory\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.working_directory.caseless\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Target.process.working_directory.text\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":true},{\"name\":\"agent.ephemeral_id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"agent.id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"agent.name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"agent.type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"agent.version\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"data_stream.dataset\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"data_stream.namespace\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"data_stream.type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination.geo.city_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination.geo.continent_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination.geo.country_iso_code\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination.geo.country_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination.geo.location\",\"type\":\"geo_point\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination.geo.name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination.geo.region_iso_code\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination.geo.region_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dll.Ext\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dll.Ext.code_signature\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dll.Ext.code_signature.exists\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dll.Ext.code_signature.status\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dll.Ext.code_signature.subject_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dll.Ext.code_signature.trusted\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dll.Ext.code_signature.valid\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dll.Ext.compile_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dll.Ext.malware_classification.features\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"searchable\":false,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"dll.Ext.malware_classification.features.data.buffer\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dll.Ext.malware_classification.features.data.decompressed_size\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dll.Ext.malware_classification.features.data.encoding\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dll.Ext.malware_classification.identifier\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dll.Ext.malware_classification.score\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dll.Ext.malware_classification.threshold\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dll.Ext.malware_classification.upx_packed\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dll.Ext.malware_classification.version\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dll.Ext.mapped_address\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dll.Ext.mapped_size\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dll.hash.md5\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dll.hash.sha1\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dll.hash.sha256\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dll.hash.sha512\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dll.name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dll.path\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dll.pe.company\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dll.pe.description\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dll.pe.file_version\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dll.pe.imphash\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dll.pe.original_file_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dll.pe.product\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"ecs.version\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"elastic.agent\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"elastic.agent.id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.action\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.category\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.code\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.created\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.dataset\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.hash\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.ingested\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.kind\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.module\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.outcome\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.provider\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.sequence\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.severity\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.Ext\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.Ext.code_signature\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.Ext.code_signature.exists\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.Ext.code_signature.status\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.Ext.code_signature.subject_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.Ext.code_signature.trusted\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.Ext.code_signature.valid\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.Ext.entry_modified\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.Ext.macro.code_page\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.Ext.macro.collection\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.Ext.macro.collection.hash.md5\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.Ext.macro.collection.hash.sha1\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.Ext.macro.collection.hash.sha256\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.Ext.macro.collection.hash.sha512\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.Ext.macro.errors\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.Ext.macro.errors.count\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.Ext.macro.errors.error_type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.Ext.macro.file_extension\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.Ext.macro.project_file\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.Ext.macro.project_file.hash.md5\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.Ext.macro.project_file.hash.sha1\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.Ext.macro.project_file.hash.sha256\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.Ext.macro.project_file.hash.sha512\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.Ext.macro.stream\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.Ext.macro.stream.hash.md5\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.Ext.macro.stream.hash.sha1\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.Ext.macro.stream.hash.sha256\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.Ext.macro.stream.hash.sha512\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.Ext.macro.stream.name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.Ext.macro.stream.raw_code\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.Ext.macro.stream.raw_code_size\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.Ext.malware_classification.features\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"searchable\":false,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"file.Ext.malware_classification.features.data.buffer\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.Ext.malware_classification.features.data.decompressed_size\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.Ext.malware_classification.features.data.encoding\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.Ext.malware_classification.identifier\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.Ext.malware_classification.score\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.Ext.malware_classification.threshold\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.Ext.malware_classification.upx_packed\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.Ext.malware_classification.version\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.Ext.original\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.Ext.original.gid\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.Ext.original.group\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.Ext.original.mode\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.Ext.original.name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.Ext.original.owner\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.Ext.original.path\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.Ext.original.uid\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.Ext.quarantine_path\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.Ext.quarantine_result\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.Ext.temp_file_path\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.Ext.windows\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.Ext.windows.zone_identifier\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.accessed\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.attributes\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.created\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.ctime\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.device\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.directory\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.drive_letter\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.extension\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.gid\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.group\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.hash.md5\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.hash.sha1\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.hash.sha256\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.hash.sha512\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.inode\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.mime_type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.mode\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.mtime\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.owner\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.path\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.path.caseless\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.path.text\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":true},{\"name\":\"file.pe.company\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.pe.description\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.pe.file_version\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.pe.imphash\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.pe.original_file_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.pe.product\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.size\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.target_path\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.target_path.caseless\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.target_path.text\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":true},{\"name\":\"file.type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.uid\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"group.Ext\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"group.Ext.real\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"group.Ext.real.id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"group.Ext.real.name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"group.domain\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"group.id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"group.name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.architecture\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.domain\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.geo.city_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.geo.continent_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.geo.country_iso_code\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.geo.country_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.geo.location\",\"type\":\"geo_point\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.geo.name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.geo.region_iso_code\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.geo.region_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.hostname\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.ip\",\"type\":\"ip\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.mac\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.os.Ext\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.os.Ext.variant\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.os.family\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.os.full\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.os.full.caseless\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.os.full.text\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":true},{\"name\":\"host.os.kernel\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.os.name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.os.name.caseless\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.os.name.text\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":true},{\"name\":\"host.os.platform\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.os.version\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.uptime\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.user.Ext\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.user.Ext.real\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.user.Ext.real.id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.user.Ext.real.name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.user.domain\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.user.email\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.user.full_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.user.full_name.text\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":true},{\"name\":\"host.user.group.Ext\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.user.group.Ext.real\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.user.group.Ext.real.id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.user.group.Ext.real.name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.user.group.domain\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.user.group.id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.user.group.name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.user.hash\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.user.id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.user.name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.user.name.text\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":true},{\"name\":\"process.Ext\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.Ext.ancestry\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.Ext.architecture\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.Ext.authentication_id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.Ext.code_signature\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.Ext.code_signature.exists\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.Ext.code_signature.status\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.Ext.code_signature.subject_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.Ext.code_signature.trusted\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.Ext.code_signature.valid\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.Ext.dll.Ext\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.Ext.dll.Ext.code_signature\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.Ext.dll.Ext.code_signature.exists\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.Ext.dll.Ext.code_signature.status\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.Ext.dll.Ext.code_signature.subject_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.Ext.dll.Ext.code_signature.trusted\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.Ext.dll.Ext.code_signature.valid\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.Ext.dll.Ext.compile_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.Ext.dll.Ext.mapped_address\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.Ext.dll.Ext.mapped_size\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.Ext.dll.hash.md5\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.Ext.dll.hash.sha1\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.Ext.dll.hash.sha256\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.Ext.dll.hash.sha512\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.Ext.dll.name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.Ext.dll.path\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.Ext.dll.pe.company\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.Ext.dll.pe.description\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.Ext.dll.pe.file_version\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.Ext.dll.pe.imphash\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.Ext.dll.pe.original_file_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.Ext.dll.pe.product\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.Ext.malware_classification.features\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"searchable\":false,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"process.Ext.malware_classification.features.data.buffer\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.Ext.malware_classification.features.data.decompressed_size\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.Ext.malware_classification.features.data.encoding\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.Ext.malware_classification.identifier\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.Ext.malware_classification.score\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.Ext.malware_classification.threshold\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.Ext.malware_classification.upx_packed\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.Ext.malware_classification.version\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.Ext.services\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.Ext.session\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.Ext.token.domain\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.Ext.token.elevation\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.Ext.token.elevation_type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.Ext.token.impersonation_level\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.Ext.token.integrity_level\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.Ext.token.integrity_level_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.Ext.token.is_appcontainer\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.Ext.token.privileges\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.Ext.token.privileges.description\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.Ext.token.privileges.enabled\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.Ext.token.privileges.name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.Ext.token.sid\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.Ext.token.type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.Ext.token.user\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.Ext.user\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.args\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.args_count\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.command_line\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.command_line.caseless\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.command_line.text\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":true},{\"name\":\"process.entity_id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.executable\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.executable.caseless\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.executable.text\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":true},{\"name\":\"process.exit_code\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.hash.md5\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.hash.sha1\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.hash.sha256\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.hash.sha512\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.name.caseless\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.name.text\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":true},{\"name\":\"process.parent.Ext\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.Ext.architecture\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.Ext.code_signature\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.Ext.code_signature.exists\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.Ext.code_signature.status\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.Ext.code_signature.subject_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.Ext.code_signature.trusted\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.Ext.code_signature.valid\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.Ext.dll.Ext\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.Ext.dll.Ext.code_signature\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.Ext.dll.Ext.code_signature.exists\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.Ext.dll.Ext.code_signature.status\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.Ext.dll.Ext.code_signature.subject_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.Ext.dll.Ext.code_signature.trusted\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.Ext.dll.Ext.code_signature.valid\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.Ext.dll.Ext.compile_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.Ext.dll.Ext.mapped_address\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.Ext.dll.Ext.mapped_size\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.Ext.dll.hash.md5\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.Ext.dll.hash.sha1\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.Ext.dll.hash.sha256\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.Ext.dll.hash.sha512\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.Ext.dll.name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.Ext.dll.path\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.Ext.dll.pe.company\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.Ext.dll.pe.description\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.Ext.dll.pe.file_version\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.Ext.dll.pe.imphash\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.Ext.dll.pe.original_file_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.Ext.dll.pe.product\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.Ext.real\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.Ext.real.pid\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.Ext.token.domain\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.Ext.token.elevation\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.Ext.token.elevation_type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.Ext.token.impersonation_level\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.Ext.token.integrity_level\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.Ext.token.integrity_level_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.Ext.token.is_appcontainer\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.Ext.token.privileges\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.Ext.token.privileges.description\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.Ext.token.privileges.enabled\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.Ext.token.privileges.name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.Ext.token.sid\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.Ext.token.type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.Ext.token.user\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.Ext.user\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.args\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.args_count\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.command_line\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.command_line.caseless\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.command_line.text\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":true},{\"name\":\"process.parent.entity_id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.executable\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.executable.caseless\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.executable.text\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":true},{\"name\":\"process.parent.exit_code\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.hash.md5\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.hash.sha1\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.hash.sha256\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.hash.sha512\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.name.caseless\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.name.text\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":true},{\"name\":\"process.parent.pe.company\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.pe.description\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.pe.file_version\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.pe.imphash\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.pe.original_file_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.pe.product\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.pgid\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.pid\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.ppid\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.start\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.thread.id\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.thread.name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.title\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.title.text\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":true},{\"name\":\"process.parent.uptime\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.working_directory\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.working_directory.caseless\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.working_directory.text\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":true},{\"name\":\"process.pe.company\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.pe.description\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.pe.file_version\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.pe.imphash\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.pe.original_file_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.pe.product\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.pgid\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.pid\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.ppid\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.start\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.thread.Ext\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.thread.Ext.call_stack.instruction_pointer\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.thread.Ext.call_stack.memory_section.address\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.thread.Ext.call_stack.memory_section.protection\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.thread.Ext.call_stack.memory_section.size\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.thread.Ext.call_stack.module_path\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.thread.Ext.call_stack.rva\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.thread.Ext.call_stack.symbol_info\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.thread.Ext.parameter\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.thread.Ext.parameter_bytes_compressed\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.thread.Ext.parameter_bytes_compressed_present\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.thread.Ext.service\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.thread.Ext.start\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.thread.Ext.start_address\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.thread.Ext.start_address_allocation_offset\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.thread.Ext.start_address_bytes\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.thread.Ext.start_address_bytes_disasm\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.thread.Ext.start_address_bytes_disasm_hash\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.thread.Ext.start_address_details.allocation_base\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.thread.Ext.start_address_details.allocation_protection\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.thread.Ext.start_address_details.allocation_size\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.thread.Ext.start_address_details.allocation_type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.thread.Ext.start_address_details.bytes_address\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.thread.Ext.start_address_details.bytes_allocation_offset\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.thread.Ext.start_address_details.bytes_compressed\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.thread.Ext.start_address_details.bytes_compressed_present\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.thread.Ext.start_address_details.mapped_pe.company\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.thread.Ext.start_address_details.mapped_pe.description\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.thread.Ext.start_address_details.mapped_pe.file_version\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.thread.Ext.start_address_details.mapped_pe.imphash\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.thread.Ext.start_address_details.mapped_pe.original_file_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.thread.Ext.start_address_details.mapped_pe.product\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.thread.Ext.start_address_details.mapped_pe_detected\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.thread.Ext.start_address_details.memory_pe.company\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.thread.Ext.start_address_details.memory_pe.description\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.thread.Ext.start_address_details.memory_pe.file_version\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.thread.Ext.start_address_details.memory_pe.imphash\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.thread.Ext.start_address_details.memory_pe.original_file_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.thread.Ext.start_address_details.memory_pe.product\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.thread.Ext.start_address_details.memory_pe_detected\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.thread.Ext.start_address_details.region_base\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.thread.Ext.start_address_details.region_protection\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.thread.Ext.start_address_details.region_size\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.thread.Ext.start_address_details.region_state\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.thread.Ext.start_address_details.strings\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.thread.Ext.start_address_module\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.thread.Ext.token.domain\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.thread.Ext.token.elevation\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.thread.Ext.token.elevation_type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.thread.Ext.token.impersonation_level\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.thread.Ext.token.integrity_level\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.thread.Ext.token.integrity_level_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.thread.Ext.token.is_appcontainer\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.thread.Ext.token.privileges\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.thread.Ext.token.privileges.description\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.thread.Ext.token.privileges.enabled\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.thread.Ext.token.privileges.name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.thread.Ext.token.sid\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.thread.Ext.token.type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.thread.Ext.token.user\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.thread.Ext.uptime\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.thread.id\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.thread.name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.title\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.title.text\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":true},{\"name\":\"process.uptime\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.working_directory\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.working_directory.caseless\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.working_directory.text\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":true},{\"name\":\"rule.author\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"rule.category\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"rule.description\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"rule.id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"rule.license\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"rule.name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"rule.reference\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"rule.ruleset\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"rule.uuid\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"rule.version\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source.geo.city_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source.geo.continent_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source.geo.country_iso_code\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source.geo.country_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source.geo.location\",\"type\":\"geo_point\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source.geo.name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source.geo.region_iso_code\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source.geo.region_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"threat.framework\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"threat.tactic.id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"threat.tactic.name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"threat.tactic.reference\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"threat.technique.id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"threat.technique.name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"threat.technique.name.text\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":true},{\"name\":\"threat.technique.reference\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"user.Ext\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"user.Ext.real\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"user.Ext.real.id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"user.Ext.real.name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"user.domain\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"user.email\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"user.full_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"user.full_name.text\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":true},{\"name\":\"user.group.Ext\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"user.group.Ext.real\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"user.group.Ext.real.id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"user.group.Ext.real.name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"user.group.domain\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"user.group.id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"user.group.name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"user.hash\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"user.id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"user.name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"user.name.text\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":true},{\"name\":\"event.Ext\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.Ext.correlation\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.Ext.correlation.id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.Ext.entropy\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.Ext.header_data\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":true},{\"name\":\"file.Ext.monotonic_id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dll.Ext.load_index\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dll.code_signature.exists\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dll.code_signature.status\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dll.code_signature.subject_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dll.code_signature.trusted\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dll.code_signature.valid\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination.address\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination.bytes\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination.domain\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination.ip\",\"type\":\"ip\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination.packets\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination.port\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination.registered_domain\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination.top_level_domain\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dns.Ext\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dns.Ext.options\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dns.Ext.status\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dns.question.name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dns.question.registered_domain\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dns.question.subdomain\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dns.question.top_level_domain\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dns.question.type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dns.resolved_ip\",\"type\":\"ip\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"http.request.body.bytes\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"http.request.body.content\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"http.request.body.content.text\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":true},{\"name\":\"http.request.bytes\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"http.response.Ext\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"http.response.Ext.version\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"http.response.body.bytes\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"http.response.body.content\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"http.response.body.content.text\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":true},{\"name\":\"http.response.bytes\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"http.response.status_code\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"network.bytes\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"network.community_id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"network.direction\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"network.iana_number\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"network.packets\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"network.protocol\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"network.transport\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"network.type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source.address\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source.bytes\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source.domain\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source.ip\",\"type\":\"ip\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source.packets\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source.port\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source.registered_domain\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source.top_level_domain\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"package.name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.Ext.defense_evasions\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.code_signature.exists\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.code_signature.status\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.code_signature.subject_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.code_signature.trusted\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.code_signature.valid\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.code_signature.exists\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.code_signature.status\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.code_signature.subject_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.code_signature.trusted\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.code_signature.valid\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"registry.data.bytes\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"registry.data.strings\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"registry.hive\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"registry.key\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"registry.path\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"registry.value\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true}]","timeFieldName":"@timestamp","title":"logs-*"},"coreMigrationVersion":"7.13.1","id":"logs-*","migrationVersion":{"index-pattern":"7.11.0"},"references":[],"sort":[1622059318492,759],"type":"index-pattern","updated_at":"2021-05-26T20:01:58.492Z","version":"WzEzOTcsMl0="} +{"attributes":{"description":"this is a logstash saved query","filters":[],"query":{"language":"kuery","query":"extension.raw :\"gif\" and machine.os.raw :\"ios\" "},"timefilter":{"from":"2015-09-20T01:56:56.132Z","refreshInterval":{"pause":true,"value":0},"to":"2015-09-21T11:18:20.471Z"},"title":"logstash_saved_query"},"coreMigrationVersion":"7.13.1","id":"logstash_saved_query","references":[],"sort":[1622059242432,736],"type":"query","updated_at":"2021-05-26T20:00:42.432Z","version":"WzEzMDAsMl0="} +{"attributes":{"allowNoIndex":true,"fieldFormatMap":"{\"event.sequence\":{\"id\":\"string\"},\"event.severity\":{\"id\":\"string\"}}","fields":"[{\"name\":\"@timestamp\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Endpoint.policy\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Endpoint.policy.applied\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Endpoint.policy.applied.id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Endpoint.policy.applied.name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Endpoint.policy.applied.status\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Endpoint.status\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"agent.id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"agent.name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"agent.type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"agent.version\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"data_stream.dataset\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"data_stream.namespace\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"data_stream.type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"ecs.version\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"elastic.agent\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"elastic.agent.id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.action\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.category\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.code\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.created\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.dataset\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.hash\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.ingested\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.kind\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.module\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.outcome\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.provider\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.sequence\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.severity\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.architecture\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.domain\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.hostname\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.ip\",\"type\":\"ip\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.mac\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.os.Ext\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.os.Ext.variant\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.os.family\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.os.full\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.os.full.caseless\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.os.full.text\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":true},{\"name\":\"host.os.kernel\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.os.name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.os.name.caseless\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.os.name.text\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":true},{\"name\":\"host.os.platform\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.os.version\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.uptime\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"message\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":true},{\"name\":\"Endpoint.metrics\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Endpoint.metrics.cpu\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Endpoint.metrics.cpu.endpoint\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Endpoint.metrics.cpu.endpoint.histogram\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Endpoint.metrics.cpu.endpoint.latest\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Endpoint.metrics.cpu.endpoint.mean\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Endpoint.metrics.disks\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"searchable\":false,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"Endpoint.metrics.disks.device\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Endpoint.metrics.disks.endpoint_drive\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Endpoint.metrics.disks.free\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Endpoint.metrics.disks.fstype\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Endpoint.metrics.disks.mount\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Endpoint.metrics.disks.total\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Endpoint.metrics.memory\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Endpoint.metrics.memory.endpoint\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Endpoint.metrics.memory.endpoint.private\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Endpoint.metrics.memory.endpoint.private.latest\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Endpoint.metrics.memory.endpoint.private.mean\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Endpoint.metrics.threads\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"searchable\":false,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"Endpoint.metrics.uptime\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Endpoint.metrics.uptime.endpoint\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Endpoint.metrics.uptime.system\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.end\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.start\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Endpoint.policy.applied.actions\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Endpoint.policy.applied.actions.message\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Endpoint.policy.applied.actions.name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Endpoint.policy.applied.actions.status\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Endpoint.policy.applied.artifacts\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"searchable\":false,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"Endpoint.policy.applied.artifacts.global\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Endpoint.policy.applied.artifacts.global.identifiers\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Endpoint.policy.applied.artifacts.global.identifiers.name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Endpoint.policy.applied.artifacts.global.identifiers.sha256\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Endpoint.policy.applied.artifacts.global.version\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Endpoint.policy.applied.artifacts.user\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Endpoint.policy.applied.artifacts.user.identifiers\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Endpoint.policy.applied.artifacts.user.identifiers.name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Endpoint.policy.applied.artifacts.user.identifiers.sha256\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Endpoint.policy.applied.artifacts.user.version\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Endpoint.policy.applied.configurations\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"searchable\":false,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"Endpoint.policy.applied.configurations.antivirus_registration\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"searchable\":false,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"Endpoint.policy.applied.configurations.antivirus_registration.concerned_actions\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Endpoint.policy.applied.configurations.antivirus_registration.status\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Endpoint.policy.applied.configurations.events\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Endpoint.policy.applied.configurations.events.concerned_actions\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Endpoint.policy.applied.configurations.events.status\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Endpoint.policy.applied.configurations.logging\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Endpoint.policy.applied.configurations.logging.concerned_actions\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Endpoint.policy.applied.configurations.logging.status\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Endpoint.policy.applied.configurations.malware\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Endpoint.policy.applied.configurations.malware.concerned_actions\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Endpoint.policy.applied.configurations.malware.status\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Endpoint.policy.applied.configurations.streaming\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Endpoint.policy.applied.configurations.streaming.concerned_actions\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Endpoint.policy.applied.configurations.streaming.status\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"Endpoint.policy.applied.response\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"searchable\":false,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"Endpoint.policy.applied.version\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true}]","timeFieldName":"@timestamp","title":"metrics-*"},"coreMigrationVersion":"7.13.1","id":"metrics-*","migrationVersion":{"index-pattern":"7.11.0"},"references":[],"sort":[1622059318495,824],"type":"index-pattern","updated_at":"2021-05-26T20:01:58.495Z","version":"WzEzOTgsMl0="} +{"attributes":{"description":"Shakespeare query","filters":[],"query":{"language":"kuery","query":"speaker : \"OTHELLO\" and play_name :\"Othello\" "},"title":"shakespeare_current_query"},"coreMigrationVersion":"7.13.1","id":"shakespeare_current_query","references":[],"sort":[1622059292632,753],"type":"query","updated_at":"2021-05-26T20:01:32.632Z","version":"WzEzNDUsMl0="} +{"attributes":{"@created":"2021-05-27T18:53:18.432Z","@timestamp":"2021-05-27T19:46:12.539Z","assets":{},"colors":["#37988d","#c19628","#b83c6f","#3f9939","#1785b0","#ca5f35","#45bdb0","#f2bc33","#e74b8b","#4fbf48","#1ea6dc","#fd7643","#72cec3","#f5cc5d","#ec77a8","#7acf74","#4cbce4","#fd986f","#a1ded7","#f8dd91","#f2a4c5","#a6dfa2","#86d2ed","#fdba9f","#000000","#444444","#777777","#BBBBBB","#FFFFFF","rgba(255,255,255,0)"],"css":".canvasPage {\n\n}","height":720,"isWriteable":true,"name":"logstash-canvas-workpad","page":1,"pages":[{"elements":[{"expression":"savedLens id=\"bb9e5bb0-be2f-11eb-9520-1b4c3ca6a781\" timerange={timerange from=\"now-15y\" to=\"now\"}\n| render","filter":null,"id":"element-56d2ba72-f227-4d04-9478-a1d6f0c7e601","position":{"angle":0,"height":300,"left":20,"parent":null,"top":20,"width":500}},{"expression":"savedVisualization id=\"0d8a8860-623a-11eb-aebf-c306684b328d\" timerange={timerange from=\"now-15y\" to=\"now\"}\n| render","filter":null,"id":"element-afbaa26e-10e7-47d4-bb41-b061dfdced2b","position":{"angle":0,"height":300,"left":527,"parent":null,"top":20,"width":500}}],"groups":[],"id":"page-0f9ef2da-2868-4c0b-9223-fd3c9e53d6c9","style":{"background":"#FFF"},"transition":{}},{"elements":[{"expression":"image dataurl=null mode=\"contain\"\n| render","id":"element-c5534ef7-68c4-46bc-b35a-9e43a7f118c3","position":{"angle":0,"height":107,"left":20,"parent":null,"top":20,"width":132}},{"expression":"filters\n| essql query=\"SELECT machine.os.raw FROM \\\"logstash-*\\\"\"\n| pointseries x=\"machine.os.raw\" y=\"size(machine.os.raw)\" color=\"machine.os.raw\" size=\"sum(machine.os.raw)\"\n| plot defaultStyle={seriesStyle points=5 fill=1}\n| render","id":"element-5f7a3312-0e77-471c-9b8f-f98cb38075fb","position":{"angle":0,"height":192,"left":221,"parent":null,"top":56,"width":451}},{"expression":"timefilterControl compact=true column=@timestamp\n| render","filter":"timefilter from=\"now-29y\" to=now column=@timestamp","id":"element-6e00dcf4-06fe-4bd9-9315-d32d9d3fac5f","position":{"angle":0,"height":50,"left":221,"parent":null,"top":-1,"width":500}},{"expression":"filters\n| esdocs index=\"logstash-*\" fields=\"@timestamp, response.raw\"\n| pointseries x=\"size(response.raw)\" y=\"@timestamp\" color=\"response.raw\"\n| plot\n| render","id":"element-20281fac-1c3a-4ee3-9132-44379fb60b74","position":{"angle":0,"height":262,"left":51,"parent":null,"top":304,"width":590}},{"expression":"filters\n| timelion query=\".es(index=logstash-*, metric=sum:bytes)\"\n| pointseries x=\"@timestamp\" y=\"sum(value)\"\n| plot defaultStyle={seriesStyle lines=3}\n| render","id":"element-337b0548-5d6d-44cd-a324-eb50d63c7bd0","position":{"angle":0,"height":309,"left":648,"parent":null,"top":290,"width":369}},{"expression":"savedLens id=\"bb9e5bb0-be2f-11eb-9520-1b4c3ca6a781\" timerange={timerange from=\"now-15y\" to=\"now\"}\n| render","filter":null,"id":"element-353e5583-0dbb-4a6b-bac7-3b2a6b305397","position":{"angle":0,"height":181.99999999999997,"left":855,"parent":"group-d2618a19-3982-414e-93df-b2cb165b7c7e","top":15.000000000000014,"width":76.961271102284}},{"expression":"savedVisualization id=\"0d8a8860-623a-11eb-aebf-c306684b328d\" timerange={timerange from=\"now-15y\" to=\"now\"}\n| render","filter":null,"id":"element-0e5501a6-9e87-42bc-b539-1e697e62051b","position":{"angle":0,"height":181.99999999999997,"left":933.038728897716,"parent":"group-d2618a19-3982-414e-93df-b2cb165b7c7e","top":15.000000000000014,"width":76.961271102284}}],"groups":[],"id":"page-59c3cf09-1811-4324-995b-7336c1c11ab8","style":{"background":"#FFF"},"transition":{}}],"variables":[],"width":1080},"coreMigrationVersion":"7.13.1","id":"workpad-f2024ca3-e366-447a-b3af-7db4400646ef","migrationVersion":{"canvas-workpad":"7.0.0"},"references":[],"sort":[1622144772545,622],"type":"canvas-workpad","updated_at":"2021-05-27T19:46:12.545Z","version":"WzIwNTEsMl0="} +{"exportedCount":71,"missingRefCount":0,"missingReferences":[]} \ No newline at end of file diff --git a/x-pack/test/functional/apps/saved_objects_management/import_saved_objects_between_versions.ts b/x-pack/test/functional/apps/saved_objects_management/import_saved_objects_between_versions.ts index 07fe0e910ea99..919ba205a0762 100644 --- a/x-pack/test/functional/apps/saved_objects_management/import_saved_objects_between_versions.ts +++ b/x-pack/test/functional/apps/saved_objects_management/import_saved_objects_between_versions.ts @@ -5,8 +5,8 @@ * 2.0. */ -/* This test is importing saved objects from 7.12.0 to 8.0 and the backported version - * will import from 6.8.x to 8.0.0 +/* This test is importing saved objects from 7.13.0 to 8.0 and the backported version + * will import from 6.8.x to 7.x.x */ import expect from '@kbn/expect'; @@ -35,20 +35,20 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await esArchiver.load('empty_kibana'); }); - it('should be able to import 7.12 saved objects into 8.0.0', async function () { + it('should be able to import 7.13 saved objects into 8.0.0', async function () { await retry.tryForTime(10000, async () => { const existingSavedObjects = await testSubjects.getVisibleText('exportAllObjects'); // Kibana always has 1 advanced setting as a saved object await expect(existingSavedObjects).to.be('Export 1 object'); }); await PageObjects.savedObjects.importFile( - path.join(__dirname, 'exports', '_7.12_import_saved_objects.ndjson') + path.join(__dirname, 'exports', '_7.13_import_saved_objects.ndjson') ); await PageObjects.savedObjects.checkImportSucceeded(); await PageObjects.savedObjects.clickImportDone(); const importedSavedObjects = await testSubjects.getVisibleText('exportAllObjects'); // verifying the count of saved objects after importing .ndjson - await expect(importedSavedObjects).to.be('Export 34 objects'); + await expect(importedSavedObjects).to.be('Export 72 objects'); }); }); } From 8529040a926c901861244d963980bc236d8a20c4 Mon Sep 17 00:00:00 2001 From: Constance Date: Fri, 28 May 2021 10:57:30 -0700 Subject: [PATCH 76/77] [Enterprise Search] Log warning for Kibana/EntSearch version mismatches (#100809) * Add server log warnings whenever Kibana and Enterprise Search versions are mismatched * Copy feedback --- .../lib/enterprise_search_config_api.test.ts | 27 ++++++++++++++++++- .../lib/enterprise_search_config_api.ts | 14 ++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/enterprise_search/server/lib/enterprise_search_config_api.test.ts b/x-pack/plugins/enterprise_search/server/lib/enterprise_search_config_api.test.ts index de13077cd1b09..66f2bf78e0c9c 100644 --- a/x-pack/plugins/enterprise_search/server/lib/enterprise_search_config_api.test.ts +++ b/x-pack/plugins/enterprise_search/server/lib/enterprise_search_config_api.test.ts @@ -12,9 +12,16 @@ import fetch from 'node-fetch'; const { Response } = jest.requireActual('node-fetch'); +jest.mock('@kbn/utils', () => ({ + kibanaPackageJson: { version: '1.0.0' }, +})); + import { loggingSystemMock } from 'src/core/server/mocks'; -import { callEnterpriseSearchConfigAPI } from './enterprise_search_config_api'; +import { + callEnterpriseSearchConfigAPI, + warnMismatchedVersions, +} from './enterprise_search_config_api'; describe('callEnterpriseSearchConfigAPI', () => { const mockConfig = { @@ -218,4 +225,22 @@ describe('callEnterpriseSearchConfigAPI', () => { "Exceeded 200ms timeout while checking http://localhost:3002. Please consider increasing your enterpriseSearch.accessCheckTimeout value so that users aren't prevented from accessing Enterprise Search plugins due to slow responses." ); }); + + describe('warnMismatchedVersions', () => { + it("logs a warning when Enterprise Search and Kibana's versions are not the same", () => { + warnMismatchedVersions('1.1.0', mockDependencies.log); + + expect(mockDependencies.log.warn).toHaveBeenCalledWith( + expect.stringContaining( + 'Your Kibana instance (v1.0.0) is not the same version as your Enterprise Search instance (v1.1.0)' + ) + ); + }); + + it("does not log a warning when Enterprise Search and Kibana's versions are the same", () => { + warnMismatchedVersions('1.0.0', mockDependencies.log); + + expect(mockDependencies.log.warn).not.toHaveBeenCalled(); + }); + }); }); diff --git a/x-pack/plugins/enterprise_search/server/lib/enterprise_search_config_api.ts b/x-pack/plugins/enterprise_search/server/lib/enterprise_search_config_api.ts index ebe718dfebd30..0f2faf1fd8a3a 100644 --- a/x-pack/plugins/enterprise_search/server/lib/enterprise_search_config_api.ts +++ b/x-pack/plugins/enterprise_search/server/lib/enterprise_search_config_api.ts @@ -8,6 +8,8 @@ import AbortController from 'abort-controller'; import fetch from 'node-fetch'; +import { kibanaPackageJson } from '@kbn/utils'; + import { KibanaRequest, Logger } from 'src/core/server'; import { stripTrailingSlash } from '../../common/strip_slashes'; @@ -58,6 +60,8 @@ export const callEnterpriseSearchConfigAPI = async ({ }); const data = await response.json(); + warnMismatchedVersions(data?.version?.number, log); + return { access: { hasAppSearchAccess: !!data?.current_user?.access?.app_search, @@ -135,3 +139,13 @@ export const callEnterpriseSearchConfigAPI = async ({ clearTimeout(timeout); } }; + +export const warnMismatchedVersions = (enterpriseSearchVersion: string, log: Logger) => { + const kibanaVersion = kibanaPackageJson.version; + + if (enterpriseSearchVersion !== kibanaVersion) { + log.warn( + `Your Kibana instance (v${kibanaVersion}) is not the same version as your Enterprise Search instance (v${enterpriseSearchVersion}), which may cause unexpected behavior. Use matching versions for the best experience.` + ); + } +}; From 4c48993bb0c419a6f1d6c9ae779232120797f9c7 Mon Sep 17 00:00:00 2001 From: Garrett Spong Date: Fri, 28 May 2021 12:38:49 -0600 Subject: [PATCH 77/77] [RAC][Security Solution] Register Security Detection Rules with Rule Registry (#96015) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary This PR starts the migration of the Security Solution rules to use the rule-registry introduced in https://github.com/elastic/kibana/pull/95903. This is a pathfinding effort in porting over the existing Security Solution rules, and may include some temporary reference rules for testing out different paradigms as we move the rules over. See https://github.com/elastic/kibana/issues/95735 for details Enable via the following feature flags in your `kibana.dev.yml`: ``` # Security Solution Rules on Rule Registry xpack.ruleRegistry.index: '.kibana-[USERNAME]-alerts' # Only necessary to scope from other devs testing, if not specified defaults to `.alerts-security-solution` xpack.securitySolution.enableExperimental: ['ruleRegistryEnabled'] ``` > Note: if setting a custom `xpack.ruleRegistry.index`, for the time being you must also update the [DEFAULT_ALERTS_INDEX](https://github.com/elastic/kibana/blob/9e213fb7a5a0337591a50a0567924ebe950b9791/x-pack/plugins/security_solution/common/constants.ts#L28) in order for the UI to display alerts within the alerts table. --- Three reference rule types have been added (`query`, `eql`, `threshold`), along with scripts for creating them located in: ``` x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/scripts/ ``` Main Detection page TGrid queries have been short-circuited to query `.alerts-security-solution*` for displaying alerts from the new alerts as data indices. To test, checkout, enable the above feature flag(s), and run one of the scripts from the above directory, e.g. `./create_reference_rule_query.sh` (ensure your ENV vars as set! :) Alerts as data within the main Detection Page 🎉

    cc @madirey @dgieselaar @pmuellr @yctercero @dhurley14 @marshallmain --- x-pack/plugins/rule_registry/README.md | 3 + x-pack/plugins/rule_registry/server/index.ts | 1 + .../server/rule_data_client/index.ts | 4 +- .../create_persistence_rule_type_factory.ts | 112 ++++++++++ .../security_solution/common/constants.ts | 13 ++ .../common/experimental_features.ts | 1 + x-pack/plugins/security_solution/kibana.json | 1 + .../exceptions/use_add_exception.test.tsx | 18 +- .../exceptions/use_add_exception.tsx | 20 +- .../public/common/mock/global_state.ts | 1 + .../public/common/mock/test_providers.tsx | 26 ++- .../alerts_table/default_config.tsx | 76 ++++++- .../components/alerts_table/index.tsx | 32 ++- .../alerts/use_signal_index.test.tsx | 31 ++- .../alerts/use_signal_index.tsx | 13 +- .../detection_engine/detection_engine.tsx | 16 +- .../detection_engine/rules/details/index.tsx | 11 +- .../security_solution/public/plugin.tsx | 18 +- .../public/timelines/containers/helpers.ts | 12 +- .../timelines/containers/index.test.tsx | 5 + .../public/timelines/containers/index.tsx | 15 +- .../reference_rules/__mocks__/rule_type.ts | 76 +++++++ .../reference_rules/__mocks__/threshold.ts | 61 ++++++ .../reference_rules/eql.test.ts | 92 ++++++++ .../detection_engine/reference_rules/eql.ts | 121 ++++++++++ .../detection_engine/reference_rules/ml.ts | 70 ++++++ .../reference_rules/query.test.ts | 99 +++++++++ .../detection_engine/reference_rules/query.ts | 88 ++++++++ .../scripts/create_reference_rule_eql.sh | 34 +++ .../scripts/create_reference_rule_query.sh | 34 +++ .../create_reference_rule_threshold.sh | 37 ++++ .../reference_rules/threshold.test.ts | 132 +++++++++++ .../reference_rules/threshold.ts | 206 ++++++++++++++++++ .../routes/index/read_index_route.ts | 16 +- .../routes/rules/create_rules_route.ts | 4 +- .../routes/rules/delete_rules_route.ts | 6 +- .../routes/rules/find_rules_route.ts | 6 +- .../routes/rules/patch_rules_route.ts | 7 +- .../routes/rules/read_rules_route.ts | 6 +- .../routes/rules/update_rules_route.ts | 7 +- .../signals/query_signals_route.test.ts | 4 +- .../routes/signals/query_signals_route.ts | 14 +- .../threshold/find_threshold_signals.ts | 2 +- .../security_solution/server/plugin.ts | 111 +++++++++- .../security_solution/server/routes/index.ts | 23 +- .../factory/hosts/details/index.test.tsx | 1 + 46 files changed, 1606 insertions(+), 80 deletions(-) create mode 100644 x-pack/plugins/rule_registry/server/utils/create_persistence_rule_type_factory.ts create mode 100644 x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/__mocks__/rule_type.ts create mode 100644 x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/__mocks__/threshold.ts create mode 100644 x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/eql.test.ts create mode 100644 x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/eql.ts create mode 100644 x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/ml.ts create mode 100644 x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/query.test.ts create mode 100644 x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/query.ts create mode 100755 x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/scripts/create_reference_rule_eql.sh create mode 100755 x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/scripts/create_reference_rule_query.sh create mode 100755 x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/scripts/create_reference_rule_threshold.sh create mode 100644 x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/threshold.test.ts create mode 100644 x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/threshold.ts diff --git a/x-pack/plugins/rule_registry/README.md b/x-pack/plugins/rule_registry/README.md index cfbde612b45a6..e12c2b29ed373 100644 --- a/x-pack/plugins/rule_registry/README.md +++ b/x-pack/plugins/rule_registry/README.md @@ -145,3 +145,6 @@ The following fields are defined in the technical field component template and s - `kibana.rac.alert.severity.value`: the severity of the alert, as a numerical value, which allows sorting. - `kibana.rac.alert.evaluation.value`: The measured (numerical value). - `kibana.rac.alert.threshold.value`: The threshold that was defined (or, in case of multiple thresholds, the one that was exceeded). +- `kibana.rac.alert.ancestors`: the array of ancestors (if any) for the alert. +- `kibana.rac.alert.depth`: the depth of the alert in the ancestral tree (default 0). +- `kibana.rac.alert.building_block_type`: the building block type of the alert (default undefined). diff --git a/x-pack/plugins/rule_registry/server/index.ts b/x-pack/plugins/rule_registry/server/index.ts index 9547f165cd705..9eefc19f34670 100644 --- a/x-pack/plugins/rule_registry/server/index.ts +++ b/x-pack/plugins/rule_registry/server/index.ts @@ -14,6 +14,7 @@ export { RuleDataClient } from './rule_data_client'; export { IRuleDataClient } from './rule_data_client/types'; export { getRuleExecutorData, RuleExecutorData } from './utils/get_rule_executor_data'; export { createLifecycleRuleTypeFactory } from './utils/create_lifecycle_rule_type_factory'; +export { createPersistenceRuleTypeFactory } from './utils/create_persistence_rule_type_factory'; export const plugin = (initContext: PluginInitializerContext) => new RuleRegistryPlugin(initContext); diff --git a/x-pack/plugins/rule_registry/server/rule_data_client/index.ts b/x-pack/plugins/rule_registry/server/rule_data_client/index.ts index 135c870f20727..43122ba49519a 100644 --- a/x-pack/plugins/rule_registry/server/rule_data_client/index.ts +++ b/x-pack/plugins/rule_registry/server/rule_data_client/index.ts @@ -73,8 +73,8 @@ export class RuleDataClient implements IRuleDataClient { return clusterClient.bulk(requestWithDefaultParameters).then((response) => { if (response.body.errors) { if ( - response.body.items.length === 1 && - response.body.items[0]?.index?.error?.type === 'index_not_found_exception' + response.body.items.length > 0 && + response.body.items?.[0]?.index?.error?.type === 'index_not_found_exception' ) { return this.createOrUpdateWriteTarget({ namespace }).then(() => { return clusterClient.bulk(requestWithDefaultParameters); diff --git a/x-pack/plugins/rule_registry/server/utils/create_persistence_rule_type_factory.ts b/x-pack/plugins/rule_registry/server/utils/create_persistence_rule_type_factory.ts new file mode 100644 index 0000000000000..0e244fbaa2ee3 --- /dev/null +++ b/x-pack/plugins/rule_registry/server/utils/create_persistence_rule_type_factory.ts @@ -0,0 +1,112 @@ +/* + * 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 { ESSearchRequest } from 'typings/elasticsearch'; +import v4 from 'uuid/v4'; +import { Logger } from '@kbn/logging'; + +import { AlertInstance } from '../../../alerting/server'; +import { + AlertInstanceContext, + AlertInstanceState, + AlertTypeParams, +} from '../../../alerting/common'; +import { RuleDataClient } from '../rule_data_client'; +import { AlertTypeWithExecutor } from '../types'; + +type PersistenceAlertService> = ( + alerts: Array> +) => Array>; + +type PersistenceAlertQueryService = ( + query: ESSearchRequest +) => Promise>>; + +type CreatePersistenceRuleTypeFactory = (options: { + ruleDataClient: RuleDataClient; + logger: Logger; +}) => < + TParams extends AlertTypeParams, + TAlertInstanceContext extends AlertInstanceContext, + TServices extends { + alertWithPersistence: PersistenceAlertService; + findAlerts: PersistenceAlertQueryService; + } +>( + type: AlertTypeWithExecutor +) => AlertTypeWithExecutor; + +export const createPersistenceRuleTypeFactory: CreatePersistenceRuleTypeFactory = ({ + logger, + ruleDataClient, +}) => (type) => { + return { + ...type, + executor: async (options) => { + const { + services: { alertInstanceFactory, scopedClusterClient }, + } = options; + + const currentAlerts: Array> = []; + const timestamp = options.startedAt.toISOString(); + + const state = await type.executor({ + ...options, + services: { + ...options.services, + alertWithPersistence: (alerts) => { + alerts.forEach((alert) => currentAlerts.push(alert)); + return alerts.map((alert) => + alertInstanceFactory(alert['kibana.rac.alert.uuid']! as string) + ); + }, + findAlerts: async (query) => { + const { body } = await scopedClusterClient.asCurrentUser.search({ + ...query, + body: { + ...query.body, + }, + ignore_unavailable: true, + }); + return body.hits.hits + .map((event: { _source: any }) => event._source!) + .map((event: { [x: string]: any }) => { + const alertUuid = event['kibana.rac.alert.uuid']; + const isAlert = alertUuid != null; + return { + ...event, + 'event.kind': 'signal', + 'kibana.rac.alert.id': '???', + 'kibana.rac.alert.status': 'open', + 'kibana.rac.alert.uuid': v4(), + 'kibana.rac.alert.ancestors': isAlert + ? ((event['kibana.rac.alert.ancestors'] as string[]) ?? []).concat([ + alertUuid!, + ] as string[]) + : [], + 'kibana.rac.alert.depth': isAlert + ? ((event['kibana.rac.alert.depth'] as number) ?? 0) + 1 + : 0, + '@timestamp': timestamp, + }; + }); + }, + }, + }); + + const numAlerts = currentAlerts.length; + logger.debug(`Found ${numAlerts} alerts.`); + + if (ruleDataClient && numAlerts) { + await ruleDataClient.getWriter().bulk({ + body: currentAlerts.flatMap((event) => [{ index: {} }, event]), + }); + } + + return state; + }, + }; +}; diff --git a/x-pack/plugins/security_solution/common/constants.ts b/x-pack/plugins/security_solution/common/constants.ts index effefdd438c5c..91b48afdc4ed1 100644 --- a/x-pack/plugins/security_solution/common/constants.ts +++ b/x-pack/plugins/security_solution/common/constants.ts @@ -25,6 +25,7 @@ export const DEFAULT_TIME_RANGE = 'timepicker:timeDefaults'; export const DEFAULT_REFRESH_RATE_INTERVAL = 'timepicker:refreshIntervalDefaults'; export const DEFAULT_APP_TIME_RANGE = 'securitySolution:timeDefaults'; export const DEFAULT_APP_REFRESH_INTERVAL = 'securitySolution:refreshIntervalDefaults'; +export const DEFAULT_ALERTS_INDEX = '.alerts-security-solution'; export const DEFAULT_SIGNALS_INDEX = '.siem-signals'; export const DEFAULT_LISTS_INDEX = '.lists'; export const DEFAULT_ITEMS_INDEX = '.items'; @@ -148,6 +149,18 @@ export const DEFAULT_TRANSFORMS_SETTING = JSON.stringify(defaultTransformsSettin */ export const SIGNALS_ID = `siem.signals`; +/** + * Id's for reference rule types + */ +export const REFERENCE_RULE_ALERT_TYPE_ID = `siem.referenceRule`; +export const REFERENCE_RULE_PERSISTENCE_ALERT_TYPE_ID = `siem.referenceRulePersistence`; + +export const CUSTOM_ALERT_TYPE_ID = `siem.customRule`; +export const EQL_ALERT_TYPE_ID = `siem.eqlRule`; +export const INDICATOR_ALERT_TYPE_ID = `siem.indicatorRule`; +export const ML_ALERT_TYPE_ID = `siem.mlRule`; +export const THRESHOLD_ALERT_TYPE_ID = `siem.thresholdRule`; + /** * Id for the notifications alerting type */ diff --git a/x-pack/plugins/security_solution/common/experimental_features.ts b/x-pack/plugins/security_solution/common/experimental_features.ts index 6195dd61a7984..02006fdb29d47 100644 --- a/x-pack/plugins/security_solution/common/experimental_features.ts +++ b/x-pack/plugins/security_solution/common/experimental_features.ts @@ -15,6 +15,7 @@ const allowedExperimentalValues = Object.freeze({ trustedAppsByPolicyEnabled: false, metricsEntitiesEnabled: false, hostIsolationEnabled: false, + ruleRegistryEnabled: false, }); type ExperimentalConfigKeys = Array; diff --git a/x-pack/plugins/security_solution/kibana.json b/x-pack/plugins/security_solution/kibana.json index 50a5f62740271..02dbc56bd3397 100644 --- a/x-pack/plugins/security_solution/kibana.json +++ b/x-pack/plugins/security_solution/kibana.json @@ -8,6 +8,7 @@ "actions", "alerting", "cases", + "ruleRegistry", "data", "dataEnhanced", "embeddable", diff --git a/x-pack/plugins/security_solution/public/common/components/exceptions/use_add_exception.test.tsx b/x-pack/plugins/security_solution/public/common/components/exceptions/use_add_exception.test.tsx index 3d29650b750dc..e4a015525dfb4 100644 --- a/x-pack/plugins/security_solution/public/common/components/exceptions/use_add_exception.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/exceptions/use_add_exception.test.tsx @@ -21,7 +21,7 @@ import type { CreateExceptionListItemSchema, UpdateExceptionListItemSchema, } from '@kbn/securitysolution-io-ts-list-types'; - +import { TestProviders } from '../../mock'; import { useAddOrUpdateException, UseAddOrUpdateExceptionProps, @@ -134,12 +134,16 @@ describe('useAddOrUpdateException', () => { addOrUpdateItemsArgs = [ruleId, itemsToAddOrUpdate]; render = () => - renderHook(() => - useAddOrUpdateException({ - http: mockKibanaHttpService, - onError, - onSuccess, - }) + renderHook( + () => + useAddOrUpdateException({ + http: mockKibanaHttpService, + onError, + onSuccess, + }), + { + wrapper: TestProviders, + } ); }); diff --git a/x-pack/plugins/security_solution/public/common/components/exceptions/use_add_exception.tsx b/x-pack/plugins/security_solution/public/common/components/exceptions/use_add_exception.tsx index 5ba73ba2c9058..dbae0964b41a8 100644 --- a/x-pack/plugins/security_solution/public/common/components/exceptions/use_add_exception.tsx +++ b/x-pack/plugins/security_solution/public/common/components/exceptions/use_add_exception.tsx @@ -19,9 +19,11 @@ import { getUpdateAlertsQuery } from '../../../detections/components/alerts_tabl import { buildAlertStatusFilter, buildAlertsRuleIdFilter, + buildAlertStatusFilterRuleRegistry, } from '../../../detections/components/alerts_table/default_config'; import { getQueryFilter } from '../../../../common/detection_engine/get_query_filter'; import { Index } from '../../../../common/detection_engine/schemas/common/schemas'; +import { useIsExperimentalFeatureEnabled } from '../../hooks/use_experimental_features'; import { formatExceptionItemForUpdate, prepareExceptionItemsForBulkClose } from './helpers'; import { useKibana } from '../../lib/kibana'; @@ -82,6 +84,8 @@ export const useAddOrUpdateException = ({ }, [] ); + // TODO: Once we are past experimental phase this code should be removed + const ruleRegistryEnabled = useIsExperimentalFeatureEnabled('ruleRegistryEnabled'); useEffect(() => { let isSubscribed = true; @@ -127,10 +131,15 @@ export const useAddOrUpdateException = ({ } if (bulkCloseIndex != null) { + // TODO: Once we are past experimental phase this code should be removed + const alertStatusFilter = ruleRegistryEnabled + ? buildAlertStatusFilterRuleRegistry('open') + : buildAlertStatusFilter('open'); + const filter = getQueryFilter( '', 'kuery', - [...buildAlertsRuleIdFilter(ruleId), ...buildAlertStatusFilter('open')], + [...buildAlertsRuleIdFilter(ruleId), ...alertStatusFilter], bulkCloseIndex, prepareExceptionItemsForBulkClose(exceptionItemsToAddOrUpdate), false @@ -176,7 +185,14 @@ export const useAddOrUpdateException = ({ isSubscribed = false; abortCtrl.abort(); }; - }, [http, onSuccess, onError, updateExceptionListItem, addExceptionListItem]); + }, [ + addExceptionListItem, + http, + onSuccess, + onError, + ruleRegistryEnabled, + updateExceptionListItem, + ]); return [{ isLoading }, addOrUpdateException]; }; diff --git a/x-pack/plugins/security_solution/public/common/mock/global_state.ts b/x-pack/plugins/security_solution/public/common/mock/global_state.ts index af278b09e719c..71e33c603b65b 100644 --- a/x-pack/plugins/security_solution/public/common/mock/global_state.ts +++ b/x-pack/plugins/security_solution/public/common/mock/global_state.ts @@ -43,6 +43,7 @@ export const mockGlobalState: State = { trustedAppsByPolicyEnabled: false, metricsEntitiesEnabled: false, hostIsolationEnabled: false, + ruleRegistryEnabled: false, }, }, hosts: { diff --git a/x-pack/plugins/security_solution/public/common/mock/test_providers.tsx b/x-pack/plugins/security_solution/public/common/mock/test_providers.tsx index 90526e84a2262..9ac7ae0f24322 100644 --- a/x-pack/plugins/security_solution/public/common/mock/test_providers.tsx +++ b/x-pack/plugins/security_solution/public/common/mock/test_providers.tsx @@ -24,11 +24,12 @@ import { import { FieldHook } from '../../shared_imports'; import { SUB_PLUGINS_REDUCER } from './utils'; import { createSecuritySolutionStorageMock, localStorageMock } from './mock_local_storage'; +import { UserPrivilegesProvider } from '../../detections/components/user_privileges'; const state: State = mockGlobalState; interface Props { - children: React.ReactNode; + children?: React.ReactNode; store?: Store; onDragEnd?: (result: DropResult, provided: ResponderProvided) => void; } @@ -59,7 +60,30 @@ const TestProvidersComponent: React.FC = ({ ); +/** + * A utility for wrapping children in the providers required to run most tests + * WITH user privileges provider. + */ +const TestProvidersWithPrivilegesComponent: React.FC = ({ + children, + store = createStore(state, SUB_PLUGINS_REDUCER, kibanaObservable, storage), + onDragEnd = jest.fn(), +}) => ( + + + + ({ eui: euiDarkVars, darkMode: true })}> + + {children} + + + + + +); + export const TestProviders = React.memo(TestProvidersComponent); +export const TestProvidersWithPrivileges = React.memo(TestProvidersWithPrivilegesComponent); export const useFormFieldMock = (options?: Partial>): FieldHook => { return { diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/default_config.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/default_config.tsx index 478c8930b8dd3..02a815bc59f3b 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/default_config.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/default_config.tsx @@ -5,11 +5,12 @@ * 2.0. */ +import { defaultColumnHeaderType } from '../../../timelines/components/timeline/body/column_headers/default_headers'; import { RowRendererId } from '../../../../common/types/timeline'; import { Status } from '../../../../common/detection_engine/schemas/common/schemas'; import { Filter } from '../../../../../../../src/plugins/data/common/es_query'; -import { SubsetTimelineModel } from '../../../timelines/store/timeline/model'; +import { ColumnHeaderOptions, SubsetTimelineModel } from '../../../timelines/store/timeline/model'; import { timelineDefaults } from '../../../timelines/store/timeline/defaults'; import { columns } from '../../configurations/security_solution_detections/columns'; @@ -124,3 +125,76 @@ export const requiredFieldsForActions = [ 'host.os.family', 'event.code', ]; + +// TODO: Once we are past experimental phase this code should be removed +export const buildAlertStatusFilterRuleRegistry = (status: Status): Filter[] => [ + { + meta: { + alias: null, + negate: false, + disabled: false, + type: 'phrase', + key: 'kibana.rac.alert.status', + params: { + query: status, + }, + }, + query: { + term: { + 'kibana.rac.alert.status': status, + }, + }, + }, +]; + +export const buildShowBuildingBlockFilterRuleRegistry = ( + showBuildingBlockAlerts: boolean +): Filter[] => + showBuildingBlockAlerts + ? [] + : [ + { + meta: { + alias: null, + negate: true, + disabled: false, + type: 'exists', + key: 'kibana.rac.rule.building_block_type', + value: 'exists', + }, + // @ts-expect-error TODO: Rework parent typings to support ExistsFilter[] + exists: { field: 'kibana.rac.rule.building_block_type' }, + }, + ]; + +export const requiredFieldMappingsForActionsRuleRegistry = { + '@timestamp': '@timestamp', + 'alert.id': 'kibana.rac.alert.id', + 'event.kind': 'event.kind', + 'alert.start': 'kibana.rac.alert.start', + 'alert.uuid': 'kibana.rac.alert.uuid', + 'event.action': 'event.action', + 'alert.status': 'kibana.rac.alert.status', + 'alert.duration.us': 'kibana.rac.alert.duration.us', + 'rule.uuid': 'rule.uuid', + 'rule.id': 'rule.id', + 'rule.name': 'rule.name', + 'rule.category': 'rule.category', + producer: 'kibana.rac.alert.producer', + tags: 'tags', +}; + +export const alertsHeadersRuleRegistry: ColumnHeaderOptions[] = Object.entries( + requiredFieldMappingsForActionsRuleRegistry +).map(([alias, field]) => ({ + columnHeaderType: defaultColumnHeaderType, + displayAsText: alias, + id: field, +})); + +export const alertsDefaultModelRuleRegistry: SubsetTimelineModel = { + ...timelineDefaults, + columns: alertsHeadersRuleRegistry, + showCheckboxes: true, + excludedRowRendererIds: Object.values(RowRendererId), +}; diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/index.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/index.tsx index 9dc83d7898963..f20754fc446d6 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/index.tsx @@ -16,6 +16,7 @@ import { TimelineIdLiteral } from '../../../../common/types/timeline'; import { useAppToasts } from '../../../common/hooks/use_app_toasts'; import { StatefulEventsViewer } from '../../../common/components/events_viewer'; import { HeaderSection } from '../../../common/components/header_section'; +import { useIsExperimentalFeatureEnabled } from '../../../common/hooks/use_experimental_features'; import { combineQueries } from '../../../timelines/components/timeline/helpers'; import { useKibana } from '../../../common/lib/kibana'; import { inputsSelectors, State, inputsModel } from '../../../common/store'; @@ -29,6 +30,8 @@ import { requiredFieldsForActions, alertsDefaultModel, buildAlertStatusFilter, + alertsDefaultModelRuleRegistry, + buildAlertStatusFilterRuleRegistry, } from './default_config'; import { FILTER_OPEN, AlertsTableFilterGroup } from './alerts_filter_group'; import { AlertsUtilityBar } from './alerts_utility_bar'; @@ -104,6 +107,8 @@ export const AlertsTableComponent: React.FC = ({ const [, dispatchToaster] = useStateToaster(); const { addWarning } = useAppToasts(); const { initializeTimeline, setSelectAll } = useManageTimeline(); + // TODO: Once we are past experimental phase this code should be removed + const ruleRegistryEnabled = useIsExperimentalFeatureEnabled('ruleRegistryEnabled'); const getGlobalQuery = useCallback( (customFilters: Filter[]) => { @@ -236,7 +241,11 @@ export const AlertsTableComponent: React.FC = ({ refetchQuery: inputsModel.Refetch, { status, selectedStatus }: UpdateAlertsStatusProps ) => { - const currentStatusFilter = buildAlertStatusFilter(status); + // TODO: Once we are past experimental phase this code should be removed + const currentStatusFilter = ruleRegistryEnabled + ? buildAlertStatusFilterRuleRegistry(status) + : buildAlertStatusFilter(status); + await updateAlertStatusAction({ query: showClearSelectionAction ? getGlobalQuery(currentStatusFilter)?.filterQuery @@ -258,6 +267,7 @@ export const AlertsTableComponent: React.FC = ({ showClearSelectionAction, onAlertStatusUpdateSuccess, onAlertStatusUpdateFailure, + ruleRegistryEnabled, ] ); @@ -301,18 +311,28 @@ export const AlertsTableComponent: React.FC = ({ ); const defaultFiltersMemo = useMemo(() => { + // TODO: Once we are past experimental phase this code should be removed + const alertStatusFilter = ruleRegistryEnabled + ? buildAlertStatusFilterRuleRegistry(filterGroup) + : buildAlertStatusFilter(filterGroup); + if (isEmpty(defaultFilters)) { - return buildAlertStatusFilter(filterGroup); + return alertStatusFilter; } else if (defaultFilters != null && !isEmpty(defaultFilters)) { - return [...defaultFilters, ...buildAlertStatusFilter(filterGroup)]; + return [...defaultFilters, ...alertStatusFilter]; } - }, [defaultFilters, filterGroup]); + }, [defaultFilters, filterGroup, ruleRegistryEnabled]); const { filterManager } = useKibana().services.data.query; + // TODO: Once we are past experimental phase this code should be removed + const defaultTimelineModel = ruleRegistryEnabled + ? alertsDefaultModelRuleRegistry + : alertsDefaultModel; + useEffect(() => { initializeTimeline({ defaultModel: { - ...alertsDefaultModel, + ...defaultTimelineModel, columns, }, documentType: i18n.ALERTS_DOCUMENT_TYPE, @@ -344,7 +364,7 @@ export const AlertsTableComponent: React.FC = ({ return ( ( - {children} -); - describe('useSignalIndex', () => { let appToastsMock: jest.Mocked>; @@ -33,7 +28,9 @@ describe('useSignalIndex', () => { await act(async () => { const { result, waitForNextUpdate } = renderHook( () => useSignalIndex(), - { wrapper: Wrapper } + { + wrapper: TestProvidersWithPrivileges, + } ); await waitForNextUpdate(); expect(result.current).toEqual({ @@ -50,7 +47,9 @@ describe('useSignalIndex', () => { await act(async () => { const { result, waitForNextUpdate } = renderHook( () => useSignalIndex(), - { wrapper: Wrapper } + { + wrapper: TestProvidersWithPrivileges, + } ); await waitForNextUpdate(); await waitForNextUpdate(); @@ -69,7 +68,9 @@ describe('useSignalIndex', () => { await act(async () => { const { result, waitForNextUpdate } = renderHook( () => useSignalIndex(), - { wrapper: Wrapper } + { + wrapper: TestProvidersWithPrivileges, + } ); await waitForNextUpdate(); await waitForNextUpdate(); @@ -93,7 +94,9 @@ describe('useSignalIndex', () => { await act(async () => { const { result, waitForNextUpdate } = renderHook( () => useSignalIndex(), - { wrapper: Wrapper } + { + wrapper: TestProvidersWithPrivileges, + } ); await waitForNextUpdate(); await waitForNextUpdate(); @@ -114,7 +117,9 @@ describe('useSignalIndex', () => { await act(async () => { const { result, waitForNextUpdate } = renderHook( () => useSignalIndex(), - { wrapper: Wrapper } + { + wrapper: TestProvidersWithPrivileges, + } ); await waitForNextUpdate(); await waitForNextUpdate(); @@ -140,7 +145,9 @@ describe('useSignalIndex', () => { await act(async () => { const { result, waitForNextUpdate } = renderHook( () => useSignalIndex(), - { wrapper: Wrapper } + { + wrapper: TestProvidersWithPrivileges, + } ); await waitForNextUpdate(); await waitForNextUpdate(); diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/alerts/use_signal_index.tsx b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/alerts/use_signal_index.tsx index fdbeab26f11f3..84eaf8e3aa93c 100644 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/alerts/use_signal_index.tsx +++ b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/alerts/use_signal_index.tsx @@ -6,8 +6,10 @@ */ import { useEffect, useState } from 'react'; +import { DEFAULT_ALERTS_INDEX } from '../../../../../common/constants'; import { useAppToasts } from '../../../../common/hooks/use_app_toasts'; +import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features'; import { createSignalIndex, getSignalIndex } from './api'; import * as i18n from './translations'; import { isSecurityAppError } from '../../../../common/utils/api'; @@ -38,6 +40,8 @@ export const useSignalIndex = (): ReturnSignalIndex => { }); const { addError } = useAppToasts(); const { hasIndexRead } = useAlertsPrivileges(); + // TODO: Once we are past experimental phase this code should be removed + const ruleRegistryEnabled = useIsExperimentalFeatureEnabled('ruleRegistryEnabled'); useEffect(() => { let isSubscribed = true; @@ -48,10 +52,15 @@ export const useSignalIndex = (): ReturnSignalIndex => { setLoading(true); const signal = await getSignalIndex({ signal: abortCtrl.signal }); + // TODO: Once we are past experimental phase we can update `getSignalIndex` to return the space-aware DEFAULT_ALERTS_INDEX + const signalIndices = ruleRegistryEnabled + ? `${DEFAULT_ALERTS_INDEX},${signal.name}` + : signal.name; + if (isSubscribed && signal != null) { setSignalIndex({ signalIndexExists: true, - signalIndexName: signal.name, + signalIndexName: signalIndices, signalIndexMappingOutdated: signal.index_mapping_outdated, createDeSignalIndex: createIndex, }); @@ -115,7 +124,7 @@ export const useSignalIndex = (): ReturnSignalIndex => { isSubscribed = false; abortCtrl.abort(); }; - }, [addError, hasIndexRead]); + }, [addError, hasIndexRead, ruleRegistryEnabled]); return { loading, ...signalIndex }; }; diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/detection_engine.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/detection_engine.tsx index c1c7e4688bbbe..8ae7e4fb2852b 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/detection_engine.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/detection_engine.tsx @@ -11,6 +11,7 @@ import { noop } from 'lodash/fp'; import React, { useCallback, useMemo, useRef, useState } from 'react'; import { useDispatch } from 'react-redux'; import { useHistory } from 'react-router-dom'; +import { useIsExperimentalFeatureEnabled } from '../../../common/hooks/use_experimental_features'; import { useDeepEqualSelector, useShallowEqualSelector } from '../../../common/hooks/use_selector'; import { SecurityPageName } from '../../../app/types'; @@ -51,6 +52,7 @@ import { timelineSelectors } from '../../../timelines/store/timeline'; import { timelineDefaults } from '../../../timelines/store/timeline/defaults'; import { buildShowBuildingBlockFilter, + buildShowBuildingBlockFilterRuleRegistry, buildThreatMatchFilter, } from '../../components/alerts_table/default_config'; import { useSourcererScope } from '../../../common/containers/sourcerer'; @@ -81,6 +83,8 @@ const DetectionEnginePageComponent = () => { const getGlobalQuerySelector = useMemo(() => inputsSelectors.globalQuerySelector(), []); const query = useDeepEqualSelector(getGlobalQuerySelector); const filters = useDeepEqualSelector(getGlobalFiltersQuerySelector); + // TODO: Once we are past experimental phase this code should be removed + const ruleRegistryEnabled = useIsExperimentalFeatureEnabled('ruleRegistryEnabled'); const { to, from, deleteQuery, setQuery } = useGlobalTime(); const { globalFullScreen } = useGlobalFullScreen(); @@ -134,19 +138,23 @@ const DetectionEnginePageComponent = () => { const alertsHistogramDefaultFilters = useMemo( () => [ ...filters, - ...buildShowBuildingBlockFilter(showBuildingBlockAlerts), + ...(ruleRegistryEnabled + ? buildShowBuildingBlockFilterRuleRegistry(showBuildingBlockAlerts) // TODO: Once we are past experimental phase this code should be removed + : buildShowBuildingBlockFilter(showBuildingBlockAlerts)), ...buildThreatMatchFilter(showOnlyThreatIndicatorAlerts), ], - [filters, showBuildingBlockAlerts, showOnlyThreatIndicatorAlerts] + [filters, ruleRegistryEnabled, showBuildingBlockAlerts, showOnlyThreatIndicatorAlerts] ); // AlertsTable manages global filters itself, so not including `filters` const alertsTableDefaultFilters = useMemo( () => [ - ...buildShowBuildingBlockFilter(showBuildingBlockAlerts), + ...(ruleRegistryEnabled + ? buildShowBuildingBlockFilterRuleRegistry(showBuildingBlockAlerts) // TODO: Once we are past experimental phase this code should be removed + : buildShowBuildingBlockFilter(showBuildingBlockAlerts)), ...buildThreatMatchFilter(showOnlyThreatIndicatorAlerts), ], - [showBuildingBlockAlerts, showOnlyThreatIndicatorAlerts] + [ruleRegistryEnabled, showBuildingBlockAlerts, showOnlyThreatIndicatorAlerts] ); const onShowBuildingBlockAlertsChangedCallback = useCallback( diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/index.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/index.tsx index d3793dad8ff1a..8dac9e03514d1 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/index.tsx @@ -36,6 +36,7 @@ import { useDeepEqualSelector, useShallowEqualSelector, } from '../../../../../common/hooks/use_selector'; +import { useIsExperimentalFeatureEnabled } from '../../../../../common/hooks/use_experimental_features'; import { useKibana } from '../../../../../common/lib/kibana'; import { TimelineId } from '../../../../../../common/types/timeline'; import { UpdateDateRange } from '../../../../../common/components/charts/common'; @@ -64,6 +65,7 @@ import { StepScheduleRule } from '../../../../components/rules/step_schedule_rul import { buildAlertsRuleIdFilter, buildShowBuildingBlockFilter, + buildShowBuildingBlockFilterRuleRegistry, buildThreatMatchFilter, } from '../../../../components/alerts_table/default_config'; import { RuleSwitch } from '../../../../components/rules/rule_switch'; @@ -222,6 +224,9 @@ const RuleDetailsPageComponent = () => { const { formatUrl } = useFormatUrl(SecurityPageName.detections); const { globalFullScreen } = useGlobalFullScreen(); + // TODO: Once we are past experimental phase this code should be removed + const ruleRegistryEnabled = useIsExperimentalFeatureEnabled('ruleRegistryEnabled'); + // TODO: Refactor license check + hasMlAdminPermissions to common check const hasMlPermissions = hasMlLicense(mlCapabilities) && hasMlAdminPermissions(mlCapabilities); const { @@ -307,10 +312,12 @@ const RuleDetailsPageComponent = () => { const alertDefaultFilters = useMemo( () => [ ...buildAlertsRuleIdFilter(ruleId), - ...buildShowBuildingBlockFilter(showBuildingBlockAlerts), + ...(ruleRegistryEnabled + ? buildShowBuildingBlockFilterRuleRegistry(showBuildingBlockAlerts) // TODO: Once we are past experimental phase this code should be removed + : buildShowBuildingBlockFilter(showBuildingBlockAlerts)), ...buildThreatMatchFilter(showOnlyThreatIndicatorAlerts), ], - [ruleId, showBuildingBlockAlerts, showOnlyThreatIndicatorAlerts] + [ruleId, ruleRegistryEnabled, showBuildingBlockAlerts, showOnlyThreatIndicatorAlerts] ); const alertMergedFilters = useMemo(() => [...alertDefaultFilters, ...filters], [ diff --git a/x-pack/plugins/security_solution/public/plugin.tsx b/x-pack/plugins/security_solution/public/plugin.tsx index c1f501d3f7094..2e41e291156aa 100644 --- a/x-pack/plugins/security_solution/public/plugin.tsx +++ b/x-pack/plugins/security_solution/public/plugin.tsx @@ -44,6 +44,7 @@ import { APP_PATH, DEFAULT_INDEX_KEY, DETECTION_ENGINE_INDEX_URL, + DEFAULT_ALERTS_INDEX, } from '../common/constants'; import { SecurityPageName } from './app/types'; @@ -446,6 +447,9 @@ export class Plugin implements IPlugin { if (!this._store) { + const experimentalFeatures = parseExperimentalConfigValue( + this.config.enableExperimental || [] + ); const defaultIndicesName = coreStart.uiSettings.get(DEFAULT_INDEX_KEY); const [ { createStore, createInitialState }, @@ -474,9 +478,15 @@ export class Plugin implements IPlugin +// TODO: Once we are past experimental phase `useRuleRegistry` should be removed +export const skipQueryForDetectionsPage = ( + id: string, + defaultIndex: string[], + useRuleRegistry = false +) => id != null && detectionsTimelineIds.some((timelineId) => timelineId === id) && - !defaultIndex.some((di) => di.toLowerCase().startsWith('.siem-signals')); + !defaultIndex.some((di) => + di.toLowerCase().startsWith(useRuleRegistry ? DEFAULT_ALERTS_INDEX : '.siem-signals') + ); diff --git a/x-pack/plugins/security_solution/public/timelines/containers/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/containers/index.test.tsx index 1032d0ec1672a..62846eb01e60f 100644 --- a/x-pack/plugins/security_solution/public/timelines/containers/index.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/containers/index.test.tsx @@ -9,6 +9,7 @@ import { renderHook, act } from '@testing-library/react-hooks'; import { initSortDefault, TimelineArgs, useTimelineEvents, UseTimelineEventsProps } from '.'; import { SecurityPageName } from '../../../common/constants'; import { TimelineId } from '../../../common/types/timeline'; +import { useIsExperimentalFeatureEnabled } from '../../common/hooks/use_experimental_features'; import { mockTimelineData } from '../../common/mock'; import { useRouteSpy } from '../../common/utils/route/use_route_spy'; @@ -26,6 +27,9 @@ const mockEvents = mockTimelineData.filter((i, index) => index <= 11); const mockSearch = jest.fn(); +jest.mock('../../common/hooks/use_experimental_features'); +const useIsExperimentalFeatureEnabledMock = useIsExperimentalFeatureEnabled as jest.Mock; + jest.mock('../../common/lib/kibana', () => ({ useToasts: jest.fn().mockReturnValue({ addError: jest.fn(), @@ -93,6 +97,7 @@ mockUseRouteSpy.mockReturnValue([ ]); describe('useTimelineEvents', () => { + useIsExperimentalFeatureEnabledMock.mockReturnValue(false); beforeEach(() => { mockSearch.mockReset(); }); diff --git a/x-pack/plugins/security_solution/public/timelines/containers/index.tsx b/x-pack/plugins/security_solution/public/timelines/containers/index.tsx index 92199336b978c..17c107899d85a 100644 --- a/x-pack/plugins/security_solution/public/timelines/containers/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/containers/index.tsx @@ -13,6 +13,7 @@ import { Subscription } from 'rxjs'; import { ESQuery } from '../../../common/typed_json'; import { isCompleteResponse, isErrorResponse } from '../../../../../../src/plugins/data/public'; +import { useIsExperimentalFeatureEnabled } from '../../common/hooks/use_experimental_features'; import { inputsModel, KueryFilterQueryKind } from '../../common/store'; import { useKibana } from '../../common/lib/kibana'; import { createFilter } from '../../common/containers/helpers'; @@ -197,6 +198,9 @@ export const useTimelineEvents = ({ }); const { addError, addWarning } = useAppToasts(); + // TODO: Once we are past experimental phase this code should be removed + const ruleRegistryEnabled = useIsExperimentalFeatureEnabled('ruleRegistryEnabled'); + const timelineSearch = useCallback( (request: TimelineRequest | null) => { if (request == null || pageName === '' || skip) { @@ -305,7 +309,10 @@ export const useTimelineEvents = ({ ); useEffect(() => { - if (skipQueryForDetectionsPage(id, indexNames) || indexNames.length === 0) { + if ( + skipQueryForDetectionsPage(id, indexNames, ruleRegistryEnabled) || + indexNames.length === 0 + ) { return; } @@ -364,7 +371,10 @@ export const useTimelineEvents = ({ activeTimeline.setActivePage(newActivePage); } } - if (!skipQueryForDetectionsPage(id, indexNames) && !deepEqual(prevRequest, currentRequest)) { + if ( + !skipQueryForDetectionsPage(id, indexNames, ruleRegistryEnabled) && + !deepEqual(prevRequest, currentRequest) + ) { return currentRequest; } return prevRequest; @@ -380,6 +390,7 @@ export const useTimelineEvents = ({ id, language, limit, + ruleRegistryEnabled, startDate, sort, fields, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/__mocks__/rule_type.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/__mocks__/rule_type.ts new file mode 100644 index 0000000000000..f7e0dd9eb3620 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/__mocks__/rule_type.ts @@ -0,0 +1,76 @@ +/* + * 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 { of } from 'rxjs'; +import { v4 } from 'uuid'; + +import { Logger } from 'kibana/server'; +import { elasticsearchServiceMock } from 'src/core/server/mocks'; + +import type { RuleDataClient } from '../../../../../../rule_registry/server'; +import { PluginSetupContract as AlertingPluginSetupContract } from '../../../../../../alerting/server'; +import { ConfigType } from '../../../../config'; + +export const createRuleTypeMocks = () => { + /* eslint-disable @typescript-eslint/no-explicit-any */ + let alertExecutor: (...args: any[]) => Promise; + + const mockedConfig$ = of({} as ConfigType); + + const loggerMock = ({ + debug: jest.fn(), + info: jest.fn(), + warn: jest.fn(), + error: jest.fn(), + } as unknown) as Logger; + + const alerting = { + registerType: ({ executor }) => { + alertExecutor = executor; + }, + } as AlertingPluginSetupContract; + + const scheduleActions = jest.fn(); + + const services = { + scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(), + alertInstanceFactory: jest.fn(() => ({ scheduleActions })), + findAlerts: jest.fn(), // TODO: does this stay? + alertWithPersistence: jest.fn(), + logger: loggerMock, + }; + + return { + dependencies: { + alerting, + config$: mockedConfig$, + logger: loggerMock, + ruleDataClient: ({ + getReader: () => { + return { + search: jest.fn(), + }; + }, + getWriter: () => { + return { + bulk: jest.fn(), + }; + }, + } as unknown) as RuleDataClient, + }, + services, + scheduleActions, + executor: async ({ params }: { params: Record }) => { + return alertExecutor({ + services, + params, + alertId: v4(), + startedAt: new Date(), + }); + }, + }; +}; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/__mocks__/threshold.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/__mocks__/threshold.ts new file mode 100644 index 0000000000000..40d2ed37a5576 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/__mocks__/threshold.ts @@ -0,0 +1,61 @@ +/* + * 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 { sampleDocNoSortId } from '../../signals/__mocks__/es_results'; + +export const mockThresholdResults = { + rawResponse: { + body: { + is_partial: false, + is_running: false, + took: 527, + timed_out: false, + hits: { + total: { + value: 0, + relation: 'eq', + }, + hits: [], + }, + aggregations: { + 'threshold_0:source.ip': { + buckets: [ + { + key: '127.0.0.1', + doc_count: 5, + 'threshold_1:host.name': { + buckets: [ + { + key: 'tardigrade', + doc_count: 3, + top_threshold_hits: { + hits: { + total: { + value: 1, + relation: 'eq', + }, + hits: [ + { + ...sampleDocNoSortId(), + 'host.name': 'tardigrade', + }, + ], + }, + }, + cardinality_count: { + value: 3, + }, + }, + ], + }, + }, + ], + }, + }, + }, + }, +}; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/eql.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/eql.test.ts new file mode 100644 index 0000000000000..6529c594dd5a5 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/eql.test.ts @@ -0,0 +1,92 @@ +/* + * 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. + */ + +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { elasticsearchClientMock } from 'src/core/server/elasticsearch/client/mocks'; + +import { sequenceResponse } from '../../../search_strategy/timeline/eql/__mocks__'; + +import { createEqlAlertType } from './eql'; +import { createRuleTypeMocks } from './__mocks__/rule_type'; + +describe('EQL alerts', () => { + it('does not send an alert when sequence not found', async () => { + const { services, dependencies, executor } = createRuleTypeMocks(); + const eqlAlertType = createEqlAlertType(dependencies.ruleDataClient, dependencies.logger); + + dependencies.alerting.registerType(eqlAlertType); + + const params = { + eqlQuery: 'sequence by host.name↵[any where true]↵[any where true]↵[any where true]', + indexPatterns: ['*'], + }; + + services.scopedClusterClient.asCurrentUser.transport.request.mockReturnValue( + elasticsearchClientMock.createSuccessTransportRequestPromise({ + hits: { + hits: [], + sequences: [], + events: [], + total: { + relation: 'eq', + value: 0, + }, + }, + took: 0, + timed_out: false, + _shards: { + failed: 0, + skipped: 0, + successful: 1, + total: 1, + }, + }) + ); + + await executor({ params }); + expect(services.alertInstanceFactory).not.toBeCalled(); + }); + + it('sends a properly formatted alert when sequence is found', async () => { + const { services, dependencies, executor } = createRuleTypeMocks(); + const eqlAlertType = createEqlAlertType(dependencies.ruleDataClient, dependencies.logger); + + dependencies.alerting.registerType(eqlAlertType); + + const params = { + eqlQuery: 'sequence by host.name↵[any where true]↵[any where true]↵[any where true]', + indexPatterns: ['*'], + }; + + services.scopedClusterClient.asCurrentUser.transport.request.mockReturnValue( + elasticsearchClientMock.createSuccessTransportRequestPromise({ + hits: sequenceResponse.rawResponse.body.hits, + took: 0, + timed_out: false, + _shards: { + failed: 0, + skipped: 0, + successful: 1, + total: 1, + }, + }) + ); + + await executor({ params }); + expect(services.alertInstanceFactory).toBeCalled(); + /* + expect(services.alertWithPersistence).toBeCalledWith( + expect.arrayContaining([ + expect.objectContaining({ + 'event.kind': 'signal', + 'kibana.rac.alert.building_block_type': 'default', + }), + ]) + ); + */ + }); +}); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/eql.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/eql.ts new file mode 100644 index 0000000000000..39d02c808d09e --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/eql.ts @@ -0,0 +1,121 @@ +/* + * 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 moment from 'moment'; +import v4 from 'uuid/v4'; + +import { ApiResponse } from '@elastic/elasticsearch'; +import { schema } from '@kbn/config-schema'; +import { Logger } from '@kbn/logging'; + +import { + RuleDataClient, + createPersistenceRuleTypeFactory, +} from '../../../../../rule_registry/server'; +import { EQL_ALERT_TYPE_ID } from '../../../../common/constants'; +import { buildEqlSearchRequest } from '../../../../common/detection_engine/get_query_filter'; +import { BaseSignalHit, EqlSignalSearchResponse } from '../signals/types'; + +export const createEqlAlertType = (ruleDataClient: RuleDataClient, logger: Logger) => { + const createPersistenceRuleType = createPersistenceRuleTypeFactory({ + ruleDataClient, + logger, + }); + return createPersistenceRuleType({ + id: EQL_ALERT_TYPE_ID, + name: 'EQL Rule', + validate: { + params: schema.object({ + eqlQuery: schema.string(), + indexPatterns: schema.arrayOf(schema.string()), + }), + }, + actionGroups: [ + { + id: 'default', + name: 'Default', + }, + ], + defaultActionGroupId: 'default', + actionVariables: { + context: [{ name: 'server', description: 'the server' }], + }, + minimumLicenseRequired: 'basic', + producer: 'security-solution', + async executor({ + startedAt, + services: { alertWithPersistence, findAlerts, scopedClusterClient }, + params: { indexPatterns, eqlQuery }, + }) { + const from = moment(startedAt).subtract(moment.duration(5, 'm')).toISOString(); // hardcoded 5-minute rule interval + const to = startedAt.toISOString(); + + const request = buildEqlSearchRequest( + eqlQuery, + indexPatterns, + from, + to, + 10, + undefined, + [], + undefined + ); + const { body: response } = (await scopedClusterClient.asCurrentUser.transport.request( + request + )) as ApiResponse; + + const buildSignalFromEvent = (event: BaseSignalHit) => { + return { + ...event, + 'event.kind': 'signal', + 'kibana.rac.alert.id': '???', + 'kibana.rac.alert.uuid': v4(), + '@timestamp': new Date().toISOString(), + }; + }; + + /* eslint-disable @typescript-eslint/no-explicit-any */ + let alerts: any[] = []; + if (response.hits.sequences !== undefined) { + alerts = response.hits.sequences.reduce((allAlerts: any[], sequence) => { + let previousAlertUuid: string | undefined; + return [ + ...allAlerts, + ...sequence.events.map((event, idx) => { + const alert = { + ...buildSignalFromEvent(event), + 'kibana.rac.alert.ancestors': previousAlertUuid != null ? [previousAlertUuid] : [], + 'kibana.rac.alert.building_block_type': 'default', + 'kibana.rac.alert.depth': idx, + }; + previousAlertUuid = alert['kibana.rac.alert.uuid']; + return alert; + }), + ]; + }, []); + } else if (response.hits.events !== undefined) { + alerts = response.hits.events.map((event) => { + return buildSignalFromEvent(event); + }, []); + } else { + throw new Error( + 'eql query response should have either `sequences` or `events` but had neither' + ); + } + + if (alerts.length > 0) { + alertWithPersistence(alerts).forEach((alert) => { + alert.scheduleActions('default', { server: 'server-test' }); + }); + } + + return { + lastChecked: new Date(), + }; + }, + }); +}; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/ml.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/ml.ts new file mode 100644 index 0000000000000..c07d0436cc90d --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/ml.ts @@ -0,0 +1,70 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +/* + +import { schema } from '@kbn/config-schema'; +import { KibanaRequest, Logger } from 'src/core/server'; +import { SavedObject } from 'src/core/types'; + +import { buildEsQuery, IIndexPattern } from '../../../../../../../src/plugins/data/common'; + +import { createPersistenceRuleTypeFactory } from '../../../../../rule_registry/server'; +import { ML_ALERT_TYPE_ID } from '../../../../common/constants'; +import { SecurityRuleRegistry } from '../../../plugin'; + +const createSecurityMlRuleType = createPersistenceRuleTypeFactory(); + +import { + AlertInstanceContext, + AlertInstanceState, + AlertServices, +} from '../../../../../alerting/server'; +import { ListClient } from '../../../../../lists/server'; +import { isJobStarted } from '../../../../common/machine_learning/helpers'; +import { ExceptionListItemSchema } from '../../../../common/shared_imports'; +import { SetupPlugins } from '../../../plugin'; +import { RefreshTypes } from '../types'; +import { bulkCreateMlSignals } from '../signals/bulk_create_ml_signals'; +import { filterEventsAgainstList } from '../signals/filters/filter_events_against_list'; +import { findMlSignals } from '../signals/find_ml_signals'; +import { BuildRuleMessage } from '../signals/rule_messages'; +import { RuleStatusService } from '../signals/rule_status_service'; +import { MachineLearningRuleAttributes } from '../signals/types'; +import { createErrorsFromShard, createSearchAfterReturnType, mergeReturns } from '../signals/utils'; + +export const mlAlertType = createSecurityMlRuleType({ + id: ML_ALERT_TYPE_ID, + name: 'Machine Learning Rule', + validate: { + params: schema.object({ + indexPatterns: schema.arrayOf(schema.string()), + customQuery: schema.string(), + }), + }, + actionGroups: [ + { + id: 'default', + name: 'Default', + }, + ], + defaultActionGroupId: 'default', + actionVariables: { + context: [{ name: 'server', description: 'the server' }], + }, + minimumLicenseRequired: 'basic', + producer: 'security-solution', + async executor({ + services: { alertWithPersistence, findAlerts }, + params: { indexPatterns, customQuery }, + }) { + return { + lastChecked: new Date(), + }; + }, +}); +*/ diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/query.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/query.test.ts new file mode 100644 index 0000000000000..e8c45e9ab7056 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/query.test.ts @@ -0,0 +1,99 @@ +/* + * 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 { v4 } from 'uuid'; + +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { elasticsearchClientMock } from 'src/core/server/elasticsearch/client/mocks'; + +import { sampleDocNoSortId } from '../signals/__mocks__/es_results'; + +import { createQueryAlertType } from './query'; +import { createRuleTypeMocks } from './__mocks__/rule_type'; + +describe('Custom query alerts', () => { + it('does not send an alert when no events found', async () => { + const { services, dependencies, executor } = createRuleTypeMocks(); + const queryAlertType = createQueryAlertType(dependencies.ruleDataClient, dependencies.logger); + + dependencies.alerting.registerType(queryAlertType); + + const params = { + customQuery: 'dne:42', + indexPatterns: ['*'], + }; + + services.scopedClusterClient.asCurrentUser.search.mockReturnValue( + elasticsearchClientMock.createSuccessTransportRequestPromise({ + hits: { + hits: [], + sequences: [], + events: [], + total: { + relation: 'eq', + value: 0, + }, + }, + took: 0, + timed_out: false, + _shards: { + failed: 0, + skipped: 0, + successful: 1, + total: 1, + }, + }) + ); + + await executor({ params }); + expect(services.alertInstanceFactory).not.toBeCalled(); + }); + + it('sends a properly formatted alert when events are found', async () => { + const { services, dependencies, executor } = createRuleTypeMocks(); + const queryAlertType = createQueryAlertType(dependencies.ruleDataClient, dependencies.logger); + + dependencies.alerting.registerType(queryAlertType); + + const params = { + customQuery: '*:*', + indexPatterns: ['*'], + }; + + services.scopedClusterClient.asCurrentUser.search.mockReturnValue( + elasticsearchClientMock.createSuccessTransportRequestPromise({ + hits: { + hits: [sampleDocNoSortId(v4()), sampleDocNoSortId(v4()), sampleDocNoSortId(v4())], + total: { + relation: 'eq', + value: 3, + }, + }, + took: 0, + timed_out: false, + _shards: { + failed: 0, + skipped: 0, + successful: 1, + total: 1, + }, + }) + ); + + await executor({ params }); + expect(services.alertInstanceFactory).toBeCalled(); + /* + expect(services.alertWithPersistence).toBeCalledWith( + expect.arrayContaining([ + expect.objectContaining({ + 'event.kind': 'signal', + }), + ]) + ); + */ + }); +}); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/query.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/query.ts new file mode 100644 index 0000000000000..3911dcabc34de --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/query.ts @@ -0,0 +1,88 @@ +/* + * 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 { QueryContainer } from '@elastic/elasticsearch/api/types'; +import { schema } from '@kbn/config-schema'; +import { Logger } from '@kbn/logging'; +import { ESSearchRequest } from 'typings/elasticsearch'; + +import { buildEsQuery, IIndexPattern } from '../../../../../../../src/plugins/data/common'; + +import { + RuleDataClient, + createPersistenceRuleTypeFactory, +} from '../../../../../rule_registry/server'; +import { CUSTOM_ALERT_TYPE_ID } from '../../../../common/constants'; + +export const createQueryAlertType = (ruleDataClient: RuleDataClient, logger: Logger) => { + const createPersistenceRuleType = createPersistenceRuleTypeFactory({ + ruleDataClient, + logger, + }); + return createPersistenceRuleType({ + id: CUSTOM_ALERT_TYPE_ID, + name: 'Custom Query Rule', + validate: { + params: schema.object({ + indexPatterns: schema.arrayOf(schema.string()), + customQuery: schema.string(), + }), + }, + actionGroups: [ + { + id: 'default', + name: 'Default', + }, + ], + defaultActionGroupId: 'default', + actionVariables: { + context: [{ name: 'server', description: 'the server' }], + }, + minimumLicenseRequired: 'basic', + producer: 'security-solution', + async executor({ + services: { alertWithPersistence, findAlerts }, + params: { indexPatterns, customQuery }, + }) { + try { + const indexPattern: IIndexPattern = { + fields: [], + title: indexPatterns.join(), + }; + + // TODO: kql or lucene? + + const esQuery = buildEsQuery( + indexPattern, + { query: customQuery, language: 'kuery' }, + [] + ) as QueryContainer; + const query: ESSearchRequest = { + body: { + query: esQuery, + fields: ['*'], + sort: { + '@timestamp': 'asc' as const, + }, + }, + }; + + const alerts = await findAlerts(query); + // console.log('alerts', alerts); + alertWithPersistence(alerts).forEach((alert) => { + alert.scheduleActions('default', { server: 'server-test' }); + }); + + return { + lastChecked: new Date(), + }; + } catch (error) { + logger.error(error); + } + }, + }); +}; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/scripts/create_reference_rule_eql.sh b/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/scripts/create_reference_rule_eql.sh new file mode 100755 index 0000000000000..25e247a08ef46 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/scripts/create_reference_rule_eql.sh @@ -0,0 +1,34 @@ +#!/bin/sh +# +# 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. +# + +curl -X POST http://localhost:5601/${BASE_PATH}/api/alerts/alert \ + -u ${ELASTICSEARCH_USERNAME}:${ELASTICSEARCH_PASSWORD} \ + -H 'kbn-xsrf: true' \ + -H 'Content-Type: application/json' \ + --verbose \ + -d ' +{ + "params":{ + "indexPatterns": ["*"], + "eqlQuery": "sequence by host.name↵[any where true]↵[any where true]↵[any where true]" + }, + "consumer":"alerts", + "alertTypeId":"siem.eqlRule", + "schedule":{ + "interval":"1m" + }, + "actions":[], + "tags":[ + "eql", + "persistence" + ], + "notifyWhen":"onActionGroupChange", + "name":"Basic EQL rule" +}' + + diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/scripts/create_reference_rule_query.sh b/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/scripts/create_reference_rule_query.sh new file mode 100755 index 0000000000000..c34af7dee4044 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/scripts/create_reference_rule_query.sh @@ -0,0 +1,34 @@ +#!/bin/sh +# +# 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. +# + +curl -X POST http://localhost:5601/${BASE_PATH}/api/alerts/alert \ + -u ${ELASTICSEARCH_USERNAME}:${ELASTICSEARCH_PASSWORD} \ + -H 'kbn-xsrf: true' \ + -H 'Content-Type: application/json' \ + --verbose \ + -d ' +{ + "params":{ + "indexPatterns": ["*"], + "customQuery": "*:*" + }, + "consumer":"alerts", + "alertTypeId":"siem.customRule", + "schedule":{ + "interval":"1m" + }, + "actions":[], + "tags":[ + "custom", + "persistence" + ], + "notifyWhen":"onActionGroupChange", + "name":"Basic custom query rule" +}' + + diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/scripts/create_reference_rule_threshold.sh b/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/scripts/create_reference_rule_threshold.sh new file mode 100755 index 0000000000000..8b486b165c34b --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/scripts/create_reference_rule_threshold.sh @@ -0,0 +1,37 @@ +#!/bin/sh +# +# 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. +# + +curl -X POST http://localhost:5601/${BASE_PATH}/api/alerts/alert \ + -u ${ELASTICSEARCH_USERNAME}:${ELASTICSEARCH_PASSWORD} \ + -H 'kbn-xsrf: true' \ + -H 'Content-Type: application/json' \ + --verbose \ + -d ' +{ + "params":{ + "indexPatterns": ["*"], + "customQuery": "*:*", + "thresholdFields": ["source.ip", "destination.ip"], + "thresholdValue": 50, + "thresholdCardinality": [] + }, + "consumer":"alerts", + "alertTypeId":"siem.thresholdRule", + "schedule":{ + "interval":"1m" + }, + "actions":[], + "tags":[ + "persistence", + "threshold" + ], + "notifyWhen":"onActionGroupChange", + "name":"Basic Threshold rule" +}' + + diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/threshold.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/threshold.test.ts new file mode 100644 index 0000000000000..36e53b8154e70 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/threshold.test.ts @@ -0,0 +1,132 @@ +/* + * 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. + */ + +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { elasticsearchClientMock } from 'src/core/server/elasticsearch/client/mocks'; + +import { createRuleTypeMocks } from './__mocks__/rule_type'; +import { mockThresholdResults } from './__mocks__/threshold'; +import { createThresholdAlertType } from './threshold'; + +describe('Threshold alerts', () => { + it('does not send an alert when threshold is not met', async () => { + const { services, dependencies, executor } = createRuleTypeMocks(); + const thresholdAlertType = createThresholdAlertType( + dependencies.ruleDataClient, + dependencies.logger + ); + + dependencies.alerting.registerType(thresholdAlertType); + + const params = { + indexPatterns: ['*'], + customQuery: '*:*', + thresholdFields: ['source.ip', 'host.name'], + thresholdValue: 4, + }; + + services.scopedClusterClient.asCurrentUser.search.mockReturnValue( + elasticsearchClientMock.createSuccessTransportRequestPromise({ + hits: { + hits: [], + sequences: [], + events: [], + total: { + relation: 'eq', + value: 0, + }, + }, + aggregations: { + 'threshold_0:source.ip': { + buckets: [], + }, + }, + took: 0, + timed_out: false, + _shards: { + failed: 0, + skipped: 0, + successful: 1, + total: 1, + }, + }) + ); + + await executor({ params }); + expect(services.alertInstanceFactory).not.toBeCalled(); + }); + + it('sends a properly formatted alert when threshold is met', async () => { + const { services, dependencies, executor } = createRuleTypeMocks(); + const thresholdAlertType = createThresholdAlertType( + dependencies.ruleDataClient, + dependencies.logger + ); + + dependencies.alerting.registerType(thresholdAlertType); + + const params = { + indexPatterns: ['*'], + customQuery: '*:*', + thresholdFields: ['source.ip', 'host.name'], + thresholdValue: 4, + }; + + services.scopedClusterClient.asCurrentUser.search + .mockReturnValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise({ + hits: { + hits: [], + total: { + relation: 'eq', + value: 0, + }, + }, + took: 0, + timed_out: false, + _shards: { + failed: 0, + skipped: 0, + successful: 1, + total: 1, + }, + }) + ) + .mockReturnValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise({ + hits: { + hits: [], + total: { + relation: 'eq', + value: 0, + }, + }, + aggregations: mockThresholdResults.rawResponse.body.aggregations, + took: 0, + timed_out: false, + _shards: { + failed: 0, + skipped: 0, + successful: 1, + total: 1, + }, + }) + ); + + await executor({ params }); + expect(services.alertInstanceFactory).toBeCalled(); + /* + expect(services.alertWithPersistence).toBeCalledWith( + expect.arrayContaining([ + expect.objectContaining({ + 'event.kind': 'signal', + }), + ]) + ); + */ + }); +}); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/threshold.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/threshold.ts new file mode 100644 index 0000000000000..d4721e8bab11d --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/reference_rules/threshold.ts @@ -0,0 +1,206 @@ +/* + * 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 moment from 'moment'; +import v4 from 'uuid/v4'; + +import { schema } from '@kbn/config-schema'; +import { Logger } from '@kbn/logging'; + +import { AlertServices } from '../../../../../alerting/server'; +import { + RuleDataClient, + createPersistenceRuleTypeFactory, +} from '../../../../../rule_registry/server'; +import { THRESHOLD_ALERT_TYPE_ID } from '../../../../common/constants'; +import { SignalSearchResponse, ThresholdSignalHistory } from '../signals/types'; +import { + findThresholdSignals, + getThresholdBucketFilters, + getThresholdSignalHistory, + transformThresholdResultsToEcs, +} from '../signals/threshold'; +import { getFilter } from '../signals/get_filter'; +import { BuildRuleMessage } from '../signals/rule_messages'; + +interface RuleParams { + indexPatterns: string[]; + customQuery: string; + thresholdFields: string[]; + thresholdValue: number; + thresholdCardinality: Array<{ + field: string; + value: number; + }>; +} + +interface BulkCreateThresholdSignalParams { + results: SignalSearchResponse; + ruleParams: RuleParams; + services: AlertServices & { logger: Logger }; + inputIndexPattern: string[]; + ruleId: string; + startedAt: Date; + from: Date; + thresholdSignalHistory: ThresholdSignalHistory; + buildRuleMessage: BuildRuleMessage; +} + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +const formatThresholdSignals = (params: BulkCreateThresholdSignalParams): any[] => { + const thresholdResults = params.results; + const threshold = { + field: params.ruleParams.thresholdFields, + value: params.ruleParams.thresholdValue, + }; + const results = transformThresholdResultsToEcs( + thresholdResults, + params.ruleParams.indexPatterns.join(','), + params.startedAt, + params.from, + undefined, + params.services.logger, + threshold, + params.ruleId, + undefined, + params.thresholdSignalHistory + ); + return results.hits.hits.map((hit) => { + return { + ...hit, + 'event.kind': 'signal', + 'kibana.rac.alert.id': '???', + 'kibana.rac.alert.uuid': v4(), + '@timestamp': new Date().toISOString(), + }; + }); +}; + +export const createThresholdAlertType = (ruleDataClient: RuleDataClient, logger: Logger) => { + const createPersistenceRuleType = createPersistenceRuleTypeFactory({ + ruleDataClient, + logger, + }); + return createPersistenceRuleType({ + id: THRESHOLD_ALERT_TYPE_ID, + name: 'Threshold Rule', + validate: { + params: schema.object({ + indexPatterns: schema.arrayOf(schema.string()), + customQuery: schema.string(), + thresholdFields: schema.arrayOf(schema.string()), + thresholdValue: schema.number(), + thresholdCardinality: schema.arrayOf( + schema.object({ + field: schema.string(), + value: schema.number(), + }) + ), + }), + }, + actionGroups: [ + { + id: 'default', + name: 'Default', + }, + ], + defaultActionGroupId: 'default', + actionVariables: { + context: [{ name: 'server', description: 'the server' }], + }, + minimumLicenseRequired: 'basic', + producer: 'security-solution', + async executor({ startedAt, services, params, alertId }) { + const fromDate = moment(startedAt).subtract(moment.duration(5, 'm')); // hardcoded 5-minute rule interval + const from = fromDate.toISOString(); + const to = startedAt.toISOString(); + + // TODO: how to get the output index? + const outputIndex = ['.kibana-madi-8-alerts-security-solution-8.0.0-000001']; + const buildRuleMessage = (...messages: string[]) => messages.join(); + const timestampOverride = undefined; + + const { + thresholdSignalHistory, + searchErrors: previousSearchErrors, + } = await getThresholdSignalHistory({ + indexPattern: outputIndex, + from, + to, + services: (services as unknown) as AlertServices, + logger, + ruleId: alertId, + bucketByFields: params.thresholdFields, + timestampOverride, + buildRuleMessage, + }); + + const bucketFilters = await getThresholdBucketFilters({ + thresholdSignalHistory, + timestampOverride, + }); + + const esFilter = await getFilter({ + type: 'threshold', + filters: bucketFilters, + language: 'kuery', + query: params.customQuery, + savedId: undefined, + services: (services as unknown) as AlertServices, + index: params.indexPatterns, + lists: [], + }); + + const { + searchResult: thresholdResults, + searchErrors, + searchDuration: thresholdSearchDuration, + } = await findThresholdSignals({ + inputIndexPattern: params.indexPatterns, + from, + to, + services: (services as unknown) as AlertServices, + logger, + filter: esFilter, + threshold: { + field: params.thresholdFields, + value: params.thresholdValue, + cardinality: params.thresholdCardinality, + }, + timestampOverride, + buildRuleMessage, + }); + + logger.info(`Threshold search took ${thresholdSearchDuration}ms`); // TODO: rule status service + + const alerts = formatThresholdSignals({ + results: thresholdResults, + ruleParams: params, + services: (services as unknown) as AlertServices & { logger: Logger }, + inputIndexPattern: ['TODO'], + ruleId: alertId, + startedAt, + from: fromDate.toDate(), + thresholdSignalHistory, + buildRuleMessage, + }); + + const errors = searchErrors.concat(previousSearchErrors); + if (errors.length === 0) { + services.alertWithPersistence(alerts).forEach((alert) => { + alert.scheduleActions('default', { server: 'server-test' }); + }); + } else { + throw new Error(errors.join('\n')); + } + + return { + lastChecked: new Date(), + }; + }, + }); +}; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/index/read_index_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/index/read_index_route.ts index 6af4397a4193a..3527e43c03d52 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/index/read_index_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/index/read_index_route.ts @@ -6,15 +6,17 @@ */ import { transformError, getIndexExists } from '@kbn/securitysolution-es-utils'; +import { parseExperimentalConfigValue } from '../../../../../common/experimental_features'; +import { ConfigType } from '../../../../config'; import type { SecuritySolutionPluginRouter } from '../../../../types'; -import { DETECTION_ENGINE_INDEX_URL } from '../../../../../common/constants'; +import { DEFAULT_ALERTS_INDEX, DETECTION_ENGINE_INDEX_URL } from '../../../../../common/constants'; import { buildSiemResponse } from '../utils'; import { SIGNALS_TEMPLATE_VERSION } from './get_signals_template'; import { getIndexVersion } from './get_index_version'; import { isOutdated } from '../../migrations/helpers'; -export const readIndexRoute = (router: SecuritySolutionPluginRouter) => { +export const readIndexRoute = (router: SecuritySolutionPluginRouter, config: ConfigType) => { router.get( { path: DETECTION_ENGINE_INDEX_URL, @@ -34,8 +36,16 @@ export const readIndexRoute = (router: SecuritySolutionPluginRouter) => { return siemResponse.error({ statusCode: 404 }); } + // TODO: Once we are past experimental phase this code should be removed + const { ruleRegistryEnabled } = parseExperimentalConfigValue(config.enableExperimental); + if (ruleRegistryEnabled) { + return response.ok({ + body: { name: DEFAULT_ALERTS_INDEX, index_mapping_outdated: false }, + }); + } + const index = siemClient.getSignalsIndex(); - const indexExists = await getIndexExists(esClient, index); + const indexExists = ruleRegistryEnabled ? true : await getIndexExists(esClient, index); if (indexExists) { let mappingOutdated: boolean | null = null; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rules_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rules_route.ts index 9b7e7bb42f423..993d9300e414f 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rules_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rules_route.ts @@ -6,6 +6,7 @@ */ import { transformError, getIndexExists } from '@kbn/securitysolution-es-utils'; +import { RuleDataClient } from '../../../../../../rule_registry/server'; import { buildRouteValidation } from '../../../../utils/build_validation/route_validation'; import { DETECTION_ENGINE_RULES_URL } from '../../../../../common/constants'; import { SetupPlugins } from '../../../../plugin'; @@ -24,7 +25,8 @@ import { convertCreateAPIToInternalSchema } from '../../schemas/rule_converters' export const createRulesRoute = ( router: SecuritySolutionPluginRouter, - ml: SetupPlugins['ml'] + ml: SetupPlugins['ml'], + ruleDataClient?: RuleDataClient | null ): void => { router.post( { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/delete_rules_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/delete_rules_route.ts index 76fb9ac0c77e3..4b05f603b85b7 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/delete_rules_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/delete_rules_route.ts @@ -6,6 +6,7 @@ */ import { transformError } from '@kbn/securitysolution-es-utils'; +import { RuleDataClient } from '../../../../../../rule_registry/server'; import { queryRuleValidateTypeDependents } from '../../../../../common/detection_engine/schemas/request/query_rules_type_dependents'; import { queryRulesSchema, @@ -22,7 +23,10 @@ import { deleteNotifications } from '../../notifications/delete_notifications'; import { deleteRuleActionsSavedObject } from '../../rule_actions/delete_rule_actions_saved_object'; import { ruleStatusSavedObjectsClientFactory } from '../../signals/rule_status_saved_objects_client'; -export const deleteRulesRoute = (router: SecuritySolutionPluginRouter) => { +export const deleteRulesRoute = ( + router: SecuritySolutionPluginRouter, + ruleDataClient?: RuleDataClient | null +) => { router.delete( { path: DETECTION_ENGINE_RULES_URL, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/find_rules_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/find_rules_route.ts index 347d005c58a4a..428978fe1d820 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/find_rules_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/find_rules_route.ts @@ -6,6 +6,7 @@ */ import { transformError } from '@kbn/securitysolution-es-utils'; +import { RuleDataClient } from '../../../../../../rule_registry/server'; import { findRuleValidateTypeDependents } from '../../../../../common/detection_engine/schemas/request/find_rules_type_dependents'; import { findRulesSchema, @@ -20,7 +21,10 @@ import { buildRouteValidation } from '../../../../utils/build_validation/route_v import { transformFindAlerts } from './utils'; import { getBulkRuleActionsSavedObject } from '../../rule_actions/get_bulk_rule_actions_saved_object'; -export const findRulesRoute = (router: SecuritySolutionPluginRouter) => { +export const findRulesRoute = ( + router: SecuritySolutionPluginRouter, + ruleDataClient?: RuleDataClient | null +) => { router.get( { path: `${DETECTION_ENGINE_RULES_URL}/_find`, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/patch_rules_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/patch_rules_route.ts index 780c248183ab9..eaaa44fcf1916 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/patch_rules_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/patch_rules_route.ts @@ -6,6 +6,7 @@ */ import { transformError } from '@kbn/securitysolution-es-utils'; +import { RuleDataClient } from '../../../../../../rule_registry/server'; import { RuleAlertAction } from '../../../../../common/detection_engine/types'; import { patchRuleValidateTypeDependents } from '../../../../../common/detection_engine/schemas/request/patch_rules_type_dependents'; import { buildRouteValidation } from '../../../../utils/build_validation/route_validation'; @@ -28,7 +29,11 @@ import { ruleStatusSavedObjectsClientFactory } from '../../signals/rule_status_s import { readRules } from '../../rules/read_rules'; import { PartialFilter } from '../../types'; -export const patchRulesRoute = (router: SecuritySolutionPluginRouter, ml: SetupPlugins['ml']) => { +export const patchRulesRoute = ( + router: SecuritySolutionPluginRouter, + ml: SetupPlugins['ml'], + ruleDataClient?: RuleDataClient | null +) => { router.patch( { path: DETECTION_ENGINE_RULES_URL, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/read_rules_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/read_rules_route.ts index ac45e5d2ed3b2..917da6c9708d5 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/read_rules_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/read_rules_route.ts @@ -6,6 +6,7 @@ */ import { transformError } from '@kbn/securitysolution-es-utils'; +import { RuleDataClient } from '../../../../../../rule_registry/server'; import { queryRuleValidateTypeDependents } from '../../../../../common/detection_engine/schemas/request/query_rules_type_dependents'; import { queryRulesSchema, @@ -21,7 +22,10 @@ import { readRules } from '../../rules/read_rules'; import { getRuleActionsSavedObject } from '../../rule_actions/get_rule_actions_saved_object'; import { ruleStatusSavedObjectsClientFactory } from '../../signals/rule_status_saved_objects_client'; -export const readRulesRoute = (router: SecuritySolutionPluginRouter) => { +export const readRulesRoute = ( + router: SecuritySolutionPluginRouter, + ruleDataClient?: RuleDataClient | null +) => { router.get( { path: DETECTION_ENGINE_RULES_URL, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_route.ts index aad0068758f7d..0ff6cb3cd2d0f 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_route.ts @@ -6,6 +6,7 @@ */ import { transformError } from '@kbn/securitysolution-es-utils'; +import { RuleDataClient } from '../../../../../../rule_registry/server'; import { updateRulesSchema } from '../../../../../common/detection_engine/schemas/request'; import { updateRuleValidateTypeDependents } from '../../../../../common/detection_engine/schemas/request/update_rules_type_dependents'; import type { SecuritySolutionPluginRouter } from '../../../../types'; @@ -22,7 +23,11 @@ import { updateRulesNotifications } from '../../rules/update_rules_notifications import { ruleStatusSavedObjectsClientFactory } from '../../signals/rule_status_saved_objects_client'; import { buildRouteValidation } from '../../../../utils/build_validation/route_validation'; -export const updateRulesRoute = (router: SecuritySolutionPluginRouter, ml: SetupPlugins['ml']) => { +export const updateRulesRoute = ( + router: SecuritySolutionPluginRouter, + ml: SetupPlugins['ml'], + ruleDataClient?: RuleDataClient | null +) => { router.put( { path: DETECTION_ENGINE_RULES_URL, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/query_signals_route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/query_signals_route.test.ts index 909c94f145528..d6b998e314234 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/query_signals_route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/query_signals_route.test.ts @@ -14,7 +14,7 @@ import { getSignalsAggsAndQueryRequest, getEmptySignalsResponse, } from '../__mocks__/request_responses'; -import { requestContextMock, serverMock, requestMock } from '../__mocks__'; +import { requestContextMock, serverMock, requestMock, createMockConfig } from '../__mocks__'; import { querySignalsRoute } from './query_signals_route'; describe('query for signal', () => { @@ -27,7 +27,7 @@ describe('query for signal', () => { clients.clusterClient.callAsCurrentUser.mockResolvedValue(getEmptySignalsResponse()); - querySignalsRoute(server.router); + querySignalsRoute(server.router, createMockConfig()); }); describe('query and agg on signals index', () => { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/query_signals_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/query_signals_route.ts index 91172a277bf54..770c1a5da344f 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/query_signals_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/query_signals_route.ts @@ -6,8 +6,13 @@ */ import { transformError } from '@kbn/securitysolution-es-utils'; +import { parseExperimentalConfigValue } from '../../../../../common/experimental_features'; +import { ConfigType } from '../../../../config'; import type { SecuritySolutionPluginRouter } from '../../../../types'; -import { DETECTION_ENGINE_QUERY_SIGNALS_URL } from '../../../../../common/constants'; +import { + DEFAULT_ALERTS_INDEX, + DETECTION_ENGINE_QUERY_SIGNALS_URL, +} from '../../../../../common/constants'; import { buildSiemResponse } from '../utils'; import { buildRouteValidation } from '../../../../utils/build_validation/route_validation'; @@ -16,7 +21,7 @@ import { QuerySignalsSchemaDecoded, } from '../../../../../common/detection_engine/schemas/request/query_signals_index_schema'; -export const querySignalsRoute = (router: SecuritySolutionPluginRouter) => { +export const querySignalsRoute = (router: SecuritySolutionPluginRouter, config: ConfigType) => { router.post( { path: DETECTION_ENGINE_QUERY_SIGNALS_URL, @@ -48,9 +53,12 @@ export const querySignalsRoute = (router: SecuritySolutionPluginRouter) => { const clusterClient = context.core.elasticsearch.legacy.client; const siemClient = context.securitySolution!.getAppClient(); + // TODO: Once we are past experimental phase this code should be removed + const { ruleRegistryEnabled } = parseExperimentalConfigValue(config.enableExperimental); + try { const result = await clusterClient.callAsCurrentUser('search', { - index: siemClient.getSignalsIndex(), + index: ruleRegistryEnabled ? DEFAULT_ALERTS_INDEX : siemClient.getSignalsIndex(), body: { query, aggs, _source, track_total_hits, size }, ignoreUnavailable: true, }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threshold/find_threshold_signals.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threshold/find_threshold_signals.ts index 986393d6d3454..ca7f22e4a7570 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threshold/find_threshold_signals.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threshold/find_threshold_signals.ts @@ -138,7 +138,7 @@ export const findThresholdSignals = async ({ logger, // @ts-expect-error refactor to pass type explicitly instead of unknown filter, - pageSize: 1, + pageSize: 0, sortOrder: 'desc', buildRuleMessage, }); diff --git a/x-pack/plugins/security_solution/server/plugin.ts b/x-pack/plugins/security_solution/server/plugin.ts index aa37a0dc1f627..2507475592e88 100644 --- a/x-pack/plugins/security_solution/server/plugin.ts +++ b/x-pack/plugins/security_solution/server/plugin.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { once } from 'lodash'; import { Observable } from 'rxjs'; import { i18n } from '@kbn/i18n'; import LRU from 'lru-cache'; @@ -27,8 +28,18 @@ import { PluginSetupContract as AlertingSetup, PluginStartContract as AlertPluginStartContract, } from '../../alerting/server'; + import { PluginStartContract as CasesPluginStartContract } from '../../cases/server'; +import { + ECS_COMPONENT_TEMPLATE_NAME, + TECHNICAL_COMPONENT_TEMPLATE_NAME, +} from '../../rule_registry/common/assets'; import { SecurityPluginSetup as SecuritySetup, SecurityPluginStart } from '../../security/server'; +import { + RuleDataClient, + RuleRegistryPluginSetupContract, + RuleRegistryPluginStartContract, +} from '../../rule_registry/server'; import { PluginSetupContract as FeaturesSetup } from '../../features/server'; import { MlPluginSetup as MlSetup } from '../../ml/server'; import { ListPluginSetup } from '../../lists/server'; @@ -38,6 +49,9 @@ import { ILicense, LicensingPluginStart } from '../../licensing/server'; import { FleetStartContract } from '../../fleet/server'; import { TaskManagerSetupContract, TaskManagerStartContract } from '../../task_manager/server'; import { compose } from './lib/compose/kibana'; +import { createQueryAlertType } from './lib/detection_engine/reference_rules/query'; +import { createEqlAlertType } from './lib/detection_engine/reference_rules/eql'; +import { createThresholdAlertType } from './lib/detection_engine/reference_rules/threshold'; import { initRoutes } from './routes'; import { isAlertExecutor } from './lib/detection_engine/signals/types'; import { signalRulesAlertType } from './lib/detection_engine/signals/signal_rule_alert_type'; @@ -54,6 +68,8 @@ import { SecurityPageName, SIGNALS_ID, NOTIFICATIONS_ID, + REFERENCE_RULE_ALERT_TYPE_ID, + REFERENCE_RULE_PERSISTENCE_ALERT_TYPE_ID, } from '../common/constants'; import { registerEndpointRoutes } from './endpoint/routes/metadata'; import { registerLimitedConcurrencyRoutes } from './endpoint/routes/limited_concurrency'; @@ -87,6 +103,7 @@ export interface SetupPlugins { features: FeaturesSetup; lists?: ListPluginSetup; ml?: MlSetup; + ruleRegistry: RuleRegistryPluginSetupContract; security?: SecuritySetup; spaces?: SpacesSetup; taskManager?: TaskManagerSetupContract; @@ -99,6 +116,7 @@ export interface StartPlugins { data: DataPluginStart; fleet?: FleetStartContract; licensing: LicensingPluginStart; + ruleRegistry: RuleRegistryPluginStartContract; taskManager?: TaskManagerStartContract; telemetry?: TelemetryPluginStart; security: SecurityPluginStart; @@ -135,6 +153,7 @@ export class Plugin implements IPlugin, plugins: SetupPlugins) { this.logger.debug('plugin setup'); + this.setupPlugins = plugins; const config = this.config; const globalConfig = this.context.config.legacy.get(); @@ -195,13 +215,75 @@ export class Plugin implements IPlugin core.getStartServices().then(([coreStart]) => coreStart); + + const ready = once(async () => { + const componentTemplateName = ruleDataService.getFullAssetName( + 'security-solution-mappings' + ); + + if (!ruleDataService.isWriteEnabled()) { + return; + } + + await ruleDataService.createOrUpdateComponentTemplate({ + name: componentTemplateName, + body: { + template: { + settings: { + number_of_shards: 1, + }, + mappings: {}, // TODO: Add mappings here via `mappingFromFieldMap()` + }, + }, + }); + + await ruleDataService.createOrUpdateIndexTemplate({ + name: ruleDataService.getFullAssetName('security-solution-index-template'), + body: { + index_patterns: [ruleDataService.getFullAssetName('security-solution*')], + composed_of: [ + ruleDataService.getFullAssetName(TECHNICAL_COMPONENT_TEMPLATE_NAME), + ruleDataService.getFullAssetName(ECS_COMPONENT_TEMPLATE_NAME), + componentTemplateName, + ], + }, + }); + }); + + ready().catch((err) => { + this.logger!.error(err); + }); + + ruleDataClient = new RuleDataClient({ + alias: plugins.ruleRegistry.ruleDataService.getFullAssetName('security-solution'), + getClusterClient: async () => { + const coreStart = await start(); + return coreStart.elasticsearch.client.asInternalUser; + }, + ready, + }); + + // Register reference rule types via rule-registry + this.setupPlugins.alerting.registerType(createQueryAlertType(ruleDataClient, this.logger)); + this.setupPlugins.alerting.registerType(createEqlAlertType(ruleDataClient, this.logger)); + this.setupPlugins.alerting.registerType( + createThresholdAlertType(ruleDataClient, this.logger) + ); + } + // TO DO We need to get the endpoint routes inside of initRoutes initRoutes( router, config, plugins.encryptedSavedObjects?.canEncrypt === true, plugins.security, - plugins.ml + plugins.ml, + ruleDataClient ); registerEndpointRoutes(router, endpointContext); registerLimitedConcurrencyRoutes(core); @@ -210,6 +292,16 @@ export class Plugin implements IPlugin { // Detection Engine Rule routes that have the REST endpoints of /api/detection_engine/rules // All REST rule creation, deletion, updating, etc...... - createRulesRoute(router, ml); - readRulesRoute(router); - updateRulesRoute(router, ml); - patchRulesRoute(router, ml); - deleteRulesRoute(router); - findRulesRoute(router); + createRulesRoute(router, ml, ruleDataClient); + readRulesRoute(router, ruleDataClient); + updateRulesRoute(router, ml, ruleDataClient); + patchRulesRoute(router, ml, ruleDataClient); + deleteRulesRoute(router, ruleDataClient); + findRulesRoute(router, ruleDataClient); + + // TODO: pass ruleDataClient to all relevant routes addPrepackedRulesRoute(router, config, security); getPrepackagedRulesStatusRoute(router, config, security); @@ -102,7 +107,7 @@ export const initRoutes = ( // POST /api/detection_engine/signals/status // Example usage can be found in security_solution/server/lib/detection_engine/scripts/signals setSignalsStatusRoute(router); - querySignalsRoute(router); + querySignalsRoute(router, config); getSignalsMigrationStatusRoute(router); createSignalsMigrationRoute(router, security); finalizeSignalsMigrationRoute(router, security); @@ -111,7 +116,7 @@ export const initRoutes = ( // Detection Engine index routes that have the REST endpoints of /api/detection_engine/index // All REST index creation, policy management for spaces createIndexRoute(router); - readIndexRoute(router); + readIndexRoute(router, config); deleteIndexRoute(router); // Detection Engine tags routes that have the REST endpoints of /api/detection_engine/tags diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/details/index.test.tsx b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/details/index.test.tsx index e43db6b86f8b9..f489fd0c16455 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/details/index.test.tsx +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/details/index.test.tsx @@ -33,6 +33,7 @@ const mockDeps = { trustedAppsByPolicyEnabled: false, metricsEntitiesEnabled: false, hostIsolationEnabled: false, + ruleRegistryEnabled: false, }, service: {} as EndpointAppContextService, } as EndpointAppContext,

    m>hB`#qD;};-wi=~~S!bOZWUZi1 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

    5!$`=<+I1Nf$N1a{(j6Hxe4o61H&rtsu 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�# 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