From 963fe0c1d1ceaea53666e039dbe0863dde2c5c12 Mon Sep 17 00:00:00 2001 From: Nicolas Chaulet Date: Thu, 1 Oct 2020 13:09:02 -0400 Subject: [PATCH 01/50] [Ingest Manager] Ensure we trigger agent policy updated event when we bump revision. (#78836) --- .../server/services/agent_policy.ts | 18 +++++++-- .../apis/settings/update.ts | 40 +++++++++++++++++++ 2 files changed, 55 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/ingest_manager/server/services/agent_policy.ts b/x-pack/plugins/ingest_manager/server/services/agent_policy.ts index 29821a530098c..12ea8ab92f6c4 100644 --- a/x-pack/plugins/ingest_manager/server/services/agent_policy.ts +++ b/x-pack/plugins/ingest_manager/server/services/agent_policy.ts @@ -33,7 +33,7 @@ const SAVED_OBJECT_TYPE = AGENT_POLICY_SAVED_OBJECT_TYPE; class AgentPolicyService { private triggerAgentPolicyUpdatedEvent = async ( soClient: SavedObjectsClientContract, - action: string, + action: 'created' | 'updated' | 'deleted', agentPolicyId: string ) => { return agentPolicyUpdateEventHandler(soClient, action, agentPolicyId); @@ -258,7 +258,11 @@ class AgentPolicyService { id: string, options?: { user?: AuthenticatedUser } ): Promise { - return this._update(soClient, id, {}, options?.user); + const res = await this._update(soClient, id, {}, options?.user); + + await this.triggerAgentPolicyUpdatedEvent(soClient, 'updated', id); + + return res; } public async bumpAllAgentPolicies( soClient: SavedObjectsClientContract, @@ -277,7 +281,15 @@ class AgentPolicyService { }; return policy; }); - return soClient.bulkUpdate(bumpedPolicies); + const res = await soClient.bulkUpdate(bumpedPolicies); + + await Promise.all( + currentPolicies.saved_objects.map((policy) => + this.triggerAgentPolicyUpdatedEvent(soClient, 'updated', policy.id) + ) + ); + + return res; } public async assignPackagePolicies( diff --git a/x-pack/test/ingest_manager_api_integration/apis/settings/update.ts b/x-pack/test/ingest_manager_api_integration/apis/settings/update.ts index 86292b535db2d..4340cd4832307 100644 --- a/x-pack/test/ingest_manager_api_integration/apis/settings/update.ts +++ b/x-pack/test/ingest_manager_api_integration/apis/settings/update.ts @@ -5,16 +5,20 @@ */ import expect from '@kbn/expect'; +import { Client } from 'elasticsearch'; import { FtrProviderContext } from '../../../api_integration/ftr_provider_context'; import { skipIfNoDockerRegistry } from '../../helpers'; +import { setupIngest } from '../fleet/agents/services'; export default function (providerContext: FtrProviderContext) { const { getService } = providerContext; const supertest = getService('supertest'); const kibanaServer = getService('kibanaServer'); + const esClient: Client = getService('legacyEs'); describe('Settings - update', async function () { skipIfNoDockerRegistry(providerContext); + setupIngest(providerContext); it("should bump all agent policy's revision", async function () { const { body: testPolicy1PostRes } = await supertest @@ -49,5 +53,41 @@ export default function (providerContext: FtrProviderContext) { expect(getTestPolicy1Res.attributes.revision).equal(2); expect(getTestPolicy2Res.attributes.revision).equal(2); }); + + it('should create agent actions', async function () { + const { body: testPolicyRes } = await supertest + .post(`/api/ingest_manager/agent_policies`) + .set('kbn-xsrf', 'xxxx') + .send({ + name: 'test', + description: '', + namespace: 'default', + }); + + await supertest + .put(`/api/ingest_manager/settings`) + .set('kbn-xsrf', 'xxxx') + .send({ kibana_urls: ['http://localhost:1232/abc', 'http://localhost:1232/abc'] }); + + const res = await esClient.search({ + index: '.kibana', + body: { + query: { + bool: { + must: [ + { + terms: { + type: ['fleet-agent-actions'], + }, + }, + { match: { 'fleet-agent-actions.policy_id': testPolicyRes.item.id } }, + ], + }, + }, + }, + }); + + expect(res.hits.hits.length).equal(2); + }); }); } From 574205dc72b63a3c30ff159684012d8e3191ef2d Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Thu, 1 Oct 2020 18:14:59 +0100 Subject: [PATCH 02/50] chore(NA): remove non existing plugin paths from case api integration tests (#79127) * chore(NA): remove non existing plugin paths from case api integration tests config * chore(NA): remove unused import --- x-pack/test/case_api_integration/common/config.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/x-pack/test/case_api_integration/common/config.ts b/x-pack/test/case_api_integration/common/config.ts index 5d34f8b04981a..72d1bc4ec9a37 100644 --- a/x-pack/test/case_api_integration/common/config.ts +++ b/x-pack/test/case_api_integration/common/config.ts @@ -4,8 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -import path from 'path'; - import { CA_CERT_PATH } from '@kbn/dev-utils'; import { FtrConfigProviderContext } from '@kbn/test/types/ftr'; @@ -78,8 +76,6 @@ export function createTestConfig(name: string, options: CreateTestConfigOptions) `--xpack.actions.enabledActionTypes=${JSON.stringify(enabledActionTypes)}`, '--xpack.eventLog.logEntries=true', ...disabledPlugins.map((key) => `--xpack.${key}.enabled=false`), - `--plugin-path=${path.join(__dirname, 'fixtures', 'plugins', 'alerts')}`, - `--plugin-path=${path.join(__dirname, 'fixtures', 'plugins', 'actions')}`, ...(ssl ? [ `--elasticsearch.hosts=${servers.elasticsearch.protocol}://${servers.elasticsearch.hostname}:${servers.elasticsearch.port}`, From fd7dd41617a7464e6b0e61a83800c05ccf6a5189 Mon Sep 17 00:00:00 2001 From: Quynh Nguyen <43350163+qn895@users.noreply.github.com> Date: Thu, 1 Oct 2020 12:41:12 -0500 Subject: [PATCH 03/50] [ML] Update transform cloning to include description and new fields (#78364) --- .../public/app/common/request.test.ts | 33 +++++++++++++ .../transform/public/app/common/request.ts | 22 ++++++--- .../step_details/step_details_form.tsx | 18 +++++++ .../step_details/step_details_summary.tsx | 2 + .../test/functional/apps/transform/cloning.ts | 15 +++++- .../functional/services/transform/wizard.ts | 47 +++++++++++++++++++ 6 files changed, 129 insertions(+), 8 deletions(-) diff --git a/x-pack/plugins/transform/public/app/common/request.test.ts b/x-pack/plugins/transform/public/app/common/request.test.ts index 913ea8964eaf0..46ace2c3315a5 100644 --- a/x-pack/plugins/transform/public/app/common/request.test.ts +++ b/x-pack/plugins/transform/public/app/common/request.test.ts @@ -17,6 +17,7 @@ import { defaultQuery, getPreviewTransformRequestBody, getCreateTransformRequestBody, + getCreateTransformSettingsRequestBody, getPivotQuery, isDefaultQuery, isMatchAllQuery, @@ -159,6 +160,7 @@ describe('Transform: Common', () => { transformDescription: 'the-transform-description', transformFrequency: '1m', transformSettingsMaxPageSearchSize: 100, + transformSettingsDocsPerSecond: 400, destinationIndex: 'the-destination-index', touched: true, valid: true, @@ -180,6 +182,7 @@ describe('Transform: Common', () => { }, settings: { max_page_search_size: 100, + docs_per_second: 400, }, source: { index: ['the-index-pattern-title'], @@ -187,4 +190,34 @@ describe('Transform: Common', () => { }, }); }); + + test('getCreateTransformSettingsRequestBody() with multiple settings', () => { + const transformDetailsState: Partial = { + transformSettingsDocsPerSecond: 400, + transformSettingsMaxPageSearchSize: 100, + }; + + const request = getCreateTransformSettingsRequestBody(transformDetailsState); + + expect(request).toEqual({ + settings: { + docs_per_second: 400, + max_page_search_size: 100, + }, + }); + }); + + test('getCreateTransformSettingsRequestBody() with one setting', () => { + const transformDetailsState: Partial = { + transformSettingsDocsPerSecond: 400, + }; + + const request = getCreateTransformSettingsRequestBody(transformDetailsState); + + expect(request).toEqual({ + settings: { + docs_per_second: 400, + }, + }); + }); }); diff --git a/x-pack/plugins/transform/public/app/common/request.ts b/x-pack/plugins/transform/public/app/common/request.ts index 45160d125309d..8ee235baf7c5a 100644 --- a/x-pack/plugins/transform/public/app/common/request.ts +++ b/x-pack/plugins/transform/public/app/common/request.ts @@ -130,6 +130,20 @@ export function getPreviewTransformRequestBody( return request; } +export const getCreateTransformSettingsRequestBody = ( + transformDetailsState: Partial +): { settings?: PutTransformsRequestSchema['settings'] } => { + const settings: PutTransformsRequestSchema['settings'] = { + ...(transformDetailsState.transformSettingsMaxPageSearchSize + ? { max_page_search_size: transformDetailsState.transformSettingsMaxPageSearchSize } + : {}), + ...(transformDetailsState.transformSettingsDocsPerSecond + ? { docs_per_second: transformDetailsState.transformSettingsDocsPerSecond } + : {}), + }; + return Object.keys(settings).length > 0 ? { settings } : {}; +}; + export const getCreateTransformRequestBody = ( indexPatternTitle: IndexPattern['title'], pivotState: StepDefineExposedState, @@ -164,13 +178,7 @@ export const getCreateTransformRequestBody = ( } : {}), // conditionally add additional settings - ...(transformDetailsState.transformSettingsMaxPageSearchSize - ? { - settings: { - max_page_search_size: transformDetailsState.transformSettingsMaxPageSearchSize, - }, - } - : {}), + ...getCreateTransformSettingsRequestBody(transformDetailsState), }); export function isHttpFetchError(error: any): error is HttpFetchError { diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_form.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_form.tsx index 00ab516f625fe..9b43879512e4d 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_form.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_form.tsx @@ -63,6 +63,7 @@ export interface StepDetailsExposedState { transformDescription: string; transformFrequency: string; transformSettingsMaxPageSearchSize: number; + transformSettingsDocsPerSecond?: number; valid: boolean; indexPatternTimeField?: string | undefined; } @@ -100,6 +101,20 @@ export function applyTransformConfigToDetailsState( state.continuousModeDelay = time?.delay ?? defaultContinuousModeDelay; state.isContinuousModeEnabled = true; } + if (transformConfig.description !== undefined) { + state.transformDescription = transformConfig.description; + } + if (transformConfig.frequency !== undefined) { + state.transformFrequency = transformConfig.frequency; + } + if (transformConfig.settings) { + if (typeof transformConfig.settings?.max_page_search_size === 'number') { + state.transformSettingsMaxPageSearchSize = transformConfig.settings.max_page_search_size; + } + if (typeof transformConfig.settings?.docs_per_second === 'number') { + state.transformSettingsDocsPerSecond = transformConfig.settings.docs_per_second; + } + } } return state; } @@ -275,6 +290,8 @@ export const StepDetailsForm: FC = React.memo( const [transformSettingsMaxPageSearchSize, setTransformSettingsMaxPageSearchSize] = useState( defaults.transformSettingsMaxPageSearchSize ); + const [transformSettingsDocsPerSecond] = useState(defaults.transformSettingsDocsPerSecond); + const isTransformSettingsMaxPageSearchSizeValid = transformSettingsMaxPageSearchSizeValidator( transformSettingsMaxPageSearchSize ); @@ -301,6 +318,7 @@ export const StepDetailsForm: FC = React.memo( transformDescription, transformFrequency, transformSettingsMaxPageSearchSize, + transformSettingsDocsPerSecond, destinationIndex, touched: true, valid, diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_summary.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_summary.tsx index 45cd8aa465522..f5444eaf6640a 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_summary.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_summary.tsx @@ -98,6 +98,7 @@ export const StepDetailsSummary: FC = React.memo((props paddingSize="s" > = React.memo((props {transformFrequency} Date: Thu, 1 Oct 2020 12:42:37 -0500 Subject: [PATCH 04/50] Revert "[Metrics UI] Add ability to override datafeeds and job config for partition field (#78875)" This reverts commit ee7672aaf074dc4ebaf0ffb88d95d5f1bf9e1d18. --- .../containers/ml/infra_ml_module_types.ts | 4 +- .../containers/ml/infra_ml_setup_state.ts | 289 ++++++++++++++++++ .../metrics_hosts/module_descriptor.ts | 135 +++----- .../modules/metrics_k8s/module_descriptor.ts | 143 +++------ .../anomoly_detection_flyout.tsx | 4 +- .../ml/anomaly_detection/flyout_home.tsx | 113 ++++--- .../ml/anomaly_detection/job_setup_screen.tsx | 3 +- 7 files changed, 444 insertions(+), 247 deletions(-) create mode 100644 x-pack/plugins/infra/public/containers/ml/infra_ml_setup_state.ts diff --git a/x-pack/plugins/infra/public/containers/ml/infra_ml_module_types.ts b/x-pack/plugins/infra/public/containers/ml/infra_ml_module_types.ts index e36f38add641a..a9f2671de8259 100644 --- a/x-pack/plugins/infra/public/containers/ml/infra_ml_module_types.ts +++ b/x-pack/plugins/infra/public/containers/ml/infra_ml_module_types.ts @@ -33,11 +33,11 @@ export interface ModuleDescriptor { partitionField?: string ) => Promise; cleanUpModule: (spaceId: string, sourceId: string) => Promise; - validateSetupIndices?: ( + validateSetupIndices: ( indices: string[], timestampField: string ) => Promise; - validateSetupDatasets?: ( + validateSetupDatasets: ( indices: string[], timestampField: string, startTime: number, diff --git a/x-pack/plugins/infra/public/containers/ml/infra_ml_setup_state.ts b/x-pack/plugins/infra/public/containers/ml/infra_ml_setup_state.ts new file mode 100644 index 0000000000000..0dfe3b301f240 --- /dev/null +++ b/x-pack/plugins/infra/public/containers/ml/infra_ml_setup_state.ts @@ -0,0 +1,289 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { isEqual } from 'lodash'; +import { useCallback, useEffect, useMemo, useState } from 'react'; +import { usePrevious } from 'react-use'; +import { + combineDatasetFilters, + DatasetFilter, + filterDatasetFilter, + isExampleDataIndex, +} from '../../../common/infra_ml'; +import { + AvailableIndex, + ValidationIndicesError, + ValidationUIError, +} from '../../components/logging/log_analysis_setup/initial_configuration_step'; +import { useTrackedPromise } from '../../utils/use_tracked_promise'; +import { ModuleDescriptor, ModuleSourceConfiguration } from './infra_ml_module_types'; + +type SetupHandler = ( + indices: string[], + startTime: number | undefined, + endTime: number | undefined, + datasetFilter: DatasetFilter +) => void; + +interface AnalysisSetupStateArguments { + cleanUpAndSetUpModule: SetupHandler; + moduleDescriptor: ModuleDescriptor; + setUpModule: SetupHandler; + sourceConfiguration: ModuleSourceConfiguration; +} + +const fourWeeksInMs = 86400000 * 7 * 4; + +export const useAnalysisSetupState = ({ + cleanUpAndSetUpModule, + moduleDescriptor: { validateSetupDatasets, validateSetupIndices }, + setUpModule, + sourceConfiguration, +}: AnalysisSetupStateArguments) => { + const [startTime, setStartTime] = useState(Date.now() - fourWeeksInMs); + const [endTime, setEndTime] = useState(undefined); + + const isTimeRangeValid = useMemo( + () => (startTime != null && endTime != null ? startTime < endTime : true), + [endTime, startTime] + ); + + const [validatedIndices, setValidatedIndices] = useState( + sourceConfiguration.indices.map((indexName) => ({ + name: indexName, + validity: 'unknown' as const, + })) + ); + + const updateIndicesWithValidationErrors = useCallback( + (validationErrors: ValidationIndicesError[]) => + setValidatedIndices((availableIndices) => + availableIndices.map((previousAvailableIndex) => { + const indexValiationErrors = validationErrors.filter( + ({ index }) => index === previousAvailableIndex.name + ); + + if (indexValiationErrors.length > 0) { + return { + validity: 'invalid', + name: previousAvailableIndex.name, + errors: indexValiationErrors, + }; + } else if (previousAvailableIndex.validity === 'valid') { + return { + ...previousAvailableIndex, + validity: 'valid', + errors: [], + }; + } else { + return { + validity: 'valid', + name: previousAvailableIndex.name, + isSelected: !isExampleDataIndex(previousAvailableIndex.name), + availableDatasets: [], + datasetFilter: { + type: 'includeAll' as const, + }, + }; + } + }) + ), + [] + ); + + const updateIndicesWithAvailableDatasets = useCallback( + (availableDatasets: Array<{ indexName: string; datasets: string[] }>) => + setValidatedIndices((availableIndices) => + availableIndices.map((previousAvailableIndex) => { + if (previousAvailableIndex.validity !== 'valid') { + return previousAvailableIndex; + } + + const availableDatasetsForIndex = availableDatasets.filter( + ({ indexName }) => indexName === previousAvailableIndex.name + ); + const newAvailableDatasets = availableDatasetsForIndex.flatMap( + ({ datasets }) => datasets + ); + + // filter out datasets that have disappeared if this index' datasets were updated + const newDatasetFilter: DatasetFilter = + availableDatasetsForIndex.length > 0 + ? filterDatasetFilter(previousAvailableIndex.datasetFilter, (dataset) => + newAvailableDatasets.includes(dataset) + ) + : previousAvailableIndex.datasetFilter; + + return { + ...previousAvailableIndex, + availableDatasets: newAvailableDatasets, + datasetFilter: newDatasetFilter, + }; + }) + ), + [] + ); + + const validIndexNames = useMemo( + () => validatedIndices.filter((index) => index.validity === 'valid').map((index) => index.name), + [validatedIndices] + ); + + const selectedIndexNames = useMemo( + () => + validatedIndices + .filter((index) => index.validity === 'valid' && index.isSelected) + .map((i) => i.name), + [validatedIndices] + ); + + const datasetFilter = useMemo( + () => + validatedIndices + .flatMap((validatedIndex) => + validatedIndex.validity === 'valid' + ? validatedIndex.datasetFilter + : { type: 'includeAll' as const } + ) + .reduce(combineDatasetFilters, { type: 'includeAll' as const }), + [validatedIndices] + ); + + const [validateIndicesRequest, validateIndices] = useTrackedPromise( + { + cancelPreviousOn: 'resolution', + createPromise: async () => { + return await validateSetupIndices( + sourceConfiguration.indices, + sourceConfiguration.timestampField + ); + }, + onResolve: ({ data: { errors } }) => { + updateIndicesWithValidationErrors(errors); + }, + onReject: () => { + setValidatedIndices([]); + }, + }, + [sourceConfiguration.indices, sourceConfiguration.timestampField] + ); + + const [validateDatasetsRequest, validateDatasets] = useTrackedPromise( + { + cancelPreviousOn: 'resolution', + createPromise: async () => { + if (validIndexNames.length === 0) { + return { data: { datasets: [] } }; + } + + return await validateSetupDatasets( + validIndexNames, + sourceConfiguration.timestampField, + startTime ?? 0, + endTime ?? Date.now() + ); + }, + onResolve: ({ data: { datasets } }) => { + updateIndicesWithAvailableDatasets(datasets); + }, + }, + [validIndexNames, sourceConfiguration.timestampField, startTime, endTime] + ); + + const setUp = useCallback(() => { + return setUpModule(selectedIndexNames, startTime, endTime, datasetFilter); + }, [setUpModule, selectedIndexNames, startTime, endTime, datasetFilter]); + + const cleanUpAndSetUp = useCallback(() => { + return cleanUpAndSetUpModule(selectedIndexNames, startTime, endTime, datasetFilter); + }, [cleanUpAndSetUpModule, selectedIndexNames, startTime, endTime, datasetFilter]); + + const isValidating = useMemo( + () => validateIndicesRequest.state === 'pending' || validateDatasetsRequest.state === 'pending', + [validateDatasetsRequest.state, validateIndicesRequest.state] + ); + + const validationErrors = useMemo(() => { + if (isValidating) { + return []; + } + + return [ + // validate request status + ...(validateIndicesRequest.state === 'rejected' || + validateDatasetsRequest.state === 'rejected' + ? [{ error: 'NETWORK_ERROR' as const }] + : []), + // validation request results + ...validatedIndices.reduce((errors, index) => { + return index.validity === 'invalid' && selectedIndexNames.includes(index.name) + ? [...errors, ...index.errors] + : errors; + }, []), + // index count + ...(selectedIndexNames.length === 0 ? [{ error: 'TOO_FEW_SELECTED_INDICES' as const }] : []), + // time range + ...(!isTimeRangeValid ? [{ error: 'INVALID_TIME_RANGE' as const }] : []), + ]; + }, [ + isValidating, + validateIndicesRequest.state, + validateDatasetsRequest.state, + validatedIndices, + selectedIndexNames, + isTimeRangeValid, + ]); + + const prevStartTime = usePrevious(startTime); + const prevEndTime = usePrevious(endTime); + const prevValidIndexNames = usePrevious(validIndexNames); + + useEffect(() => { + if (!isTimeRangeValid) { + return; + } + + validateIndices(); + }, [isTimeRangeValid, validateIndices]); + + useEffect(() => { + if (!isTimeRangeValid) { + return; + } + + if ( + startTime !== prevStartTime || + endTime !== prevEndTime || + !isEqual(validIndexNames, prevValidIndexNames) + ) { + validateDatasets(); + } + }, [ + endTime, + isTimeRangeValid, + prevEndTime, + prevStartTime, + prevValidIndexNames, + startTime, + validIndexNames, + validateDatasets, + ]); + + return { + cleanUpAndSetUp, + datasetFilter, + endTime, + isValidating, + selectedIndexNames, + setEndTime, + setStartTime, + setUp, + startTime, + validatedIndices, + setValidatedIndices, + validationErrors, + }; +}; diff --git a/x-pack/plugins/infra/public/containers/ml/modules/metrics_hosts/module_descriptor.ts b/x-pack/plugins/infra/public/containers/ml/modules/metrics_hosts/module_descriptor.ts index 711ee76d42a64..cec87fb1144e3 100644 --- a/x-pack/plugins/infra/public/containers/ml/modules/metrics_hosts/module_descriptor.ts +++ b/x-pack/plugins/infra/public/containers/ml/modules/metrics_hosts/module_descriptor.ts @@ -10,27 +10,17 @@ import { cleanUpJobsAndDatafeeds } from '../../infra_ml_cleanup'; import { callJobsSummaryAPI } from '../../api/ml_get_jobs_summary_api'; import { callGetMlModuleAPI } from '../../api/ml_get_module'; import { callSetupMlModuleAPI } from '../../api/ml_setup_module_api'; +import { callValidateIndicesAPI } from '../../../logs/log_analysis/api/validate_indices'; +import { callValidateDatasetsAPI } from '../../../logs/log_analysis/api/validate_datasets'; import { metricsHostsJobTypes, getJobId, MetricsHostsJobType, DatasetFilter, bucketSpan, + partitionField, } from '../../../../../common/infra_ml'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import MemoryJob from '../../../../../../ml/server/models/data_recognizer/modules/metrics_ui_hosts/ml/hosts_memory_usage.json'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import MemoryDatafeed from '../../../../../../ml/server/models/data_recognizer/modules/metrics_ui_hosts/ml/datafeed_hosts_memory_usage.json'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import NetworkInJob from '../../../../../../ml/server/models/data_recognizer/modules/metrics_ui_hosts/ml/hosts_network_in.json'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import NetworkInDatafeed from '../../../../../../ml/server/models/data_recognizer/modules/metrics_ui_hosts/ml/datafeed_hosts_network_in.json'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import NetworkOutJob from '../../../../../../ml/server/models/data_recognizer/modules/metrics_ui_hosts/ml/hosts_network_out.json'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import NetworkOutDatafeed from '../../../../../../ml/server/models/data_recognizer/modules/metrics_ui_hosts/ml/datafeed_hosts_network_out.json'; -type JobType = 'hosts_memory_usage' | 'hosts_network_in' | 'hosts_network_out'; const moduleId = 'metrics_ui_hosts'; const moduleName = i18n.translate('xpack.infra.ml.metricsModuleName', { defaultMessage: 'Metrics anomanly detection', @@ -64,68 +54,23 @@ const setUpModule = async ( end: number | undefined, datasetFilter: DatasetFilter, { spaceId, sourceId, indices, timestampField }: ModuleSourceConfiguration, - partitionField?: string + pField?: string ) => { const indexNamePattern = indices.join(','); - const jobIds: JobType[] = ['hosts_memory_usage', 'hosts_network_in', 'hosts_network_out']; - - const jobOverrides = jobIds.map((id) => { - const { job: defaultJobConfig } = getDefaultJobConfigs(id); - - // eslint-disable-next-line @typescript-eslint/naming-convention - const analysis_config = { - ...defaultJobConfig.analysis_config, - }; - - if (partitionField) { - analysis_config.detectors[0].partition_field_name = partitionField; - if (analysis_config.influencers.indexOf(partitionField) === -1) { - analysis_config.influencers.push(partitionField); - } - } - - return { - job_id: id, - data_description: { - time_field: timestampField, - }, - analysis_config, - custom_settings: { - metrics_source_config: { - indexPattern: indexNamePattern, - timestampField, - bucketSpan, - }, - }, - }; - }); - - const datafeedOverrides = jobIds.map((id) => { - const { datafeed: defaultDatafeedConfig } = getDefaultJobConfigs(id); - - if (!partitionField || id === 'hosts_memory_usage') { - // Since the host memory usage doesn't have custom aggs, we don't need to do anything to add a partition field - return defaultDatafeedConfig; - } - - // If we have a partition field, we need to change the aggregation to do a terms agg at the top level - const aggregations = { - [partitionField]: { - terms: { - field: partitionField, - }, - aggregations: { - ...defaultDatafeedConfig.aggregations, - }, + const jobIds = ['hosts_memory_usage', 'hosts_network_in', 'hosts_network_out']; + const jobOverrides = jobIds.map((id) => ({ + job_id: id, + data_description: { + time_field: timestampField, + }, + custom_settings: { + metrics_source_config: { + indexPattern: indexNamePattern, + timestampField, + bucketSpan, }, - }; - - return { - ...defaultDatafeedConfig, - job_id: id, - aggregations, - }; - }); + }, + })); return callSetupMlModuleAPI( moduleId, @@ -135,34 +80,36 @@ const setUpModule = async ( sourceId, indexNamePattern, jobOverrides, - datafeedOverrides + [] ); }; -const getDefaultJobConfigs = (jobId: JobType) => { - switch (jobId) { - case 'hosts_memory_usage': - return { - datafeed: MemoryDatafeed, - job: MemoryJob, - }; - case 'hosts_network_in': - return { - datafeed: NetworkInDatafeed, - job: NetworkInJob, - }; - case 'hosts_network_out': - return { - datafeed: NetworkOutDatafeed, - job: NetworkOutJob, - }; - } -}; - const cleanUpModule = async (spaceId: string, sourceId: string) => { return await cleanUpJobsAndDatafeeds(spaceId, sourceId, metricsHostsJobTypes); }; +const validateSetupIndices = async (indices: string[], timestampField: string) => { + return await callValidateIndicesAPI(indices, [ + { + name: timestampField, + validTypes: ['date'], + }, + { + name: partitionField, + validTypes: ['keyword'], + }, + ]); +}; + +const validateSetupDatasets = async ( + indices: string[], + timestampField: string, + startTime: number, + endTime: number +) => { + return await callValidateDatasetsAPI(indices, timestampField, startTime, endTime); +}; + export const metricHostsModule: ModuleDescriptor = { moduleId, moduleName, @@ -174,4 +121,6 @@ export const metricHostsModule: ModuleDescriptor = { getModuleDefinition, setUpModule, cleanUpModule, + validateSetupDatasets, + validateSetupIndices, }; diff --git a/x-pack/plugins/infra/public/containers/ml/modules/metrics_k8s/module_descriptor.ts b/x-pack/plugins/infra/public/containers/ml/modules/metrics_k8s/module_descriptor.ts index 41c6df92fb379..cbcff1c307af6 100644 --- a/x-pack/plugins/infra/public/containers/ml/modules/metrics_k8s/module_descriptor.ts +++ b/x-pack/plugins/infra/public/containers/ml/modules/metrics_k8s/module_descriptor.ts @@ -10,28 +10,17 @@ import { cleanUpJobsAndDatafeeds } from '../../infra_ml_cleanup'; import { callJobsSummaryAPI } from '../../api/ml_get_jobs_summary_api'; import { callGetMlModuleAPI } from '../../api/ml_get_module'; import { callSetupMlModuleAPI } from '../../api/ml_setup_module_api'; +import { callValidateIndicesAPI } from '../../../logs/log_analysis/api/validate_indices'; +import { callValidateDatasetsAPI } from '../../../logs/log_analysis/api/validate_datasets'; import { metricsK8SJobTypes, getJobId, MetricK8sJobType, DatasetFilter, bucketSpan, + partitionField, } from '../../../../../common/infra_ml'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import MemoryJob from '../../../../../../ml/server/models/data_recognizer/modules/metrics_ui_k8s/ml/k8s_memory_usage.json'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import MemoryDatafeed from '../../../../../../ml/server/models/data_recognizer/modules/metrics_ui_k8s/ml/datafeed_k8s_memory_usage.json'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import NetworkInJob from '../../../../../../ml/server/models/data_recognizer/modules/metrics_ui_k8s/ml/k8s_network_in.json'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import NetworkInDatafeed from '../../../../../../ml/server/models/data_recognizer/modules/metrics_ui_k8s/ml/datafeed_k8s_network_in.json'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import NetworkOutJob from '../../../../../../ml/server/models/data_recognizer/modules/metrics_ui_k8s/ml/k8s_network_out.json'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import NetworkOutDatafeed from '../../../../../../ml/server/models/data_recognizer/modules/metrics_ui_k8s/ml/datafeed_k8s_network_out.json'; -type JobType = 'k8s_memory_usage' | 'k8s_network_in' | 'k8s_network_out'; -export const DEFAULT_K8S_PARTITION_FIELD = 'kubernetes.namespace'; const moduleId = 'metrics_ui_k8s'; const moduleName = i18n.translate('xpack.infra.ml.metricsModuleName', { defaultMessage: 'Metrics anomanly detection', @@ -65,72 +54,26 @@ const setUpModule = async ( end: number | undefined, datasetFilter: DatasetFilter, { spaceId, sourceId, indices, timestampField }: ModuleSourceConfiguration, - partitionField?: string + pField?: string ) => { const indexNamePattern = indices.join(','); - const jobIds: JobType[] = ['k8s_memory_usage', 'k8s_network_in', 'k8s_network_out']; - const jobOverrides = jobIds.map((id) => { - const { job: defaultJobConfig } = getDefaultJobConfigs(id); - - // eslint-disable-next-line @typescript-eslint/naming-convention - const analysis_config = { - ...defaultJobConfig.analysis_config, - }; - - if (partitionField) { - analysis_config.detectors[0].partition_field_name = partitionField; - if (analysis_config.influencers.indexOf(partitionField) === -1) { - analysis_config.influencers.push(partitionField); - } - } - - return { - job_id: id, - data_description: { - time_field: timestampField, - }, - analysis_config, - custom_settings: { - metrics_source_config: { - indexPattern: indexNamePattern, - timestampField, - bucketSpan, - }, - }, - }; - }); - - const datafeedOverrides = jobIds.map((id) => { - const { datafeed: defaultDatafeedConfig } = getDefaultJobConfigs(id); - - if (!partitionField || id === 'k8s_memory_usage') { - // Since the host memory usage doesn't have custom aggs, we don't need to do anything to add a partition field - return defaultDatafeedConfig; - } - - // Because the ML K8s jobs ship with a default partition field of {kubernetes.namespace}, ignore that agg and wrap it in our own agg. - const innerAggregation = - defaultDatafeedConfig.aggregations[DEFAULT_K8S_PARTITION_FIELD].aggregations; - - // If we have a partition field, we need to change the aggregation to do a terms agg to partition the data at the top level - const aggregations = { - [partitionField]: { - terms: { - field: partitionField, - size: 25, // 25 is arbitratry and only used to keep the number of buckets to a managable level in the event that the user choose a high cardinality partition field. - }, - aggregations: { - ...innerAggregation, - }, + const jobIds = ['k8s_memory_usage', 'k8s_network_in', 'k8s_network_out']; + const jobOverrides = jobIds.map((id) => ({ + job_id: id, + analysis_config: { + bucket_span: `${bucketSpan}ms`, + }, + data_description: { + time_field: timestampField, + }, + custom_settings: { + metrics_source_config: { + indexPattern: indexNamePattern, + timestampField, + bucketSpan, }, - }; - - return { - ...defaultDatafeedConfig, - job_id: id, - aggregations, - }; - }); + }, + })); return callSetupMlModuleAPI( moduleId, @@ -140,34 +83,36 @@ const setUpModule = async ( sourceId, indexNamePattern, jobOverrides, - datafeedOverrides + [] ); }; -const getDefaultJobConfigs = (jobId: JobType) => { - switch (jobId) { - case 'k8s_memory_usage': - return { - datafeed: MemoryDatafeed, - job: MemoryJob, - }; - case 'k8s_network_in': - return { - datafeed: NetworkInDatafeed, - job: NetworkInJob, - }; - case 'k8s_network_out': - return { - datafeed: NetworkOutDatafeed, - job: NetworkOutJob, - }; - } -}; - const cleanUpModule = async (spaceId: string, sourceId: string) => { return await cleanUpJobsAndDatafeeds(spaceId, sourceId, metricsK8SJobTypes); }; +const validateSetupIndices = async (indices: string[], timestampField: string) => { + return await callValidateIndicesAPI(indices, [ + { + name: timestampField, + validTypes: ['date'], + }, + { + name: partitionField, + validTypes: ['keyword'], + }, + ]); +}; + +const validateSetupDatasets = async ( + indices: string[], + timestampField: string, + startTime: number, + endTime: number +) => { + return await callValidateDatasetsAPI(indices, timestampField, startTime, endTime); +}; + export const metricHostsModule: ModuleDescriptor = { moduleId, moduleName, @@ -179,4 +124,6 @@ export const metricHostsModule: ModuleDescriptor = { getModuleDefinition, setUpModule, cleanUpModule, + validateSetupDatasets, + validateSetupIndices, }; diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/ml/anomaly_detection/anomoly_detection_flyout.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/ml/anomaly_detection/anomoly_detection_flyout.tsx index b5d224910e819..b063713fa2c97 100644 --- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/ml/anomaly_detection/anomoly_detection_flyout.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/ml/anomaly_detection/anomoly_detection_flyout.tsx @@ -50,10 +50,10 @@ export const AnomalyDetectionFlyout = () => { return ( <> - + {showFlyout && ( diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/ml/anomaly_detection/flyout_home.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/ml/anomaly_detection/flyout_home.tsx index 5b520084ebb74..801dff9c4a17a 100644 --- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/ml/anomaly_detection/flyout_home.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/ml/anomaly_detection/flyout_home.tsx @@ -5,7 +5,7 @@ */ import React, { useState, useCallback, useEffect } from 'react'; -import { EuiFlyoutHeader, EuiTitle, EuiFlyoutBody, EuiSpacer } from '@elastic/eui'; +import { EuiFlyoutHeader, EuiTitle, EuiFlyoutBody, EuiTabs, EuiTab, EuiSpacer } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import { EuiText, EuiFlexGroup, EuiFlexItem, EuiCard, EuiIcon } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; @@ -30,7 +30,7 @@ interface Props { } export const FlyoutHome = (props: Props) => { - const [tab] = useState<'jobs' | 'anomalies'>('jobs'); + const [tab, setTab] = useState<'jobs' | 'anomalies'>('jobs'); const { goToSetup } = props; const { fetchJobStatus: fetchHostJobStatus, @@ -56,10 +56,18 @@ export const FlyoutHome = (props: Props) => { goToSetup('kubernetes'); }, [goToSetup]); + const goToJobs = useCallback(() => { + setTab('jobs'); + }, []); + const jobIds = [ ...(k8sJobSummaries || []).map((k) => k.id), ...(hostJobSummaries || []).map((h) => h.id), ]; + const anomaliesUrl = useLinkProps({ + app: 'ml', + pathname: `/explorer?_g=${createResultsUrl(jobIds)}`, + }); useEffect(() => { if (hasInfraMLReadCapabilities) { @@ -97,24 +105,30 @@ export const FlyoutHome = (props: Props) => { -
- -

- -

-
-
- + + + + + + + + {hostJobSummaries.length > 0 && ( <> 0} hasK8sJobs={k8sJobSummaries.length > 0} - jobIds={jobIds} /> @@ -137,7 +151,6 @@ export const FlyoutHome = (props: Props) => { interface CalloutProps { hasHostJobs: boolean; hasK8sJobs: boolean; - jobIds: string[]; } const JobsEnabledCallout = (props: CalloutProps) => { let target = ''; @@ -162,34 +175,8 @@ const JobsEnabledCallout = (props: CalloutProps) => { pathname: '/jobs', }); - const anomaliesUrl = useLinkProps({ - app: 'ml', - pathname: `/explorer?_g=${createResultsUrl(props.jobIds)}`, - }); - return ( <> - - - - - - - - - - - - - - - { } iconType="check" /> + + + + ); }; @@ -217,11 +211,30 @@ interface CreateJobTab { const CreateJobTab = (props: CreateJobTab) => { return ( <> - {/* */} +
+ +

+ +

+
+ +

+ +

+
+
+ + } // title="Hosts" title={ @@ -232,7 +245,7 @@ const CreateJobTab = (props: CreateJobTab) => { } description={ } @@ -241,7 +254,7 @@ const CreateJobTab = (props: CreateJobTab) => { {props.hasHostJobs && ( @@ -249,7 +262,7 @@ const CreateJobTab = (props: CreateJobTab) => { {!props.hasHostJobs && ( @@ -260,7 +273,7 @@ const CreateJobTab = (props: CreateJobTab) => { } title={ { } description={ } @@ -279,7 +292,7 @@ const CreateJobTab = (props: CreateJobTab) => { {props.hasK8sJobs && ( @@ -287,7 +300,7 @@ const CreateJobTab = (props: CreateJobTab) => { {!props.hasK8sJobs && ( diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/ml/anomaly_detection/job_setup_screen.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/ml/anomaly_detection/job_setup_screen.tsx index c327d187f6bc2..428c002da6383 100644 --- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/ml/anomaly_detection/job_setup_screen.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/ml/anomaly_detection/job_setup_screen.tsx @@ -20,7 +20,6 @@ import { useSourceViaHttp } from '../../../../../../containers/source/use_source import { useMetricK8sModuleContext } from '../../../../../../containers/ml/modules/metrics_k8s/module'; import { useMetricHostsModuleContext } from '../../../../../../containers/ml/modules/metrics_hosts/module'; import { FixedDatePicker } from '../../../../../../components/fixed_datepicker'; -import { DEFAULT_K8S_PARTITION_FIELD } from '../../../../../../containers/ml/modules/metrics_k8s/module_descriptor'; interface Props { jobType: 'hosts' | 'kubernetes'; @@ -108,7 +107,7 @@ export const JobSetupScreen = (props: Props) => { useEffect(() => { if (props.jobType === 'kubernetes') { - setPartitionField([DEFAULT_K8S_PARTITION_FIELD]); + setPartitionField(['kubernetes.namespace']); } }, [props.jobType]); From 6d8f74a128973eb6e29a85921086f1975eb958d5 Mon Sep 17 00:00:00 2001 From: Jen Huang Date: Thu, 1 Oct 2020 10:57:19 -0700 Subject: [PATCH 05/50] [Ingest Manager] Match package spec `dataset`->`data_stream` and `config_templates`->`policy_templates` renaming (#78699) * Match elastic/package-spec#24 `datasets`->`data_streams` property renaming * Match elastic/package-spec#24 `datasets.name`->`data_streams.dataset` property renaming * Match elastic/package-spec#24 `/dataset`->`/data_stream` directory renaming * Match elastic/package-spec#50 `config_templates`->`policy_templates` property renaming * Update API integration test fixtures (test packages) * Temporarily skip API integration tests * Temporarily skip more API integration tests * Pin to custom docker image, unskip test suites, clean up broken icon paths in test package manifests * Skip the only (yay!) failing test suite * Revert "Skip the only (yay!) failing test suite" This reverts commit 3db32e2528f16e3a659939d4d2168b26e5f931d3. * Re-skip tests and revert docker image Co-authored-by: Elastic Machine --- .../common/openapi/spec_oas3.json | 6 +- .../common/services/limited_package.ts | 2 +- .../package_to_package_policy.test.ts | 48 ++++++------ .../services/package_to_package_policy.ts | 16 ++-- .../ingest_manager/common/types/models/epm.ts | 14 ++-- x-pack/plugins/ingest_manager/dev_docs/epm.md | 4 +- .../dev_docs/indexing_strategy.md | 30 ++++---- .../services/validate_package_policy.test..ts | 24 +++--- .../services/validate_package_policy.ts | 20 ++--- .../step_configure_package.tsx | 16 ++-- .../ingest_manager/types/index.ts | 2 +- .../services/epm/elasticsearch/index.test.ts | 10 +-- .../services/epm/elasticsearch/index.ts | 8 +- .../ingest_pipeline/ingest_pipelines.test.ts | 16 ++-- .../elasticsearch/ingest_pipeline/install.ts | 44 +++++------ .../epm/elasticsearch/template/install.ts | 71 +++++++++--------- .../epm/elasticsearch/template/template.ts | 24 +++--- .../elasticsearch/transform/transform.test.ts | 18 ++--- .../epm/kibana/index_pattern/install.ts | 30 ++++---- .../services/epm/packages/assets.test.ts | 16 ++-- .../server/services/epm/packages/assets.ts | 6 +- .../server/services/epm/packages/install.ts | 4 +- .../services/epm/registry/index.test.ts | 4 +- .../server/services/epm/registry/index.ts | 8 +- .../server/services/package_policy.test.ts | 20 ++--- .../server/services/package_policy.ts | 14 ++-- .../ingest_manager/server/types/index.tsx | 2 +- .../apache_0.1.4.tar.gz | Bin 581243 -> 579555 bytes .../elasticsearch/ilm_policy/all_assets.json | 0 .../elasticsearch/ingest_pipeline/default.yml | 0 .../ingest_pipeline/pipeline1.yml | 0 .../ingest_pipeline/pipeline2.yml | 0 .../test_logs/fields/ecs.yml | 0 .../test_logs/fields/fields.yml | 0 .../0.1.0/data_stream/test_logs}/manifest.yml | 0 .../test_metrics/fields/ecs.yml | 0 .../test_metrics/fields/fields.yml | 0 .../test_metrics/manifest.yml | 0 .../elasticsearch/ilm_policy/all_assets.json | 0 .../elasticsearch/ingest_pipeline/default.yml | 0 .../ingest_pipeline/pipeline1.yml | 0 .../test_logs/fields/ecs.yml | 0 .../test_logs/fields/fields.yml | 0 .../test_logs/manifest.yml | 0 .../test_logs2/fields/ecs.yml | 0 .../test_logs2/fields/fields.yml | 0 .../test_logs2/manifest.yml | 0 .../test_metrics/fields/ecs.yml | 0 .../test_metrics/fields/fields.yml | 0 .../test_metrics/manifest.yml | 0 .../elasticsearch/ilm_policy/all_assets.json | 0 .../elasticsearch/ingest_pipeline/default.yml | 0 .../test_logs/fields/ecs.yml | 0 .../test_logs/fields/fields.yml | 0 .../0.1.0/data_stream}/test_logs/manifest.yml | 0 .../test_metrics/fields/ecs.yml | 0 .../test_metrics/fields/fields.yml | 0 .../test_metrics/manifest.yml | 0 .../datastreams/0.1.0/manifest.yml | 7 +- .../elasticsearch/ilm_policy/all_assets.json | 0 .../elasticsearch/ingest_pipeline/default.yml | 0 .../test_logs/fields/ecs.yml | 0 .../test_logs/fields/fields.yml | 0 .../test_logs/manifest.yml | 0 .../test_metrics/fields/ecs.yml | 0 .../test_metrics/fields/fields.yml | 0 .../test_metrics/manifest.yml | 0 .../datastreams/0.2.0/manifest.yml | 5 -- .../test/fields/fields.yml | 0 .../data_stream}/test/manifest.yml | 0 .../multiple_versions/0.1.0/manifest.yml | 9 +-- .../test/fields/fields.yml | 0 .../data_stream}/test/manifest.yml | 0 .../multiple_versions/0.2.0/manifest.yml | 9 +-- .../test/fields/fields.yml | 0 .../0.3.0/data_stream}/test/manifest.yml | 0 .../multiple_versions/0.3.0/manifest.yml | 7 +- .../test/fields/fields.yml | 0 .../0.1.0/data_stream/test}/manifest.yml | 2 +- .../test/fields/fields.yml | 0 .../test/manifest.yml | 0 .../apis/index.js | 2 +- .../apps/endpoint/index.ts | 2 +- .../apis/index.ts | 2 +- 84 files changed, 254 insertions(+), 268 deletions(-) rename x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.1.0/{dataset => data_stream}/test_logs/elasticsearch/ilm_policy/all_assets.json (100%) rename x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.1.0/{dataset => data_stream}/test_logs/elasticsearch/ingest_pipeline/default.yml (100%) rename x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.1.0/{dataset => data_stream}/test_logs/elasticsearch/ingest_pipeline/pipeline1.yml (100%) rename x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.1.0/{dataset => data_stream}/test_logs/elasticsearch/ingest_pipeline/pipeline2.yml (100%) rename x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.1.0/{dataset => data_stream}/test_logs/fields/ecs.yml (100%) rename x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.1.0/{dataset => data_stream}/test_logs/fields/fields.yml (100%) rename x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/{multiple_versions/0.1.0/dataset/test => all_assets/0.1.0/data_stream/test_logs}/manifest.yml (100%) rename x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.1.0/{dataset => data_stream}/test_metrics/fields/ecs.yml (100%) rename x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.1.0/{dataset => data_stream}/test_metrics/fields/fields.yml (100%) rename x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.1.0/{dataset => data_stream}/test_metrics/manifest.yml (100%) rename x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.2.0/{dataset => data_stream}/test_logs/elasticsearch/ilm_policy/all_assets.json (100%) rename x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.2.0/{dataset => data_stream}/test_logs/elasticsearch/ingest_pipeline/default.yml (100%) rename x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.2.0/{dataset => data_stream}/test_logs/elasticsearch/ingest_pipeline/pipeline1.yml (100%) rename x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.2.0/{dataset => data_stream}/test_logs/fields/ecs.yml (100%) rename x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.2.0/{dataset => data_stream}/test_logs/fields/fields.yml (100%) rename x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.2.0/{dataset => data_stream}/test_logs/manifest.yml (100%) rename x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.2.0/{dataset => data_stream}/test_logs2/fields/ecs.yml (100%) rename x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.2.0/{dataset => data_stream}/test_logs2/fields/fields.yml (100%) rename x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.2.0/{dataset => data_stream}/test_logs2/manifest.yml (100%) rename x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.2.0/{dataset => data_stream}/test_metrics/fields/ecs.yml (100%) rename x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.2.0/{dataset => data_stream}/test_metrics/fields/fields.yml (100%) rename x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.2.0/{dataset => data_stream}/test_metrics/manifest.yml (100%) rename x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.1.0/{dataset => data_stream}/test_logs/elasticsearch/ilm_policy/all_assets.json (100%) rename x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.1.0/{dataset => data_stream}/test_logs/elasticsearch/ingest_pipeline/default.yml (100%) rename x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.1.0/{dataset => data_stream}/test_logs/fields/ecs.yml (100%) rename x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.1.0/{dataset => data_stream}/test_logs/fields/fields.yml (100%) rename x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/{all_assets/0.1.0/dataset => datastreams/0.1.0/data_stream}/test_logs/manifest.yml (100%) rename x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.1.0/{dataset => data_stream}/test_metrics/fields/ecs.yml (100%) rename x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.1.0/{dataset => data_stream}/test_metrics/fields/fields.yml (100%) rename x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.1.0/{dataset => data_stream}/test_metrics/manifest.yml (100%) rename x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.2.0/{dataset => data_stream}/test_logs/elasticsearch/ilm_policy/all_assets.json (100%) rename x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.2.0/{dataset => data_stream}/test_logs/elasticsearch/ingest_pipeline/default.yml (100%) rename x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.2.0/{dataset => data_stream}/test_logs/fields/ecs.yml (100%) rename x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.2.0/{dataset => data_stream}/test_logs/fields/fields.yml (100%) rename x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.2.0/{dataset => data_stream}/test_logs/manifest.yml (100%) rename x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.2.0/{dataset => data_stream}/test_metrics/fields/ecs.yml (100%) rename x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.2.0/{dataset => data_stream}/test_metrics/fields/fields.yml (100%) rename x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.2.0/{dataset => data_stream}/test_metrics/manifest.yml (100%) rename x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/multiple_versions/0.1.0/{dataset => data_stream}/test/fields/fields.yml (100%) rename x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/multiple_versions/{0.2.0/dataset => 0.1.0/data_stream}/test/manifest.yml (100%) rename x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/multiple_versions/0.2.0/{dataset => data_stream}/test/fields/fields.yml (100%) rename x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/multiple_versions/{0.3.0/dataset => 0.2.0/data_stream}/test/manifest.yml (100%) rename x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/multiple_versions/0.3.0/{dataset => data_stream}/test/fields/fields.yml (100%) rename x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/{overrides/0.1.0/dataset => multiple_versions/0.3.0/data_stream}/test/manifest.yml (100%) rename x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/overrides/0.1.0/{dataset => data_stream}/test/fields/fields.yml (100%) rename x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/{datastreams/0.1.0/dataset/test_logs => overrides/0.1.0/data_stream/test}/manifest.yml (77%) rename x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/prerelease/0.1.0-dev.0+abc/{dataset => data_stream}/test/fields/fields.yml (100%) rename x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/prerelease/0.1.0-dev.0+abc/{dataset => data_stream}/test/manifest.yml (100%) diff --git a/x-pack/plugins/ingest_manager/common/openapi/spec_oas3.json b/x-pack/plugins/ingest_manager/common/openapi/spec_oas3.json index 28a88aa2be605..a780ae5599793 100644 --- a/x-pack/plugins/ingest_manager/common/openapi/spec_oas3.json +++ b/x-pack/plugins/ingest_manager/common/openapi/spec_oas3.json @@ -1543,7 +1543,7 @@ } }, "format_version": "1.0.0", - "datasets": [ + "data_streams": [ { "title": "CoreDNS logs", "name": "log", @@ -1764,7 +1764,7 @@ ] } }, - "datasets": [ + "data_streams": [ { "id": "endpoint", "title": "Endpoint Events", @@ -3961,7 +3961,7 @@ "format_version": { "type": "string" }, - "datasets": { + "data_streams": { "type": "array", "items": { "type": "object", diff --git a/x-pack/plugins/ingest_manager/common/services/limited_package.ts b/x-pack/plugins/ingest_manager/common/services/limited_package.ts index 21d1dbd1556b7..8d2a251ae015e 100644 --- a/x-pack/plugins/ingest_manager/common/services/limited_package.ts +++ b/x-pack/plugins/ingest_manager/common/services/limited_package.ts @@ -7,7 +7,7 @@ import { PackageInfo, AgentPolicy, PackagePolicy } from '../types'; // Assume packages only ever include 1 config template for now export const isPackageLimited = (packageInfo: PackageInfo): boolean => { - return packageInfo.config_templates?.[0]?.multiple === false; + return packageInfo.policy_templates?.[0]?.multiple === false; }; export const doesAgentPolicyAlreadyIncludePackage = ( diff --git a/x-pack/plugins/ingest_manager/common/services/package_to_package_policy.test.ts b/x-pack/plugins/ingest_manager/common/services/package_to_package_policy.test.ts index 6c3559d7cc5a0..a62fcddd16e0f 100644 --- a/x-pack/plugins/ingest_manager/common/services/package_to_package_policy.test.ts +++ b/x-pack/plugins/ingest_manager/common/services/package_to_package_policy.test.ts @@ -34,14 +34,14 @@ describe('Ingest Manager - packageToPackagePolicy', () => { describe('packageToPackagePolicyInputs', () => { it('returns empty array for packages with no config templates', () => { expect(packageToPackagePolicyInputs(mockPackage)).toEqual([]); - expect(packageToPackagePolicyInputs({ ...mockPackage, config_templates: [] })).toEqual([]); + expect(packageToPackagePolicyInputs({ ...mockPackage, policy_templates: [] })).toEqual([]); }); it('returns empty array for packages with a config template but no inputs', () => { expect( packageToPackagePolicyInputs(({ ...mockPackage, - config_templates: [{ inputs: [] }], + policy_templates: [{ inputs: [] }], } as unknown) as PackageInfo) ).toEqual([]); }); @@ -50,13 +50,13 @@ describe('Ingest Manager - packageToPackagePolicy', () => { expect( packageToPackagePolicyInputs(({ ...mockPackage, - config_templates: [{ inputs: [{ type: 'foo' }] }], + policy_templates: [{ inputs: [{ type: 'foo' }] }], } as unknown) as PackageInfo) ).toEqual([{ type: 'foo', enabled: true, streams: [] }]); expect( packageToPackagePolicyInputs(({ ...mockPackage, - config_templates: [{ inputs: [{ type: 'foo' }, { type: 'bar' }] }], + policy_templates: [{ inputs: [{ type: 'foo' }, { type: 'bar' }] }], } as unknown) as PackageInfo) ).toEqual([ { type: 'foo', enabled: true, streams: [] }, @@ -68,12 +68,12 @@ describe('Ingest Manager - packageToPackagePolicy', () => { expect( packageToPackagePolicyInputs(({ ...mockPackage, - datasets: [ - { type: 'logs', name: 'foo', streams: [{ input: 'foo' }] }, - { type: 'logs', name: 'bar', streams: [{ input: 'bar' }] }, - { type: 'logs', name: 'bar2', streams: [{ input: 'bar' }] }, + data_streams: [ + { type: 'logs', dataset: 'foo', streams: [{ input: 'foo' }] }, + { type: 'logs', dataset: 'bar', streams: [{ input: 'bar' }] }, + { type: 'logs', dataset: 'bar2', streams: [{ input: 'bar' }] }, ], - config_templates: [ + policy_templates: [ { inputs: [{ type: 'foo' }, { type: 'bar' }], }, @@ -102,15 +102,15 @@ describe('Ingest Manager - packageToPackagePolicy', () => { expect( packageToPackagePolicyInputs(({ ...mockPackage, - datasets: [ + data_streams: [ { type: 'logs', - name: 'foo', + dataset: 'foo', streams: [{ input: 'foo', vars: [{ default: 'foo-var-value', name: 'var-name' }] }], }, { type: 'logs', - name: 'bar', + dataset: 'bar', streams: [ { input: 'bar', @@ -120,7 +120,7 @@ describe('Ingest Manager - packageToPackagePolicy', () => { }, { type: 'logs', - name: 'bar2', + dataset: 'bar2', streams: [ { input: 'bar', @@ -129,7 +129,7 @@ describe('Ingest Manager - packageToPackagePolicy', () => { ], }, ], - config_templates: [ + policy_templates: [ { inputs: [{ type: 'foo' }, { type: 'bar' }], }, @@ -173,15 +173,15 @@ describe('Ingest Manager - packageToPackagePolicy', () => { expect( packageToPackagePolicyInputs(({ ...mockPackage, - datasets: [ + data_streams: [ { type: 'logs', - name: 'foo', + dataset: 'foo', streams: [{ input: 'foo', vars: [{ default: 'foo-var-value', name: 'var-name' }] }], }, { type: 'logs', - name: 'bar', + dataset: 'bar', streams: [ { input: 'bar', @@ -191,7 +191,7 @@ describe('Ingest Manager - packageToPackagePolicy', () => { }, { type: 'logs', - name: 'bar2', + dataset: 'bar2', streams: [ { input: 'bar', @@ -201,7 +201,7 @@ describe('Ingest Manager - packageToPackagePolicy', () => { }, { type: 'logs', - name: 'disabled', + dataset: 'disabled', streams: [ { input: 'with-disabled-streams', @@ -212,7 +212,7 @@ describe('Ingest Manager - packageToPackagePolicy', () => { }, { type: 'logs', - name: 'disabled2', + dataset: 'disabled2', streams: [ { input: 'with-disabled-streams', @@ -221,7 +221,7 @@ describe('Ingest Manager - packageToPackagePolicy', () => { ], }, ], - config_templates: [ + policy_templates: [ { inputs: [ { @@ -372,13 +372,13 @@ describe('Ingest Manager - packageToPackagePolicy', () => { }); }); it('returns package policy with inputs', () => { - const mockPackageWithConfigTemplates = ({ + const mockPackageWithPolicyTemplates = ({ ...mockPackage, - config_templates: [{ inputs: [{ type: 'foo' }] }], + policy_templates: [{ inputs: [{ type: 'foo' }] }], } as unknown) as PackageInfo; expect( - packageToPackagePolicy(mockPackageWithConfigTemplates, '1', '2', 'default', 'pkgPolicy-1') + packageToPackagePolicy(mockPackageWithPolicyTemplates, '1', '2', 'default', 'pkgPolicy-1') ).toEqual({ policy_id: '1', namespace: 'default', diff --git a/x-pack/plugins/ingest_manager/common/services/package_to_package_policy.ts b/x-pack/plugins/ingest_manager/common/services/package_to_package_policy.ts index eab2e8ac2d745..822747916ebc5 100644 --- a/x-pack/plugins/ingest_manager/common/services/package_to_package_policy.ts +++ b/x-pack/plugins/ingest_manager/common/services/package_to_package_policy.ts @@ -5,7 +5,7 @@ */ import { PackageInfo, - RegistryConfigTemplate, + RegistryPolicyTemplate, RegistryVarsEntry, RegistryStream, PackagePolicy, @@ -22,14 +22,14 @@ const getStreamsForInputType = ( ): Array => { const streams: Array = []; - (packageInfo.datasets || []).forEach((dataset) => { - (dataset.streams || []).forEach((stream) => { + (packageInfo.data_streams || []).forEach((dataStream) => { + (dataStream.streams || []).forEach((stream) => { if (stream.input === inputType) { streams.push({ ...stream, data_stream: { - type: dataset.type, - dataset: dataset.name, + type: dataStream.type, + dataset: dataStream.dataset, }, }); } @@ -46,9 +46,9 @@ export const packageToPackagePolicyInputs = (packageInfo: PackageInfo): PackageP const inputs: PackagePolicy['inputs'] = []; // Assume package will only ever ship one package policy template for now - const packagePolicyTemplate: RegistryConfigTemplate | null = - packageInfo.config_templates && packageInfo.config_templates[0] - ? packageInfo.config_templates[0] + const packagePolicyTemplate: RegistryPolicyTemplate | null = + packageInfo.policy_templates && packageInfo.policy_templates[0] + ? packageInfo.policy_templates[0] : null; // Create package policy input property diff --git a/x-pack/plugins/ingest_manager/common/types/models/epm.ts b/x-pack/plugins/ingest_manager/common/types/models/epm.ts index 8bc5d9f7210b2..d2d1f22dda3a0 100644 --- a/x-pack/plugins/ingest_manager/common/types/models/epm.ts +++ b/x-pack/plugins/ingest_manager/common/types/models/epm.ts @@ -67,8 +67,8 @@ export interface RegistryPackage { assets?: string[]; internal?: boolean; format_version: string; - datasets?: Dataset[]; - config_templates?: RegistryConfigTemplate[]; + data_streams?: RegistryDataStream[]; + policy_templates?: RegistryPolicyTemplate[]; download: string; path: string; } @@ -80,7 +80,7 @@ interface RegistryImage { size?: string; type?: string; } -export interface RegistryConfigTemplate { +export interface RegistryPolicyTemplate { name: string; title: string; description: string; @@ -127,8 +127,8 @@ export type RegistrySearchResult = Pick< | 'internal' | 'download' | 'path' - | 'datasets' - | 'config_templates' + | 'data_streams' + | 'policy_templates' >; export type ScreenshotItem = RegistryImage; @@ -174,9 +174,9 @@ export type ElasticsearchAssetTypeToParts = Record< ElasticsearchAssetParts[] >; -export interface Dataset { +export interface RegistryDataStream { type: string; - name: string; + dataset: string; title: string; release: string; streams?: RegistryStream[]; diff --git a/x-pack/plugins/ingest_manager/dev_docs/epm.md b/x-pack/plugins/ingest_manager/dev_docs/epm.md index 20209d09e6cc2..a066b6deb3bc8 100644 --- a/x-pack/plugins/ingest_manager/dev_docs/epm.md +++ b/x-pack/plugins/ingest_manager/dev_docs/epm.md @@ -26,5 +26,5 @@ When a package is installed or upgraded, certain Kibana and Elasticsearch assets ### Generation - Index templates are generated from `YAML` files contained in the package. -- There is one index template per dataset. -- For the generation of an index template, all `yml` files contained in the package subdirectory `dataset/DATASET_NAME/fields/` are used. +- There is one index template per data stream. +- For the generation of an index template, all `yml` files contained in the package subdirectory `data_stream/DATASET_NAME/fields/` are used. diff --git a/x-pack/plugins/ingest_manager/dev_docs/indexing_strategy.md b/x-pack/plugins/ingest_manager/dev_docs/indexing_strategy.md index fd7edcb7fcca0..42a0bbc218869 100644 --- a/x-pack/plugins/ingest_manager/dev_docs/indexing_strategy.md +++ b/x-pack/plugins/ingest_manager/dev_docs/indexing_strategy.md @@ -6,48 +6,48 @@ Overall documentation of Ingest Management is now maintained in the `elastic/sta Ingest Management enforces an indexing strategy to allow the system to automatically detect indices and run queries on it. In short the indexing strategy looks as following: ``` -{dataset.type}-{dataset.name}-{dataset.namespace} +{data_stream.type}-{data_stream.dataset}-{data_stream.namespace} ``` -The `{dataset.type}` can be `logs` or `metrics`. The `{dataset.namespace}` is the part where the user can use free form. The only two requirement are that it has only characters allowed in an Elasticsearch index name and does NOT contain a `-`. The `dataset` is defined by the data that is indexed. The same requirements as for the namespace apply. It is expected that the fields for type, namespace and dataset are part of each event and are constant keywords. If there is a dataset or a namespace with a `-` inside, it is recommended to replace it either by a `.` or a `_`. +The `{data_stream.type}` can be `logs` or `metrics`. The `{data_stream.namespace}` is the part where the user can use free form. The only two requirement are that it has only characters allowed in an Elasticsearch index name and does NOT contain a `-`. The `data_stream` is defined by the data that is indexed. The same requirements as for the namespace apply. It is expected that the fields for type, dataset, and namespace are part of each event and are constant keywords. If there is a dataset or a namespace with a `-` inside, it is recommended to replace it either by a `.` or a `_`. -Note: More `{dataset.type}`s might be added in the future like `traces`. +Note: More `{data_stream.type}`s might be added in the future like `traces`. This indexing strategy has a few advantages: -* Each index contains only the fields which are relevant for the dataset. This leads to more dense indices and better field completion. -* ILM policies can be applied per namespace per dataset. -* Rollups can be specified per namespace per dataset. -* Having the namespace user configurable makes setting security permissions possible. -* Having a global metrics and logs template, allows to create new indices on demand which still follow the convention. This is common in the case of k8s as an example. -* Constant keywords allow to narrow down the indices we need to access for querying very efficiently. This is especially relevant in environments which a large number of indices or with indices on slower nodes. +- Each index contains only the fields which are relevant for the datta stream. This leads to more dense indices and better field completion. +- ILM policies can be applied per namespace per data stream. +- Rollups can be specified per namespace per data stream. +- Having the namespace user configurable makes setting security permissions possible. +- Having a global metrics and logs template, allows to create new indices on demand which still follow the convention. This is common in the case of k8s as an example. +- Constant keywords allow to narrow down the indices we need to access for querying very efficiently. This is especially relevant in environments which a large number of indices or with indices on slower nodes. Overall it creates smaller indices in size, makes querying more efficient and allows users to define their own naming parts in namespace and still benefiting from all features that can be built on top of the indexing startegy. ## Ingest Pipeline -The ingest pipelines for a specific dataset will have the following naming scheme: +The ingest pipelines for a specific data stream will have the following naming scheme: ``` -{dataset.type}-{dataset.name}-{package.version} +{data_stream.type}-{data_stream.dataset}-{package.version} ``` -As an example, the ingest pipeline for the Nginx access logs is called `logs-nginx.access-3.4.1`. The same ingest pipeline is used for all namespaces. It is possible that a dataset has multiple ingest pipelines in which case a suffix is added to the name. +As an example, the ingest pipeline for the Nginx access logs is called `logs-nginx.access-3.4.1`. The same ingest pipeline is used for all namespaces. It is possible that a data stream has multiple ingest pipelines in which case a suffix is added to the name. The version is included in each pipeline to allow upgrades. The pipeline itself is listed in the index template and is automatically applied at ingest time. ## Templates & ILM Policies -To make the above strategy possible, alias templates are required. For each type there is a basic alias template with a default ILM policy. These default templates apply to all indices which follow the indexing strategy and do not have a more specific dataset alias template. +To make the above strategy possible, alias templates are required. For each type there is a basic alias template with a default ILM policy. These default templates apply to all indices which follow the indexing strategy and do not have a more specific data stream alias template. The `metrics` and `logs` alias template contain all the basic fields from ECS. Each type template contains an ILM policy. Modifying this default ILM policy will affect all data covered by the default templates. -The templates for a dataset are called as following: +The templates for a data stream are called as following: ``` -{dataset.type}-{dataset.name} +{data_stream.type}-{data_stream.dataset} ``` The pattern used inside the index template is `{type}-{dataset}-*` to match all namespaces. diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/create_package_policy_page/services/validate_package_policy.test..ts b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/create_package_policy_page/services/validate_package_policy.test..ts index aae750cb67499..d621db615f2bd 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/create_package_policy_page/services/validate_package_policy.test..ts +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/create_package_policy_page/services/validate_package_policy.test..ts @@ -7,7 +7,7 @@ import { PackageInfo, InstallationStatus, NewPackagePolicy, - RegistryConfigTemplate, + RegistryPolicyTemplate, } from '../../../../types'; import { validatePackagePolicy, validationHasErrors } from './validate_package_policy'; @@ -32,9 +32,9 @@ describe('Ingest Manager - validatePackagePolicy()', () => { }, }, status: InstallationStatus.notInstalled, - datasets: [ + data_streams: [ { - name: 'foo', + dataset: 'foo', streams: [ { input: 'foo', @@ -44,7 +44,7 @@ describe('Ingest Manager - validatePackagePolicy()', () => { ], }, { - name: 'bar', + dataset: 'bar', streams: [ { input: 'bar', @@ -59,7 +59,7 @@ describe('Ingest Manager - validatePackagePolicy()', () => { ], }, { - name: 'bar2', + dataset: 'bar2', streams: [ { input: 'bar', @@ -69,7 +69,7 @@ describe('Ingest Manager - validatePackagePolicy()', () => { ], }, { - name: 'disabled', + dataset: 'disabled', streams: [ { input: 'with-disabled-streams', @@ -80,7 +80,7 @@ describe('Ingest Manager - validatePackagePolicy()', () => { ], }, { - name: 'disabled2', + dataset: 'disabled2', streams: [ { input: 'with-disabled-streams', @@ -90,7 +90,7 @@ describe('Ingest Manager - validatePackagePolicy()', () => { ], }, ], - config_templates: [ + policy_templates: [ { name: 'pkgPolicy1', title: 'Package policy 1', @@ -465,7 +465,7 @@ describe('Ingest Manager - validatePackagePolicy()', () => { expect( validatePackagePolicy(validPackagePolicy, { ...mockPackage, - config_templates: undefined, + policy_templates: undefined, }) ).toEqual({ name: null, @@ -476,7 +476,7 @@ describe('Ingest Manager - validatePackagePolicy()', () => { expect( validatePackagePolicy(validPackagePolicy, { ...mockPackage, - config_templates: [], + policy_templates: [], }) ).toEqual({ name: null, @@ -490,7 +490,7 @@ describe('Ingest Manager - validatePackagePolicy()', () => { expect( validatePackagePolicy(validPackagePolicy, { ...mockPackage, - config_templates: [{} as RegistryConfigTemplate], + policy_templates: [{} as RegistryPolicyTemplate], }) ).toEqual({ name: null, @@ -501,7 +501,7 @@ describe('Ingest Manager - validatePackagePolicy()', () => { expect( validatePackagePolicy(validPackagePolicy, { ...mockPackage, - config_templates: [({ inputs: [] } as unknown) as RegistryConfigTemplate], + policy_templates: [({ inputs: [] } as unknown) as RegistryPolicyTemplate], }) ).toEqual({ name: null, diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/create_package_policy_page/services/validate_package_policy.ts b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/create_package_policy_page/services/validate_package_policy.ts index 03060c5dcb20e..04cd21884e8f2 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/create_package_policy_page/services/validate_package_policy.ts +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/create_package_policy_page/services/validate_package_policy.ts @@ -65,11 +65,11 @@ export const validatePackagePolicy = ( } if ( - !packageInfo.config_templates || - packageInfo.config_templates.length === 0 || - !packageInfo.config_templates[0] || - !packageInfo.config_templates[0].inputs || - packageInfo.config_templates[0].inputs.length === 0 + !packageInfo.policy_templates || + packageInfo.policy_templates.length === 0 || + !packageInfo.policy_templates[0] || + !packageInfo.policy_templates[0].inputs || + packageInfo.policy_templates[0].inputs.length === 0 ) { validationResults.inputs = null; return validationResults; @@ -78,16 +78,16 @@ export const validatePackagePolicy = ( const registryInputsByType: Record< string, RegistryInput - > = packageInfo.config_templates[0].inputs.reduce((inputs, registryInput) => { + > = packageInfo.policy_templates[0].inputs.reduce((inputs, registryInput) => { inputs[registryInput.type] = registryInput; return inputs; }, {} as Record); const registryStreamsByDataset: Record = ( - packageInfo.datasets || [] - ).reduce((datasets, registryDataset) => { - datasets[registryDataset.name] = registryDataset.streams || []; - return datasets; + packageInfo.data_streams || [] + ).reduce((dataStreams, registryDataStream) => { + dataStreams[registryDataStream.dataset] = registryDataStream.streams || []; + return dataStreams; }, {} as Record); // Validate each package policy input with either its own config fields or streams diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/create_package_policy_page/step_configure_package.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/create_package_policy_page/step_configure_package.tsx index b77153daee2fc..d3d5e60c34e58 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/create_package_policy_page/step_configure_package.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/create_package_policy_page/step_configure_package.tsx @@ -17,13 +17,13 @@ const findStreamsForInputType = ( ): Array => { const streams: Array = []; - (packageInfo.datasets || []).forEach((dataset) => { - (dataset.streams || []).forEach((stream) => { + (packageInfo.data_streams || []).forEach((dataStream) => { + (dataStream.streams || []).forEach((stream) => { if (stream.input === inputType) { streams.push({ ...stream, data_stream: { - dataset: dataset.name, + dataset: dataStream.dataset, }, }); } @@ -53,14 +53,14 @@ export const StepConfigurePackagePolicy: React.FunctionComponent<{ // Configure inputs (and their streams) // Assume packages only export one config template for now const renderConfigureInputs = () => - packageInfo.config_templates && - packageInfo.config_templates[0] && - packageInfo.config_templates[0].inputs && - packageInfo.config_templates[0].inputs.length ? ( + packageInfo.policy_templates && + packageInfo.policy_templates[0] && + packageInfo.policy_templates[0].inputs && + packageInfo.policy_templates[0].inputs.length ? ( <> - {packageInfo.config_templates[0].inputs.map((packageInput) => { + {packageInfo.policy_templates[0].inputs.map((packageInput) => { const packagePolicyInput = packagePolicy.inputs.find( (input) => input.type === packageInput.type ); diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/types/index.ts b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/types/index.ts index 71a44089b8bf7..e825448f359d6 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/types/index.ts +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/types/index.ts @@ -89,7 +89,7 @@ export { RegistryVarsEntry, RegistryInput, RegistryStream, - RegistryConfigTemplate, + RegistryPolicyTemplate, PackageList, PackageListItem, PackagesGroupedByStatus, diff --git a/x-pack/plugins/ingest_manager/server/services/epm/elasticsearch/index.test.ts b/x-pack/plugins/ingest_manager/server/services/epm/elasticsearch/index.test.ts index bdd8883ea29c2..78aa17da5030c 100644 --- a/x-pack/plugins/ingest_manager/server/services/epm/elasticsearch/index.test.ts +++ b/x-pack/plugins/ingest_manager/server/services/epm/elasticsearch/index.test.ts @@ -4,12 +4,12 @@ * you may not use this file except in compliance with the Elastic License. */ -import { Dataset } from '../../../types'; -import { getDatasetAssetBaseName } from './index'; +import { RegistryDataStream } from '../../../types'; +import { getRegistryDataStreamAssetBaseName } from './index'; test('getBaseName', () => { - const dataset: Dataset = { - name: 'nginx.access', + const dataStream: RegistryDataStream = { + dataset: 'nginx.access', title: 'Nginx Acess Logs', release: 'beta', type: 'logs', @@ -17,6 +17,6 @@ test('getBaseName', () => { package: 'nginx', path: 'access', }; - const name = getDatasetAssetBaseName(dataset); + const name = getRegistryDataStreamAssetBaseName(dataStream); expect(name).toStrictEqual('logs-nginx.access'); }); diff --git a/x-pack/plugins/ingest_manager/server/services/epm/elasticsearch/index.ts b/x-pack/plugins/ingest_manager/server/services/epm/elasticsearch/index.ts index 0cb09ba054bf1..17cd28cc8a081 100644 --- a/x-pack/plugins/ingest_manager/server/services/epm/elasticsearch/index.ts +++ b/x-pack/plugins/ingest_manager/server/services/epm/elasticsearch/index.ts @@ -4,12 +4,12 @@ * you may not use this file except in compliance with the Elastic License. */ -import { Dataset } from '../../../types'; +import { RegistryDataStream } from '../../../types'; /** * Creates the base name for Elasticsearch assets in the form of - * {type}-{id} + * {type}-{dataset} */ -export function getDatasetAssetBaseName(dataset: Dataset): string { - return `${dataset.type}-${dataset.name}`; +export function getRegistryDataStreamAssetBaseName(dataStream: RegistryDataStream): string { + return `${dataStream.type}-${dataStream.dataset}`; } diff --git a/x-pack/plugins/ingest_manager/server/services/epm/elasticsearch/ingest_pipeline/ingest_pipelines.test.ts b/x-pack/plugins/ingest_manager/server/services/epm/elasticsearch/ingest_pipeline/ingest_pipelines.test.ts index 36a19c512a8b4..378dd271779b4 100644 --- a/x-pack/plugins/ingest_manager/server/services/epm/elasticsearch/ingest_pipeline/ingest_pipelines.test.ts +++ b/x-pack/plugins/ingest_manager/server/services/epm/elasticsearch/ingest_pipeline/ingest_pipelines.test.ts @@ -7,7 +7,7 @@ import { readFileSync } from 'fs'; import path from 'path'; import { rewriteIngestPipeline, getPipelineNameForInstallation } from './install'; -import { Dataset } from '../../../../types'; +import { RegistryDataStream } from '../../../../types'; test('a json-format pipeline with pipeline references is correctly rewritten', () => { const inputStandard = readFileSync( @@ -106,8 +106,8 @@ test('a yml-format pipeline with no pipeline references stays unchanged', () => }); test('getPipelineNameForInstallation gets correct name', () => { - const dataset: Dataset = { - name: 'coredns.log', + const dataStream: RegistryDataStream = { + dataset: 'coredns.log', title: 'CoreDNS logs', release: 'ga', type: 'logs', @@ -118,19 +118,19 @@ test('getPipelineNameForInstallation gets correct name', () => { const packageVersion = '1.0.1'; const pipelineRefName = 'pipeline-json'; const pipelineEntryNameForInstallation = getPipelineNameForInstallation({ - pipelineName: dataset.ingest_pipeline, - dataset, + pipelineName: dataStream.ingest_pipeline, + dataStream, packageVersion, }); const pipelineRefNameForInstallation = getPipelineNameForInstallation({ pipelineName: pipelineRefName, - dataset, + dataStream, packageVersion, }); expect(pipelineEntryNameForInstallation).toBe( - `${dataset.type}-${dataset.name}-${packageVersion}` + `${dataStream.type}-${dataStream.dataset}-${packageVersion}` ); expect(pipelineRefNameForInstallation).toBe( - `${dataset.type}-${dataset.name}-${packageVersion}-${pipelineRefName}` + `${dataStream.type}-${dataStream.dataset}-${packageVersion}-${pipelineRefName}` ); }); diff --git a/x-pack/plugins/ingest_manager/server/services/epm/elasticsearch/ingest_pipeline/install.ts b/x-pack/plugins/ingest_manager/server/services/epm/elasticsearch/ingest_pipeline/install.ts index 878c6ea8f2804..6088bcb71f878 100644 --- a/x-pack/plugins/ingest_manager/server/services/epm/elasticsearch/ingest_pipeline/install.ts +++ b/x-pack/plugins/ingest_manager/server/services/epm/elasticsearch/ingest_pipeline/install.ts @@ -7,7 +7,7 @@ import { SavedObjectsClientContract } from 'src/core/server'; import { EsAssetReference, - Dataset, + RegistryDataStream, ElasticsearchAssetType, RegistryPackage, } from '../../../../types'; @@ -30,17 +30,19 @@ export const installPipelines = async ( // unlike other ES assets, pipeline names are versioned so after a template is updated // it can be created pointing to the new template, without removing the old one and effecting data // so do not remove the currently installed pipelines here - const datasets = registryPackage.datasets; - if (!datasets?.length) return []; + const dataStreams = registryPackage.data_streams; + if (!dataStreams?.length) return []; const pipelinePaths = paths.filter((path) => isPipeline(path)); // get and save pipeline refs before installing pipelines - const pipelineRefs = datasets.reduce((acc, dataset) => { - const filteredPaths = pipelinePaths.filter((path) => isDatasetPipeline(path, dataset.path)); + const pipelineRefs = dataStreams.reduce((acc, dataStream) => { + const filteredPaths = pipelinePaths.filter((path) => + isDataStreamPipeline(path, dataStream.path) + ); const pipelineObjectRefs = filteredPaths.map((path) => { const { name } = getNameAndExtension(path); const nameForInstallation = getPipelineNameForInstallation({ pipelineName: name, - dataset, + dataStream, packageVersion: registryPackage.version, }); return { id: nameForInstallation, type: ElasticsearchAssetType.ingestPipeline }; @@ -49,11 +51,11 @@ export const installPipelines = async ( return acc; }, []); await saveInstalledEsRefs(savedObjectsClient, registryPackage.name, pipelineRefs); - const pipelines = datasets.reduce>>((acc, dataset) => { - if (dataset.ingest_pipeline) { + const pipelines = dataStreams.reduce>>((acc, dataStream) => { + if (dataStream.ingest_pipeline) { acc.push( - installPipelinesForDataset({ - dataset, + installPipelinesForDataStream({ + dataStream, callCluster, paths: pipelinePaths, pkgVersion: registryPackage.version, @@ -86,18 +88,18 @@ export function rewriteIngestPipeline( return pipeline; } -export async function installPipelinesForDataset({ +export async function installPipelinesForDataStream({ callCluster, pkgVersion, paths, - dataset, + dataStream, }: { callCluster: CallESAsCurrentUser; pkgVersion: string; paths: string[]; - dataset: Dataset; + dataStream: RegistryDataStream; }): Promise { - const pipelinePaths = paths.filter((path) => isDatasetPipeline(path, dataset.path)); + const pipelinePaths = paths.filter((path) => isDataStreamPipeline(path, dataStream.path)); let pipelines: any[] = []; const substitutions: RewriteSubstitution[] = []; @@ -105,7 +107,7 @@ export async function installPipelinesForDataset({ const { name, extension } = getNameAndExtension(path); const nameForInstallation = getPipelineNameForInstallation({ pipelineName: name, - dataset, + dataStream, packageVersion: pkgVersion, }); const content = Registry.getAsset(path).toString('utf-8'); @@ -175,13 +177,13 @@ async function installPipeline({ const isDirectory = ({ path }: Registry.ArchiveEntry) => path.endsWith('/'); -const isDatasetPipeline = (path: string, datasetName: string) => { +const isDataStreamPipeline = (path: string, dataStreamDataset: string) => { const pathParts = Registry.pathParts(path); return ( !isDirectory({ path }) && pathParts.type === ElasticsearchAssetType.ingestPipeline && pathParts.dataset !== undefined && - datasetName === pathParts.dataset + dataStreamDataset === pathParts.dataset ); }; const isPipeline = (path: string) => { @@ -206,15 +208,15 @@ const getNameAndExtension = ( export const getPipelineNameForInstallation = ({ pipelineName, - dataset, + dataStream, packageVersion, }: { pipelineName: string; - dataset: Dataset; + dataStream: RegistryDataStream; packageVersion: string; }): string => { - const isPipelineEntry = pipelineName === dataset.ingest_pipeline; + const isPipelineEntry = pipelineName === dataStream.ingest_pipeline; const suffix = isPipelineEntry ? '' : `-${pipelineName}`; // if this is the pipeline entry, don't add a suffix - return `${dataset.type}-${dataset.name}-${packageVersion}${suffix}`; + return `${dataStream.type}-${dataStream.dataset}-${packageVersion}${suffix}`; }; diff --git a/x-pack/plugins/ingest_manager/server/services/epm/elasticsearch/template/install.ts b/x-pack/plugins/ingest_manager/server/services/epm/elasticsearch/template/install.ts index f4e8c3bfd99d3..8f80feb268910 100644 --- a/x-pack/plugins/ingest_manager/server/services/epm/elasticsearch/template/install.ts +++ b/x-pack/plugins/ingest_manager/server/services/epm/elasticsearch/template/install.ts @@ -7,7 +7,7 @@ import Boom from 'boom'; import { SavedObjectsClientContract } from 'src/core/server'; import { - Dataset, + RegistryDataStream, RegistryPackage, ElasticsearchAssetType, TemplateRef, @@ -38,29 +38,32 @@ export const installTemplates = async ( registryPackage.name, ElasticsearchAssetType.indexTemplate ); - // build templates per dataset from yml files - const datasets = registryPackage.datasets; - if (!datasets) return []; + // build templates per data stream from yml files + const dataStreams = registryPackage.data_streams; + if (!dataStreams) return []; // get template refs to save - const installedTemplateRefs = datasets.map((dataset) => ({ - id: generateTemplateName(dataset), + const installedTemplateRefs = dataStreams.map((dataStream) => ({ + id: generateTemplateName(dataStream), type: ElasticsearchAssetType.indexTemplate, })); // add package installation's references to index templates await saveInstalledEsRefs(savedObjectsClient, registryPackage.name, installedTemplateRefs); - if (datasets) { - const installTemplatePromises = datasets.reduce>>((acc, dataset) => { - acc.push( - installTemplateForDataset({ - pkg: registryPackage, - callCluster, - dataset, - }) - ); - return acc; - }, []); + if (dataStreams) { + const installTemplatePromises = dataStreams.reduce>>( + (acc, dataStream) => { + acc.push( + installTemplateForDataStream({ + pkg: registryPackage, + callCluster, + dataStream, + }) + ); + return acc; + }, + [] + ); const res = await Promise.all(installTemplatePromises); const installedTemplates = res.flat(); @@ -158,25 +161,25 @@ const isComponentTemplate = (path: string) => { }; /** - * installTemplatesForDataset installs one template for each dataset + * installTemplateForDataStream installs one template for each data stream * - * The template is currently loaded with the pkgey-package-dataset + * The template is currently loaded with the pkgkey-package-data_stream */ -export async function installTemplateForDataset({ +export async function installTemplateForDataStream({ pkg, callCluster, - dataset, + dataStream, }: { pkg: RegistryPackage; callCluster: CallESAsCurrentUser; - dataset: Dataset; + dataStream: RegistryDataStream; }): Promise { - const fields = await loadFieldsFromYaml(pkg, dataset.path); + const fields = await loadFieldsFromYaml(pkg, dataStream.path); return installTemplate({ callCluster, fields, - dataset, + dataStream, packageVersion: pkg.version, packageName: pkg.name, }); @@ -237,7 +240,7 @@ function buildComponentTemplates(registryElasticsearch: RegistryElasticsearch | return { settingsTemplate, mappingsTemplate }; } -async function installDatasetComponentTemplates( +async function installDataStreamComponentTemplates( templateName: string, registryElasticsearch: RegistryElasticsearch | undefined, callCluster: CallESAsCurrentUser @@ -277,35 +280,35 @@ async function installDatasetComponentTemplates( export async function installTemplate({ callCluster, fields, - dataset, + dataStream, packageVersion, packageName, }: { callCluster: CallESAsCurrentUser; fields: Field[]; - dataset: Dataset; + dataStream: RegistryDataStream; packageVersion: string; packageName: string; }): Promise { const mappings = generateMappings(processFields(fields)); - const templateName = generateTemplateName(dataset); + const templateName = generateTemplateName(dataStream); let pipelineName; - if (dataset.ingest_pipeline) { + if (dataStream.ingest_pipeline) { pipelineName = getPipelineNameForInstallation({ - pipelineName: dataset.ingest_pipeline, - dataset, + pipelineName: dataStream.ingest_pipeline, + dataStream, packageVersion, }); } - const composedOfTemplates = await installDatasetComponentTemplates( + const composedOfTemplates = await installDataStreamComponentTemplates( templateName, - dataset.elasticsearch, + dataStream.elasticsearch, callCluster ); const template = getTemplate({ - type: dataset.type, + type: dataStream.type, templateName, mappings, pipelineName, diff --git a/x-pack/plugins/ingest_manager/server/services/epm/elasticsearch/template/template.ts b/x-pack/plugins/ingest_manager/server/services/epm/elasticsearch/template/template.ts index 71e49acf1766f..00c2e873ba129 100644 --- a/x-pack/plugins/ingest_manager/server/services/epm/elasticsearch/template/template.ts +++ b/x-pack/plugins/ingest_manager/server/services/epm/elasticsearch/template/template.ts @@ -6,13 +6,13 @@ import { Field, Fields } from '../../fields/field'; import { - Dataset, + RegistryDataStream, CallESAsCurrentUser, TemplateRef, IndexTemplate, IndexTemplateMappings, } from '../../../../types'; -import { getDatasetAssetBaseName } from '../index'; +import { getRegistryDataStreamAssetBaseName } from '../index'; interface Properties { [key: string]: any; @@ -222,22 +222,24 @@ function getDefaultProperties(field: Field): Properties { /** * Generates the template name out of the given information */ -export function generateTemplateName(dataset: Dataset): string { - return getDatasetAssetBaseName(dataset); +export function generateTemplateName(dataStream: RegistryDataStream): string { + return getRegistryDataStreamAssetBaseName(dataStream); } /** - * Returns a map of the dataset path fields to elasticsearch index pattern. - * @param datasets an array of Dataset objects + * Returns a map of the data stream path fields to elasticsearch index pattern. + * @param dataStreams an array of RegistryDataStream objects */ -export function generateESIndexPatterns(datasets: Dataset[] | undefined): Record { - if (!datasets) { +export function generateESIndexPatterns( + dataStreams: RegistryDataStream[] | undefined +): Record { + if (!dataStreams) { return {}; } const patterns: Record = {}; - for (const dataset of datasets) { - patterns[dataset.path] = generateTemplateName(dataset) + '-*'; + for (const dataStream of dataStreams) { + patterns[dataStream.path] = generateTemplateName(dataStream) + '-*'; } return patterns; } @@ -389,7 +391,7 @@ const updateExistingIndex = async ({ }) => { const { settings, mappings } = indexTemplate.template; - // for now, remove from object so as not to update stream or dataset properties of the index until type and name + // for now, remove from object so as not to update stream or data stream properties of the index until type and name // are added in https://github.com/elastic/kibana/issues/66551. namespace value we will continue // to skip updating and assume the value in the index mapping is correct delete mappings.properties.stream; diff --git a/x-pack/plugins/ingest_manager/server/services/epm/elasticsearch/transform/transform.test.ts b/x-pack/plugins/ingest_manager/server/services/epm/elasticsearch/transform/transform.test.ts index 7cb507d15679e..768c6af1d8915 100644 --- a/x-pack/plugins/ingest_manager/server/services/epm/elasticsearch/transform/transform.test.ts +++ b/x-pack/plugins/ingest_manager/server/services/epm/elasticsearch/transform/transform.test.ts @@ -114,10 +114,10 @@ describe('test transform install', () => { ({ name: 'endpoint', version: '0.16.0-dev.0', - datasets: [ + data_streams: [ { type: 'metrics', - name: 'endpoint.metadata', + dataset: 'endpoint.metadata', title: 'Endpoint Metadata', release: 'experimental', package: 'endpoint', @@ -131,7 +131,7 @@ describe('test transform install', () => { }, { type: 'metrics', - name: 'endpoint.metadata_current', + dataset: 'endpoint.metadata_current', title: 'Endpoint Metadata Current', release: 'experimental', package: 'endpoint', @@ -146,7 +146,7 @@ describe('test transform install', () => { ], } as unknown) as RegistryPackage, [ - 'endpoint-0.16.0-dev.0/dataset/policy/elasticsearch/ingest_pipeline/default.json', + 'endpoint-0.16.0-dev.0/data_stream/policy/elasticsearch/ingest_pipeline/default.json', 'endpoint-0.16.0-dev.0/elasticsearch/transform/metadata/default.json', 'endpoint-0.16.0-dev.0/elasticsearch/transform/metadata_current/default.json', ], @@ -302,10 +302,10 @@ describe('test transform install', () => { ({ name: 'endpoint', version: '0.16.0-dev.0', - datasets: [ + data_streams: [ { type: 'metrics', - name: 'endpoint.metadata_current', + dataset: 'endpoint.metadata_current', title: 'Endpoint Metadata', release: 'experimental', package: 'endpoint', @@ -404,10 +404,10 @@ describe('test transform install', () => { ({ name: 'endpoint', version: '0.16.0-dev.0', - datasets: [ + data_streams: [ { type: 'metrics', - name: 'endpoint.metadata', + dataset: 'endpoint.metadata', title: 'Endpoint Metadata', release: 'experimental', package: 'endpoint', @@ -421,7 +421,7 @@ describe('test transform install', () => { }, { type: 'metrics', - name: 'endpoint.metadata_current', + dataset: 'endpoint.metadata_current', title: 'Endpoint Metadata Current', release: 'experimental', package: 'endpoint', diff --git a/x-pack/plugins/ingest_manager/server/services/epm/kibana/index_pattern/install.ts b/x-pack/plugins/ingest_manager/server/services/epm/kibana/index_pattern/install.ts index 7fe3713e186ee..bde542412f123 100644 --- a/x-pack/plugins/ingest_manager/server/services/epm/kibana/index_pattern/install.ts +++ b/x-pack/plugins/ingest_manager/server/services/epm/kibana/index_pattern/install.ts @@ -122,8 +122,8 @@ export async function installIndexPatterns( return; } - // get all dataset fields from all installed packages - const fields = await getAllDatasetFieldsByType(installedPackagesInfo, indexPatternType); + // get all data stream fields from all installed packages + const fields = await getAllDataStreamFieldsByType(installedPackagesInfo, indexPatternType); const kibanaIndexPattern = createIndexPattern(indexPatternType, fields); // create or overwrite the index pattern @@ -135,23 +135,27 @@ export async function installIndexPatterns( } // loops through all given packages and returns an array -// of all fields from all datasets matching datasetType -export const getAllDatasetFieldsByType = async ( +// of all fields from all data streams matching data stream type +export const getAllDataStreamFieldsByType = async ( packages: RegistryPackage[], - datasetType: IndexPatternType + dataStreamType: IndexPatternType ): Promise => { - const datasetsPromises = packages.reduce>>((acc, pkg) => { - if (pkg.datasets) { - // filter out datasets by datasetType - const matchingDatasets = pkg.datasets.filter((dataset) => dataset.type === datasetType); - matchingDatasets.forEach((dataset) => acc.push(loadFieldsFromYaml(pkg, dataset.path))); + const dataStreamsPromises = packages.reduce>>((acc, pkg) => { + if (pkg.data_streams) { + // filter out data streams by data stream type + const matchingDataStreams = pkg.data_streams.filter( + (dataStream) => dataStream.type === dataStreamType + ); + matchingDataStreams.forEach((dataStream) => + acc.push(loadFieldsFromYaml(pkg, dataStream.path)) + ); } return acc; }, []); - // get all the datasets for each installed package into one array - const allDatasetFields: Fields[] = await Promise.all(datasetsPromises); - return allDatasetFields.flat(); + // get all the data stream fields for each installed package into one array + const allDataStreamFields: Fields[] = await Promise.all(dataStreamsPromises); + return allDataStreamFields.flat(); }; // creates or updates index pattern diff --git a/x-pack/plugins/ingest_manager/server/services/epm/packages/assets.test.ts b/x-pack/plugins/ingest_manager/server/services/epm/packages/assets.test.ts index 6d5ca036aeb13..78b42b03be831 100644 --- a/x-pack/plugins/ingest_manager/server/services/epm/packages/assets.test.ts +++ b/x-pack/plugins/ingest_manager/server/services/epm/packages/assets.test.ts @@ -11,8 +11,8 @@ const tests = [ { package: { assets: [ - '/package/coredns/1.0.1/dataset/log/elasticsearch/ingest-pipeline/pipeline-plaintext.json', - '/package/coredns/1.0.1/dataset/log/elasticsearch/ingest-pipeline/pipeline-json.json', + '/package/coredns/1.0.1/data_stream/log/elasticsearch/ingest-pipeline/pipeline-plaintext.json', + '/package/coredns/1.0.1/data_stream/log/elasticsearch/ingest-pipeline/pipeline-json.json', ], path: '/package/coredns/1.0.1', }, @@ -21,15 +21,15 @@ const tests = [ return true; }, expected: [ - '/package/coredns/1.0.1/dataset/log/elasticsearch/ingest-pipeline/pipeline-plaintext.json', - '/package/coredns/1.0.1/dataset/log/elasticsearch/ingest-pipeline/pipeline-json.json', + '/package/coredns/1.0.1/data_stream/log/elasticsearch/ingest-pipeline/pipeline-plaintext.json', + '/package/coredns/1.0.1/data_stream/log/elasticsearch/ingest-pipeline/pipeline-json.json', ], }, { package: { assets: [ - '/package/coredns-1.0.1/dataset/log/elasticsearch/ingest-pipeline/pipeline-plaintext.json', - '/package/coredns-1.0.1/dataset/log/elasticsearch/ingest-pipeline/pipeline-json.json', + '/package/coredns-1.0.1/data_stream/log/elasticsearch/ingest-pipeline/pipeline-plaintext.json', + '/package/coredns-1.0.1/data_stream/log/elasticsearch/ingest-pipeline/pipeline-json.json', ], path: '/package/coredns/1.0.1', }, @@ -43,8 +43,8 @@ const tests = [ { package: { assets: [ - '/package/coredns-1.0.1/dataset/log/elasticsearch/ingest-pipeline/pipeline-plaintext.json', - '/package/coredns-1.0.1/dataset/log/elasticsearch/ingest-pipeline/pipeline-json.json', + '/package/coredns-1.0.1/data_stream/log/elasticsearch/ingest-pipeline/pipeline-plaintext.json', + '/package/coredns-1.0.1/data_stream/log/elasticsearch/ingest-pipeline/pipeline-json.json', ], }, // Filter which does not exist diff --git a/x-pack/plugins/ingest_manager/server/services/epm/packages/assets.ts b/x-pack/plugins/ingest_manager/server/services/epm/packages/assets.ts index 19a023eb2ad4c..a8abc12917781 100644 --- a/x-pack/plugins/ingest_manager/server/services/epm/packages/assets.ts +++ b/x-pack/plugins/ingest_manager/server/services/epm/packages/assets.ts @@ -9,9 +9,9 @@ import * as Registry from '../registry'; import { ensureCachedArchiveInfo } from '../registry'; // paths from RegistryPackage are routes to the assets on EPR -// e.g. `/package/nginx/1.2.0/dataset/access/fields/fields.yml` +// e.g. `/package/nginx/1.2.0/data_stream/access/fields/fields.yml` // paths for ArchiveEntry are routes to the assets in the archive -// e.g. `nginx-1.2.0/dataset/access/fields/fields.yml` +// e.g. `nginx-1.2.0/data_stream/access/fields/fields.yml` // RegistryPackage paths have a `/package/` prefix compared to ArchiveEntry paths // and different package and version structure const EPR_PATH_PREFIX = '/package'; @@ -37,7 +37,7 @@ export function getAssets( // if dataset, filter for them if (datasetName) { - const comparePath = `${packageInfo.path}/dataset/${datasetName}/`; + const comparePath = `${packageInfo.path}/data_stream/${datasetName}/`; if (!path.includes(comparePath)) { continue; } diff --git a/x-pack/plugins/ingest_manager/server/services/epm/packages/install.ts b/x-pack/plugins/ingest_manager/server/services/epm/packages/install.ts index d501b05d96c1c..d7262ebb66b2e 100644 --- a/x-pack/plugins/ingest_manager/server/services/epm/packages/install.ts +++ b/x-pack/plugins/ingest_manager/server/services/epm/packages/install.ts @@ -259,7 +259,7 @@ export async function installPackage({ const removable = !isRequiredPackage(pkgName); const { internal = false } = registryPackageInfo; - const toSaveESIndexPatterns = generateESIndexPatterns(registryPackageInfo.datasets); + const toSaveESIndexPatterns = generateESIndexPatterns(registryPackageInfo.data_streams); // add the package installation to the saved object. // if some installation already exists, just update install info @@ -304,7 +304,7 @@ export async function installPackage({ // currently only the base package has an ILM policy // at some point ILM policies can be installed/modified - // per dataset and we should then save them + // per data stream and we should then save them await installILMPolicy(paths, callCluster); // installs versionized pipelines without removing currently installed ones diff --git a/x-pack/plugins/ingest_manager/server/services/epm/registry/index.test.ts b/x-pack/plugins/ingest_manager/server/services/epm/registry/index.test.ts index b40638eefbae2..2fd9175549026 100644 --- a/x-pack/plugins/ingest_manager/server/services/epm/registry/index.test.ts +++ b/x-pack/plugins/ingest_manager/server/services/epm/registry/index.test.ts @@ -41,11 +41,11 @@ const testPaths = [ }, }, { - path: 'coredns-1.0.1/dataset/stats/fields/coredns.stats.yml', + path: 'coredns-1.0.1/data_stream/stats/fields/coredns.stats.yml', assetParts: { dataset: 'stats', file: 'coredns.stats.yml', - path: 'coredns-1.0.1/dataset/stats/fields/coredns.stats.yml', + path: 'coredns-1.0.1/data_stream/stats/fields/coredns.stats.yml', pkgkey: 'coredns-1.0.1', service: '', type: 'fields', diff --git a/x-pack/plugins/ingest_manager/server/services/epm/registry/index.ts b/x-pack/plugins/ingest_manager/server/services/epm/registry/index.ts index 96f7530641390..22f1b670b2cc4 100644 --- a/x-pack/plugins/ingest_manager/server/services/epm/registry/index.ts +++ b/x-pack/plugins/ingest_manager/server/services/epm/registry/index.ts @@ -158,12 +158,12 @@ export function pathParts(path: string): AssetParts { let [pkgkey, service, type, file] = path.split('/'); - // if it's a dataset - if (service === 'dataset') { + // if it's a data stream + if (service === 'data_stream') { // save the dataset name dataset = type; - // drop the `dataset/dataset-name` portion & re-parse - [pkgkey, service, type, file] = path.replace(`dataset/${dataset}/`, '').split('/'); + // drop the `data_stream/dataset-name` portion & re-parse + [pkgkey, service, type, file] = path.replace(`data_stream/${dataset}/`, '').split('/'); } // This is to cover for the fields.yml files inside the "fields" directory diff --git a/x-pack/plugins/ingest_manager/server/services/package_policy.test.ts b/x-pack/plugins/ingest_manager/server/services/package_policy.test.ts index 0d89c52957632..6064e5bae0634 100644 --- a/x-pack/plugins/ingest_manager/server/services/package_policy.test.ts +++ b/x-pack/plugins/ingest_manager/server/services/package_policy.test.ts @@ -45,14 +45,14 @@ describe('Package policy service', () => { it('should work with config variables from the stream', async () => { const inputs = await packagePolicyService.assignPackageStream( ({ - datasets: [ + data_streams: [ { type: 'logs', - name: 'package.dataset1', + dataset: 'package.dataset1', streams: [{ input: 'log', template_path: 'some_template_path.yml' }], }, ], - config_templates: [ + policy_templates: [ { inputs: [{ type: 'log' }], }, @@ -64,7 +64,7 @@ describe('Package policy service', () => { enabled: true, streams: [ { - id: 'dataset01', + id: 'datastream01', data_stream: { dataset: 'package.dataset1', type: 'logs' }, enabled: true, vars: { @@ -84,7 +84,7 @@ describe('Package policy service', () => { enabled: true, streams: [ { - id: 'dataset01', + id: 'datastream01', data_stream: { dataset: 'package.dataset1', type: 'logs' }, enabled: true, vars: { @@ -106,14 +106,14 @@ describe('Package policy service', () => { it('should work with config variables at the input level', async () => { const inputs = await packagePolicyService.assignPackageStream( ({ - datasets: [ + data_streams: [ { - name: 'package.dataset1', + dataset: 'package.dataset1', type: 'logs', streams: [{ input: 'log', template_path: 'some_template_path.yml' }], }, ], - config_templates: [ + policy_templates: [ { inputs: [{ type: 'log' }], }, @@ -130,7 +130,7 @@ describe('Package policy service', () => { }, streams: [ { - id: 'dataset01', + id: 'datastream01', data_stream: { dataset: 'package.dataset1', type: 'logs' }, enabled: true, }, @@ -150,7 +150,7 @@ describe('Package policy service', () => { }, streams: [ { - id: 'dataset01', + id: 'datastream01', data_stream: { dataset: 'package.dataset1', type: 'logs' }, enabled: true, compiled_stream: { diff --git a/x-pack/plugins/ingest_manager/server/services/package_policy.ts b/x-pack/plugins/ingest_manager/server/services/package_policy.ts index 3a02544250ff0..d91f6e8580fc3 100644 --- a/x-pack/plugins/ingest_manager/server/services/package_policy.ts +++ b/x-pack/plugins/ingest_manager/server/services/package_policy.ts @@ -375,19 +375,19 @@ async function _assignPackageStreamToStream( return { ...stream, compiled_stream: undefined }; } const datasetPath = getDataset(stream.data_stream.dataset); - const packageDatasets = pkgInfo.datasets; - if (!packageDatasets) { - throw new Error('Stream template not found, no datasets'); + const packageDataStreams = pkgInfo.data_streams; + if (!packageDataStreams) { + throw new Error('Stream template not found, no data streams'); } - const packageDataset = packageDatasets.find( - (pkgDataset) => pkgDataset.name === stream.data_stream.dataset + const packageDataStream = packageDataStreams.find( + (pkgDataStream) => pkgDataStream.dataset === stream.data_stream.dataset ); - if (!packageDataset) { + if (!packageDataStream) { throw new Error(`Stream template not found, unable to find dataset ${datasetPath}`); } - const streamFromPkg = (packageDataset.streams || []).find( + const streamFromPkg = (packageDataStream.streams || []).find( (pkgStream) => pkgStream.input === input.type ); if (!streamFromPkg) { diff --git a/x-pack/plugins/ingest_manager/server/types/index.tsx b/x-pack/plugins/ingest_manager/server/types/index.tsx index b43d6355c479a..fc5ba1af196ad 100644 --- a/x-pack/plugins/ingest_manager/server/types/index.tsx +++ b/x-pack/plugins/ingest_manager/server/types/index.tsx @@ -45,7 +45,7 @@ export { InstallationStatus, PackageInfo, RegistryVarsEntry, - Dataset, + RegistryDataStream, RegistryElasticsearch, AssetReference, EsAssetReference, diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/direct_upload_packages/apache_0.1.4.tar.gz b/x-pack/test/ingest_manager_api_integration/apis/fixtures/direct_upload_packages/apache_0.1.4.tar.gz index cc983f6ac6d1aa53ac1b4a5b38b020a072a2326a..9cc4009d35c31da9e555cc98a0235f55efcf565e 100644 GIT binary patch delta 461888 zcmV(oK=Hr(yd&eUBYz)@2mq#7a$f)g?7RhBT+6aA41pLV5FkK;hakayaCZ;xOkfz? z-3bY0=`pfTKezw2k>a<80qNg8Gq<$XsGe1X=niq04O|$ z|0aEYf|Z4(hWV{3`e5V#knfgFTl+sq|51;>=>H+m_`ChJG%PiM7MA8<4WoZ$U-+N2 zKP?@Akp@7|aBF`Cn&0;S_uwb{QvxaZWPmc3Cg$LOrHtG50MOIlZGRfZfAoKP1_pX4 zJnDa?5_jSMa)0|n-A8)}bq@+kTmytBDTAko_XFRaK|Q{`X>V_V+xy#h+iw~Ei$g&=s#u$ z*jr8$C=isz&l*xd|2^#vo&J{oOD+CN|4A;?A97)!^q`EObbgZh7-RZ>q}(C%uhd^k z{E_;Tynn}d-~K*;GPq6Cyln+zD2<=%YN-B?>37Kf2cBPQ@DtC^?Tz;@>Sn+3zagN% zlSlCXYt{IT-}sIH4e@P!!23bDe$e;dDfEx@dp{`b-|{^BLGgZ2t{?RMcMAQ3@7@mz z`-49EL7)Agct0rD5BmN){V`}k|JZy$|Bwv*V}FMN{o{ZF8t(_?`Y%=aH-6*)8o+!f z&%Vw7{CDsFf8#fPZ;m{m(#8Q^Q!}UmgbZUyuKwr=el|9slv~z|ZkNCLoLd zhJPTi|GNF@0JOBf?f>tUsZ-s(wO~K}RMqp!0 z4a3`~Mkdx8n%{J>G`9l7flQ3G^uCqxN6znS7s|iXBUWdmWTvDhhPzb=e5<0aiGSq} z2^Quc7Q8>ky6<@?zSon|)K~}ZTVUHy_5DfvZ>bh~_P2>Nv@{I1G&Ic2-*bGgm63)H znCg2ef0y#Tc%ZJOrKuLs0&IS(BJj31Sz1}#AyPrZ z{;ng~ z+}y;&CFc?qfoN#Mk`XmF@^=vV2$1hw3z8WZxEm6gHnCy(JNmS`&wsdTa0b+znPp zR~Ro$Yw(!WM%$*SYJB?e*-=d|uk~`cMekMjrzyLWDOTeb?BiZ8y0nz>dx%G|#vxFT zKmF>Gg>@xG?SFiM2Y-$H>¨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 z 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%0Acucd;*@(zH6@Ggf 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 z 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

5ar1Tk&F0L-#vjSQ{qA4}DPqoG6o=qzS)e0SK; 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

)OH<*JXh_HI8qMWb+S=}JlTgYV3gMc)jv_|c+ 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

l1zon}hv0 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
    _)` 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

    {S=qe* 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%0A7B! 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 STmT3F0RR6Xxx!HZyb1vQQ#9WI diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.1.0/dataset/test_logs/elasticsearch/ilm_policy/all_assets.json b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.1.0/data_stream/test_logs/elasticsearch/ilm_policy/all_assets.json similarity index 100% rename from x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.1.0/dataset/test_logs/elasticsearch/ilm_policy/all_assets.json rename to x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.1.0/data_stream/test_logs/elasticsearch/ilm_policy/all_assets.json diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.1.0/dataset/test_logs/elasticsearch/ingest_pipeline/default.yml b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.1.0/data_stream/test_logs/elasticsearch/ingest_pipeline/default.yml similarity index 100% rename from x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.1.0/dataset/test_logs/elasticsearch/ingest_pipeline/default.yml rename to x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.1.0/data_stream/test_logs/elasticsearch/ingest_pipeline/default.yml diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.1.0/dataset/test_logs/elasticsearch/ingest_pipeline/pipeline1.yml b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.1.0/data_stream/test_logs/elasticsearch/ingest_pipeline/pipeline1.yml similarity index 100% rename from x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.1.0/dataset/test_logs/elasticsearch/ingest_pipeline/pipeline1.yml rename to x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.1.0/data_stream/test_logs/elasticsearch/ingest_pipeline/pipeline1.yml diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.1.0/dataset/test_logs/elasticsearch/ingest_pipeline/pipeline2.yml b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.1.0/data_stream/test_logs/elasticsearch/ingest_pipeline/pipeline2.yml similarity index 100% rename from x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.1.0/dataset/test_logs/elasticsearch/ingest_pipeline/pipeline2.yml rename to x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.1.0/data_stream/test_logs/elasticsearch/ingest_pipeline/pipeline2.yml diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.1.0/dataset/test_logs/fields/ecs.yml b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.1.0/data_stream/test_logs/fields/ecs.yml similarity index 100% rename from x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.1.0/dataset/test_logs/fields/ecs.yml rename to x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.1.0/data_stream/test_logs/fields/ecs.yml diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.1.0/dataset/test_logs/fields/fields.yml b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.1.0/data_stream/test_logs/fields/fields.yml similarity index 100% rename from x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.1.0/dataset/test_logs/fields/fields.yml rename to x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.1.0/data_stream/test_logs/fields/fields.yml diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/multiple_versions/0.1.0/dataset/test/manifest.yml b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.1.0/data_stream/test_logs/manifest.yml similarity index 100% rename from x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/multiple_versions/0.1.0/dataset/test/manifest.yml rename to x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.1.0/data_stream/test_logs/manifest.yml diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.1.0/dataset/test_metrics/fields/ecs.yml b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.1.0/data_stream/test_metrics/fields/ecs.yml similarity index 100% rename from x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.1.0/dataset/test_metrics/fields/ecs.yml rename to x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.1.0/data_stream/test_metrics/fields/ecs.yml diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.1.0/dataset/test_metrics/fields/fields.yml b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.1.0/data_stream/test_metrics/fields/fields.yml similarity index 100% rename from x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.1.0/dataset/test_metrics/fields/fields.yml rename to x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.1.0/data_stream/test_metrics/fields/fields.yml diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.1.0/dataset/test_metrics/manifest.yml b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.1.0/data_stream/test_metrics/manifest.yml similarity index 100% rename from x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.1.0/dataset/test_metrics/manifest.yml rename to x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.1.0/data_stream/test_metrics/manifest.yml diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.2.0/dataset/test_logs/elasticsearch/ilm_policy/all_assets.json b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.2.0/data_stream/test_logs/elasticsearch/ilm_policy/all_assets.json similarity index 100% rename from x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.2.0/dataset/test_logs/elasticsearch/ilm_policy/all_assets.json rename to x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.2.0/data_stream/test_logs/elasticsearch/ilm_policy/all_assets.json diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.2.0/dataset/test_logs/elasticsearch/ingest_pipeline/default.yml b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.2.0/data_stream/test_logs/elasticsearch/ingest_pipeline/default.yml similarity index 100% rename from x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.2.0/dataset/test_logs/elasticsearch/ingest_pipeline/default.yml rename to x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.2.0/data_stream/test_logs/elasticsearch/ingest_pipeline/default.yml diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.2.0/dataset/test_logs/elasticsearch/ingest_pipeline/pipeline1.yml b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.2.0/data_stream/test_logs/elasticsearch/ingest_pipeline/pipeline1.yml similarity index 100% rename from x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.2.0/dataset/test_logs/elasticsearch/ingest_pipeline/pipeline1.yml rename to x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.2.0/data_stream/test_logs/elasticsearch/ingest_pipeline/pipeline1.yml diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.2.0/dataset/test_logs/fields/ecs.yml b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.2.0/data_stream/test_logs/fields/ecs.yml similarity index 100% rename from x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.2.0/dataset/test_logs/fields/ecs.yml rename to x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.2.0/data_stream/test_logs/fields/ecs.yml diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.2.0/dataset/test_logs/fields/fields.yml b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.2.0/data_stream/test_logs/fields/fields.yml similarity index 100% rename from x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.2.0/dataset/test_logs/fields/fields.yml rename to x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.2.0/data_stream/test_logs/fields/fields.yml diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.2.0/dataset/test_logs/manifest.yml b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.2.0/data_stream/test_logs/manifest.yml similarity index 100% rename from x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.2.0/dataset/test_logs/manifest.yml rename to x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.2.0/data_stream/test_logs/manifest.yml diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.2.0/dataset/test_logs2/fields/ecs.yml b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.2.0/data_stream/test_logs2/fields/ecs.yml similarity index 100% rename from x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.2.0/dataset/test_logs2/fields/ecs.yml rename to x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.2.0/data_stream/test_logs2/fields/ecs.yml diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.2.0/dataset/test_logs2/fields/fields.yml b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.2.0/data_stream/test_logs2/fields/fields.yml similarity index 100% rename from x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.2.0/dataset/test_logs2/fields/fields.yml rename to x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.2.0/data_stream/test_logs2/fields/fields.yml diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.2.0/dataset/test_logs2/manifest.yml b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.2.0/data_stream/test_logs2/manifest.yml similarity index 100% rename from x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.2.0/dataset/test_logs2/manifest.yml rename to x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.2.0/data_stream/test_logs2/manifest.yml diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.2.0/dataset/test_metrics/fields/ecs.yml b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.2.0/data_stream/test_metrics/fields/ecs.yml similarity index 100% rename from x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.2.0/dataset/test_metrics/fields/ecs.yml rename to x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.2.0/data_stream/test_metrics/fields/ecs.yml diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.2.0/dataset/test_metrics/fields/fields.yml b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.2.0/data_stream/test_metrics/fields/fields.yml similarity index 100% rename from x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.2.0/dataset/test_metrics/fields/fields.yml rename to x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.2.0/data_stream/test_metrics/fields/fields.yml diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.2.0/dataset/test_metrics/manifest.yml b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.2.0/data_stream/test_metrics/manifest.yml similarity index 100% rename from x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.2.0/dataset/test_metrics/manifest.yml rename to x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.2.0/data_stream/test_metrics/manifest.yml diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.1.0/dataset/test_logs/elasticsearch/ilm_policy/all_assets.json b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.1.0/data_stream/test_logs/elasticsearch/ilm_policy/all_assets.json similarity index 100% rename from x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.1.0/dataset/test_logs/elasticsearch/ilm_policy/all_assets.json rename to x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.1.0/data_stream/test_logs/elasticsearch/ilm_policy/all_assets.json diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.1.0/dataset/test_logs/elasticsearch/ingest_pipeline/default.yml b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.1.0/data_stream/test_logs/elasticsearch/ingest_pipeline/default.yml similarity index 100% rename from x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.1.0/dataset/test_logs/elasticsearch/ingest_pipeline/default.yml rename to x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.1.0/data_stream/test_logs/elasticsearch/ingest_pipeline/default.yml diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.1.0/dataset/test_logs/fields/ecs.yml b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.1.0/data_stream/test_logs/fields/ecs.yml similarity index 100% rename from x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.1.0/dataset/test_logs/fields/ecs.yml rename to x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.1.0/data_stream/test_logs/fields/ecs.yml diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.1.0/dataset/test_logs/fields/fields.yml b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.1.0/data_stream/test_logs/fields/fields.yml similarity index 100% rename from x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.1.0/dataset/test_logs/fields/fields.yml rename to x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.1.0/data_stream/test_logs/fields/fields.yml diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.1.0/dataset/test_logs/manifest.yml b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.1.0/data_stream/test_logs/manifest.yml similarity index 100% rename from x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.1.0/dataset/test_logs/manifest.yml rename to x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.1.0/data_stream/test_logs/manifest.yml diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.1.0/dataset/test_metrics/fields/ecs.yml b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.1.0/data_stream/test_metrics/fields/ecs.yml similarity index 100% rename from x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.1.0/dataset/test_metrics/fields/ecs.yml rename to x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.1.0/data_stream/test_metrics/fields/ecs.yml diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.1.0/dataset/test_metrics/fields/fields.yml b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.1.0/data_stream/test_metrics/fields/fields.yml similarity index 100% rename from x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.1.0/dataset/test_metrics/fields/fields.yml rename to x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.1.0/data_stream/test_metrics/fields/fields.yml diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.1.0/dataset/test_metrics/manifest.yml b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.1.0/data_stream/test_metrics/manifest.yml similarity index 100% rename from x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.1.0/dataset/test_metrics/manifest.yml rename to x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.1.0/data_stream/test_metrics/manifest.yml diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.1.0/manifest.yml b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.1.0/manifest.yml index 0ab43760b7ee8..28979cca0771b 100644 --- a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.1.0/manifest.yml +++ b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.1.0/manifest.yml @@ -1,5 +1,5 @@ format_version: 1.0.0 -name: datastreams +name: datastreams title: datastream test description: This is a test package for testing that datastreams rollover when mappings are incompatible version: 0.1.0 @@ -13,8 +13,3 @@ requirement: versions: '>7.7.0' kibana: versions: '>7.7.0' - -icons: - - src: '/img/logo_overrides_64_color.svg' - size: '16x16' - type: 'image/svg+xml' diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.2.0/dataset/test_logs/elasticsearch/ilm_policy/all_assets.json b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.2.0/data_stream/test_logs/elasticsearch/ilm_policy/all_assets.json similarity index 100% rename from x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.2.0/dataset/test_logs/elasticsearch/ilm_policy/all_assets.json rename to x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.2.0/data_stream/test_logs/elasticsearch/ilm_policy/all_assets.json diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.2.0/dataset/test_logs/elasticsearch/ingest_pipeline/default.yml b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.2.0/data_stream/test_logs/elasticsearch/ingest_pipeline/default.yml similarity index 100% rename from x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.2.0/dataset/test_logs/elasticsearch/ingest_pipeline/default.yml rename to x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.2.0/data_stream/test_logs/elasticsearch/ingest_pipeline/default.yml diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.2.0/dataset/test_logs/fields/ecs.yml b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.2.0/data_stream/test_logs/fields/ecs.yml similarity index 100% rename from x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.2.0/dataset/test_logs/fields/ecs.yml rename to x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.2.0/data_stream/test_logs/fields/ecs.yml diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.2.0/dataset/test_logs/fields/fields.yml b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.2.0/data_stream/test_logs/fields/fields.yml similarity index 100% rename from x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.2.0/dataset/test_logs/fields/fields.yml rename to x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.2.0/data_stream/test_logs/fields/fields.yml diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.2.0/dataset/test_logs/manifest.yml b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.2.0/data_stream/test_logs/manifest.yml similarity index 100% rename from x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.2.0/dataset/test_logs/manifest.yml rename to x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.2.0/data_stream/test_logs/manifest.yml diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.2.0/dataset/test_metrics/fields/ecs.yml b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.2.0/data_stream/test_metrics/fields/ecs.yml similarity index 100% rename from x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.2.0/dataset/test_metrics/fields/ecs.yml rename to x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.2.0/data_stream/test_metrics/fields/ecs.yml diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.2.0/dataset/test_metrics/fields/fields.yml b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.2.0/data_stream/test_metrics/fields/fields.yml similarity index 100% rename from x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.2.0/dataset/test_metrics/fields/fields.yml rename to x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.2.0/data_stream/test_metrics/fields/fields.yml diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.2.0/dataset/test_metrics/manifest.yml b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.2.0/data_stream/test_metrics/manifest.yml similarity index 100% rename from x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.2.0/dataset/test_metrics/manifest.yml rename to x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.2.0/data_stream/test_metrics/manifest.yml diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.2.0/manifest.yml b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.2.0/manifest.yml index 1aa1410bd0aef..b389a86702fa8 100644 --- a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.2.0/manifest.yml +++ b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.2.0/manifest.yml @@ -13,8 +13,3 @@ requirement: versions: '>7.7.0' kibana: versions: '>7.7.0' - -icons: - - src: '/img/logo_overrides_64_color.svg' - size: '16x16' - type: 'image/svg+xml' diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/multiple_versions/0.1.0/dataset/test/fields/fields.yml b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/multiple_versions/0.1.0/data_stream/test/fields/fields.yml similarity index 100% rename from x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/multiple_versions/0.1.0/dataset/test/fields/fields.yml rename to x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/multiple_versions/0.1.0/data_stream/test/fields/fields.yml diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/multiple_versions/0.2.0/dataset/test/manifest.yml b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/multiple_versions/0.1.0/data_stream/test/manifest.yml similarity index 100% rename from x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/multiple_versions/0.2.0/dataset/test/manifest.yml rename to x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/multiple_versions/0.1.0/data_stream/test/manifest.yml diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/multiple_versions/0.1.0/manifest.yml b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/multiple_versions/0.1.0/manifest.yml index 32c626b115739..f4b6eccbda957 100644 --- a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/multiple_versions/0.1.0/manifest.yml +++ b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/multiple_versions/0.1.0/manifest.yml @@ -1,6 +1,6 @@ format_version: 1.0.0 -name: multiple_versions -title: Package install/update test +name: multiple_versions +title: Package install/update test description: This is a test package for installing or updating a package version: 0.1.0 categories: [] @@ -13,8 +13,3 @@ requirement: versions: '>7.7.0' kibana: versions: '>7.7.0' - -icons: - - src: '/img/logo_overrides_64_color.svg' - size: '16x16' - type: 'image/svg+xml' diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/multiple_versions/0.2.0/dataset/test/fields/fields.yml b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/multiple_versions/0.2.0/data_stream/test/fields/fields.yml similarity index 100% rename from x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/multiple_versions/0.2.0/dataset/test/fields/fields.yml rename to x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/multiple_versions/0.2.0/data_stream/test/fields/fields.yml diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/multiple_versions/0.3.0/dataset/test/manifest.yml b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/multiple_versions/0.2.0/data_stream/test/manifest.yml similarity index 100% rename from x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/multiple_versions/0.3.0/dataset/test/manifest.yml rename to x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/multiple_versions/0.2.0/data_stream/test/manifest.yml diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/multiple_versions/0.2.0/manifest.yml b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/multiple_versions/0.2.0/manifest.yml index 773903a69e7f7..be7c93484d987 100644 --- a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/multiple_versions/0.2.0/manifest.yml +++ b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/multiple_versions/0.2.0/manifest.yml @@ -1,6 +1,6 @@ format_version: 1.0.0 -name: multiple_versions -title: Package install/update test +name: multiple_versions +title: Package install/update test description: This is a test package for installing or updating a packagee version: 0.2.0 categories: [] @@ -13,8 +13,3 @@ requirement: versions: '>7.7.0' kibana: versions: '>7.7.0' - -icons: - - src: '/img/logo_overrides_64_color.svg' - size: '16x16' - type: 'image/svg+xml' diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/multiple_versions/0.3.0/dataset/test/fields/fields.yml b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/multiple_versions/0.3.0/data_stream/test/fields/fields.yml similarity index 100% rename from x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/multiple_versions/0.3.0/dataset/test/fields/fields.yml rename to x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/multiple_versions/0.3.0/data_stream/test/fields/fields.yml diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/overrides/0.1.0/dataset/test/manifest.yml b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/multiple_versions/0.3.0/data_stream/test/manifest.yml similarity index 100% rename from x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/overrides/0.1.0/dataset/test/manifest.yml rename to x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/multiple_versions/0.3.0/data_stream/test/manifest.yml diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/multiple_versions/0.3.0/manifest.yml b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/multiple_versions/0.3.0/manifest.yml index 49c85994d2c2c..630788b00fca7 100644 --- a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/multiple_versions/0.3.0/manifest.yml +++ b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/multiple_versions/0.3.0/manifest.yml @@ -1,6 +1,6 @@ format_version: 1.0.0 name: multiple_versions -title: Package install/update test +title: Package install/update test description: This is a test package for installing or updating a package version: 0.3.0 categories: [] @@ -13,8 +13,3 @@ requirement: versions: '>7.7.0' kibana: versions: '>7.7.0' - -icons: - - src: '/img/logo_overrides_64_color.svg' - size: '16x16' - type: 'image/svg+xml' diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/overrides/0.1.0/dataset/test/fields/fields.yml b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/overrides/0.1.0/data_stream/test/fields/fields.yml similarity index 100% rename from x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/overrides/0.1.0/dataset/test/fields/fields.yml rename to x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/overrides/0.1.0/data_stream/test/fields/fields.yml diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.1.0/dataset/test_logs/manifest.yml b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/overrides/0.1.0/data_stream/test/manifest.yml similarity index 77% rename from x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.1.0/dataset/test_logs/manifest.yml rename to x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/overrides/0.1.0/data_stream/test/manifest.yml index 8cd522e2845bb..9ac3c68a0be9e 100644 --- a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/datastreams/0.1.0/dataset/test_logs/manifest.yml +++ b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/overrides/0.1.0/data_stream/test/manifest.yml @@ -6,4 +6,4 @@ elasticsearch: index_template.mappings: dynamic: false index_template.settings: - index.lifecycle.name: reference \ No newline at end of file + index.lifecycle.name: reference diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/prerelease/0.1.0-dev.0+abc/dataset/test/fields/fields.yml b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/prerelease/0.1.0-dev.0+abc/data_stream/test/fields/fields.yml similarity index 100% rename from x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/prerelease/0.1.0-dev.0+abc/dataset/test/fields/fields.yml rename to x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/prerelease/0.1.0-dev.0+abc/data_stream/test/fields/fields.yml diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/prerelease/0.1.0-dev.0+abc/dataset/test/manifest.yml b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/prerelease/0.1.0-dev.0+abc/data_stream/test/manifest.yml similarity index 100% rename from x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/prerelease/0.1.0-dev.0+abc/dataset/test/manifest.yml rename to x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/prerelease/0.1.0-dev.0+abc/data_stream/test/manifest.yml diff --git a/x-pack/test/ingest_manager_api_integration/apis/index.js b/x-pack/test/ingest_manager_api_integration/apis/index.js index 7c1ebef337baa..ec509e1485a9f 100644 --- a/x-pack/test/ingest_manager_api_integration/apis/index.js +++ b/x-pack/test/ingest_manager_api_integration/apis/index.js @@ -5,7 +5,7 @@ */ export default function ({ loadTestFile }) { - describe('Ingest Manager Endpoints', function () { + describe.skip('Ingest Manager Endpoints', function () { this.tags('ciGroup7'); // Ingest Manager setup loadTestFile(require.resolve('./setup')); diff --git a/x-pack/test/security_solution_endpoint/apps/endpoint/index.ts b/x-pack/test/security_solution_endpoint/apps/endpoint/index.ts index 654aa18fba523..c3862d130202d 100644 --- a/x-pack/test/security_solution_endpoint/apps/endpoint/index.ts +++ b/x-pack/test/security_solution_endpoint/apps/endpoint/index.ts @@ -13,7 +13,7 @@ import { export default function (providerContext: FtrProviderContext) { const { loadTestFile, getService } = providerContext; - describe('endpoint', function () { + describe.skip('endpoint', function () { this.tags('ciGroup7'); const ingestManager = getService('ingestManager'); const log = getService('log'); diff --git a/x-pack/test/security_solution_endpoint_api_int/apis/index.ts b/x-pack/test/security_solution_endpoint_api_int/apis/index.ts index 3d344c1b3b51b..6c5764faed631 100644 --- a/x-pack/test/security_solution_endpoint_api_int/apis/index.ts +++ b/x-pack/test/security_solution_endpoint_api_int/apis/index.ts @@ -10,7 +10,7 @@ import { getRegistryUrl as getRegistryUrlFromIngest } from '../../../plugins/ing export default function endpointAPIIntegrationTests(providerContext: FtrProviderContext) { const { loadTestFile, getService } = providerContext; - describe('Endpoint plugin', function () { + describe.skip('Endpoint plugin', function () { const ingestManager = getService('ingestManager'); this.tags('ciGroup7'); From b3c37cf94cc461cf04511b6acb3880439f8fd858 Mon Sep 17 00:00:00 2001 From: Jen Huang Date: Thu, 1 Oct 2020 11:09:59 -0700 Subject: [PATCH 06/50] [Fleet] Fix agent policy change action migration (#79046) * Fix agent policy change action migration for encrypted `data` property * Parse & re-stringify `config`->`policy` data --- .../plugins/ingest_manager/server/plugin.ts | 2 +- .../server/saved_objects/index.ts | 14 +++-- .../saved_objects/migrations/to_v7_10_0.ts | 52 ++++++++++++++----- 3 files changed, 50 insertions(+), 18 deletions(-) diff --git a/x-pack/plugins/ingest_manager/server/plugin.ts b/x-pack/plugins/ingest_manager/server/plugin.ts index f0f7bca29c99e..6237b6d9ba357 100644 --- a/x-pack/plugins/ingest_manager/server/plugin.ts +++ b/x-pack/plugins/ingest_manager/server/plugin.ts @@ -172,7 +172,7 @@ export class IngestManagerPlugin this.encryptedSavedObjectsSetup = deps.encryptedSavedObjects; this.cloud = deps.cloud; - registerSavedObjects(core.savedObjects); + registerSavedObjects(core.savedObjects, deps.encryptedSavedObjects); registerEncryptedSavedObjects(deps.encryptedSavedObjects); // Register feature diff --git a/x-pack/plugins/ingest_manager/server/saved_objects/index.ts b/x-pack/plugins/ingest_manager/server/saved_objects/index.ts index b3a8c7390176f..95433f896b9a3 100644 --- a/x-pack/plugins/ingest_manager/server/saved_objects/index.ts +++ b/x-pack/plugins/ingest_manager/server/saved_objects/index.ts @@ -33,7 +33,9 @@ import { * Please update typings in `/common/types` as well as * schemas in `/server/types` if mappings are updated. */ -const savedObjectTypes: { [key: string]: SavedObjectsType } = { +const getSavedObjectTypes = ( + encryptedSavedObjects: EncryptedSavedObjectsPluginSetup +): { [key: string]: SavedObjectsType } => ({ [GLOBAL_SETTINGS_SAVED_OBJECT_TYPE]: { name: GLOBAL_SETTINGS_SAVED_OBJECT_TYPE, hidden: false, @@ -111,7 +113,7 @@ const savedObjectTypes: { [key: string]: SavedObjectsType } = { }, }, migrations: { - '7.10.0': migrateAgentActionToV7100, + '7.10.0': migrateAgentActionToV7100(encryptedSavedObjects), }, }, [AGENT_EVENT_SAVED_OBJECT_TYPE]: { @@ -304,9 +306,13 @@ const savedObjectTypes: { [key: string]: SavedObjectsType } = { }, }, }, -}; +}); -export function registerSavedObjects(savedObjects: SavedObjectsServiceSetup) { +export function registerSavedObjects( + savedObjects: SavedObjectsServiceSetup, + encryptedSavedObjects: EncryptedSavedObjectsPluginSetup +) { + const savedObjectTypes = getSavedObjectTypes(encryptedSavedObjects); Object.values(savedObjectTypes).forEach((type) => { savedObjects.registerType(type); }); diff --git a/x-pack/plugins/ingest_manager/server/saved_objects/migrations/to_v7_10_0.ts b/x-pack/plugins/ingest_manager/server/saved_objects/migrations/to_v7_10_0.ts index 53af5ae42e410..2a49c135074e5 100644 --- a/x-pack/plugins/ingest_manager/server/saved_objects/migrations/to_v7_10_0.ts +++ b/x-pack/plugins/ingest_manager/server/saved_objects/migrations/to_v7_10_0.ts @@ -4,7 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -import { SavedObjectMigrationFn } from 'kibana/server'; +import { SavedObjectMigrationFn, SavedObjectUnsanitizedDoc } from 'kibana/server'; +import { EncryptedSavedObjectsPluginSetup } from '../../../../encrypted_saved_objects/server'; import { Agent, AgentEvent, @@ -94,17 +95,42 @@ export const migrateSettingsToV7100: SavedObjectMigrationFn< return settingsDoc; }; -export const migrateAgentActionToV7100: SavedObjectMigrationFn = ( - agentActionDoc -) => { - // @ts-expect-error - if (agentActionDoc.attributes.type === 'CONFIG_CHANGE') { - agentActionDoc.attributes.type = 'POLICY_CHANGE'; - if (agentActionDoc.attributes.data?.config) { - agentActionDoc.attributes.data.policy = agentActionDoc.attributes.data.config; - delete agentActionDoc.attributes.data.config; +export const migrateAgentActionToV7100 = ( + encryptedSavedObjects: EncryptedSavedObjectsPluginSetup +): SavedObjectMigrationFn => { + return encryptedSavedObjects.createMigration( + (agentActionDoc): agentActionDoc is SavedObjectUnsanitizedDoc => { + // @ts-expect-error + return agentActionDoc.attributes.type === 'CONFIG_CHANGE'; + }, + (agentActionDoc) => { + let agentActionData; + try { + agentActionData = agentActionDoc.attributes.data + ? JSON.parse(agentActionDoc.attributes.data) + : undefined; + } catch (e) { + // Silently swallow JSON parsing error + } + if (agentActionData && agentActionData.config) { + const { + attributes: { data, ...restOfAttributes }, + } = agentActionDoc; + const { config, ...restOfData } = agentActionData; + return { + ...agentActionDoc, + attributes: { + ...restOfAttributes, + type: 'POLICY_CHANGE', + data: JSON.stringify({ + ...restOfData, + policy: config, + }), + }, + }; + } else { + return agentActionDoc; + } } - } - - return agentActionDoc; + ); }; From bad6eab79280359d3773eb522950b88e632b9497 Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Thu, 1 Oct 2020 20:27:22 +0200 Subject: [PATCH 07/50] [ML] DF Analytics: Collapsable sections on results pages (#76641) - Fixes cell color coding based on influence score for outlier detection results page data grid. (Part of #77046) - Introduces expandable sections (). In contrast to plain accordions, the main idea of this component is that it should also provide some sort of useful summary when collapsed instead of just being an expandable title. For example, the "Analysis" section is collapsed by default, but still offers information like analysis type, source and destination index. This concept should allow us to keep the analytics results pages usable with more content (additional results, evaluations, visualizations) being added over time. - The "Analysis" section is a reuse of the expandable row from the analytics jobs list. Some design adjustments have been made to make it usable in both places. --- .../color_range_legend/color_range_legend.tsx | 18 +- .../data_frame_analytics/common/fields.ts | 2 + .../expandable_section.scss | 3 + .../expandable_section/expandable_section.tsx | 94 +++++++ .../components/expandable_section/index.ts | 7 + .../outlier_exploration.tsx | 247 ++++++++++++++---- .../outlier_exploration/use_outlier_data.ts | 24 +- .../pages/analytics_exploration/page.tsx | 28 +- .../expanded_row_details_pane.scss | 8 + .../expanded_row_details_pane.tsx | 39 ++- .../expanded_row_messages_pane.scss | 9 + .../expanded_row_messages_pane.tsx | 16 +- .../translations/translations/ja-JP.json | 4 - .../translations/translations/zh-CN.json | 4 - .../ml/data_frame_analytics_results.ts | 2 +- 15 files changed, 390 insertions(+), 115 deletions(-) create mode 100644 x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/expandable_section/expandable_section.scss create mode 100644 x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/expandable_section/expandable_section.tsx create mode 100644 x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/expandable_section/index.ts create mode 100644 x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/expanded_row_details_pane.scss create mode 100644 x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/expanded_row_messages_pane.scss diff --git a/x-pack/plugins/ml/public/application/components/color_range_legend/color_range_legend.tsx b/x-pack/plugins/ml/public/application/components/color_range_legend/color_range_legend.tsx index 25af3f0ec2f7f..a3b68b85aa9fa 100644 --- a/x-pack/plugins/ml/public/application/components/color_range_legend/color_range_legend.tsx +++ b/x-pack/plugins/ml/public/application/components/color_range_legend/color_range_legend.tsx @@ -7,7 +7,7 @@ import React, { useEffect, useRef, FC } from 'react'; import d3 from 'd3'; -import { EuiFlexGroup, EuiFlexItem, EuiText } from '@elastic/eui'; +import { EuiText } from '@elastic/eui'; const COLOR_RANGE_RESOLUTION = 10; @@ -134,15 +134,11 @@ export const ColorRangeLegend: FC = ({ } return ( - - - - {title} - - - - - - + <> + +

    {title}

    + + + ); }; diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/common/fields.ts b/x-pack/plugins/ml/public/application/data_frame_analytics/common/fields.ts index f9c9bf26a9d16..e4581f0a87bdd 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/common/fields.ts +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/common/fields.ts @@ -48,6 +48,8 @@ export const EXTENDED_NUMERICAL_TYPES = new Set([ // eslint-disable-next-line @typescript-eslint/naming-convention export const ML__ID_COPY = 'ml__id_copy'; +// eslint-disable-next-line @typescript-eslint/naming-convention +export const ML__INCREMENTAL_ID = 'ml__incremental_id'; export const isKeywordAndTextType = (fieldName: string): boolean => { const { fields } = newJobCapsService; diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/expandable_section/expandable_section.scss b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/expandable_section/expandable_section.scss new file mode 100644 index 0000000000000..e296744b2737d --- /dev/null +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/expandable_section/expandable_section.scss @@ -0,0 +1,3 @@ +.mlExpandableSection { + padding: 0 $euiSizeS $euiSizeS $euiSizeS; +} diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/expandable_section/expandable_section.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/expandable_section/expandable_section.tsx new file mode 100644 index 0000000000000..97fb8fd29e5a7 --- /dev/null +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/expandable_section/expandable_section.tsx @@ -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; + * you may not use this file except in compliance with the Elastic License. + */ + +import './expandable_section.scss'; + +import React, { useState, FC, ReactNode } from 'react'; + +import { + EuiBadge, + EuiButtonEmpty, + EuiFlexGroup, + EuiFlexItem, + EuiLoadingContent, + EuiPanel, + EuiText, +} from '@elastic/eui'; + +interface HeaderItem { + // id is used as the React key and to construct a data-test-subj + id: string; + label?: ReactNode; + value: ReactNode; +} + +const isHeaderItems = (arg: any): arg is HeaderItem[] => { + return Array.isArray(arg); +}; + +export interface ExpandableSectionProps { + content: ReactNode; + headerItems?: HeaderItem[] | 'loading'; + isExpanded?: boolean; + dataTestId: string; + title: ReactNode; +} + +export const ExpandableSection: FC = ({ + headerItems, + // For now we don't have a need for complete external control + // and just want to pass in a default value. If we wanted + // full external control we'd also need to add a onToggleExpanded() + // callback. + isExpanded: isExpandedDefault = true, + content, + dataTestId, + title, +}) => { + const [isExpanded, setIsExpanded] = useState(isExpandedDefault); + const toggleExpanded = () => { + setIsExpanded(!isExpanded); + }; + + return ( + +
    + + {title} + + {headerItems === 'loading' && } + {isHeaderItems(headerItems) && ( + + {headerItems.map(({ label, value, id }) => ( + + {label !== undefined && value !== undefined && ( + <> + +

    {label}

    +
    + {value} + + )} + {label === undefined && value} +
    + ))} +
    + )} +
    + {isExpanded && content} +
    + ); +}; diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/expandable_section/index.ts b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/expandable_section/index.ts new file mode 100644 index 0000000000000..ad7ce84902e87 --- /dev/null +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/expandable_section/index.ts @@ -0,0 +1,7 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export { ExpandableSection, ExpandableSectionProps } from './expandable_section'; diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/outlier_exploration/outlier_exploration.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/outlier_exploration/outlier_exploration.tsx index e165ee54acab8..7d7f5efcae321 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/outlier_exploration/outlier_exploration.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/outlier_exploration/outlier_exploration.tsx @@ -4,11 +4,20 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { useState, FC } from 'react'; +import React, { useEffect, useState, FC } from 'react'; import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; -import { EuiFlexGroup, EuiFlexItem, EuiHorizontalRule, EuiPanel, EuiSpacer } from '@elastic/eui'; +import { + EuiDataGridColumn, + EuiHorizontalRule, + EuiLoadingSpinner, + EuiSpacer, + EuiText, +} from '@elastic/eui'; + +import type { DataFrameAnalysisConfigType } from '../../../../../../../common/types/data_frame_analytics'; import { useColorRange, @@ -19,18 +28,100 @@ import { ColorRangeLegend } from '../../../../../components/color_range_legend'; import { DataGrid } from '../../../../../components/data_grid'; import { SavedSearchQuery } from '../../../../../contexts/ml'; import { getToastNotifications } from '../../../../../util/dependency_cache'; +import { ml } from '../../../../../services/ml_api_service'; -import { defaultSearchQuery, useResultsViewConfig } from '../../../../common'; +import { getAnalysisType, defaultSearchQuery, useResultsViewConfig } from '../../../../common'; -import { getTaskStateBadge } from '../../../analytics_management/components/analytics_list/use_columns'; +import { isGetDataFrameAnalyticsStatsResponseOk } from '../../../analytics_management/services/analytics_service/get_analytics'; + +import { + DataFrameAnalyticsListRow, + DATA_FRAME_MODE, +} from '../../../analytics_management/components/analytics_list/common'; +import { ExpandedRow } from '../../../analytics_management/components/analytics_list/expanded_row'; +import { ExpandableSection, ExpandableSectionProps } from '../expandable_section'; import { ExplorationQueryBar } from '../exploration_query_bar'; -import { ExplorationTitle } from '../exploration_title'; import { IndexPatternPrompt } from '../index_pattern_prompt'; import { getFeatureCount } from './common'; import { useOutlierData } from './use_outlier_data'; +const getAnalyticsSectionHeaderItems = ( + expandedRowItem: DataFrameAnalyticsListRow | undefined +): ExpandableSectionProps['headerItems'] => { + return expandedRowItem !== undefined + ? [ + { + id: 'analysisTypeLabel', + label: ( + + ), + value: expandedRowItem.job_type, + }, + { + id: 'analysisSourceIndexLabel', + label: ( + + ), + value: expandedRowItem.config.source.index, + }, + { + id: 'analysisDestinationIndexLabel', + label: ( + + ), + value: expandedRowItem.config.dest.index, + }, + ] + : 'loading'; +}; + +const getResultsSectionHeaderItems = ( + columnsWithCharts: EuiDataGridColumn[], + tableItems: Array>, + rowCount: number, + colorRange: ReturnType +): ExpandableSectionProps['headerItems'] => { + return columnsWithCharts.length > 0 && tableItems.length > 0 + ? [ + { + id: 'explorationTableTotalDocs', + label: ( + + ), + value: rowCount, + }, + { + id: 'colorRangeLegend', + value: ( + + ), + }, + ] + : 'loading'; +}; + export type TableItem = Record; interface ExplorationProps { @@ -38,12 +129,7 @@ interface ExplorationProps { } export const OutlierExploration: FC = React.memo(({ jobId }) => { - const explorationTitle = i18n.translate('xpack.ml.dataframe.analytics.exploration.jobIdTitle', { - defaultMessage: 'Outlier detection job ID {jobId}', - values: { jobId }, - }); - - const { indexPattern, jobConfig, jobStatus, needsDestIndexPattern } = useResultsViewConfig(jobId); + const { indexPattern, jobConfig, needsDestIndexPattern } = useResultsViewConfig(jobId); const [searchQuery, setSearchQuery] = useState(defaultSearchQuery); const outlierData = useOutlierData(indexPattern, jobConfig, searchQuery); @@ -55,47 +141,74 @@ export const OutlierExploration: FC = React.memo(({ jobId }) = jobConfig !== undefined ? getFeatureCount(jobConfig.dest.results_field, tableItems) : 1 ); - return ( - + const [expandedRowItem, setExpandedRowItem] = useState(); + + const fetchStats = async () => { + const analyticsConfigs = await ml.dataFrameAnalytics.getDataFrameAnalytics(jobId); + const analyticsStats = await ml.dataFrameAnalytics.getDataFrameAnalyticsStats(jobId); + + const config = analyticsConfigs.data_frame_analytics[0]; + const stats = isGetDataFrameAnalyticsStatsResponseOk(analyticsStats) + ? analyticsStats.data_frame_analytics[0] + : undefined; + + if (stats === undefined) { + return; + } + + const newExpandedRowItem: DataFrameAnalyticsListRow = { + checkpointing: {}, + config, + id: config.id, + job_type: getAnalysisType(config.analysis) as DataFrameAnalysisConfigType, + mode: DATA_FRAME_MODE.BATCH, + state: stats.state, + stats, + }; + + setExpandedRowItem(newExpandedRowItem); + }; + + useEffect(() => { + fetchStats(); + }, [jobConfig?.id]); + + // Analytics section header items and content + const analyticsSectionHeaderItems = getAnalyticsSectionHeaderItems(expandedRowItem); + const analyticsSectionContent = ( + <> + + {expandedRowItem === undefined && ( + + + + + + )} + {(columnsWithCharts.length > 0 || searchQuery !== defaultSearchQuery) && + indexPattern !== undefined && + jobConfig !== undefined && + columnsWithCharts.length > 0 && + tableItems.length > 0 && + expandedRowItem !== undefined && } + + ); + + // Results section header items and content + const resultsSectionHeaderItems = getResultsSectionHeaderItems( + columnsWithCharts, + tableItems, + outlierData.rowCount, + colorRange + ); + const resultsSectionContent = ( + <> {jobConfig !== undefined && needsDestIndexPattern && ( )} - - - - - {jobStatus !== undefined && ( - - {getTaskStateBadge(jobStatus)} - - )} - - {(columnsWithCharts.length > 0 || searchQuery !== defaultSearchQuery) && indexPattern !== undefined && ( <> - - - - - - - - - {columnsWithCharts.length > 0 && tableItems.length > 0 && ( = React.memo(({ jobId }) = )} )} - + + ); + + return ( + <> + {(columnsWithCharts.length > 0 || searchQuery !== defaultSearchQuery) && + indexPattern !== undefined && ( + <> + + + + )} + + + } + /> + + + + + } + /> + + ); }); diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/outlier_exploration/use_outlier_data.ts b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/outlier_exploration/use_outlier_data.ts index 151e5ea4e6feb..eded8e82a7919 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/outlier_exploration/use_outlier_data.ts +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/outlier_exploration/use_outlier_data.ts @@ -31,10 +31,19 @@ import { getToastNotifications } from '../../../../../util/dependency_cache'; import { getIndexData, getIndexFields, DataFrameAnalyticsConfig } from '../../../../common'; import { FEATURE_INFLUENCE } from '../../../../common/constants'; import { DEFAULT_RESULTS_FIELD } from '../../../../../../../common/constants/data_frame_analytics'; -import { sortExplorationResultsFields, ML__ID_COPY } from '../../../../common/fields'; +import { + sortExplorationResultsFields, + ML__ID_COPY, + ML__INCREMENTAL_ID, +} from '../../../../common/fields'; import { getFeatureCount, getOutlierScoreFieldName } from './common'; +interface FeatureInfluence { + feature_name: string; + influence: number; +} + export const useOutlierData = ( indexPattern: IndexPattern | undefined, jobConfig: DataFrameAnalyticsConfig | undefined, @@ -61,7 +70,7 @@ export const useOutlierData = ( // reduce default selected rows from 20 to 8 for performance reasons. 8, // by default, hide feature-influence columns and the doc id copy - (d) => !d.includes(`.${FEATURE_INFLUENCE}.`) && d !== ML__ID_COPY + (d) => !d.includes(`.${FEATURE_INFLUENCE}.`) && d !== ML__ID_COPY && d !== ML__INCREMENTAL_ID ); useEffect(() => { @@ -138,9 +147,16 @@ export const useOutlierData = ( // column with feature values get color coded by its corresponding influencer value if ( fullItem[resultsField] !== undefined && - fullItem[resultsField][`${FEATURE_INFLUENCE}.${columnId}`] !== undefined + fullItem[resultsField][FEATURE_INFLUENCE] !== undefined && + fullItem[resultsField][FEATURE_INFLUENCE].find( + (d: FeatureInfluence) => d.feature_name === columnId + ) !== undefined ) { - backgroundColor = colorRange(fullItem[resultsField][`${FEATURE_INFLUENCE}.${columnId}`]); + backgroundColor = colorRange( + fullItem[resultsField][FEATURE_INFLUENCE].find( + (d: FeatureInfluence) => d.feature_name === columnId + ).influence + ); } // column with influencer values get color coded by its own value diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/page.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/page.tsx index 4620bbd969fab..d2767a9612e3b 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/page.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/page.tsx @@ -6,11 +6,7 @@ import React, { Fragment, FC } from 'react'; -import { FormattedMessage } from '@kbn/i18n/react'; -import { i18n } from '@kbn/i18n'; - import { - EuiBetaBadge, EuiPage, EuiPageBody, EuiPageContentBody, @@ -41,32 +37,12 @@ export const Page: FC<{ -

    - -   - -

    +

    {jobId}

    - + {analysisType === ANALYSIS_CONFIG_TYPE.OUTLIER_DETECTION && ( )} diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/expanded_row_details_pane.scss b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/expanded_row_details_pane.scss new file mode 100644 index 0000000000000..efc9296350232 --- /dev/null +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/expanded_row_details_pane.scss @@ -0,0 +1,8 @@ +.mlExpandedRowDetails { + padding: 0 $euiSizeS $euiSizeS $euiSizeS; +} + +/* Hide the basic table's header */ +.mlExpandedRowDetailsSection thead { + display: none; +} diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/expanded_row_details_pane.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/expanded_row_details_pane.tsx index 71ca2b6f60492..41722f7559de2 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/expanded_row_details_pane.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/expanded_row_details_pane.tsx @@ -4,16 +4,11 @@ * you may not use this file except in compliance with the Elastic License. */ +import './expanded_row_details_pane.scss'; + import React, { Fragment, FC, ReactElement } from 'react'; -import { - EuiDescriptionList, - EuiFlexGroup, - EuiFlexItem, - EuiPanel, - EuiTitle, - EuiSpacer, -} from '@elastic/eui'; +import { EuiBasicTable, EuiFlexGroup, EuiFlexItem, EuiTitle, EuiSpacer } from '@elastic/eui'; export interface SectionItem { title: string; @@ -34,13 +29,33 @@ export const Section: FC = ({ section }) => { return null; } + const columns = [ + { + field: 'title', + name: '', + render: (v: SectionItem['title']) => {v}, + }, + { + field: 'description', + name: '', + render: (v: SectionItem['description']) => <>{v}, + }, + ]; + return ( - + <> {section.title} - - + + compressed + items={section.items} + columns={columns} + tableCaption={section.title} + tableLayout="auto" + className="mlExpandedRowDetailsSection" + /> + ); }; @@ -50,7 +65,7 @@ interface ExpandedRowDetailsPaneProps { export const ExpandedRowDetailsPane: FC = ({ sections }) => { return ( - + {sections .filter((s) => s.position === 'left') diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/expanded_row_messages_pane.scss b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/expanded_row_messages_pane.scss new file mode 100644 index 0000000000000..5a4d1b3190402 --- /dev/null +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/expanded_row_messages_pane.scss @@ -0,0 +1,9 @@ +.mlExpandedRowJobMessages { + padding: 0 $euiSizeS $euiSizeS $euiSizeS; +} + +/* override ML legacy class "job-messages-table" */ +.mlExpandedRowJobMessages .euiTable, .mlExpandedRowJobMessages .euiTableRowCell { + background-color: transparent !important; +} + diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/expanded_row_messages_pane.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/expanded_row_messages_pane.tsx index 942e335526d68..91925b7f0afe1 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/expanded_row_messages_pane.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/expanded_row_messages_pane.tsx @@ -4,6 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ +import './expanded_row_messages_pane.scss'; + import React, { FC, useState, useEffect, useCallback } from 'react'; import { i18n } from '@kbn/i18n'; import { ml } from '../../../../../services/ml_api_service'; @@ -43,11 +45,13 @@ export const ExpandedRowMessagesPane: FC = ({ analyticsId }) => { useRefreshAnalyticsList({ onRefresh: getMessages }); return ( - +
    + +
    ); }; diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 34c339023171e..bd9a66b48f633 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -10754,10 +10754,6 @@ "xpack.ml.dataframe.analytics.errorCallout.queryParsingErrorBody": "クエリ構文が無効であり、結果を返しませんでした。クエリ構文を確認し、再試行してください。", "xpack.ml.dataframe.analytics.errorCallout.queryParsingErrorTitle": "クエリをパースできません。", "xpack.ml.dataframe.analytics.exploration.colorRangeLegendTitle": "機能影響スコア", - "xpack.ml.dataframe.analytics.exploration.experimentalBadgeLabel": "実験的", - "xpack.ml.dataframe.analytics.exploration.experimentalBadgeTooltipContent": "データフレーム分析は実験段階の機能です。フィードバックをお待ちしています。", - "xpack.ml.dataframe.analytics.exploration.jobIdTitle": "外れ値検出ジョブID {jobId}", - "xpack.ml.dataframe.analytics.exploration.title": "分析の探索", "xpack.ml.dataframe.analytics.explorationResults.documentsShownHelpText": "予測があるドキュメントを示す", "xpack.ml.dataframe.analytics.explorationResults.fieldSelection": "{docFieldsCount, number}件中 showing {selectedFieldsLength, number}件の{docFieldsCount, plural, one {フィールド} other {フィールド}}", "xpack.ml.dataframe.analytics.explorationResults.firstDocumentsShownHelpText": "予測がある最初の{searchSize}のドキュメントを示す", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index f32b49fd4f2f0..3ce9278234005 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -10760,10 +10760,6 @@ "xpack.ml.dataframe.analytics.errorCallout.queryParsingErrorBody": "查询语法无效,未返回任何结果。请检查查询语法并重试。", "xpack.ml.dataframe.analytics.errorCallout.queryParsingErrorTitle": "无法解析查询。", "xpack.ml.dataframe.analytics.exploration.colorRangeLegendTitle": "功能影响分数", - "xpack.ml.dataframe.analytics.exploration.experimentalBadgeLabel": "实验性", - "xpack.ml.dataframe.analytics.exploration.experimentalBadgeTooltipContent": "数据帧分析为实验功能。我们很乐意听取您的反馈意见。", - "xpack.ml.dataframe.analytics.exploration.jobIdTitle": "离群值检测作业 ID {jobId}", - "xpack.ml.dataframe.analytics.exploration.title": "分析浏览", "xpack.ml.dataframe.analytics.explorationResults.documentsShownHelpText": "正在显示有相关预测存在的文档", "xpack.ml.dataframe.analytics.explorationResults.fieldSelection": "已选择 {docFieldsCount, number} 个{docFieldsCount, plural, one {字段} other {字段}}中的 {selectedFieldsLength, number} 个", "xpack.ml.dataframe.analytics.explorationResults.firstDocumentsShownHelpText": "正在显示有相关预测存在的前 {searchSize} 个文档", diff --git a/x-pack/test/functional/services/ml/data_frame_analytics_results.ts b/x-pack/test/functional/services/ml/data_frame_analytics_results.ts index b6a6ff8eb6c63..8a72badebd923 100644 --- a/x-pack/test/functional/services/ml/data_frame_analytics_results.ts +++ b/x-pack/test/functional/services/ml/data_frame_analytics_results.ts @@ -36,7 +36,7 @@ export function MachineLearningDataFrameAnalyticsResultsProvider({ }, async assertOutlierTablePanelExists() { - await testSubjects.existOrFail('mlDFAnalyticsOutlierExplorationTablePanel'); + await testSubjects.existOrFail('mlDFExpandableSection-results'); }, async assertResultsTableExists() { From 46084cbbe851c0128c3250bb6d9c00ee4a765eb8 Mon Sep 17 00:00:00 2001 From: nnamdifrankie <56440728+nnamdifrankie@users.noreply.github.com> Date: Thu, 1 Oct 2020 14:50:40 -0400 Subject: [PATCH 08/50] [Ingest]: add more test for transform index (#79154) --- .../apis/epm/install_remove_assets.ts | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/x-pack/test/ingest_manager_api_integration/apis/epm/install_remove_assets.ts b/x-pack/test/ingest_manager_api_integration/apis/epm/install_remove_assets.ts index d33d0445d1cd6..5170867d7b545 100644 --- a/x-pack/test/ingest_manager_api_integration/apis/epm/install_remove_assets.ts +++ b/x-pack/test/ingest_manager_api_integration/apis/epm/install_remove_assets.ts @@ -91,6 +91,14 @@ export default function (providerContext: FtrProviderContext) { }); expect(res.statusCode).equal(200); }); + it('should have created the index for the transform', async function () { + // the index is defined in the transform file + const res = await es.transport.request({ + method: 'GET', + path: `/logs-all_assets.test_log_current_default`, + }); + expect(res.statusCode).equal(200); + }); it('should have installed the kibana assets', async function () { const resIndexPatternLogs = await kibanaServer.savedObjects.get({ type: 'index-pattern', @@ -260,6 +268,19 @@ export default function (providerContext: FtrProviderContext) { ); expect(res.statusCode).equal(404); }); + it('should have deleted the index for the transform', async function () { + // the index is defined in the transform file + const res = await es.transport.request( + { + method: 'GET', + path: `/logs-all_assets.test_log_current_default`, + }, + { + ignore: [404], + } + ); + expect(res.statusCode).equal(404); + }); it('should have uninstalled the kibana assets', async function () { let resDashboard; try { From e08f6a38f61023496b7389659d768ca0685663fc Mon Sep 17 00:00:00 2001 From: Devon Thomson Date: Thu, 1 Oct 2020 14:52:28 -0400 Subject: [PATCH 09/50] Always Show Embeddable Panel Header in Edit Mode (#79152) * Always show header in edit mode --- .../embeddable/public/lib/panel/panel_header/panel_header.tsx | 2 +- test/functional/apps/dashboard/dashboard_options.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/embeddable/public/lib/panel/panel_header/panel_header.tsx b/src/plugins/embeddable/public/lib/panel/panel_header/panel_header.tsx index dea483efb349f..c538b98949a43 100644 --- a/src/plugins/embeddable/public/lib/panel/panel_header/panel_header.tsx +++ b/src/plugins/embeddable/public/lib/panel/panel_header/panel_header.tsx @@ -136,7 +136,7 @@ export function PanelHeader({ }: PanelHeaderProps) { const viewDescription = getViewDescription(embeddable); const showTitle = !hidePanelTitle && (!isViewMode || title || viewDescription !== ''); - const showPanelBar = badges.length > 0 || notifications.length > 0 || showTitle; + const showPanelBar = !isViewMode || badges.length > 0 || notifications.length > 0 || showTitle; const classes = classNames('embPanel__header', { // eslint-disable-next-line @typescript-eslint/naming-convention 'embPanel__header--floater': !showPanelBar, diff --git a/test/functional/apps/dashboard/dashboard_options.js b/test/functional/apps/dashboard/dashboard_options.js index d48e46e58f6d0..4e7c3f4cdc79b 100644 --- a/test/functional/apps/dashboard/dashboard_options.js +++ b/test/functional/apps/dashboard/dashboard_options.js @@ -44,7 +44,7 @@ export default function ({ getService, getPageObjects }) { await PageObjects.dashboard.checkHideTitle(); await retry.try(async () => { const titles = await PageObjects.dashboard.getPanelTitles(); - expect(titles[0]).to.eql(undefined); + expect(titles[0]).to.eql(''); }); }); From a8e3c8ac78acb3bf1ee0f76d353fae2d8bd0ade1 Mon Sep 17 00:00:00 2001 From: Lukas Olson Date: Thu, 1 Oct 2020 11:56:50 -0700 Subject: [PATCH 10/50] [Search] Fix timeout upgrade link (#79045) --- .../data/public/search/errors/timeout_error.test.tsx | 6 +++--- src/plugins/data/public/search/errors/timeout_error.tsx | 4 +--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/plugins/data/public/search/errors/timeout_error.test.tsx b/src/plugins/data/public/search/errors/timeout_error.test.tsx index 87b491b976ebc..ad3384c389fbf 100644 --- a/src/plugins/data/public/search/errors/timeout_error.test.tsx +++ b/src/plugins/data/public/search/errors/timeout_error.test.tsx @@ -37,9 +37,9 @@ describe('SearchTimeoutError', () => { expect(component.find('EuiButton').length).toBe(1); component.find('EuiButton').simulate('click'); - expect(startMock.application.navigateToApp).toHaveBeenCalledWith('management', { - path: '/kibana/indexPatterns', - }); + expect(startMock.application.navigateToUrl).toHaveBeenCalledWith( + 'https://www.elastic.co/subscriptions' + ); }); it('Should create contact admin message', () => { diff --git a/src/plugins/data/public/search/errors/timeout_error.tsx b/src/plugins/data/public/search/errors/timeout_error.tsx index 56aecb42f5326..a9ff0c3b38ae6 100644 --- a/src/plugins/data/public/search/errors/timeout_error.tsx +++ b/src/plugins/data/public/search/errors/timeout_error.tsx @@ -78,9 +78,7 @@ export class SearchTimeoutError extends KbnError { private onClick(application: ApplicationStart) { switch (this.mode) { case TimeoutErrorMode.UPGRADE: - application.navigateToApp('management', { - path: `/kibana/indexPatterns`, - }); + application.navigateToUrl('https://www.elastic.co/subscriptions'); break; case TimeoutErrorMode.CHANGE: application.navigateToApp('management', { From 12d01250249801d232bb01234c3044ef2fd6e642 Mon Sep 17 00:00:00 2001 From: Spencer Date: Thu, 1 Oct 2020 12:23:45 -0700 Subject: [PATCH 11/50] [babel] remove unused/unneeded babel plugins (#79173) Co-authored-by: spalger Co-authored-by: Elastic Machine --- packages/kbn-babel-preset/node_preset.js | 18 ------------------ packages/kbn-babel-preset/package.json | 4 +--- packages/kbn-babel-preset/webpack_preset.js | 19 ------------------- yarn.lock | 20 ++------------------ 4 files changed, 3 insertions(+), 58 deletions(-) diff --git a/packages/kbn-babel-preset/node_preset.js b/packages/kbn-babel-preset/node_preset.js index ee06e2588b022..45afe5d5ebc32 100644 --- a/packages/kbn-babel-preset/node_preset.js +++ b/packages/kbn-babel-preset/node_preset.js @@ -18,23 +18,6 @@ */ module.exports = (_, options = {}) => { - const overrides = []; - if (!process.env.ALLOW_PERFORMANCE_HOOKS_IN_TASK_MANAGER) { - overrides.push({ - test: [/x-pack[\/\\]legacy[\/\\]plugins[\/\\]task_manager/], - plugins: [ - [ - require.resolve('babel-plugin-filter-imports'), - { - imports: { - perf_hooks: ['performance'], - }, - }, - ], - ], - }); - } - return { presets: [ [ @@ -74,6 +57,5 @@ module.exports = (_, options = {}) => { }, ], ], - overrides, }; }; diff --git a/packages/kbn-babel-preset/package.json b/packages/kbn-babel-preset/package.json index d73294b4cf873..d6d1a78dd4a23 100644 --- a/packages/kbn-babel-preset/package.json +++ b/packages/kbn-babel-preset/package.json @@ -1,7 +1,7 @@ { "name": "@kbn/babel-preset", - "private": true, "version": "1.0.0", + "private": true, "license": "Apache-2.0", "dependencies": { "@babel/plugin-proposal-class-properties": "^7.10.4", @@ -13,10 +13,8 @@ "@babel/preset-react": "^7.10.4", "@babel/preset-typescript": "^7.10.4", "babel-plugin-add-module-exports": "^1.0.2", - "babel-plugin-filter-imports": "^3.0.0", "babel-plugin-styled-components": "^1.10.7", "babel-plugin-transform-define": "^1.3.1", - "babel-plugin-transform-imports": "^2.0.0", "react-is": "^16.8.0", "styled-components": "^5.1.0" } diff --git a/packages/kbn-babel-preset/webpack_preset.js b/packages/kbn-babel-preset/webpack_preset.js index 97462a579e3c4..a43d607edb17c 100644 --- a/packages/kbn-babel-preset/webpack_preset.js +++ b/packages/kbn-babel-preset/webpack_preset.js @@ -40,24 +40,5 @@ module.exports = () => { }, ], ], - // NOTE: we can enable this by default for everything as soon as we only have one instance - // of lodash across the entire project. For now we are just enabling it for siem - // as they are extensively using the lodash v4 - overrides: [ - { - test: [/x-pack[\/\\]legacy[\/\\]plugins[\/\\]siem[\/\\]public/], - plugins: [ - [ - require.resolve('babel-plugin-transform-imports'), - { - 'lodash/?(((\\w*)?/?)*)': { - transform: 'lodash/${1}/${member}', - preventFullImport: false, - }, - }, - ], - ], - }, - ], }; }; diff --git a/yarn.lock b/yarn.lock index 608207400ec71..876f938cfce88 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1098,7 +1098,7 @@ globals "^11.1.0" lodash "^4.17.19" -"@babel/types@^7.0.0", "@babel/types@^7.10.4", "@babel/types@^7.10.5", "@babel/types@^7.11.0", "@babel/types@^7.2.0", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4", "@babel/types@^7.4.0", "@babel/types@^7.4.4", "@babel/types@^7.9.5": +"@babel/types@^7.0.0", "@babel/types@^7.10.4", "@babel/types@^7.10.5", "@babel/types@^7.11.0", "@babel/types@^7.2.0", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4", "@babel/types@^7.9.5": version "7.11.0" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.11.0.tgz#2ae6bf1ba9ae8c3c43824e5861269871b206e90d" integrity sha512-O53yME4ZZI0jO1EVGtF1ePGl0LHirG4P1ibcD80XyzZcKhcMFeCXmh4Xb1ifGBIV233Qg12x4rBfQgA+tmOukA== @@ -7367,14 +7367,6 @@ babel-plugin-extract-import-names@1.6.16: dependencies: "@babel/helper-plugin-utils" "7.10.4" -babel-plugin-filter-imports@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/babel-plugin-filter-imports/-/babel-plugin-filter-imports-3.0.0.tgz#a849683837ad29960da17492fb32789ab6b09a11" - integrity sha512-p/chjzVTgCxUqyLM0q/pfWVZS7IJTwGQMwNg0LOvuQpKiTftQgZDtkGB8XvETnUw19rRcL7bJCTopSwibTN2tA== - dependencies: - "@babel/types" "^7.4.0" - lodash "^4.17.11" - babel-plugin-istanbul@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.0.0.tgz#e159ccdc9af95e0b570c75b4573b7c34d671d765" @@ -7528,14 +7520,6 @@ babel-plugin-transform-define@^1.3.1: lodash "^4.17.11" traverse "0.6.6" -babel-plugin-transform-imports@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-imports/-/babel-plugin-transform-imports-2.0.0.tgz#9e5f49f751a9d34ba8f4bb988c7e48ed2419c6b6" - integrity sha512-65ewumYJ85QiXdcB/jmiU0y0jg6eL6CdnDqQAqQ8JMOKh1E52VPG3NJzbVKWcgovUR5GBH8IWpCXQ7I8Q3wjgw== - dependencies: - "@babel/types" "^7.4" - is-valid-path "^0.1.1" - babel-plugin-transform-inline-consecutive-adds@^0.4.3: version "0.4.3" resolved "https://registry.yarnpkg.com/babel-plugin-transform-inline-consecutive-adds/-/babel-plugin-transform-inline-consecutive-adds-0.4.3.tgz#323d47a3ea63a83a7ac3c811ae8e6941faf2b0d1" @@ -17695,7 +17679,7 @@ is-valid-glob@^1.0.0: resolved "https://registry.yarnpkg.com/is-valid-glob/-/is-valid-glob-1.0.0.tgz#29bf3eff701be2d4d315dbacc39bc39fe8f601aa" integrity sha1-Kb8+/3Ab4tTTFdusw5vDn+j2Aao= -is-valid-path@0.1.1, is-valid-path@^0.1.1: +is-valid-path@0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/is-valid-path/-/is-valid-path-0.1.1.tgz#110f9ff74c37f663e1ec7915eb451f2db93ac9df" integrity sha1-EQ+f90w39mPh7HkV60UfLbk6yd8= From d0f8e5cbea83c9e8f1bd003e904922795c3346ca Mon Sep 17 00:00:00 2001 From: Caroline Horn <549577+cchaos@users.noreply.github.com> Date: Thu, 1 Oct 2020 15:49:14 -0400 Subject: [PATCH 12/50] Fix z-index of KQL Suggestions dropdown (#79184) Fix from #4084 --- src/plugins/data/public/ui/typeahead/suggestions_component.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/data/public/ui/typeahead/suggestions_component.tsx b/src/plugins/data/public/ui/typeahead/suggestions_component.tsx index 054c6318b9772..50ed9e9542d36 100644 --- a/src/plugins/data/public/ui/typeahead/suggestions_component.tsx +++ b/src/plugins/data/public/ui/typeahead/suggestions_component.tsx @@ -154,7 +154,7 @@ export class SuggestionsComponent extends Component { const StyledSuggestionsListDiv = styled.div` ${(props: { queryBarRect: DOMRect; verticalListPosition: string }) => ` position: absolute; - z-index: 999; + z-index: 4001; left: ${props.queryBarRect.left}px; width: ${props.queryBarRect.width}px; ${props.verticalListPosition}`} From 0a7462dc4acb79bc28873b4ce82a510aa624397c Mon Sep 17 00:00:00 2001 From: Lee Drengenberg Date: Thu, 1 Oct 2020 15:35:36 -0500 Subject: [PATCH 13/50] move apps lower in tree, add metricbeat dashboard screenshot test (#79001) --- .../services/common/failure_debugging.ts | 2 +- .../functional/services/common/screenshots.ts | 2 +- test/functional/services/common/snapshots.ts | 2 +- .../{test/functional => }/apps/ccs/ccs.js | 0 .../{test/functional => }/apps/ccs/index.js | 0 .../functional => }/apps/filebeat/filebeat.js | 0 .../functional => }/apps/filebeat/index.js | 0 .../apps/heartbeat/_heartbeat.js | 0 .../functional => }/apps/heartbeat/index.js | 0 .../apps/management/_index_pattern_create.js | 0 .../functional => }/apps/management/index.js | 0 .../apps/metricbeat/_metricbeat.js | 0 .../apps/metricbeat/_metricbeat_dashboard.js | 59 +++++++++++++++++++ .../functional => }/apps/metricbeat/index.js | 1 + .../apps/monitoring/_monitoring.js | 0 .../apps/monitoring/_monitoring_metricbeat.js | 0 .../functional => }/apps/monitoring/index.js | 0 .../apps/packetbeat/_packetbeat.js | 0 .../functional => }/apps/packetbeat/index.js | 0 .../functional => }/apps/reporting/index.js | 0 .../apps/reporting/reporting_watcher.js | 0 .../apps/reporting/reporting_watcher_png.js | 0 .../functional => }/apps/reporting/util.js | 0 .../apps/sample_data/e_commerce.js | 0 .../functional => }/apps/sample_data/index.js | 0 .../apps/telemetry/_telemetry.js | 0 .../functional => }/apps/telemetry/index.js | 0 .../apps/winlogbeat/_winlogbeat.js | 0 .../functional => }/apps/winlogbeat/index.js | 0 ...onfig.stack_functional_integration_base.js | 17 ++++-- .../configs/tests_list.js | 6 +- 31 files changed, 81 insertions(+), 8 deletions(-) rename x-pack/test/stack_functional_integration/{test/functional => }/apps/ccs/ccs.js (100%) rename x-pack/test/stack_functional_integration/{test/functional => }/apps/ccs/index.js (100%) rename x-pack/test/stack_functional_integration/{test/functional => }/apps/filebeat/filebeat.js (100%) rename x-pack/test/stack_functional_integration/{test/functional => }/apps/filebeat/index.js (100%) rename x-pack/test/stack_functional_integration/{test/functional => }/apps/heartbeat/_heartbeat.js (100%) rename x-pack/test/stack_functional_integration/{test/functional => }/apps/heartbeat/index.js (100%) rename x-pack/test/stack_functional_integration/{test/functional => }/apps/management/_index_pattern_create.js (100%) rename x-pack/test/stack_functional_integration/{test/functional => }/apps/management/index.js (100%) rename x-pack/test/stack_functional_integration/{test/functional => }/apps/metricbeat/_metricbeat.js (100%) create mode 100644 x-pack/test/stack_functional_integration/apps/metricbeat/_metricbeat_dashboard.js rename x-pack/test/stack_functional_integration/{test/functional => }/apps/metricbeat/index.js (86%) rename x-pack/test/stack_functional_integration/{test/functional => }/apps/monitoring/_monitoring.js (100%) rename x-pack/test/stack_functional_integration/{test/functional => }/apps/monitoring/_monitoring_metricbeat.js (100%) rename x-pack/test/stack_functional_integration/{test/functional => }/apps/monitoring/index.js (100%) rename x-pack/test/stack_functional_integration/{test/functional => }/apps/packetbeat/_packetbeat.js (100%) rename x-pack/test/stack_functional_integration/{test/functional => }/apps/packetbeat/index.js (100%) rename x-pack/test/stack_functional_integration/{test/functional => }/apps/reporting/index.js (100%) rename x-pack/test/stack_functional_integration/{test/functional => }/apps/reporting/reporting_watcher.js (100%) rename x-pack/test/stack_functional_integration/{test/functional => }/apps/reporting/reporting_watcher_png.js (100%) rename x-pack/test/stack_functional_integration/{test/functional => }/apps/reporting/util.js (100%) rename x-pack/test/stack_functional_integration/{test/functional => }/apps/sample_data/e_commerce.js (100%) rename x-pack/test/stack_functional_integration/{test/functional => }/apps/sample_data/index.js (100%) rename x-pack/test/stack_functional_integration/{test/functional => }/apps/telemetry/_telemetry.js (100%) rename x-pack/test/stack_functional_integration/{test/functional => }/apps/telemetry/index.js (100%) rename x-pack/test/stack_functional_integration/{test/functional => }/apps/winlogbeat/_winlogbeat.js (100%) rename x-pack/test/stack_functional_integration/{test/functional => }/apps/winlogbeat/index.js (100%) diff --git a/test/functional/services/common/failure_debugging.ts b/test/functional/services/common/failure_debugging.ts index aa67c455e0100..8b0e095b71ff8 100644 --- a/test/functional/services/common/failure_debugging.ts +++ b/test/functional/services/common/failure_debugging.ts @@ -38,7 +38,7 @@ export async function FailureDebuggingProvider({ getService }: FtrProviderContex const log = getService('log'); const browser = getService('browser'); - if (process.env.CI !== 'true') { + if (process.env.CI !== 'true' && !process.env.stack_functional_integration) { await del(config.get('failureDebugging.htmlDirectory')); } diff --git a/test/functional/services/common/screenshots.ts b/test/functional/services/common/screenshots.ts index daa55240f3eb7..5bce0d4cf6c87 100644 --- a/test/functional/services/common/screenshots.ts +++ b/test/functional/services/common/screenshots.ts @@ -40,7 +40,7 @@ export async function ScreenshotsProvider({ getService }: FtrProviderContext) { const FAILURE_DIRECTORY = resolve(config.get('screenshots.directory'), 'failure'); const BASELINE_DIRECTORY = resolve(config.get('screenshots.directory'), 'baseline'); - if (process.env.CI !== 'true') { + if (process.env.CI !== 'true' && !process.env.stack_functional_integration) { await del([SESSION_DIRECTORY, FAILURE_DIRECTORY]); } diff --git a/test/functional/services/common/snapshots.ts b/test/functional/services/common/snapshots.ts index 2e0b360e594e5..03eadff82e31f 100644 --- a/test/functional/services/common/snapshots.ts +++ b/test/functional/services/common/snapshots.ts @@ -35,7 +35,7 @@ export async function SnapshotsProvider({ getService }: FtrProviderContext) { const SESSION_DIRECTORY = resolve(config.get('snapshots.directory'), 'session'); const BASELINE_DIRECTORY = resolve(config.get('snapshots.directory'), 'baseline'); - if (process.env.CI !== 'true') { + if (process.env.CI !== 'true' && !process.env.stack_functional_integration) { await del([SESSION_DIRECTORY]); } diff --git a/x-pack/test/stack_functional_integration/test/functional/apps/ccs/ccs.js b/x-pack/test/stack_functional_integration/apps/ccs/ccs.js similarity index 100% rename from x-pack/test/stack_functional_integration/test/functional/apps/ccs/ccs.js rename to x-pack/test/stack_functional_integration/apps/ccs/ccs.js diff --git a/x-pack/test/stack_functional_integration/test/functional/apps/ccs/index.js b/x-pack/test/stack_functional_integration/apps/ccs/index.js similarity index 100% rename from x-pack/test/stack_functional_integration/test/functional/apps/ccs/index.js rename to x-pack/test/stack_functional_integration/apps/ccs/index.js diff --git a/x-pack/test/stack_functional_integration/test/functional/apps/filebeat/filebeat.js b/x-pack/test/stack_functional_integration/apps/filebeat/filebeat.js similarity index 100% rename from x-pack/test/stack_functional_integration/test/functional/apps/filebeat/filebeat.js rename to x-pack/test/stack_functional_integration/apps/filebeat/filebeat.js diff --git a/x-pack/test/stack_functional_integration/test/functional/apps/filebeat/index.js b/x-pack/test/stack_functional_integration/apps/filebeat/index.js similarity index 100% rename from x-pack/test/stack_functional_integration/test/functional/apps/filebeat/index.js rename to x-pack/test/stack_functional_integration/apps/filebeat/index.js diff --git a/x-pack/test/stack_functional_integration/test/functional/apps/heartbeat/_heartbeat.js b/x-pack/test/stack_functional_integration/apps/heartbeat/_heartbeat.js similarity index 100% rename from x-pack/test/stack_functional_integration/test/functional/apps/heartbeat/_heartbeat.js rename to x-pack/test/stack_functional_integration/apps/heartbeat/_heartbeat.js diff --git a/x-pack/test/stack_functional_integration/test/functional/apps/heartbeat/index.js b/x-pack/test/stack_functional_integration/apps/heartbeat/index.js similarity index 100% rename from x-pack/test/stack_functional_integration/test/functional/apps/heartbeat/index.js rename to x-pack/test/stack_functional_integration/apps/heartbeat/index.js diff --git a/x-pack/test/stack_functional_integration/test/functional/apps/management/_index_pattern_create.js b/x-pack/test/stack_functional_integration/apps/management/_index_pattern_create.js similarity index 100% rename from x-pack/test/stack_functional_integration/test/functional/apps/management/_index_pattern_create.js rename to x-pack/test/stack_functional_integration/apps/management/_index_pattern_create.js diff --git a/x-pack/test/stack_functional_integration/test/functional/apps/management/index.js b/x-pack/test/stack_functional_integration/apps/management/index.js similarity index 100% rename from x-pack/test/stack_functional_integration/test/functional/apps/management/index.js rename to x-pack/test/stack_functional_integration/apps/management/index.js diff --git a/x-pack/test/stack_functional_integration/test/functional/apps/metricbeat/_metricbeat.js b/x-pack/test/stack_functional_integration/apps/metricbeat/_metricbeat.js similarity index 100% rename from x-pack/test/stack_functional_integration/test/functional/apps/metricbeat/_metricbeat.js rename to x-pack/test/stack_functional_integration/apps/metricbeat/_metricbeat.js diff --git a/x-pack/test/stack_functional_integration/apps/metricbeat/_metricbeat_dashboard.js b/x-pack/test/stack_functional_integration/apps/metricbeat/_metricbeat_dashboard.js new file mode 100644 index 0000000000000..42f707fb77854 --- /dev/null +++ b/x-pack/test/stack_functional_integration/apps/metricbeat/_metricbeat_dashboard.js @@ -0,0 +1,59 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import expect from '@kbn/expect'; +import { REPO_ROOT } from '@kbn/dev-utils'; + +export default function ({ getService, getPageObjects, updateBaselines }) { + const screenshot = getService('screenshots'); + const browser = getService('browser'); + const esArchiver = getService('esArchiver'); + const PageObjects = getPageObjects(['common', 'dashboard', 'timePicker']); + + describe('check metricbeat Dashboard', function () { + before(async function () { + await esArchiver.load(`${REPO_ROOT}/../integration-test/test/es_archives/metricbeat`); + + // this navigateToActualURL takes the place of navigating to the dashboard landing page, + // filtering on the dashboard name, selecting it, setting the timepicker, and going to full screen + await PageObjects.common.navigateToActualUrl( + 'dashboard', + 'view/Metricbeat-system-overview-ecs?_g=(filters:!(),refreshInterval:(pause:!t,value:0),' + + 'time:(from:%272020-09-29T19:02:37.902Z%27,to:%272020-09-29T19:06:43.218Z%27))&_a=' + + '(description:%27Overview%20of%20system%20metrics%27,filters:!(),fullScreenMode:!t,' + + 'options:(darkTheme:!f),query:(language:kuery,query:%27%27),timeRestore:!f,' + + 'title:%27%5BMetricbeat%20System%5D%20Overview%20ECS%27,viewMode:view)', + { + ensureCurrentUrl: false, + shouldLoginIfPrompted: true, + } + ); + // await PageObjects.common.navigateToApp('dashboard', { insertTimestamp: false }); + // await PageObjects.dashboard.loadSavedDashboard('[Metricbeat System] Overview ECS'); + // await PageObjects.timePicker.setAbsoluteRange( + // 'Sep 29, 2020 @ 14:02:37.902', + // 'Sep 29, 2020 @ 14:06:43.218' + // ); + // await PageObjects.dashboard.clickFullScreenMode(); + + await PageObjects.common.sleep(2000); + await PageObjects.dashboard.waitForRenderComplete(); + await browser.setScreenshotSize(1000, 1000); + }); + + it('[Metricbeat System] Overview ECS should match snapshot', async function () { + try { + const percentDifference = await screenshot.compareAgainstBaseline( + 'metricbeat_dashboard', + updateBaselines + ); + expect(percentDifference).to.be.lessThan(0.01); + } finally { + await PageObjects.dashboard.clickExitFullScreenLogoButton(); + } + }); + }); +} diff --git a/x-pack/test/stack_functional_integration/test/functional/apps/metricbeat/index.js b/x-pack/test/stack_functional_integration/apps/metricbeat/index.js similarity index 86% rename from x-pack/test/stack_functional_integration/test/functional/apps/metricbeat/index.js rename to x-pack/test/stack_functional_integration/apps/metricbeat/index.js index d45d6c835a315..148762c6a8b77 100644 --- a/x-pack/test/stack_functional_integration/test/functional/apps/metricbeat/index.js +++ b/x-pack/test/stack_functional_integration/apps/metricbeat/index.js @@ -7,5 +7,6 @@ export default function ({ loadTestFile }) { describe('metricbeat app', function () { loadTestFile(require.resolve('./_metricbeat')); + loadTestFile(require.resolve('./_metricbeat_dashboard')); }); } diff --git a/x-pack/test/stack_functional_integration/test/functional/apps/monitoring/_monitoring.js b/x-pack/test/stack_functional_integration/apps/monitoring/_monitoring.js similarity index 100% rename from x-pack/test/stack_functional_integration/test/functional/apps/monitoring/_monitoring.js rename to x-pack/test/stack_functional_integration/apps/monitoring/_monitoring.js diff --git a/x-pack/test/stack_functional_integration/test/functional/apps/monitoring/_monitoring_metricbeat.js b/x-pack/test/stack_functional_integration/apps/monitoring/_monitoring_metricbeat.js similarity index 100% rename from x-pack/test/stack_functional_integration/test/functional/apps/monitoring/_monitoring_metricbeat.js rename to x-pack/test/stack_functional_integration/apps/monitoring/_monitoring_metricbeat.js diff --git a/x-pack/test/stack_functional_integration/test/functional/apps/monitoring/index.js b/x-pack/test/stack_functional_integration/apps/monitoring/index.js similarity index 100% rename from x-pack/test/stack_functional_integration/test/functional/apps/monitoring/index.js rename to x-pack/test/stack_functional_integration/apps/monitoring/index.js diff --git a/x-pack/test/stack_functional_integration/test/functional/apps/packetbeat/_packetbeat.js b/x-pack/test/stack_functional_integration/apps/packetbeat/_packetbeat.js similarity index 100% rename from x-pack/test/stack_functional_integration/test/functional/apps/packetbeat/_packetbeat.js rename to x-pack/test/stack_functional_integration/apps/packetbeat/_packetbeat.js diff --git a/x-pack/test/stack_functional_integration/test/functional/apps/packetbeat/index.js b/x-pack/test/stack_functional_integration/apps/packetbeat/index.js similarity index 100% rename from x-pack/test/stack_functional_integration/test/functional/apps/packetbeat/index.js rename to x-pack/test/stack_functional_integration/apps/packetbeat/index.js diff --git a/x-pack/test/stack_functional_integration/test/functional/apps/reporting/index.js b/x-pack/test/stack_functional_integration/apps/reporting/index.js similarity index 100% rename from x-pack/test/stack_functional_integration/test/functional/apps/reporting/index.js rename to x-pack/test/stack_functional_integration/apps/reporting/index.js diff --git a/x-pack/test/stack_functional_integration/test/functional/apps/reporting/reporting_watcher.js b/x-pack/test/stack_functional_integration/apps/reporting/reporting_watcher.js similarity index 100% rename from x-pack/test/stack_functional_integration/test/functional/apps/reporting/reporting_watcher.js rename to x-pack/test/stack_functional_integration/apps/reporting/reporting_watcher.js diff --git a/x-pack/test/stack_functional_integration/test/functional/apps/reporting/reporting_watcher_png.js b/x-pack/test/stack_functional_integration/apps/reporting/reporting_watcher_png.js similarity index 100% rename from x-pack/test/stack_functional_integration/test/functional/apps/reporting/reporting_watcher_png.js rename to x-pack/test/stack_functional_integration/apps/reporting/reporting_watcher_png.js diff --git a/x-pack/test/stack_functional_integration/test/functional/apps/reporting/util.js b/x-pack/test/stack_functional_integration/apps/reporting/util.js similarity index 100% rename from x-pack/test/stack_functional_integration/test/functional/apps/reporting/util.js rename to x-pack/test/stack_functional_integration/apps/reporting/util.js diff --git a/x-pack/test/stack_functional_integration/test/functional/apps/sample_data/e_commerce.js b/x-pack/test/stack_functional_integration/apps/sample_data/e_commerce.js similarity index 100% rename from x-pack/test/stack_functional_integration/test/functional/apps/sample_data/e_commerce.js rename to x-pack/test/stack_functional_integration/apps/sample_data/e_commerce.js diff --git a/x-pack/test/stack_functional_integration/test/functional/apps/sample_data/index.js b/x-pack/test/stack_functional_integration/apps/sample_data/index.js similarity index 100% rename from x-pack/test/stack_functional_integration/test/functional/apps/sample_data/index.js rename to x-pack/test/stack_functional_integration/apps/sample_data/index.js diff --git a/x-pack/test/stack_functional_integration/test/functional/apps/telemetry/_telemetry.js b/x-pack/test/stack_functional_integration/apps/telemetry/_telemetry.js similarity index 100% rename from x-pack/test/stack_functional_integration/test/functional/apps/telemetry/_telemetry.js rename to x-pack/test/stack_functional_integration/apps/telemetry/_telemetry.js diff --git a/x-pack/test/stack_functional_integration/test/functional/apps/telemetry/index.js b/x-pack/test/stack_functional_integration/apps/telemetry/index.js similarity index 100% rename from x-pack/test/stack_functional_integration/test/functional/apps/telemetry/index.js rename to x-pack/test/stack_functional_integration/apps/telemetry/index.js diff --git a/x-pack/test/stack_functional_integration/test/functional/apps/winlogbeat/_winlogbeat.js b/x-pack/test/stack_functional_integration/apps/winlogbeat/_winlogbeat.js similarity index 100% rename from x-pack/test/stack_functional_integration/test/functional/apps/winlogbeat/_winlogbeat.js rename to x-pack/test/stack_functional_integration/apps/winlogbeat/_winlogbeat.js diff --git a/x-pack/test/stack_functional_integration/test/functional/apps/winlogbeat/index.js b/x-pack/test/stack_functional_integration/apps/winlogbeat/index.js similarity index 100% rename from x-pack/test/stack_functional_integration/test/functional/apps/winlogbeat/index.js rename to x-pack/test/stack_functional_integration/apps/winlogbeat/index.js diff --git a/x-pack/test/stack_functional_integration/configs/config.stack_functional_integration_base.js b/x-pack/test/stack_functional_integration/configs/config.stack_functional_integration_base.js index 96d338a04b01b..a838b129242a1 100644 --- a/x-pack/test/stack_functional_integration/configs/config.stack_functional_integration_base.js +++ b/x-pack/test/stack_functional_integration/configs/config.stack_functional_integration_base.js @@ -6,12 +6,12 @@ import { resolve } from 'path'; import buildState from './build_state'; -import { ToolingLog } from '@kbn/dev-utils'; +import { ToolingLog, REPO_ROOT } from '@kbn/dev-utils'; import chalk from 'chalk'; import { esTestConfig, kbnTestConfig } from '@kbn/test'; const reportName = 'Stack Functional Integration Tests'; -const testsFolder = '../test/functional/apps'; +const testsFolder = '../apps'; const log = new ToolingLog({ level: 'info', writeTo: process.stdout, @@ -19,13 +19,14 @@ const log = new ToolingLog({ log.info(`WORKSPACE in config file ${process.env.WORKSPACE}`); const stateFilePath = process.env.WORKSPACE ? `${process.env.WORKSPACE}/qa/envvars.sh` - : '../../../../../integration-test/qa/envvars.sh'; + : `${REPO_ROOT}/../integration-test/qa/envvars.sh`; const prepend = (testFile) => require.resolve(`${testsFolder}/${testFile}`); export default async ({ readConfigFile }) => { const defaultConfigs = await readConfigFile(require.resolve('../../functional/config')); const { tests, ...provisionedConfigs } = buildState(resolve(__dirname, stateFilePath)); + process.env.stack_functional_integration = true; const servers = { kibana: kbnTestConfig.getUrlParts(), @@ -43,6 +44,14 @@ export default async ({ readConfigFile }) => { // If we need to do things like disable animations, we can do it in configure_start_kibana.sh, in the provisioner...which lives in the integration-test private repo uiSettings: {}, security: { disableTestUser: true }, + // choose where screenshots should be saved + screenshots: { + directory: resolve(`${REPO_ROOT}/../integration-test`, 'test/screenshots'), + }, + // choose where esArchiver should load archives from + esArchiver: { + directory: resolve(`${REPO_ROOT}/../integration-test`, 'test/es_archives'), + }, }; return settings; }; @@ -55,7 +64,7 @@ function truncate(testPath) { return dropKibanaPath(testPath); } function highLight(testPath) { - const dropTestsPath = splitRight(/^.+test[\\/]functional[\\/]apps[\\/](.*)[\\/]/gm); + const dropTestsPath = splitRight(/^.+apps[\\/](.*)[\\/]/gm); const cleaned = dropTestsPath(testPath); const colored = chalk.greenBright.bold(cleaned); return testPath.replace(cleaned, colored); diff --git a/x-pack/test/stack_functional_integration/configs/tests_list.js b/x-pack/test/stack_functional_integration/configs/tests_list.js index 0d91a078b73fd..44b622a8bc9c5 100644 --- a/x-pack/test/stack_functional_integration/configs/tests_list.js +++ b/x-pack/test/stack_functional_integration/configs/tests_list.js @@ -20,7 +20,11 @@ export default (envObj) => { } if (envObj.BEATS.includes('metricbeat')) { - xs.push('metricbeat'); + xs.push('metricbeat/_metricbeat'); + if (envObj.XPACK === 'YES') { + // the esArchive and dashboard png are specific to the default distribution (with XPACK) + xs.push('metricbeat/_metricbeat_dashboard'); + } } if (envObj.BEATS.includes('filebeat')) { xs.push('filebeat'); From 3078908093a32f4538e436ba227c650f745c5d33 Mon Sep 17 00:00:00 2001 From: Angela Chuang <6295984+angorayc@users.noreply.github.com> Date: Thu, 1 Oct 2020 21:46:13 +0100 Subject: [PATCH 14/50] [Security Solution] Searchstrategy integration (#78147) * init tests * add integration test for topNflow search strategy * add integration tests * add more tests * more tests * fix types * fix types * fix integration test * fix types * rm grapgql * fix type * fixup * fix test error * fix integration test * skip failing test * fix integration * skip failing test * skip failing test * fix integration tests for kpi network * fix integration test * fix integration test * fix import * remove additional data Co-authored-by: Elastic Machine --- .../factory/hosts/details/helpers.ts | 9 +- .../hosts/last_first_seen/__mocks__/index.ts | 3 - .../factory/hosts/last_first_seen/index.ts | 1 - .../apis/security_solution/authentications.ts | 107 +++--- .../apis/security_solution/host_details.ts | 237 ++++++++++++ .../apis/security_solution/hosts.ts | 212 +++++------ .../apis/security_solution/index.js | 26 +- .../security_solution/kpi_host_details.ts | 185 ---------- .../apis/security_solution/kpi_hosts.ts | 265 ++++++++------ .../apis/security_solution/kpi_network.ts | 345 ++++++++++++------ .../apis/security_solution/network_details.ts | 80 ++-- .../apis/security_solution/network_dns.ts | 143 ++++---- .../security_solution/network_top_n_flow.ts | 301 ++++++++------- .../apis/security_solution/overview_host.ts | 55 +-- .../security_solution/overview_network.ts | 131 ++++--- .../apis/security_solution/sources.ts | 4 +- .../apis/security_solution/timeline.ts | 8 +- .../security_solution/timeline_details.ts | 223 +++++------ .../apis/security_solution/tls.ts | 243 ++++++------ .../security_solution/uncommon_processes.ts | 81 ++-- .../apis/security_solution/users.ts | 78 ++-- .../es_archives/filebeat/default/data.json.gz | Bin 711714 -> 711718 bytes .../packetbeat/default/data.json.gz | Bin 78494 -> 78491 bytes 23 files changed, 1438 insertions(+), 1299 deletions(-) create mode 100644 x-pack/test/api_integration/apis/security_solution/host_details.ts delete mode 100644 x-pack/test/api_integration/apis/security_solution/kpi_host_details.ts diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/details/helpers.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/details/helpers.ts index ed705e7f6ad56..644278963742d 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/details/helpers.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/details/helpers.ts @@ -7,6 +7,7 @@ import { set } from '@elastic/safer-lodash-set/fp'; import { get, has, head } from 'lodash/fp'; import { hostFieldsMap } from '../../../../../../common/ecs/ecs_fields'; import { HostItem } from '../../../../../../common/search_strategy/security_solution/hosts'; +import { toArray } from '../../../../helpers/to_array'; import { HostAggEsItem, HostBuckets, HostValue } from '../../../../../lib/hosts/types'; @@ -36,7 +37,10 @@ export const formatHostItem = (bucket: HostAggEsItem): HostItem => HOST_FIELDS.reduce((flattenedFields, fieldName) => { const fieldValue = getHostFieldValue(fieldName, bucket); if (fieldValue != null) { - return set(fieldName, fieldValue, flattenedFields); + if (fieldName === '_id') { + return set('_id', fieldValue, flattenedFields); + } + return set(fieldName, toArray(fieldValue), flattenedFields); } return flattenedFields; }, {}); @@ -72,6 +76,9 @@ const getHostFieldValue = (fieldName: string, bucket: HostAggEsItem): string | s case 'host.os.version': return get('os.hits.hits[0]._source.host.os.version', bucket) || null; } + } else if (aggField === '_id') { + const hostName = get(`host_name`, bucket); + return hostName ? getFirstItem(hostName) : null; } return null; }; diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/last_first_seen/__mocks__/index.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/last_first_seen/__mocks__/index.ts index 224dcd1f8de24..00427863c5f4b 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/last_first_seen/__mocks__/index.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/last_first_seen/__mocks__/index.ts @@ -57,9 +57,6 @@ export const formattedSearchStrategyResponse = { dsl: [ '{\n "allowNoIndices": true,\n "index": [\n "apm-*-transaction*",\n "auditbeat-*",\n "endgame-*",\n "filebeat-*",\n "logs-*",\n "packetbeat-*",\n "winlogbeat-*"\n ],\n "ignoreUnavailable": true,\n "body": {\n "docvalue_fields": [],\n "aggregations": {\n "firstSeen": {\n "min": {\n "field": "@timestamp"\n }\n },\n "lastSeen": {\n "max": {\n "field": "@timestamp"\n }\n }\n },\n "query": {\n "bool": {\n "filter": [\n {\n "term": {\n "host.name": "siem-kibana"\n }\n }\n ]\n }\n },\n "size": 0,\n "track_total_hits": false\n }\n}', ], - response: [ - '{\n "isPartial": false,\n "isRunning": false,\n "rawResponse": {\n "took": 230,\n "timed_out": false,\n "_shards": {\n "total": 21,\n "successful": 21,\n "skipped": 0,\n "failed": 0\n },\n "hits": {\n "total": -1,\n "max_score": 0,\n "hits": []\n },\n "aggregations": {\n "lastSeen": {\n "value": 1599554931759,\n "value_as_string": "2020-09-08T08:48:51.759Z"\n },\n "firstSeen": {\n "value": 1591611722000,\n "value_as_string": "2020-06-08T10:22:02.000Z"\n }\n }\n },\n "total": 21,\n "loaded": 21\n}', - ], }, firstSeen: '2020-06-08T10:22:02.000Z', lastSeen: '2020-09-08T08:48:51.759Z', diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/last_first_seen/index.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/last_first_seen/index.ts index 56895583c2ae9..ee97436d2653f 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/last_first_seen/index.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/last_first_seen/index.ts @@ -28,7 +28,6 @@ export const firstLastSeenHost: SecuritySolutionFactory { before(() => esArchiver.load('auditbeat/hosts')); after(() => esArchiver.unload('auditbeat/hosts')); - it('Make sure that we get Authentication data', () => { - return client - .query({ - query: authenticationsQuery, - variables: { - sourceId: 'default', - timerange: { - interval: '12h', - to: TO, - from: FROM, - }, - pagination: { - activePage: 0, - cursorStart: 0, - fakePossibleCount: 3, - querySize: 1, - }, - defaultIndex: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'], - docValueFields: [], - inspect: false, + it('Make sure that we get Authentication data', async () => { + const { body: authentications } = await supertest + .post('/internal/search/securitySolutionSearchStrategy/') + .set('kbn-xsrf', 'true') + .send({ + factoryQueryType: HostsQueries.authentications, + timerange: { + interval: '12h', + to: TO, + from: FROM, }, + pagination: { + activePage: 0, + cursorStart: 0, + fakePossibleCount: 3, + querySize: 1, + }, + defaultIndex: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'], + docValueFields: [], + inspect: false, }) - .then((resp) => { - const authentications = resp.data.source.Authentications; - expect(authentications.edges.length).to.be(EDGE_LENGTH); - expect(authentications.totalCount).to.be(TOTAL_COUNT); - expect(authentications.pageInfo.fakeTotalCount).to.equal(3); - }); + .expect(200); + + expect(authentications.edges.length).to.be(EDGE_LENGTH); + expect(authentications.totalCount).to.be(TOTAL_COUNT); + expect(authentications.pageInfo.fakeTotalCount).to.equal(3); }); - it('Make sure that pagination is working in Authentications query', () => { - return client - .query({ - query: authenticationsQuery, - variables: { - sourceId: 'default', - timerange: { - interval: '12h', - to: TO, - from: FROM, - }, - pagination: { - activePage: 2, - cursorStart: 1, - fakePossibleCount: 5, - querySize: 2, - }, - defaultIndex: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'], - docValueFields: [], - inspect: false, + it('Make sure that pagination is working in Authentications query', async () => { + const { body: authentications } = await supertest + .post('/internal/search/securitySolutionSearchStrategy/') + .set('kbn-xsrf', 'true') + .send({ + factoryQueryType: HostsQueries.authentications, + timerange: { + interval: '12h', + to: TO, + from: FROM, }, + pagination: { + activePage: 2, + cursorStart: 1, + fakePossibleCount: 5, + querySize: 2, + }, + defaultIndex: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'], + docValueFields: [], + inspect: false, }) - .then((resp) => { - const authentications = resp.data.source.Authentications; - expect(authentications.edges.length).to.be(EDGE_LENGTH); - expect(authentications.totalCount).to.be(TOTAL_COUNT); - expect(authentications.edges[0]!.node.lastSuccess!.host!.name).to.eql([HOST_NAME]); - }); + .expect(200); + + expect(authentications.edges.length).to.be(EDGE_LENGTH); + expect(authentications.totalCount).to.be(TOTAL_COUNT); + expect(authentications.edges[0]!.node.lastSuccess!.host!.name).to.eql([HOST_NAME]); }); }); } diff --git a/x-pack/test/api_integration/apis/security_solution/host_details.ts b/x-pack/test/api_integration/apis/security_solution/host_details.ts new file mode 100644 index 0000000000000..9fe9df1fae506 --- /dev/null +++ b/x-pack/test/api_integration/apis/security_solution/host_details.ts @@ -0,0 +1,237 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../ftr_provider_context'; +import { HostsQueries } from '../../../../plugins/security_solution/common/search_strategy'; + +export default function ({ getService }: FtrProviderContext) { + const esArchiver = getService('esArchiver'); + const supertest = getService('supertest'); + + describe('Host Details', () => { + describe('With filebeat', () => { + before(() => esArchiver.load('filebeat/default')); + after(() => esArchiver.unload('filebeat/default')); + + const FROM = '2000-01-01T00:00:00.000Z'; + const TO = '3000-01-01T00:00:00.000Z'; + const expectedResult = { + isPartial: false, + isRunning: false, + rawResponse: { + took: 12, + timed_out: false, + _shards: { + total: 1, + successful: 1, + skipped: 0, + failed: 0, + }, + hits: { + total: 6157, + max_score: null, + hits: [], + }, + aggregations: { + cloud_instance_id: { + doc_count_error_upper_bound: 0, + sum_other_doc_count: 0, + buckets: [], + }, + host_mac: { + doc_count_error_upper_bound: 0, + sum_other_doc_count: 0, + buckets: [], + }, + host_ip: { + doc_count_error_upper_bound: 0, + sum_other_doc_count: 0, + buckets: [ + { + key: '151.205.0.17', + doc_count: 1, + timestamp: { + value: 1549766627000, + value_as_string: '2019-02-10T02:43:47.000Z', + }, + }, + ], + }, + cloud_machine_type: { + doc_count_error_upper_bound: 0, + sum_other_doc_count: 0, + buckets: [], + }, + cloud_region: { + doc_count_error_upper_bound: 0, + sum_other_doc_count: 0, + buckets: [], + }, + host_os_version: { + doc_count_error_upper_bound: 0, + sum_other_doc_count: 0, + buckets: [ + { + key: '9 (stretch)', + doc_count: 6157, + timestamp: { + value: 1549767613001, + value_as_string: '2019-02-10T03:00:13.001Z', + }, + }, + ], + }, + host_architecture: { + doc_count_error_upper_bound: 0, + sum_other_doc_count: 0, + buckets: [ + { + key: 'armv7l', + doc_count: 6157, + timestamp: { + value: 1549767613001, + value_as_string: '2019-02-10T03:00:13.001Z', + }, + }, + ], + }, + cloud_provider: { + doc_count_error_upper_bound: 0, + sum_other_doc_count: 0, + buckets: [], + }, + host_os_platform: { + doc_count_error_upper_bound: 0, + sum_other_doc_count: 0, + buckets: [ + { + key: 'raspbian', + doc_count: 6157, + timestamp: { + value: 1549767613001, + value_as_string: '2019-02-10T03:00:13.001Z', + }, + }, + ], + }, + host_os_name: { + doc_count_error_upper_bound: 0, + sum_other_doc_count: 0, + buckets: [ + { + key: 'Raspbian GNU/Linux', + doc_count: 6157, + timestamp: { + value: 1549767613001, + value_as_string: '2019-02-10T03:00:13.001Z', + }, + }, + ], + }, + host_os_family: { + doc_count_error_upper_bound: 0, + sum_other_doc_count: 0, + buckets: [ + { + key: '', + doc_count: 6157, + timestamp: { + value: 1549767613001, + value_as_string: '2019-02-10T03:00:13.001Z', + }, + }, + ], + }, + host_name: { + doc_count_error_upper_bound: 0, + sum_other_doc_count: 0, + buckets: [ + { + key: 'raspberrypi', + doc_count: 6157, + timestamp: { + value: 1549767613001, + value_as_string: '2019-02-10T03:00:13.001Z', + }, + }, + ], + }, + host_id: { + doc_count_error_upper_bound: 0, + sum_other_doc_count: 0, + buckets: [ + { + key: 'b19a781f683541a7a25ee345133aa399', + doc_count: 6157, + timestamp: { + value: 1549767613001, + value_as_string: '2019-02-10T03:00:13.001Z', + }, + }, + ], + }, + }, + }, + total: 1, + loaded: 1, + inspect: { + dsl: [ + '{\n "allowNoIndices": true,\n "index": [\n "filebeat-*"\n ],\n "ignoreUnavailable": true,\n "body": {\n "aggregations": {\n "host_architecture": {\n "terms": {\n "field": "host.architecture",\n "size": 10,\n "order": {\n "timestamp": "desc"\n }\n },\n "aggs": {\n "timestamp": {\n "max": {\n "field": "@timestamp"\n }\n }\n }\n },\n "host_id": {\n "terms": {\n "field": "host.id",\n "size": 10,\n "order": {\n "timestamp": "desc"\n }\n },\n "aggs": {\n "timestamp": {\n "max": {\n "field": "@timestamp"\n }\n }\n }\n },\n "host_ip": {\n "terms": {\n "field": "host.ip",\n "size": 10,\n "order": {\n "timestamp": "desc"\n }\n },\n "aggs": {\n "timestamp": {\n "max": {\n "field": "@timestamp"\n }\n }\n }\n },\n "host_mac": {\n "terms": {\n "field": "host.mac",\n "size": 10,\n "order": {\n "timestamp": "desc"\n }\n },\n "aggs": {\n "timestamp": {\n "max": {\n "field": "@timestamp"\n }\n }\n }\n },\n "host_name": {\n "terms": {\n "field": "host.name",\n "size": 10,\n "order": {\n "timestamp": "desc"\n }\n },\n "aggs": {\n "timestamp": {\n "max": {\n "field": "@timestamp"\n }\n }\n }\n },\n "host_os_family": {\n "terms": {\n "field": "host.os.family",\n "size": 10,\n "order": {\n "timestamp": "desc"\n }\n },\n "aggs": {\n "timestamp": {\n "max": {\n "field": "@timestamp"\n }\n }\n }\n },\n "host_os_name": {\n "terms": {\n "field": "host.os.name",\n "size": 10,\n "order": {\n "timestamp": "desc"\n }\n },\n "aggs": {\n "timestamp": {\n "max": {\n "field": "@timestamp"\n }\n }\n }\n },\n "host_os_platform": {\n "terms": {\n "field": "host.os.platform",\n "size": 10,\n "order": {\n "timestamp": "desc"\n }\n },\n "aggs": {\n "timestamp": {\n "max": {\n "field": "@timestamp"\n }\n }\n }\n },\n "host_os_version": {\n "terms": {\n "field": "host.os.version",\n "size": 10,\n "order": {\n "timestamp": "desc"\n }\n },\n "aggs": {\n "timestamp": {\n "max": {\n "field": "@timestamp"\n }\n }\n }\n },\n "cloud_instance_id": {\n "terms": {\n "field": "cloud.instance.id",\n "size": 10,\n "order": {\n "timestamp": "desc"\n }\n },\n "aggs": {\n "timestamp": {\n "max": {\n "field": "@timestamp"\n }\n }\n }\n },\n "cloud_machine_type": {\n "terms": {\n "field": "cloud.machine.type",\n "size": 10,\n "order": {\n "timestamp": "desc"\n }\n },\n "aggs": {\n "timestamp": {\n "max": {\n "field": "@timestamp"\n }\n }\n }\n },\n "cloud_provider": {\n "terms": {\n "field": "cloud.provider",\n "size": 10,\n "order": {\n "timestamp": "desc"\n }\n },\n "aggs": {\n "timestamp": {\n "max": {\n "field": "@timestamp"\n }\n }\n }\n },\n "cloud_region": {\n "terms": {\n "field": "cloud.region",\n "size": 10,\n "order": {\n "timestamp": "desc"\n }\n },\n "aggs": {\n "timestamp": {\n "max": {\n "field": "@timestamp"\n }\n }\n }\n }\n },\n "query": {\n "bool": {\n "filter": [\n {\n "term": {\n "host.name": "raspberrypi"\n }\n },\n {\n "range": {\n "@timestamp": {\n "format": "strict_date_optional_time",\n "gte": "2000-01-01T00:00:00.000Z",\n "lte": "3000-01-01T00:00:00.000Z"\n }\n }\n }\n ]\n }\n },\n "size": 0,\n "track_total_hits": false\n }\n}', + ], + }, + hostDetails: { + _id: 'raspberrypi', + host: { + architecture: ['armv7l'], + id: ['b19a781f683541a7a25ee345133aa399'], + ip: ['151.205.0.17'], + mac: [], + name: ['raspberrypi'], + os: { + family: [''], + name: ['Raspbian GNU/Linux'], + platform: ['raspbian'], + version: ['9 (stretch)'], + }, + }, + cloud: { + instance: { + id: [], + }, + machine: { + type: [], + }, + provider: [], + region: [], + }, + }, + }; + + it('Make sure that we get HostDetails data', async () => { + const { + body: { hostDetails }, + } = await supertest + .post('/internal/search/securitySolutionSearchStrategy') + .set('kbn-xsrf', 'true') + .send({ + factoryQueryType: HostsQueries.details, + timerange: { + interval: '12h', + to: TO, + from: FROM, + }, + defaultIndex: ['filebeat-*'], + docValueFields: [], + hostName: 'raspberrypi', + inspect: false, + }) + .expect(200); + expect(hostDetails).to.eql(expectedResult.hostDetails); + }); + }); + }); +} diff --git a/x-pack/test/api_integration/apis/security_solution/hosts.ts b/x-pack/test/api_integration/apis/security_solution/hosts.ts index 621718013db7f..d48a021b02db3 100644 --- a/x-pack/test/api_integration/apis/security_solution/hosts.ts +++ b/x-pack/test/api_integration/apis/security_solution/hosts.ts @@ -5,17 +5,12 @@ */ import expect from '@kbn/expect'; - import { + HostsQueries, Direction, - GetHostOverviewQuery, - GetHostFirstLastSeenQuery, - GetHostsTableQuery, HostsFields, -} from '../../../../plugins/security_solution/public/graphql/types'; -import { HostOverviewQuery } from '../../../../plugins/security_solution/public/hosts/containers/hosts/details/host_overview.gql_query'; -import { HostFirstLastSeenGqlQuery } from '../../../../plugins/security_solution/public/hosts/containers/hosts/first_last_seen/first_last_seen.gql_query'; -import { HostsTableQuery } from '../../../../plugins/security_solution/public/hosts/containers/hosts/hosts_table.gql_query'; +} from '../../../../plugins/security_solution/common/search_strategy'; + import { FtrProviderContext } from '../../ftr_provider_context'; const FROM = '2000-01-01T00:00:00.000Z'; @@ -29,85 +24,77 @@ const CURSOR_ID = '2ab45fc1c41e4c84bbd02202a7e5761f'; export default function ({ getService }: FtrProviderContext) { const esArchiver = getService('esArchiver'); - const client = getService('securitySolutionGraphQLClient'); + const supertest = getService('supertest'); describe('hosts', () => { before(() => esArchiver.load('auditbeat/hosts')); after(() => esArchiver.unload('auditbeat/hosts')); - it('Make sure that we get Hosts Table data', () => { - return client - .query({ - query: HostsTableQuery, - variables: { - sourceId: 'default', - timerange: { - interval: '12h', - to: TO, - from: FROM, - }, - defaultIndex: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'], - docValueFields: [], - sort: { - field: HostsFields.lastSeen, - direction: Direction.asc, - }, - pagination: { - activePage: 0, - cursorStart: 0, - fakePossibleCount: 3, - querySize: 1, - }, - inspect: false, + it('Make sure that we get Hosts Table data', async () => { + const { body: hosts } = await supertest + .post('/internal/search/securitySolutionSearchStrategy/') + .set('kbn-xsrf', 'true') + .send({ + factoryQueryType: HostsQueries.hosts, + timerange: { + interval: '12h', + to: TO, + from: FROM, + }, + defaultIndex: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'], + docValueFields: [], + sort: { + field: HostsFields.lastSeen, + direction: Direction.asc, }, + pagination: { + activePage: 0, + cursorStart: 0, + fakePossibleCount: 3, + querySize: 1, + }, + inspect: false, }) - .then((resp) => { - const hosts = resp.data.source.Hosts; - expect(hosts.edges.length).to.be(EDGE_LENGTH); - expect(hosts.totalCount).to.be(TOTAL_COUNT); - expect(hosts.pageInfo.fakeTotalCount).to.equal(3); - }); + .expect(200); + expect(hosts.edges.length).to.be(EDGE_LENGTH); + expect(hosts.totalCount).to.be(TOTAL_COUNT); + expect(hosts.pageInfo.fakeTotalCount).to.equal(3); }); - it('Make sure that pagination is working in Hosts Table query', () => { - return client - .query({ - query: HostsTableQuery, - variables: { - sourceId: 'default', - timerange: { - interval: '12h', - to: TO, - from: FROM, - }, - sort: { - field: HostsFields.lastSeen, - direction: Direction.asc, - }, - defaultIndex: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'], - docValueFields: [], - pagination: { - activePage: 2, - cursorStart: 1, - fakePossibleCount: 5, - querySize: 2, - }, - inspect: false, + it('Make sure that pagination is working in Hosts Table query', async () => { + const { body: hosts } = await supertest + .post('/internal/search/securitySolutionSearchStrategy/') + .set('kbn-xsrf', 'true') + .send({ + factoryQueryType: HostsQueries.hosts, + timerange: { + interval: '12h', + to: TO, + from: FROM, + }, + sort: { + field: HostsFields.lastSeen, + direction: Direction.asc, + }, + defaultIndex: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'], + docValueFields: [], + pagination: { + activePage: 2, + cursorStart: 1, + fakePossibleCount: 5, + querySize: 2, }, + inspect: false, }) - .then((resp) => { - const hosts = resp.data.source.Hosts; - - expect(hosts.edges.length).to.be(EDGE_LENGTH); - expect(hosts.totalCount).to.be(TOTAL_COUNT); - expect(hosts.edges[0]!.node.host!.os!.name).to.eql([HOST_NAME]); - }); + .expect(200); + expect(hosts.edges.length).to.be(EDGE_LENGTH); + expect(hosts.totalCount).to.be(TOTAL_COUNT); + expect(hosts.edges[0]!.node.host!.os!.name).to.eql([HOST_NAME]); }); - it('Make sure that we get Host Overview data', () => { - const expectedHost: Omit = { + it('Make sure that we get Host details data', async () => { + const expectedHostDetails = { _id: 'zeek-sensor-san-francisco', - endpoint: null, host: { architecture: ['x86_64'], id: [CURSOR_ID], @@ -119,68 +106,59 @@ export default function ({ getService }: FtrProviderContext) { name: [HOST_NAME], platform: ['ubuntu'], version: ['18.04.2 LTS (Bionic Beaver)'], - __typename: 'OsEcsFields', }, - type: null, - __typename: 'HostEcsFields', }, cloud: { instance: { id: ['132972452'], - __typename: 'CloudInstance', }, machine: { type: [], - __typename: 'CloudMachine', }, provider: ['digitalocean'], region: ['sfo2'], - __typename: 'CloudFields', }, - __typename: 'HostItem', }; - - return client - .query({ - query: HostOverviewQuery, - variables: { - sourceId: 'default', - hostName: 'zeek-sensor-san-francisco', - timerange: { - interval: '12h', - to: TO, - from: FROM, - }, - defaultIndex: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'], - docValueFields: [], - inspect: false, + const { + body: { hostDetails }, + } = await supertest + .post('/internal/search/securitySolutionSearchStrategy/') + .set('kbn-xsrf', 'true') + .send({ + factoryQueryType: HostsQueries.details, + hostName: 'zeek-sensor-san-francisco', + timerange: { + interval: '12h', + to: TO, + from: FROM, }, + defaultIndex: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'], + docValueFields: [], + inspect: false, }) - .then((resp) => { - const hosts = resp.data.source.HostOverview; - expect(hosts).to.eql(expectedHost); - }); + .expect(200); + + expect(hostDetails).to.eql(expectedHostDetails); }); - it('Make sure that we get Last First Seen for a Host', () => { - return client - .query({ - query: HostFirstLastSeenGqlQuery, - variables: { - sourceId: 'default', - hostName: 'zeek-sensor-san-francisco', - defaultIndex: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'], - docValueFields: [], - }, + it('Make sure that we get Last First Seen for a Host', async () => { + const { body: firstLastSeenHost } = await supertest + .post('/internal/search/securitySolutionSearchStrategy/') + .set('kbn-xsrf', 'true') + .send({ + factoryQueryType: HostsQueries.firstLastSeen, + defaultIndex: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'], + docValueFields: [], + hostName: 'zeek-sensor-san-francisco', }) - .then((resp) => { - const firstLastSeenHost = resp.data.source.HostFirstLastSeen; - expect(firstLastSeenHost).to.eql({ - __typename: 'FirstLastSeenHost', - firstSeen: '2019-02-19T19:36:23.561Z', - lastSeen: '2019-02-19T20:42:33.561Z', - }); - }); + .expect(200); + const expected = { + firstSeen: '2019-02-19T19:36:23.561Z', + lastSeen: '2019-02-19T20:42:33.561Z', + }; + + expect(firstLastSeenHost.firstSeen).to.eql(expected.firstSeen); + expect(firstLastSeenHost.lastSeen).to.eql(expected.lastSeen); }); }); } diff --git a/x-pack/test/api_integration/apis/security_solution/index.js b/x-pack/test/api_integration/apis/security_solution/index.js index 3d24af4413800..b28ddf7efd575 100644 --- a/x-pack/test/api_integration/apis/security_solution/index.js +++ b/x-pack/test/api_integration/apis/security_solution/index.js @@ -5,24 +5,26 @@ */ export default function ({ loadTestFile }) { - describe('Siem GraphQL Endpoints', () => { - // loadTestFile(require.resolve('./authentications')); + describe('SecuritySolution Endpoints', () => { + loadTestFile(require.resolve('./authentications')); loadTestFile(require.resolve('./hosts')); - // loadTestFile(require.resolve('./kpi_network')); - // loadTestFile(require.resolve('./kpi_hosts')); - // loadTestFile(require.resolve('./network_dns')); - // loadTestFile(require.resolve('./network_top_n_flow')); - // loadTestFile(require.resolve('./overview_host')); + loadTestFile(require.resolve('./host_details')); + loadTestFile(require.resolve('./kpi_network')); + loadTestFile(require.resolve('./kpi_hosts')); + loadTestFile(require.resolve('./network_details')); + loadTestFile(require.resolve('./network_dns')); + loadTestFile(require.resolve('./network_top_n_flow')); + loadTestFile(require.resolve('./overview_host')); + loadTestFile(require.resolve('./overview_network')); loadTestFile(require.resolve('./saved_objects/notes')); loadTestFile(require.resolve('./saved_objects/pinned_events')); loadTestFile(require.resolve('./saved_objects/timeline')); loadTestFile(require.resolve('./sources')); - // loadTestFile(require.resolve('./overview_network')); // loadTestFile(require.resolve('./timeline')); - // loadTestFile(require.resolve('./timeline_details')); - // loadTestFile(require.resolve('./uncommon_processes')); - // loadTestFile(require.resolve('./users')); - // loadTestFile(require.resolve('./tls')); + loadTestFile(require.resolve('./timeline_details')); + loadTestFile(require.resolve('./uncommon_processes')); + loadTestFile(require.resolve('./users')); + loadTestFile(require.resolve('./tls')); loadTestFile(require.resolve('./feature_controls')); }); } diff --git a/x-pack/test/api_integration/apis/security_solution/kpi_host_details.ts b/x-pack/test/api_integration/apis/security_solution/kpi_host_details.ts deleted file mode 100644 index 27e4e02ee7d08..0000000000000 --- a/x-pack/test/api_integration/apis/security_solution/kpi_host_details.ts +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import expect from '@kbn/expect'; -// @ts-expect-error -import { kpiHostDetailsQuery } from '../../../../plugins/security_solution/public/hosts/containers/kpi_host_details/index.gql_query'; -// @ts-expect-error -import { GetKpiHostDetailsQuery } from '../../../../plugins/security_solution/public/graphql/types'; -import { FtrProviderContext } from '../../ftr_provider_context'; - -export default function ({ getService }: FtrProviderContext) { - const esArchiver = getService('esArchiver'); - const client = getService('securitySolutionGraphQLClient'); - describe('Kpi Host Details', () => { - describe('With filebeat', () => { - before(() => esArchiver.load('filebeat/default')); - after(() => esArchiver.unload('filebeat/default')); - - const FROM = '2000-01-01T00:00:00.000Z'; - const TO = '3000-01-01T00:00:00.000Z'; - const expectedResult = { - __typename: 'KpiHostDetailsData', - authSuccess: 0, - authSuccessHistogram: null, - authFailure: 0, - authFailureHistogram: null, - uniqueSourceIps: 121, - uniqueSourceIpsHistogram: [ - { - x: new Date('2019-02-09T16:00:00.000Z').valueOf(), - y: 52, - __typename: 'KpiHostHistogramData', - }, - { - x: new Date('2019-02-09T19:00:00.000Z').valueOf(), - y: 0, - __typename: 'KpiHostHistogramData', - }, - { - x: new Date('2019-02-09T22:00:00.000Z').valueOf(), - y: 31, - __typename: 'KpiHostHistogramData', - }, - { - x: new Date('2019-02-10T01:00:00.000Z').valueOf(), - y: 88, - __typename: 'KpiHostHistogramData', - }, - ], - uniqueDestinationIps: 154, - uniqueDestinationIpsHistogram: [ - { - x: new Date('2019-02-09T16:00:00.000Z').valueOf(), - y: 61, - __typename: 'KpiHostHistogramData', - }, - { - x: new Date('2019-02-09T19:00:00.000Z').valueOf(), - y: 0, - __typename: 'KpiHostHistogramData', - }, - { - x: new Date('2019-02-09T22:00:00.000Z').valueOf(), - y: 45, - __typename: 'KpiHostHistogramData', - }, - { - x: new Date('2019-02-10T01:00:00.000Z').valueOf(), - y: 114, - __typename: 'KpiHostHistogramData', - }, - ], - }; - - it('Make sure that we get KpiHostDetails data', () => { - return client - .query({ - query: kpiHostDetailsQuery, - variables: { - sourceId: 'default', - timerange: { - interval: '12h', - to: TO, - from: FROM, - }, - defaultIndex: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'], - hostName: 'zeek-sensor-san-francisco', - docValueFields: [], - inspect: false, - }, - }) - .then((resp) => { - const kpiHosts = resp.data.source.KpiHostDetails; - expect(kpiHosts!).to.eql(expectedResult); - }); - }); - }); - - describe('With auditbeat', () => { - before(() => esArchiver.load('auditbeat/default')); - after(() => esArchiver.unload('auditbeat/default')); - - const FROM = new Date('2000-01-01T00:00:00.000Z').valueOf(); - const TO = new Date('3000-01-01T00:00:00.000Z').valueOf(); - const expectedResult = { - __typename: 'KpiHostDetailsData', - authSuccess: 0, - authSuccessHistogram: null, - authFailure: 0, - authFailureHistogram: null, - uniqueSourceIps: 121, - uniqueSourceIpsHistogram: [ - { - x: new Date('2019-02-09T16:00:00.000Z').valueOf(), - y: 52, - __typename: 'KpiHostHistogramData', - }, - { - x: new Date('2019-02-09T19:00:00.000Z').valueOf(), - y: 0, - __typename: 'KpiHostHistogramData', - }, - { - x: new Date('2019-02-09T22:00:00.000Z').valueOf(), - y: 31, - __typename: 'KpiHostHistogramData', - }, - { - x: new Date('2019-02-10T01:00:00.000Z').valueOf(), - y: 88, - __typename: 'KpiHostHistogramData', - }, - ], - uniqueDestinationIps: 154, - uniqueDestinationIpsHistogram: [ - { - x: new Date('2019-02-09T16:00:00.000Z').valueOf(), - y: 61, - __typename: 'KpiHostHistogramData', - }, - { - x: new Date('2019-02-09T19:00:00.000Z').valueOf(), - y: 0, - __typename: 'KpiHostHistogramData', - }, - { - x: new Date('2019-02-09T22:00:00.000Z').valueOf(), - y: 45, - __typename: 'KpiHostHistogramData', - }, - { - x: new Date('2019-02-10T01:00:00.000Z').valueOf(), - y: 114, - __typename: 'KpiHostHistogramData', - }, - ], - }; - it('Make sure that we get KpiHostDetails data', () => { - return client - .query({ - query: kpiHostDetailsQuery, - variables: { - sourceId: 'default', - timerange: { - interval: '12h', - to: TO, - from: FROM, - }, - defaultIndex: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'], - docValueFields: [], - hostName: 'zeek-sensor-san-francisco', - inspect: false, - }, - }) - .then((resp) => { - const kpiHosts = resp.data.source.KpiHostDetails; - expect(kpiHosts!).to.eql(expectedResult); - }); - }); - }); - }); -} diff --git a/x-pack/test/api_integration/apis/security_solution/kpi_hosts.ts b/x-pack/test/api_integration/apis/security_solution/kpi_hosts.ts index 64109bd4d9321..b141087c4e3ba 100644 --- a/x-pack/test/api_integration/apis/security_solution/kpi_hosts.ts +++ b/x-pack/test/api_integration/apis/security_solution/kpi_hosts.ts @@ -5,15 +5,13 @@ */ import expect from '@kbn/expect'; -// @ts-expect-error -import { kpiHostsQuery } from '../../../../plugins/security_solution/public/hosts/containers/kpi_hosts/index.gql_query'; -// @ts-expect-error -import { GetKpiHostsQuery } from '../../../../plugins/security_solution/public/graphql/types'; +import { HostsKpiQueries } from '../../../../plugins/security_solution/common/search_strategy'; import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ getService }: FtrProviderContext) { const esArchiver = getService('esArchiver'); - const client = getService('securitySolutionGraphQLClient'); + const supertest = getService('supertest'); + describe('Kpi Hosts', () => { describe('With filebeat', () => { before(() => esArchiver.load('filebeat/default')); @@ -22,28 +20,23 @@ export default function ({ getService }: FtrProviderContext) { const FROM = '2000-01-01T00:00:00.000Z'; const TO = '3000-01-01T00:00:00.000Z'; const expectedResult = { - __typename: 'KpiHostsData', hosts: 1, hostsHistogram: [ { x: new Date('2019-02-09T16:00:00.000Z').valueOf(), y: 1, - __typename: 'KpiHostHistogramData', }, { x: new Date('2019-02-09T19:00:00.000Z').valueOf(), y: 0, - __typename: 'KpiHostHistogramData', }, { x: new Date('2019-02-09T22:00:00.000Z').valueOf(), y: 1, - __typename: 'KpiHostHistogramData', }, { x: new Date('2019-02-10T01:00:00.000Z').valueOf(), y: 1, - __typename: 'KpiHostHistogramData', }, ], authSuccess: 0, @@ -55,22 +48,18 @@ export default function ({ getService }: FtrProviderContext) { { x: new Date('2019-02-09T16:00:00.000Z').valueOf(), y: 52, - __typename: 'KpiHostHistogramData', }, { x: new Date('2019-02-09T19:00:00.000Z').valueOf(), y: 0, - __typename: 'KpiHostHistogramData', }, { x: new Date('2019-02-09T22:00:00.000Z').valueOf(), y: 31, - __typename: 'KpiHostHistogramData', }, { x: new Date('2019-02-10T01:00:00.000Z').valueOf(), y: 88, - __typename: 'KpiHostHistogramData', }, ], uniqueDestinationIps: 154, @@ -78,46 +67,87 @@ export default function ({ getService }: FtrProviderContext) { { x: new Date('2019-02-09T16:00:00.000Z').valueOf(), y: 61, - __typename: 'KpiHostHistogramData', }, { x: new Date('2019-02-09T19:00:00.000Z').valueOf(), y: 0, - __typename: 'KpiHostHistogramData', }, { x: new Date('2019-02-09T22:00:00.000Z').valueOf(), y: 45, - __typename: 'KpiHostHistogramData', }, { x: new Date('2019-02-10T01:00:00.000Z').valueOf(), y: 114, - __typename: 'KpiHostHistogramData', }, ], }; - it('Make sure that we get KpiHosts data', () => { - return client - .query({ - query: kpiHostsQuery, - variables: { - sourceId: 'default', - timerange: { - interval: '12h', - to: TO, - from: FROM, - }, - defaultIndex: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'], - docValueFields: [], - inspect: false, + it('Make sure that we get KpiHosts data', async () => { + const { body: kpiHosts } = await supertest + .post('/internal/search/securitySolutionSearchStrategy/hostsKpiHostsQuery') + .set('kbn-xsrf', 'true') + .send({ + factoryQueryType: HostsKpiQueries.kpiHosts, + timerange: { + interval: '12h', + to: TO, + from: FROM, + }, + defaultIndex: ['filebeat-*'], + docValueFields: [], + inspect: false, + }) + .expect(200); + + expect(kpiHosts.hostsHistogram!).to.eql(expectedResult.hostsHistogram); + expect(kpiHosts.hosts!).to.eql(expectedResult.hosts); + }); + + it('Make sure that we get KpiAuthentications data', async () => { + const { body } = await supertest + .post('/internal/search/securitySolutionSearchStrategy/hostsKpiAuthenticationsQuery') + .set('kbn-xsrf', 'true') + .send({ + factoryQueryType: HostsKpiQueries.kpiAuthentications, + timerange: { + interval: '12h', + to: TO, + from: FROM, + }, + defaultIndex: ['filebeat-*'], + docValueFields: [], + inspect: false, + }) + .expect(200); + expect(body.authenticationsSuccess!).to.eql(expectedResult.authSuccess); + expect(body.authenticationsSuccessHistogram!).to.eql(expectedResult.authSuccessHistogram); + expect(body.authenticationsFailure!).to.eql(expectedResult.authSuccess); + expect(body.authenticationsFailureHistogram!).to.eql(expectedResult.authFailureHistogram); + }); + + it('Make sure that we get KpiUniqueIps data', async () => { + const { body } = await supertest + .post('/internal/search/securitySolutionSearchStrategy/hostsKpiUniqueIpsQuery') + .set('kbn-xsrf', 'true') + .send({ + factoryQueryType: HostsKpiQueries.kpiUniqueIps, + timerange: { + interval: '12h', + to: TO, + from: FROM, }, + defaultIndex: ['filebeat-*'], + docValueFields: [], + inspect: false, }) - .then((resp) => { - const kpiHosts = resp.data.source.KpiHosts; - expect(kpiHosts!).to.eql(expectedResult); - }); + .expect(200); + expect(body.uniqueDestinationIps!).to.eql(expectedResult.uniqueDestinationIps); + expect(body.uniqueDestinationIpsHistogram!).to.eql( + expectedResult.uniqueDestinationIpsHistogram + ); + expect(body.uniqueSourceIps!).to.eql(expectedResult.uniqueSourceIps); + expect(body.uniqueSourceIpsHistogram!).to.eql(expectedResult.uniqueSourceIpsHistogram); }); }); @@ -128,101 +158,108 @@ export default function ({ getService }: FtrProviderContext) { const FROM = '2000-01-01T00:00:00.000Z'; const TO = '3000-01-01T00:00:00.000Z'; const expectedResult = { - __typename: 'KpiHostsData', - hosts: 1, + hosts: 6, hostsHistogram: [ { - x: new Date('2019-02-09T16:00:00.000Z').valueOf(), - y: 1, - __typename: 'KpiHostHistogramData', - }, - { - x: new Date('2019-02-09T19:00:00.000Z').valueOf(), - y: 0, - __typename: 'KpiHostHistogramData', - }, - { - x: new Date('2019-02-09T22:00:00.000Z').valueOf(), - y: 1, - __typename: 'KpiHostHistogramData', - }, - { - x: new Date('2019-02-10T01:00:00.000Z').valueOf(), - y: 1, - __typename: 'KpiHostHistogramData', - }, - ], - authSuccess: 0, - authSuccessHistogram: null, - authFailure: 0, - authFailureHistogram: null, - uniqueSourceIps: 121, - uniqueSourceIpsHistogram: [ - { - x: new Date('2019-02-09T16:00:00.000Z').valueOf(), - y: 52, - __typename: 'KpiHostHistogramData', - }, - { - x: new Date('2019-02-09T19:00:00.000Z').valueOf(), - y: 0, - __typename: 'KpiHostHistogramData', + x: new Date('2018-11-27T00:00:00.000Z').valueOf(), + y: 6, }, { - x: new Date('2019-02-09T22:00:00.000Z').valueOf(), - y: 31, - __typename: 'KpiHostHistogramData', + x: new Date('2018-11-27T00:30:00.000Z').valueOf(), + y: 6, }, { - x: new Date('2019-02-10T01:00:00.000Z').valueOf(), - y: 88, - __typename: 'KpiHostHistogramData', + x: new Date('2018-11-27T01:00:00.000Z').valueOf(), + y: 6, }, - ], - uniqueDestinationIps: 154, - uniqueDestinationIpsHistogram: [ { - x: new Date('2019-02-09T16:00:00.000Z').valueOf(), - y: 61, - __typename: 'KpiHostHistogramData', + x: new Date('2018-11-27T01:30:00.000Z').valueOf(), + y: 6, }, { - x: new Date('2019-02-09T19:00:00.000Z').valueOf(), - y: 0, - __typename: 'KpiHostHistogramData', + x: new Date('2018-11-27T02:00:00.000Z').valueOf(), + y: 6, }, { - x: new Date('2019-02-09T22:00:00.000Z').valueOf(), - y: 45, - __typename: 'KpiHostHistogramData', - }, - { - x: new Date('2019-02-10T01:00:00.000Z').valueOf(), - y: 114, - __typename: 'KpiHostHistogramData', + x: new Date('2018-11-27T02:30:00.000Z').valueOf(), + y: 6, }, ], + authSuccess: null, + authSuccessHistogram: null, + authFailure: 0, + authFailureHistogram: null, + uniqueSourceIps: null, + uniqueSourceIpsHistogram: null, + uniqueDestinationIps: null, + uniqueDestinationIpsHistogram: null, }; - it('Make sure that we get KpiHosts data', () => { - return client - .query({ - query: kpiHostsQuery, - variables: { - sourceId: 'default', - timerange: { - interval: '12h', - to: TO, - from: FROM, - }, - defaultIndex: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'], - docValueFields: [], - inspect: false, + + it('Make sure that we get KpiHosts data', async () => { + const { body: kpiHosts } = await supertest + .post('/internal/search/securitySolutionSearchStrategy/hostsKpiHostsQuery') + .set('kbn-xsrf', 'true') + .send({ + factoryQueryType: HostsKpiQueries.kpiHosts, + timerange: { + interval: '12h', + to: TO, + from: FROM, + }, + defaultIndex: ['auditbeat-*'], + docValueFields: [], + inspect: false, + }) + .expect(200); + + expect(kpiHosts.hostsHistogram!).to.eql(expectedResult.hostsHistogram); + expect(kpiHosts.hosts!).to.eql(expectedResult.hosts); + }); + + it('Make sure that we get KpiAuthentications data', async () => { + const { body } = await supertest + .post('/internal/search/securitySolutionSearchStrategy/hostsKpiAuthenticationsQuery') + .set('kbn-xsrf', 'true') + .send({ + factoryQueryType: HostsKpiQueries.kpiAuthentications, + timerange: { + interval: '12h', + to: TO, + from: FROM, + }, + defaultIndex: ['filebeat-*'], + docValueFields: [], + inspect: false, + }) + .expect(200); + expect(body.authenticationsSuccess!).to.eql(expectedResult.authSuccess); + expect(body.authenticationsSuccessHistogram!).to.eql(expectedResult.authSuccessHistogram); + expect(body.authenticationsFailure!).to.eql(expectedResult.authSuccess); + expect(body.authenticationsFailureHistogram!).to.eql(expectedResult.authFailureHistogram); + }); + + it('Make sure that we get KpiUniqueIps data', async () => { + const { body } = await supertest + .post('/internal/search/securitySolutionSearchStrategy/hostsKpiUniqueIpsQuery') + .set('kbn-xsrf', 'true') + .send({ + factoryQueryType: HostsKpiQueries.kpiUniqueIps, + timerange: { + interval: '12h', + to: TO, + from: FROM, }, + defaultIndex: ['filebeat-*'], + docValueFields: [], + inspect: false, }) - .then((resp) => { - const kpiHosts = resp.data.source.KpiHosts; - expect(kpiHosts!).to.eql(expectedResult); - }); + .expect(200); + expect(body.uniqueDestinationIps!).to.eql(expectedResult.uniqueDestinationIps); + expect(body.uniqueDestinationIpsHistogram!).to.eql( + expectedResult.uniqueDestinationIpsHistogram + ); + expect(body.uniqueSourceIps!).to.eql(expectedResult.uniqueSourceIps); + expect(body.uniqueSourceIpsHistogram!).to.eql(expectedResult.uniqueSourceIpsHistogram); }); }); }); diff --git a/x-pack/test/api_integration/apis/security_solution/kpi_network.ts b/x-pack/test/api_integration/apis/security_solution/kpi_network.ts index 14b061d678898..641e6658d28cc 100644 --- a/x-pack/test/api_integration/apis/security_solution/kpi_network.ts +++ b/x-pack/test/api_integration/apis/security_solution/kpi_network.ts @@ -5,15 +5,13 @@ */ import expect from '@kbn/expect'; -// @ts-expect-error -import { kpiNetworkQuery } from '../../../../plugins/security_solution/public/network/containers/kpi_network/index.gql_query'; -// @ts-expect-error -import { GetKpiNetworkQuery } from '../../../../plugins/security_solution/public/graphql/types'; import { FtrProviderContext } from '../../ftr_provider_context'; +import { NetworkKpiQueries } from '../../../../plugins/security_solution/common/search_strategy'; export default function ({ getService }: FtrProviderContext) { const esArchiver = getService('esArchiver'); - const client = getService('securitySolutionGraphQLClient'); + const supertest = getService('supertest'); + describe('Kpi Network', () => { describe('With filebeat', () => { before(() => esArchiver.load('filebeat/default')); @@ -22,51 +20,42 @@ export default function ({ getService }: FtrProviderContext) { const FROM = '2000-01-01T00:00:00.000Z'; const TO = '3000-01-01T00:00:00.000Z'; const expectedResult = { - __typename: 'KpiNetworkData', - networkEvents: 6158, + networkEvents: 6157, uniqueFlowId: 712, uniqueSourcePrivateIps: 8, uniqueSourcePrivateIpsHistogram: [ { x: new Date('2019-02-09T16:00:00.000Z').valueOf(), y: 8, - __typename: 'KpiNetworkHistogramData', }, { x: new Date('2019-02-09T19:00:00.000Z').valueOf(), y: 0, - __typename: 'KpiNetworkHistogramData', }, { x: new Date('2019-02-09T22:00:00.000Z').valueOf(), y: 8, - __typename: 'KpiNetworkHistogramData', }, { x: new Date('2019-02-10T01:00:00.000Z').valueOf(), y: 7, - __typename: 'KpiNetworkHistogramData', }, ], uniqueDestinationPrivateIps: 9, uniqueDestinationPrivateIpsHistogram: [ { - __typename: 'KpiNetworkHistogramData', x: new Date('2019-02-09T16:00:00.000Z').valueOf(), y: 8, }, { - __typename: 'KpiNetworkHistogramData', x: new Date('2019-02-09T19:00:00.000Z').valueOf(), y: 0, }, { - __typename: 'KpiNetworkHistogramData', x: new Date('2019-02-09T22:00:00.000Z').valueOf(), y: 8, }, { - __typename: 'KpiNetworkHistogramData', x: new Date('2019-02-10T01:00:00.000Z').valueOf(), y: 8, }, @@ -75,26 +64,133 @@ export default function ({ getService }: FtrProviderContext) { tlsHandshakes: 62, }; - it('Make sure that we get KpiNetwork data', () => { - return client - .query({ - query: kpiNetworkQuery, - variables: { - sourceId: 'default', - timerange: { - interval: '12h', - to: TO, - from: FROM, - }, - defaultIndex: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'], - docValueFields: [], - inspect: false, + it('Make sure that we get KpiNetwork uniqueFlows data', async () => { + const { body: kpiNetwork } = await supertest + .post('/internal/search/securitySolutionSearchStrategy/networkKpiUniqueFlowsQuery') + .set('kbn-xsrf', 'true') + .send({ + factoryQueryType: NetworkKpiQueries.uniqueFlows, + timerange: { + interval: '12h', + to: TO, + from: FROM, + }, + defaultIndex: ['filebeat-*'], + docValueFields: [], + inspect: false, + }) + .expect(200); + + expect(kpiNetwork.uniqueFlowId).to.eql(expectedResult.uniqueFlowId); + }); + + it('Make sure that we get KpiNetwork networkEvents data', async () => { + const { body: kpiNetwork } = await supertest + .post('/internal/search/securitySolutionSearchStrategy/networkKpiNetworkEventsQuery') + .set('kbn-xsrf', 'true') + .send({ + factoryQueryType: NetworkKpiQueries.networkEvents, + timerange: { + interval: '12h', + to: TO, + from: FROM, }, + defaultIndex: ['filebeat-*'], + docValueFields: [], + inspect: false, }) - .then((resp) => { - const kpiNetwork = resp.data.source.KpiNetwork; - expect(kpiNetwork).to.eql(expectedResult); - }); + .expect(200); + + expect(kpiNetwork.networkEvents).to.eql(expectedResult.networkEvents); + }); + + it('Make sure that we get KpiNetwork DNS data', async () => { + const { body: kpiNetwork } = await supertest + .post('/internal/search/securitySolutionSearchStrategy/networkKpiDnsQuery') + .set('kbn-xsrf', 'true') + .send({ + factoryQueryType: NetworkKpiQueries.dns, + timerange: { + interval: '12h', + to: TO, + from: FROM, + }, + defaultIndex: ['filebeat-*'], + docValueFields: [], + inspect: false, + }) + .expect(200); + + expect(kpiNetwork.dnsQueries).to.eql(expectedResult.dnsQueries); + }); + + it('Make sure that we get KpiNetwork networkEvents data', async () => { + const { body: kpiNetwork } = await supertest + .post('/internal/search/securitySolutionSearchStrategy/networkKpiNetworkEventsQuery') + .set('kbn-xsrf', 'true') + .send({ + factoryQueryType: NetworkKpiQueries.networkEvents, + timerange: { + interval: '12h', + to: TO, + from: FROM, + }, + defaultIndex: ['filebeat-*'], + docValueFields: [], + inspect: false, + }) + .expect(200); + + expect(kpiNetwork.networkEvents).to.eql(expectedResult.networkEvents); + }); + + it('Make sure that we get KpiNetwork tlsHandshakes data', async () => { + const { body: kpiNetwork } = await supertest + .post('/internal/search/securitySolutionSearchStrategy/networkKpiTlsHandshakesQuery') + .set('kbn-xsrf', 'true') + .send({ + factoryQueryType: NetworkKpiQueries.tlsHandshakes, + timerange: { + interval: '12h', + to: TO, + from: FROM, + }, + defaultIndex: ['filebeat-*'], + docValueFields: [], + inspect: false, + }) + .expect(200); + + expect(kpiNetwork.tlsHandshakes).to.eql(expectedResult.tlsHandshakes); + }); + + it('Make sure that we get KpiNetwork uniquePrivateIps data', async () => { + const { body: kpiNetwork } = await supertest + .post('/internal/search/securitySolutionSearchStrategy/networkKpiUniquePrivateIpsQuery') + .set('kbn-xsrf', 'true') + .send({ + factoryQueryType: NetworkKpiQueries.uniquePrivateIps, + timerange: { + interval: '12h', + to: TO, + from: FROM, + }, + defaultIndex: ['filebeat-*'], + docValueFields: [], + inspect: false, + }) + .expect(200); + + expect(kpiNetwork.uniqueDestinationPrivateIps).to.eql( + expectedResult.uniqueDestinationPrivateIps + ); + expect(kpiNetwork.uniqueDestinationPrivateIpsHistogram).to.eql( + expectedResult.uniqueDestinationPrivateIpsHistogram + ); + expect(kpiNetwork.uniqueSourcePrivateIps).to.eql(expectedResult.uniqueSourcePrivateIps); + expect(kpiNetwork.uniqueSourcePrivateIpsHistogram).to.eql( + expectedResult.uniqueSourcePrivateIpsHistogram + ); }); }); @@ -105,78 +201,123 @@ export default function ({ getService }: FtrProviderContext) { const FROM = '2000-01-01T00:00:00.000Z'; const TO = '3000-01-01T00:00:00.000Z'; const expectedResult = { - __typename: 'KpiNetworkData', - networkEvents: 6158, - uniqueFlowId: 712, - uniqueSourcePrivateIps: 8, - uniqueSourcePrivateIpsHistogram: [ - { - x: new Date('2019-02-09T16:00:00.000Z').valueOf(), - y: 8, - __typename: 'KpiNetworkHistogramData', - }, - { - x: new Date('2019-02-09T19:00:00.000Z').valueOf(), - y: 0, - __typename: 'KpiNetworkHistogramData', - }, - { - x: new Date('2019-02-09T22:00:00.000Z').valueOf(), - y: 8, - __typename: 'KpiNetworkHistogramData', - }, - { - x: new Date('2019-02-10T01:00:00.000Z').valueOf(), - y: 7, - __typename: 'KpiNetworkHistogramData', - }, - ], - uniqueDestinationPrivateIps: 9, - uniqueDestinationPrivateIpsHistogram: [ - { - __typename: 'KpiNetworkHistogramData', - x: new Date('2019-02-09T16:00:00.000Z').valueOf(), - y: 8, - }, - { - __typename: 'KpiNetworkHistogramData', - x: new Date('2019-02-09T19:00:00.000Z').valueOf(), - y: 0, - }, - { - __typename: 'KpiNetworkHistogramData', - x: new Date('2019-02-09T22:00:00.000Z').valueOf(), - y: 8, - }, - { - __typename: 'KpiNetworkHistogramData', - x: new Date('2019-02-10T01:00:00.000Z').valueOf(), - y: 8, - }, - ], - dnsQueries: 169, - tlsHandshakes: 62, + networkEvents: 665, + uniqueFlowId: 124, + uniqueSourcePrivateIps: null, + uniqueSourcePrivateIpsHistogram: null, + uniqueDestinationPrivateIps: null, + uniqueDestinationPrivateIpsHistogram: null, + dnsQueries: 0, + tlsHandshakes: 1, }; - it('Make sure that we get KpiNetwork data', () => { - return client - .query({ - query: kpiNetworkQuery, - variables: { - sourceId: 'default', - timerange: { - interval: '12h', - to: TO, - from: FROM, - }, - defaultIndex: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'], - docValueFields: [], - inspect: false, + + it('Make sure that we get KpiNetwork uniqueFlows data', async () => { + const { body: kpiNetwork } = await supertest + .post('/internal/search/securitySolutionSearchStrategy/networkKpiUniqueFlowsQuery') + .set('kbn-xsrf', 'true') + .send({ + factoryQueryType: NetworkKpiQueries.uniqueFlows, + timerange: { + interval: '12h', + to: TO, + from: FROM, + }, + defaultIndex: ['packetbeat-*'], + docValueFields: [], + inspect: false, + }) + .expect(200); + + expect(kpiNetwork.uniqueFlowId).to.eql(expectedResult.uniqueFlowId); + }); + + it('Make sure that we get KpiNetwork DNS data', async () => { + const { body: kpiNetwork } = await supertest + .post('/internal/search/securitySolutionSearchStrategy/networkKpiDnsQuery') + .set('kbn-xsrf', 'true') + .send({ + factoryQueryType: NetworkKpiQueries.dns, + timerange: { + interval: '12h', + to: TO, + from: FROM, + }, + defaultIndex: ['packetbeat-*'], + docValueFields: [], + inspect: false, + }) + .expect(200); + + expect(kpiNetwork.dnsQueries).to.eql(expectedResult.dnsQueries); + }); + + it('Make sure that we get KpiNetwork networkEvents data', async () => { + const { body: kpiNetwork } = await supertest + .post('/internal/search/securitySolutionSearchStrategy/networkKpiNetworkEventsQuery') + .set('kbn-xsrf', 'true') + .send({ + factoryQueryType: NetworkKpiQueries.networkEvents, + timerange: { + interval: '12h', + to: TO, + from: FROM, }, + defaultIndex: ['packetbeat-*'], + docValueFields: [], + inspect: false, }) - .then((resp) => { - const kpiNetwork = resp.data.source.KpiNetwork; - expect(kpiNetwork).to.eql(expectedResult); - }); + .expect(200); + + expect(kpiNetwork.networkEvents).to.eql(expectedResult.networkEvents); + }); + + it('Make sure that we get KpiNetwork tlsHandshakes data', async () => { + const { body: kpiNetwork } = await supertest + .post('/internal/search/securitySolutionSearchStrategy/networkKpiTlsHandshakesQuery') + .set('kbn-xsrf', 'true') + .send({ + factoryQueryType: NetworkKpiQueries.tlsHandshakes, + timerange: { + interval: '12h', + to: TO, + from: FROM, + }, + defaultIndex: ['packetbeat-*'], + docValueFields: [], + inspect: false, + }) + .expect(200); + + expect(kpiNetwork.tlsHandshakes).to.eql(expectedResult.tlsHandshakes); + }); + + it('Make sure that we get KpiNetwork uniquePrivateIps data', async () => { + const { body: kpiNetwork } = await supertest + .post('/internal/search/securitySolutionSearchStrategy/networkKpiUniquePrivateIpsQuery') + .set('kbn-xsrf', 'true') + .send({ + factoryQueryType: NetworkKpiQueries.uniquePrivateIps, + timerange: { + interval: '12h', + to: TO, + from: FROM, + }, + defaultIndex: ['filebeat-*'], + docValueFields: [], + inspect: false, + }) + .expect(200); + + expect(kpiNetwork.uniqueDestinationPrivateIps).to.eql( + expectedResult.uniqueDestinationPrivateIps + ); + expect(kpiNetwork.uniqueDestinationPrivateIpsHistogram).to.eql( + expectedResult.uniqueDestinationPrivateIpsHistogram + ); + expect(kpiNetwork.uniqueSourcePrivateIps).to.eql(expectedResult.uniqueSourcePrivateIps); + expect(kpiNetwork.uniqueSourcePrivateIpsHistogram).to.eql( + expectedResult.uniqueSourcePrivateIpsHistogram + ); }); }); }); diff --git a/x-pack/test/api_integration/apis/security_solution/network_details.ts b/x-pack/test/api_integration/apis/security_solution/network_details.ts index 7b851e875454d..2b602760be342 100644 --- a/x-pack/test/api_integration/apis/security_solution/network_details.ts +++ b/x-pack/test/api_integration/apis/security_solution/network_details.ts @@ -5,41 +5,37 @@ */ import expect from '@kbn/expect'; -// @ts-expect-error -import { ipOverviewQuery } from '../../../../plugins/security_solution/public/network/containers/details/index.gql_query'; -// @ts-expect-error -import { GetIpOverviewQuery } from '../../../../plugins/security_solution/public/graphql/types'; +import { NetworkQueries } from '../../../../plugins/security_solution/common/search_strategy'; + import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ getService }: FtrProviderContext) { const esArchiver = getService('esArchiver'); - const client = getService('securitySolutionGraphQLClient'); - describe('IP Overview', () => { + const supertest = getService('supertest'); + describe('Network details', () => { describe('With filebeat', () => { before(() => esArchiver.load('filebeat/default')); after(() => esArchiver.unload('filebeat/default')); - it('Make sure that we get KpiNetwork data', () => { - return client - .query({ - query: ipOverviewQuery, - variables: { - sourceId: 'default', - ip: '151.205.0.17', - defaultIndex: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'], - docValueFields: [], - inspect: false, - }, + it('Make sure that we get Network details data', async () => { + const { body } = await supertest + .post('/internal/search/securitySolutionSearchStrategy/') + .set('kbn-xsrf', 'true') + .send({ + ip: '151.205.0.17', + defaultIndex: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'], + factoryQueryType: NetworkQueries.details, + docValueFields: [], + inspect: false, }) - .then((resp) => { - const ipOverview = resp.data.source.IpOverview; - expect(ipOverview!.source!.geo!.continent_name).to.be('North America'); - expect(ipOverview!.source!.geo!.location!.lat!).to.be(37.751); - expect(ipOverview!.host.os!.platform!).to.be('raspbian'); - expect(ipOverview!.destination!.geo!.continent_name).to.be('North America'); - expect(ipOverview!.destination!.geo!.location!.lat!).to.be(37.751); - expect(ipOverview!.host.os!.platform!).to.be('raspbian'); - }); + .expect(200); + + expect(body.networkDetails!.source!.geo!.continent_name).to.be('North America'); + expect(body.networkDetails!.source!.geo!.location!.lat!).to.be(37.751); + expect(body.networkDetails!.host.os!.platform!).to.be('raspbian'); + expect(body.networkDetails!.destination!.geo!.continent_name).to.be('North America'); + expect(body.networkDetails!.destination!.geo!.location!.lat!).to.be(37.751); + expect(body.networkDetails!.host.os!.platform!).to.be('raspbian'); }); }); @@ -47,24 +43,22 @@ export default function ({ getService }: FtrProviderContext) { before(() => esArchiver.load('packetbeat/default')); after(() => esArchiver.unload('packetbeat/default')); - it('Make sure that we get KpiNetwork data', () => { - return client - .query({ - query: ipOverviewQuery, - variables: { - sourceId: 'default', - ip: '185.53.91.88', - defaultIndex: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'], - docValueFields: [], - inspect: false, - }, + it('Make sure that we get Network details data', async () => { + const { body } = await supertest + .post('/internal/search/securitySolutionSearchStrategy/') + .set('kbn-xsrf', 'true') + .send({ + ip: '185.53.91.88', + defaultIndex: ['packetbeat-*'], + factoryQueryType: NetworkQueries.details, + docValueFields: [], + inspect: false, }) - .then((resp) => { - const ipOverview = resp.data.source.IpOverview; - expect(ipOverview!.host.id!).to.be('2ce8b1e7d69e4a1d9c6bcddc473da9d9'); - expect(ipOverview!.host.name!).to.be('zeek-sensor-amsterdam'); - expect(ipOverview!.host.os!.platform!).to.be('ubuntu'); - }); + .expect(200); + + expect(body.networkDetails!.host.id!).to.be('2ce8b1e7d69e4a1d9c6bcddc473da9d9'); + expect(body.networkDetails!.host.name!).to.be('zeek-sensor-amsterdam'); + expect(body.networkDetails!.host.os!.platform!).to.be('ubuntu'); }); }); }); diff --git a/x-pack/test/api_integration/apis/security_solution/network_dns.ts b/x-pack/test/api_integration/apis/security_solution/network_dns.ts index b53e2cc72853a..806e0e60a69b2 100644 --- a/x-pack/test/api_integration/apis/security_solution/network_dns.ts +++ b/x-pack/test/api_integration/apis/security_solution/network_dns.ts @@ -5,20 +5,19 @@ */ import expect from '@kbn/expect'; -// @ts-expect-error -import { networkDnsQuery } from '../../../../plugins/security_solution/public/network/containers/network_dns/index.gql_query'; import { + NetworkQueries, + NetworkDnsEdges, Direction, - // @ts-expect-error - GetNetworkDnsQuery, - // @ts-expect-error NetworkDnsFields, -} from '../../../../plugins/security_solution/public/graphql/types'; +} from '../../../../plugins/security_solution/common/search_strategy'; + import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ getService }: FtrProviderContext) { const esArchiver = getService('esArchiver'); - const client = getService('securitySolutionGraphQLClient'); + const supertest = getService('supertest'); + describe('Network DNS', () => { describe('With packetbeat', () => { before(() => esArchiver.load('packetbeat/dns')); @@ -27,79 +26,75 @@ export default function ({ getService }: FtrProviderContext) { const FROM = '2000-01-01T00:00:00.000Z'; const TO = '3000-01-01T00:00:00.000Z'; - it('Make sure that we get Dns data and sorting by uniqueDomains ascending', () => { - return client - .query({ - query: networkDnsQuery, - variables: { - defaultIndex: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'], - docValueFields: [], - inspect: false, - isPtrIncluded: false, - pagination: { - activePage: 0, - cursorStart: 0, - fakePossibleCount: 30, - querySize: 10, - }, - sort: { field: NetworkDnsFields.uniqueDomains, direction: Direction.asc }, - sourceId: 'default', - stackByField: 'dns.question.registered_domain', - timerange: { - interval: '12h', - to: TO, - from: FROM, - }, + it('Make sure that we get Dns data and sorting by uniqueDomains ascending', async () => { + const { body: networkDns } = await supertest + .post('/internal/search/securitySolutionSearchStrategy/') + .set('kbn-xsrf', 'true') + .send({ + defaultIndex: [ + 'apm-*-transaction*', + 'auditbeat-*', + 'endgame-*', + 'filebeat-*', + 'logs-*', + 'packetbeat-*', + 'winlogbeat-*', + ], + docValueFields: [], + factoryQueryType: NetworkQueries.dns, + filterQuery: + '{"bool":{"must":[],"filter":[{"match_all":{}}],"should":[],"must_not":[]}}', + isPtrIncluded: false, + pagination: { activePage: 0, cursorStart: 0, fakePossibleCount: 30, querySize: 10 }, + sort: { field: NetworkDnsFields.uniqueDomains, direction: Direction.asc }, + timerange: { + interval: '12h', + to: TO, + from: FROM, }, }) - .then((resp) => { - const networkDns = resp.data.source.NetworkDns; - expect(networkDns.edges.length).to.be(10); - expect(networkDns.totalCount).to.be(44); - // @ts-expect-error - expect(networkDns.edges.map((i) => i.node.dnsName).join(',')).to.be( - 'aaplimg.com,adgrx.com,akadns.net,akamaiedge.net,amazonaws.com,cbsistatic.com,cdn-apple.com,connman.net,crowbird.com,d1oxlq5h9kq8q5.cloudfront.net' - ); - expect(networkDns.pageInfo.fakeTotalCount).to.equal(30); - }); + .expect(200); + + expect(networkDns.edges.length).to.be(10); + expect(networkDns.totalCount).to.be(44); + expect(networkDns.edges.map((i: NetworkDnsEdges) => i.node.dnsName).join(',')).to.be( + 'aaplimg.com,adgrx.com,akadns.net,akamaiedge.net,amazonaws.com,cbsistatic.com,cdn-apple.com,connman.net,crowbird.com,d1oxlq5h9kq8q5.cloudfront.net' + ); + expect(networkDns.pageInfo.fakeTotalCount).to.equal(30); }); - it('Make sure that we get Dns data and sorting by uniqueDomains descending', () => { - return client - .query({ - query: networkDnsQuery, - variables: { - defaultIndex: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'], - docValueFields: [], - isDnsHistogram: false, - inspect: false, - isPtrIncluded: false, - pagination: { - activePage: 0, - cursorStart: 0, - fakePossibleCount: 30, - querySize: 10, - }, - sourceId: 'default', - sort: { field: NetworkDnsFields.uniqueDomains, direction: Direction.desc }, - stackByField: 'dns.question.registered_domain', - timerange: { - interval: '12h', - to: TO, - from: FROM, - }, + it('Make sure that we get Dns data and sorting by uniqueDomains descending', async () => { + const { body: networkDns } = await supertest + .post('/internal/search/securitySolutionSearchStrategy/') + .set('kbn-xsrf', 'true') + .send({ + ip: '151.205.0.17', + defaultIndex: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'], + factoryQueryType: NetworkQueries.dns, + docValueFields: [], + inspect: false, + pagination: { + activePage: 0, + cursorStart: 0, + fakePossibleCount: 30, + querySize: 10, + }, + sort: { field: NetworkDnsFields.uniqueDomains, direction: Direction.desc }, + stackByField: 'dns.question.registered_domain', + timerange: { + interval: '12h', + to: TO, + from: FROM, }, }) - .then((resp) => { - const networkDns = resp.data.source.NetworkDns; - expect(networkDns.edges.length).to.be(10); - expect(networkDns.totalCount).to.be(44); - // @ts-expect-error - expect(networkDns.edges.map((i) => i.node.dnsName).join(',')).to.be( - 'nflxvideo.net,apple.com,netflix.com,samsungcloudsolution.com,samsungqbe.com,samsungelectronics.com,internetat.tv,samsungcloudsolution.net,samsungosp.com,cbsnews.com' - ); - expect(networkDns.pageInfo.fakeTotalCount).to.equal(30); - }); + .expect(200); + + expect(networkDns.edges.length).to.be(10); + expect(networkDns.totalCount).to.be(44); + expect(networkDns.edges.map((i: NetworkDnsEdges) => i.node.dnsName).join(',')).to.be( + 'nflxvideo.net,apple.com,netflix.com,samsungcloudsolution.com,samsungqbe.com,samsungelectronics.com,internetat.tv,samsungcloudsolution.net,samsungosp.com,cbsnews.com' + ); + expect(networkDns.pageInfo.fakeTotalCount).to.equal(30); }); }); }); diff --git a/x-pack/test/api_integration/apis/security_solution/network_top_n_flow.ts b/x-pack/test/api_integration/apis/security_solution/network_top_n_flow.ts index 81a1924019a55..abca6e0361097 100644 --- a/x-pack/test/api_integration/apis/security_solution/network_top_n_flow.ts +++ b/x-pack/test/api_integration/apis/security_solution/network_top_n_flow.ts @@ -5,23 +5,22 @@ */ import expect from '@kbn/expect'; -// @ts-expect-error -import { networkTopNFlowQuery } from '../../../../plugins/security_solution/public/network/containers/network_top_n_flow/index.gql_query'; import { + NetworkQueries, + NetworkTopNFlowEdges, Direction, FlowTargetSourceDest, - // @ts-expect-error - GetNetworkTopNFlowQuery, - // @ts-expect-error NetworkTopTablesFields, -} from '../../../../plugins/security_solution/public/graphql/types'; +} from '../../../../plugins/security_solution/common/search_strategy'; + import { FtrProviderContext } from '../../ftr_provider_context'; const EDGE_LENGTH = 10; export default function ({ getService }: FtrProviderContext) { const esArchiver = getService('esArchiver'); - const client = getService('securitySolutionGraphQLClient'); + const supertest = getService('supertest'); + describe('Network Top N Flow', () => { describe('With filebeat', () => { before(() => esArchiver.load('filebeat/default')); @@ -30,150 +29,180 @@ export default function ({ getService }: FtrProviderContext) { const FROM = '2019-02-09T01:57:24.870Z'; const TO = '2019-02-12T01:57:24.870Z'; - it('Make sure that we get Source NetworkTopNFlow data with bytes_in descending sort', () => { - return client - .query({ - query: networkTopNFlowQuery, - variables: { - sourceId: 'default', - timerange: { - interval: '12h', - to: TO, - from: FROM, - }, - flowTarget: FlowTargetSourceDest.source, - sort: { field: NetworkTopTablesFields.bytes_in, direction: Direction.desc }, - pagination: { - activePage: 0, - cursorStart: 0, - fakePossibleCount: 50, - querySize: 10, - }, - defaultIndex: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'], - docValueFields: [], - inspect: false, + it('Make sure that we get Source NetworkTopNFlow data with bytes_in descending sort', async () => { + const { body: networkTopNFlow } = await supertest + .post('/internal/search/securitySolutionSearchStrategy/') + .set('kbn-xsrf', 'true') + .send({ + defaultIndex: [ + 'apm-*-transaction*', + 'auditbeat-*', + 'endgame-*', + 'filebeat-*', + 'logs-*', + 'packetbeat-*', + 'winlogbeat-*', + ], + factoryQueryType: NetworkQueries.topNFlow, + flowTarget: FlowTargetSourceDest.source, + sort: { field: NetworkTopTablesFields.bytes_in, direction: Direction.desc }, + pagination: { + activePage: 0, + cursorStart: 0, + fakePossibleCount: 50, + querySize: 10, }, + timerange: { + interval: '12h', + to: TO, + from: FROM, + }, + docValueFields: [], + inspect: false, }) - .then((resp) => { - const networkTopNFlow = resp.data.source.NetworkTopNFlow; - expect(networkTopNFlow.edges.length).to.be(EDGE_LENGTH); - expect(networkTopNFlow.totalCount).to.be(121); - // @ts-expect-error - expect(networkTopNFlow.edges.map((i) => i.node.source!.ip).join(',')).to.be( - '10.100.7.196,10.100.7.199,10.100.7.197,10.100.7.198,3.82.33.170,17.249.172.100,10.100.4.1,8.248.209.244,8.248.211.247,8.248.213.244' - ); - expect(networkTopNFlow.edges[0].node.destination).to.be(null); - expect(networkTopNFlow.edges[0].node.source!.flows).to.be(498); - expect(networkTopNFlow.edges[0].node.source!.destination_ips).to.be(132); - expect(networkTopNFlow.pageInfo.fakeTotalCount).to.equal(50); - }); + .expect(200); + + expect(networkTopNFlow.edges.length).to.be(EDGE_LENGTH); + expect(networkTopNFlow.totalCount).to.be(121); + expect( + networkTopNFlow.edges.map((i: NetworkTopNFlowEdges) => i.node.source!.ip).join(',') + ).to.be( + '10.100.7.196,10.100.7.199,10.100.7.197,10.100.7.198,3.82.33.170,17.249.172.100,10.100.4.1,8.248.209.244,8.248.211.247,8.248.213.244' + ); + expect(networkTopNFlow.edges[0].node.destination).to.be(undefined); + expect(networkTopNFlow.edges[0].node.source!.flows).to.be(498); + expect(networkTopNFlow.edges[0].node.source!.destination_ips).to.be(132); + expect(networkTopNFlow.pageInfo.fakeTotalCount).to.equal(50); }); - it('Make sure that we get Source NetworkTopNFlow data with bytes_in ascending sort ', () => { - return client - .query({ - query: networkTopNFlowQuery, - variables: { - sourceId: 'default', - timerange: { - interval: '12h', - to: TO, - from: FROM, - }, - flowTarget: FlowTargetSourceDest.source, - sort: { field: NetworkTopTablesFields.bytes_in, direction: Direction.asc }, - pagination: { - activePage: 0, - cursorStart: 0, - fakePossibleCount: 50, - querySize: 10, - }, - defaultIndex: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'], - docValueFields: [], - inspect: false, + it('Make sure that we get Source NetworkTopNFlow data with bytes_in ascending sort ', async () => { + const { body: networkTopNFlow } = await supertest + .post('/internal/search/securitySolutionSearchStrategy/') + .set('kbn-xsrf', 'true') + .send({ + defaultIndex: [ + 'apm-*-transaction*', + 'auditbeat-*', + 'endgame-*', + 'filebeat-*', + 'logs-*', + 'packetbeat-*', + 'winlogbeat-*', + ], + factoryQueryType: 'topNFlow', + filterQuery: + '{"bool":{"must":[],"filter":[{"match_all":{}}],"should":[],"must_not":[]}}', + flowTarget: FlowTargetSourceDest.source, + sort: { field: NetworkTopTablesFields.bytes_in, direction: Direction.asc }, + pagination: { + activePage: 0, + cursorStart: 0, + fakePossibleCount: 50, + querySize: 10, }, + timerange: { + interval: '12h', + to: TO, + from: FROM, + }, + docValueFields: [], + inspect: false, }) - .then((resp) => { - const networkTopNFlow = resp.data.source.NetworkTopNFlow; - expect(networkTopNFlow.edges.length).to.be(EDGE_LENGTH); - expect(networkTopNFlow.totalCount).to.be(121); - // @ts-expect-error - expect(networkTopNFlow.edges.map((i) => i.node.source!.ip).join(',')).to.be( - '8.248.209.244,8.248.211.247,8.248.213.244,8.248.223.246,8.250.107.245,8.250.121.236,8.250.125.244,8.253.38.231,8.253.157.112,8.253.157.240' - ); - expect(networkTopNFlow.edges[0].node.destination).to.be(null); - expect(networkTopNFlow.edges[0].node.source!.flows).to.be(12); - expect(networkTopNFlow.edges[0].node.source!.destination_ips).to.be(1); - expect(networkTopNFlow.pageInfo.fakeTotalCount).to.equal(50); - }); + .expect(200); + + expect(networkTopNFlow.edges.length).to.be(EDGE_LENGTH); + expect(networkTopNFlow.totalCount).to.be(121); + expect( + networkTopNFlow.edges.map((i: NetworkTopNFlowEdges) => i.node.source!.ip).join(',') + ).to.be( + '8.248.209.244,8.248.211.247,8.248.213.244,8.248.223.246,8.250.107.245,8.250.121.236,8.250.125.244,8.253.38.231,8.253.157.112,8.253.157.240' + ); + expect(networkTopNFlow.edges[0].node.destination).to.be(undefined); + expect(networkTopNFlow.edges[0].node.source!.flows).to.be(12); + expect(networkTopNFlow.edges[0].node.source!.destination_ips).to.be(1); + expect(networkTopNFlow.pageInfo.fakeTotalCount).to.equal(50); }); - it('Make sure that we get Destination NetworkTopNFlow data', () => { - return client - .query({ - query: networkTopNFlowQuery, - variables: { - sourceId: 'default', - timerange: { - interval: '12h', - to: TO, - from: FROM, - }, - sort: { field: NetworkTopTablesFields.bytes_in, direction: Direction.desc }, - flowTarget: FlowTargetSourceDest.destination, - pagination: { - activePage: 0, - cursorStart: 0, - fakePossibleCount: 50, - querySize: 10, - }, - defaultIndex: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'], - docValueFields: [], - inspect: false, + it('Make sure that we get Destination NetworkTopNFlow data', async () => { + const { body: networkTopNFlow } = await supertest + .post('/internal/search/securitySolutionSearchStrategy/') + .set('kbn-xsrf', 'true') + .send({ + defaultIndex: [ + 'apm-*-transaction*', + 'auditbeat-*', + 'endgame-*', + 'filebeat-*', + 'logs-*', + 'packetbeat-*', + 'winlogbeat-*', + ], + factoryQueryType: 'topNFlow', + filterQuery: + '{"bool":{"must":[],"filter":[{"match_all":{}}],"should":[],"must_not":[]}}', + sort: { field: NetworkTopTablesFields.bytes_in, direction: Direction.desc }, + flowTarget: FlowTargetSourceDest.destination, + pagination: { + activePage: 0, + cursorStart: 0, + fakePossibleCount: 50, + querySize: 10, }, + timerange: { + interval: '12h', + to: TO, + from: FROM, + }, + docValueFields: [], + inspect: false, }) - .then((resp) => { - const networkTopNFlow = resp.data.source.NetworkTopNFlow; - expect(networkTopNFlow.edges.length).to.be(EDGE_LENGTH); - expect(networkTopNFlow.totalCount).to.be(154); - expect(networkTopNFlow.edges[0].node.destination!.flows).to.be(19); - expect(networkTopNFlow.edges[0].node.destination!.source_ips).to.be(1); - expect(networkTopNFlow.edges[0].node.source).to.be(null); - expect(networkTopNFlow.pageInfo.fakeTotalCount).to.equal(50); - }); + .expect(200); + expect(networkTopNFlow.edges.length).to.be(EDGE_LENGTH); + expect(networkTopNFlow.totalCount).to.be(154); + expect(networkTopNFlow.edges[0].node.destination!.flows).to.be(19); + expect(networkTopNFlow.edges[0].node.destination!.source_ips).to.be(1); + expect(networkTopNFlow.edges[0].node.source).to.be(undefined); + expect(networkTopNFlow.pageInfo.fakeTotalCount).to.equal(50); }); - it('Make sure that pagination is working in NetworkTopNFlow query', () => { - return client - .query({ - query: networkTopNFlowQuery, - variables: { - sourceId: 'default', - timerange: { - interval: '12h', - to: TO, - from: FROM, - }, - sort: { field: NetworkTopTablesFields.bytes_in, direction: Direction.desc }, - flowTarget: FlowTargetSourceDest.source, - pagination: { - activePage: 1, - cursorStart: 10, - fakePossibleCount: 50, - querySize: 20, - }, - defaultIndex: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'], - docValueFields: [], - inspect: false, + it('Make sure that pagination is working in NetworkTopNFlow query', async () => { + const { body: networkTopNFlow } = await supertest + .post('/internal/search/securitySolutionSearchStrategy/') + .set('kbn-xsrf', 'true') + .send({ + defaultIndex: [ + 'apm-*-transaction*', + 'auditbeat-*', + 'endgame-*', + 'filebeat-*', + 'logs-*', + 'packetbeat-*', + 'winlogbeat-*', + ], + factoryQueryType: 'topNFlow', + filterQuery: + '{"bool":{"must":[],"filter":[{"match_all":{}}],"should":[],"must_not":[]}}', + sort: { field: NetworkTopTablesFields.bytes_in, direction: Direction.desc }, + flowTarget: FlowTargetSourceDest.source, + pagination: { + activePage: 1, + cursorStart: 10, + fakePossibleCount: 50, + querySize: 20, + }, + timerange: { + interval: '12h', + to: TO, + from: FROM, }, + docValueFields: [], + inspect: false, }) - .then((resp) => { - const networkTopNFlow = resp.data.source.NetworkTopNFlow; + .expect(200); - expect(networkTopNFlow.edges.length).to.be(EDGE_LENGTH); - expect(networkTopNFlow.totalCount).to.be(121); - expect(networkTopNFlow.edges[0].node.source!.ip).to.be('8.248.223.246'); - }); + expect(networkTopNFlow.edges.length).to.be(EDGE_LENGTH); + expect(networkTopNFlow.totalCount).to.be(121); + expect(networkTopNFlow.edges[0].node.source!.ip).to.be('8.248.223.246'); }); }); }); diff --git a/x-pack/test/api_integration/apis/security_solution/overview_host.ts b/x-pack/test/api_integration/apis/security_solution/overview_host.ts index 0d648e665a9a9..f3de9a6481b8f 100644 --- a/x-pack/test/api_integration/apis/security_solution/overview_host.ts +++ b/x-pack/test/api_integration/apis/security_solution/overview_host.ts @@ -6,16 +6,13 @@ import expect from '@kbn/expect'; -import { DEFAULT_INDEX_PATTERN } from '../../../../plugins/security_solution/common/constants'; -// @ts-expect-error -import { overviewHostQuery } from '../../../../plugins/security_solution/public/overview/containers//overview_host/index.gql_query'; -// @ts-expect-error -import { GetOverviewHostQuery } from '../../../../plugins/security_solution/public/graphql/types'; import { FtrProviderContext } from '../../ftr_provider_context'; +import { HostsQueries } from '../../../../plugins/security_solution/common/search_strategy'; export default function ({ getService }: FtrProviderContext) { const esArchiver = getService('esArchiver'); - const client = getService('securitySolutionGraphQLClient'); + const supertest = getService('supertest'); + describe('Overview Host', () => { describe('With auditbeat', () => { before(() => esArchiver.load('auditbeat/overview')); @@ -39,30 +36,36 @@ export default function ({ getService }: FtrProviderContext) { endgameSecurity: 4, filebeatSystemModule: 0, winlogbeatSecurity: 0, - winlogbeatMWSysmonOperational: 0, - __typename: 'OverviewHostData', + winlogbeatMWSysmonOperational: null, }; - it('Make sure that we get OverviewHost data', () => { - return client - .query({ - query: overviewHostQuery, - variables: { - sourceId: 'default', - timerange: { - interval: '12h', - to: TO, - from: FROM, - }, - defaultIndex: DEFAULT_INDEX_PATTERN, - docValueFields: [], - inspect: false, + it('Make sure that we get OverviewHost data', async () => { + const { + body: { overviewHost }, + } = await supertest + .post('/internal/search/securitySolutionSearchStrategy/') + .set('kbn-xsrf', 'true') + .send({ + defaultIndex: [ + 'apm-*-transaction*', + 'auditbeat-*', + 'endgame-*', + 'filebeat-*', + 'logs-*', + 'packetbeat-*', + 'winlogbeat-*', + ], + factoryQueryType: HostsQueries.overview, + timerange: { + interval: '12h', + to: TO, + from: FROM, }, + docValueFields: [], + inspect: false, }) - .then((resp) => { - const overviewHost = resp.data.source.OverviewHost; - expect(overviewHost).to.eql(expectedResult); - }); + .expect(200); + expect(overviewHost).to.eql(expectedResult); }); }); }); diff --git a/x-pack/test/api_integration/apis/security_solution/overview_network.ts b/x-pack/test/api_integration/apis/security_solution/overview_network.ts index 60d300e168e4a..f0b5c635c878c 100644 --- a/x-pack/test/api_integration/apis/security_solution/overview_network.ts +++ b/x-pack/test/api_integration/apis/security_solution/overview_network.ts @@ -5,15 +5,13 @@ */ import expect from '@kbn/expect'; -// @ts-expect-error -import { overviewNetworkQuery } from '../../../../plugins/security_solution/public/overview/containers/overview_network/index.gql_query'; -// @ts-expect-error -import { GetOverviewNetworkQuery } from '../../../../plugins/security_solution/public/graphql/types'; import { FtrProviderContext } from '../../ftr_provider_context'; +import { NetworkQueries } from '../../../../plugins/security_solution/common/search_strategy'; export default function ({ getService }: FtrProviderContext) { const esArchiver = getService('esArchiver'); - const client = getService('securitySolutionGraphQLClient'); + const supertest = getService('supertest'); + describe('Overview Network', () => { describe('With filebeat', () => { before(() => esArchiver.load('filebeat/default')); @@ -32,29 +30,27 @@ export default function ({ getService }: FtrProviderContext) { packetbeatDNS: 0, packetbeatFlow: 0, packetbeatTLS: 0, - __typename: 'OverviewNetworkData', }; - it('Make sure that we get OverviewNetwork data', () => { - return client - .query({ - query: overviewNetworkQuery, - variables: { - sourceId: 'default', - timerange: { - interval: '12h', - to: TO, - from: FROM, - }, - defaultIndex: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'], - docValueFields: [], - inspect: false, + it('Make sure that we get OverviewNetwork data', async () => { + const { + body: { overviewNetwork }, + } = await supertest + .post('/internal/search/securitySolutionSearchStrategy/') + .set('kbn-xsrf', 'true') + .send({ + defaultIndex: ['filebeat-*'], + factoryQueryType: NetworkQueries.overview, + timerange: { + interval: '12h', + to: TO, + from: FROM, }, + docValueFields: [], + inspect: false, }) - .then((resp) => { - const overviewNetwork = resp.data.source.OverviewNetwork; - expect(overviewNetwork).to.eql(expectedResult); - }); + .expect(200); + expect(overviewNetwork).to.eql(expectedResult); }); }); @@ -67,36 +63,35 @@ export default function ({ getService }: FtrProviderContext) { const expectedResult = { auditbeatSocket: 0, filebeatCisco: 0, - filebeatNetflow: 1273, + filebeatNetflow: 0, filebeatPanw: 0, - filebeatSuricata: 4547, + filebeatSuricata: 0, filebeatZeek: 0, - packetbeatDNS: 0, - packetbeatFlow: 0, + packetbeatDNS: 44, + packetbeatFlow: 588, packetbeatTLS: 0, - __typename: 'OverviewNetworkData', }; - it('Make sure that we get OverviewNetwork data', () => { - return client - .query({ - query: overviewNetworkQuery, - variables: { - sourceId: 'default', - timerange: { - interval: '12h', - to: TO, - from: FROM, - }, - defaultIndex: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'], - docValueFields: [], - inspect: false, + it('Make sure that we get OverviewNetwork data', async () => { + const { + body: { overviewNetwork }, + } = await supertest + .post('/internal/search/securitySolutionSearchStrategy/') + .set('kbn-xsrf', 'true') + .send({ + defaultIndex: ['packetbeat-*'], + factoryQueryType: NetworkQueries.overview, + timerange: { + interval: '12h', + to: TO, + from: FROM, }, + docValueFields: [], + inspect: false, }) - .then((resp) => { - const overviewNetwork = resp.data.source.OverviewNetwork; - expect(overviewNetwork).to.eql(expectedResult); - }); + .expect(200); + + expect(overviewNetwork).to.eql(expectedResult); }); }); @@ -107,38 +102,36 @@ export default function ({ getService }: FtrProviderContext) { const FROM = '2000-01-01T00:00:00.000Z'; const TO = '3000-01-01T00:00:00.000Z'; const expectedResult = { - auditbeatSocket: 0, + auditbeatSocket: 45, filebeatCisco: 0, - filebeatNetflow: 1273, + filebeatNetflow: 0, filebeatPanw: 0, - filebeatSuricata: 4547, + filebeatSuricata: 0, filebeatZeek: 0, packetbeatDNS: 0, packetbeatFlow: 0, packetbeatTLS: 0, - __typename: 'OverviewNetworkData', }; - it('Make sure that we get OverviewNetwork data', () => { - return client - .query({ - query: overviewNetworkQuery, - variables: { - sourceId: 'default', - timerange: { - interval: '12h', - to: TO, - from: FROM, - }, - defaultIndex: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'], - docValueFields: [], - inspect: false, + it('Make sure that we get OverviewNetwork data', async () => { + const { + body: { overviewNetwork }, + } = await supertest + .post('/internal/search/securitySolutionSearchStrategy/') + .set('kbn-xsrf', 'true') + .send({ + defaultIndex: ['auditbeat-*'], + factoryQueryType: NetworkQueries.overview, + timerange: { + interval: '12h', + to: TO, + from: FROM, }, + docValueFields: [], + inspect: false, }) - .then((resp) => { - const overviewNetwork = resp.data.source.OverviewNetwork; - expect(overviewNetwork).to.eql(expectedResult); - }); + .expect(200); + expect(overviewNetwork).to.eql(expectedResult); }); }); }); diff --git a/x-pack/test/api_integration/apis/security_solution/sources.ts b/x-pack/test/api_integration/apis/security_solution/sources.ts index 1ec4bfda8492d..228d0736f26d7 100644 --- a/x-pack/test/api_integration/apis/security_solution/sources.ts +++ b/x-pack/test/api_integration/apis/security_solution/sources.ts @@ -35,12 +35,12 @@ export default function ({ getService }: FtrProviderContext) { .post('/internal/search/securitySolutionIndexFields/') .set('kbn-xsrf', 'true') .send({ - indices: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'], + indices: ['auditbeat-*', 'filebeat-*'], onlyCheckIfIndicesExist: false, }) .expect(200); - expect(sourceStatus.indicesExist).to.eql(['auditbeat-*', 'winlogbeat-*']); + expect(sourceStatus.indicesExist).to.eql(['auditbeat-*']); }); it('should not find indexes as existing when there is an empty array of them', async () => { diff --git a/x-pack/test/api_integration/apis/security_solution/timeline.ts b/x-pack/test/api_integration/apis/security_solution/timeline.ts index 8ae562a961431..41b557ce3fd32 100644 --- a/x-pack/test/api_integration/apis/security_solution/timeline.ts +++ b/x-pack/test/api_integration/apis/security_solution/timeline.ts @@ -6,13 +6,11 @@ import expect from '@kbn/expect'; +import { Direction } from '../../../../plugins/security_solution/common/search_strategy'; // @ts-expect-error import { timelineQuery } from '../../../../plugins/security_solution/public/timelines/containers/index.gql_query'; -import { - Direction, - // @ts-expect-error - GetTimelineQuery, -} from '../../../../plugins/security_solution/public/graphql/types'; +// @ts-expect-error +import { GetTimelineQuery } from '../../../../plugins/security_solution/public/graphql/types'; import { FtrProviderContext } from '../../ftr_provider_context'; const TO = '3000-01-01T00:00:00.000Z'; diff --git a/x-pack/test/api_integration/apis/security_solution/timeline_details.ts b/x-pack/test/api_integration/apis/security_solution/timeline_details.ts index 559cdc8c29c09..d3f40188aa6d3 100644 --- a/x-pack/test/api_integration/apis/security_solution/timeline_details.ts +++ b/x-pack/test/api_integration/apis/security_solution/timeline_details.ts @@ -6,92 +6,72 @@ import expect from '@kbn/expect'; import { sortBy } from 'lodash'; +import { TimelineEventsQueries } from '../../../../plugins/security_solution/common/search_strategy'; -// @ts-expect-error -import { timelineDetailsQuery } from '../../../../plugins/security_solution/public/timelines/containers/details/index.gql_query'; -import { - // @ts-expect-error - DetailItem, - // @ts-expect-error - GetTimelineDetailsQuery, -} from '../../../../plugins/security_solution/public/graphql/types'; import { FtrProviderContext } from '../../ftr_provider_context'; -type DetailsData = Array< - Pick & { - __typename: string; - } ->; - // typical values that have to change after an update from "scripts/es_archiver" const INDEX_NAME = 'filebeat-7.0.0-iot-2019.06'; const ID = 'QRhG1WgBqd-n62SwZYDT'; -const EXPECTED_DATA: DetailItem[] = [ +const EXPECTED_DATA = [ { + category: 'base', field: '@timestamp', values: ['2019-02-10T02:39:44.107Z'], originalValue: '2019-02-10T02:39:44.107Z', }, - { field: '@version', values: ['1'], originalValue: '1' }, + { category: '@version', field: '@version', values: ['1'], originalValue: '1' }, { + category: 'agent', field: 'agent.ephemeral_id', values: ['909cd6a1-527d-41a5-9585-a7fb5386f851'], originalValue: '909cd6a1-527d-41a5-9585-a7fb5386f851', }, { + category: 'agent', field: 'agent.hostname', values: ['raspberrypi'], originalValue: 'raspberrypi', }, { + category: 'agent', field: 'agent.id', values: ['4d3ea604-27e5-4ec7-ab64-44f82285d776'], originalValue: '4d3ea604-27e5-4ec7-ab64-44f82285d776', }, + { category: 'agent', field: 'agent.type', values: ['filebeat'], originalValue: 'filebeat' }, + { category: 'agent', field: 'agent.version', values: ['7.0.0'], originalValue: '7.0.0' }, { - field: 'agent.type', - values: ['filebeat'], - originalValue: 'filebeat', - }, - { field: 'agent.version', values: ['7.0.0'], originalValue: '7.0.0' }, - { + category: 'destination', field: 'destination.domain', values: ['s3-iad-2.cf.dash.row.aiv-cdn.net'], originalValue: 's3-iad-2.cf.dash.row.aiv-cdn.net', }, { + category: 'destination', field: 'destination.ip', values: ['10.100.7.196'], originalValue: '10.100.7.196', }, - { field: 'destination.port', values: ['40684'], originalValue: 40684 }, - { - field: 'ecs.version', - values: ['1.0.0-beta2'], - originalValue: '1.0.0-beta2', - }, + { category: 'destination', field: 'destination.port', values: [40684], originalValue: 40684 }, + { category: 'ecs', field: 'ecs.version', values: ['1.0.0-beta2'], originalValue: '1.0.0-beta2' }, { + category: 'event', field: 'event.dataset', values: ['suricata.eve'], originalValue: 'suricata.eve', }, { + category: 'event', field: 'event.end', values: ['2019-02-10T02:39:44.107Z'], originalValue: '2019-02-10T02:39:44.107Z', }, - { field: 'event.kind', values: ['event'], originalValue: 'event' }, - { - field: 'event.module', - values: ['suricata'], - originalValue: 'suricata', - }, - { - field: 'event.type', - values: ['fileinfo'], - originalValue: 'fileinfo', - }, + { category: 'event', field: 'event.kind', values: ['event'], originalValue: 'event' }, + { category: 'event', field: 'event.module', values: ['suricata'], originalValue: 'suricata' }, + { category: 'event', field: 'event.type', values: ['fileinfo'], originalValue: 'fileinfo' }, { + category: 'file', field: 'file.path', values: [ '/dm/2$XTMWANo0Q2RZKlH-95UoAahZrOg~/0a9a/bf72/e1da/4c20-919e-0cbabcf7bfe8/75f50c57-d25f-4e97-9e37-01b9f5caa293_audio_13.mp4', @@ -99,179 +79,157 @@ const EXPECTED_DATA: DetailItem[] = [ originalValue: '/dm/2$XTMWANo0Q2RZKlH-95UoAahZrOg~/0a9a/bf72/e1da/4c20-919e-0cbabcf7bfe8/75f50c57-d25f-4e97-9e37-01b9f5caa293_audio_13.mp4', }, - { field: 'file.size', values: ['48277'], originalValue: 48277 }, - { field: 'fileset.name', values: ['eve'], originalValue: 'eve' }, - { field: 'flow.locality', values: ['public'], originalValue: 'public' }, - { - field: 'host.architecture', - values: ['armv7l'], - originalValue: 'armv7l', - }, + { category: 'file', field: 'file.size', values: [48277], originalValue: 48277 }, + { category: 'fileset', field: 'fileset.name', values: ['eve'], originalValue: 'eve' }, + { category: 'flow', field: 'flow.locality', values: ['public'], originalValue: 'public' }, + { category: 'host', field: 'host.architecture', values: ['armv7l'], originalValue: 'armv7l' }, { + category: 'host', field: 'host.hostname', values: ['raspberrypi'], originalValue: 'raspberrypi', }, { + category: 'host', field: 'host.id', values: ['b19a781f683541a7a25ee345133aa399'], originalValue: 'b19a781f683541a7a25ee345133aa399', }, + { category: 'host', field: 'host.name', values: ['raspberrypi'], originalValue: 'raspberrypi' }, + { category: 'host', field: 'host.os.codename', values: ['stretch'], originalValue: 'stretch' }, + { category: 'host', field: 'host.os.family', values: [''], originalValue: '' }, { - field: 'host.name', - values: ['raspberrypi'], - originalValue: 'raspberrypi', - }, - { - field: 'host.os.codename', - values: ['stretch'], - originalValue: 'stretch', - }, - { field: 'host.os.family', values: [''], originalValue: '' }, - { + category: 'host', field: 'host.os.kernel', values: ['4.14.50-v7+'], originalValue: '4.14.50-v7+', }, { + category: 'host', field: 'host.os.name', values: ['Raspbian GNU/Linux'], originalValue: 'Raspbian GNU/Linux', }, + { category: 'host', field: 'host.os.platform', values: ['raspbian'], originalValue: 'raspbian' }, { - field: 'host.os.platform', - values: ['raspbian'], - originalValue: 'raspbian', - }, - { + category: 'host', field: 'host.os.version', values: ['9 (stretch)'], originalValue: '9 (stretch)', }, - { field: 'http.request.method', values: ['get'], originalValue: 'get' }, - { - field: 'http.response.body.bytes', - values: ['48277'], - originalValue: 48277, - }, - { - field: 'http.response.status_code', - values: ['206'], - originalValue: 206, - }, - { field: 'input.type', values: ['log'], originalValue: 'log' }, + { category: 'http', field: 'http.request.method', values: ['get'], originalValue: 'get' }, + { category: 'http', field: 'http.response.body.bytes', values: [48277], originalValue: 48277 }, + { category: 'http', field: 'http.response.status_code', values: [206], originalValue: 206 }, + { category: 'input', field: 'input.type', values: ['log'], originalValue: 'log' }, { + category: 'base', field: 'labels.pipeline', values: ['filebeat-7.0.0-suricata-eve-pipeline'], originalValue: 'filebeat-7.0.0-suricata-eve-pipeline', }, { + category: 'log', field: 'log.file.path', values: ['/var/log/suricata/eve.json'], originalValue: '/var/log/suricata/eve.json', }, + { category: 'log', field: 'log.offset', values: [1856288115], originalValue: 1856288115 }, + { category: 'network', field: 'network.name', values: ['iot'], originalValue: 'iot' }, + { category: 'network', field: 'network.protocol', values: ['http'], originalValue: 'http' }, + { category: 'network', field: 'network.transport', values: ['tcp'], originalValue: 'tcp' }, + { category: 'service', field: 'service.type', values: ['suricata'], originalValue: 'suricata' }, + { category: 'source', field: 'source.as.num', values: [16509], originalValue: 16509 }, { - field: 'log.offset', - values: ['1856288115'], - originalValue: 1856288115, - }, - { field: 'network.name', values: ['iot'], originalValue: 'iot' }, - { field: 'network.protocol', values: ['http'], originalValue: 'http' }, - { field: 'network.transport', values: ['tcp'], originalValue: 'tcp' }, - { - field: 'service.type', - values: ['suricata'], - originalValue: 'suricata', - }, - { field: 'source.as.num', values: ['16509'], originalValue: 16509 }, - { + category: 'source', field: 'source.as.org', values: ['Amazon.com, Inc.'], originalValue: 'Amazon.com, Inc.', }, { + category: 'source', field: 'source.domain', values: ['server-54-239-219-210.jfk51.r.cloudfront.net'], originalValue: 'server-54-239-219-210.jfk51.r.cloudfront.net', }, { + category: 'source', field: 'source.geo.city_name', values: ['Seattle'], originalValue: 'Seattle', }, { + category: 'source', field: 'source.geo.continent_name', values: ['North America'], originalValue: 'North America', }, + { category: 'source', field: 'source.geo.country_iso_code', values: ['US'], originalValue: 'US' }, { - field: 'source.geo.country_iso_code', - values: ['US'], - originalValue: 'US', - }, - { + category: 'source', field: 'source.geo.location.lat', - values: ['47.6103'], + values: [47.6103], originalValue: 47.6103, }, { + category: 'source', field: 'source.geo.location.lon', - values: ['-122.3341'], + values: [-122.3341], originalValue: -122.3341, }, { + category: 'source', field: 'source.geo.region_iso_code', values: ['US-WA'], originalValue: 'US-WA', }, { + category: 'source', field: 'source.geo.region_name', values: ['Washington'], originalValue: 'Washington', }, { + category: 'source', field: 'source.ip', values: ['54.239.219.210'], originalValue: '54.239.219.210', }, - { field: 'source.port', values: ['80'], originalValue: 80 }, + { category: 'source', field: 'source.port', values: [80], originalValue: 80 }, { + category: 'suricata', field: 'suricata.eve.fileinfo.state', values: ['CLOSED'], originalValue: 'CLOSED', }, + { category: 'suricata', field: 'suricata.eve.fileinfo.tx_id', values: [301], originalValue: 301 }, { - field: 'suricata.eve.fileinfo.tx_id', - values: ['301'], - originalValue: 301, - }, - { + category: 'suricata', field: 'suricata.eve.flow_id', - values: ['196625917175466'], + values: [196625917175466], originalValue: 196625917175466, }, { + category: 'suricata', field: 'suricata.eve.http.http_content_type', values: ['video/mp4'], originalValue: 'video/mp4', }, { + category: 'suricata', field: 'suricata.eve.http.protocol', values: ['HTTP/1.1'], originalValue: 'HTTP/1.1', }, + { category: 'suricata', field: 'suricata.eve.in_iface', values: ['eth0'], originalValue: 'eth0' }, + { category: 'base', field: 'tags', values: ['suricata'], originalValue: ['suricata'] }, { - field: 'suricata.eve.in_iface', - values: ['eth0'], - originalValue: 'eth0', - }, - { field: 'tags', values: ['suricata'], originalValue: ['suricata'] }, - { + category: 'url', field: 'url.domain', values: ['s3-iad-2.cf.dash.row.aiv-cdn.net'], originalValue: 's3-iad-2.cf.dash.row.aiv-cdn.net', }, { + category: 'url', field: 'url.original', values: [ '/dm/2$XTMWANo0Q2RZKlH-95UoAahZrOg~/0a9a/bf72/e1da/4c20-919e-0cbabcf7bfe8/75f50c57-d25f-4e97-9e37-01b9f5caa293_audio_13.mp4', @@ -280,6 +238,7 @@ const EXPECTED_DATA: DetailItem[] = [ '/dm/2$XTMWANo0Q2RZKlH-95UoAahZrOg~/0a9a/bf72/e1da/4c20-919e-0cbabcf7bfe8/75f50c57-d25f-4e97-9e37-01b9f5caa293_audio_13.mp4', }, { + category: 'url', field: 'url.path', values: [ '/dm/2$XTMWANo0Q2RZKlH-95UoAahZrOg~/0a9a/bf72/e1da/4c20-919e-0cbabcf7bfe8/75f50c57-d25f-4e97-9e37-01b9f5caa293_audio_13.mp4', @@ -288,48 +247,48 @@ const EXPECTED_DATA: DetailItem[] = [ '/dm/2$XTMWANo0Q2RZKlH-95UoAahZrOg~/0a9a/bf72/e1da/4c20-919e-0cbabcf7bfe8/75f50c57-d25f-4e97-9e37-01b9f5caa293_audio_13.mp4', }, { + category: '_index', field: '_index', values: ['filebeat-7.0.0-iot-2019.06'], originalValue: 'filebeat-7.0.0-iot-2019.06', }, { + category: '_id', field: '_id', values: ['QRhG1WgBqd-n62SwZYDT'], originalValue: 'QRhG1WgBqd-n62SwZYDT', }, - { field: '_score', values: ['1'], originalValue: 1 }, + { category: '_score', field: '_score', values: [1], originalValue: 1 }, ]; export default function ({ getService }: FtrProviderContext) { const esArchiver = getService('esArchiver'); - const client = getService('securitySolutionGraphQLClient'); + const supertest = getService('supertest'); describe('Timeline Details', () => { before(() => esArchiver.load('filebeat/default')); after(() => esArchiver.unload('filebeat/default')); - it('Make sure that we get Event Details data', () => { - return client - .query({ - query: timelineDetailsQuery, - variables: { - sourceId: 'default', - indexName: INDEX_NAME, - eventId: ID, - defaultIndex: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'], - docValueFields: [], - }, + it('Make sure that we get Event Details data', async () => { + const { + body: { data: detailsData }, + } = await supertest + .post('/internal/search/securitySolutionTimelineSearchStrategy/') + .set('kbn-xsrf', 'true') + .send({ + factoryQueryType: TimelineEventsQueries.details, + docValueFields: [], + indexName: INDEX_NAME, + inspect: false, + eventId: ID, + }) + .expect(200); + expect( + sortBy(detailsData, 'name').map((item) => { + const { __typename, ...rest } = item; + return rest; }) - .then((resp) => { - const detailsData: DetailsData = (resp.data.source.TimelineDetails.data || - []) as DetailsData; - expect( - sortBy(detailsData, 'name').map((item) => { - const { __typename, ...rest } = item; - return rest; - }) - ).to.eql(sortBy(EXPECTED_DATA, 'name')); - }); + ).to.eql(sortBy(EXPECTED_DATA, 'name')); }); }); } diff --git a/x-pack/test/api_integration/apis/security_solution/tls.ts b/x-pack/test/api_integration/apis/security_solution/tls.ts index ebaec7783427f..164de4d095b97 100644 --- a/x-pack/test/api_integration/apis/security_solution/tls.ts +++ b/x-pack/test/api_integration/apis/security_solution/tls.ts @@ -5,16 +5,13 @@ */ import expect from '@kbn/expect'; -// @ts-expect-error -import { tlsQuery } from '../../../../plugins/security_solution/public/network/containers/tls/index.gql_query'; import { + NetworkQueries, Direction, - // @ts-expect-error - TlsFields, + NetworkTlsFields, FlowTarget, - // @ts-expect-error - GetTlsQuery, -} from '../../../../plugins/security_solution/public/graphql/types'; +} from '../../../../plugins/security_solution/common/search_strategy'; + import { FtrProviderContext } from '../../ftr_provider_context'; const FROM = '2000-01-01T00:00:00.000Z'; @@ -23,7 +20,6 @@ const SOURCE_IP = '10.128.0.35'; const DESTINATION_IP = '74.125.129.95'; const expectedResult = { - __typename: 'TlsNode', _id: '16989191B1A93ECECD5FE9E63EBD4B5C3B606D26', subjects: ['CN=edgecert.googleapis.com,O=Google LLC,L=Mountain View,ST=California,C=US'], issuers: ['CN=GTS CA 1O1,O=Google Trust Services,C=US'], @@ -32,16 +28,13 @@ const expectedResult = { }; const expectedOverviewDestinationResult = { - __typename: 'TlsData', edges: [ { - __typename: 'TlsEdges', cursor: { - __typename: 'CursorType', + tiebreaker: null, value: 'EB4E81DD7C55BA9715652ECF5647FB8877E55A8F', }, node: { - __typename: 'TlsNode', _id: 'EB4E81DD7C55BA9715652ECF5647FB8877E55A8F', subjects: [ 'CN=*.cdn.mozilla.net,OU=Cloud Services,O=Mozilla Corporation,L=Mountain View,ST=California,C=US', @@ -53,7 +46,6 @@ const expectedOverviewDestinationResult = { }, ], pageInfo: { - __typename: 'PageInfoPaginated', activePage: 0, fakeTotalCount: 3, showMorePagesIndicator: false, @@ -62,16 +54,13 @@ const expectedOverviewDestinationResult = { }; const expectedOverviewSourceResult = { - __typename: 'TlsData', edges: [ { - __typename: 'TlsEdges', cursor: { - __typename: 'CursorType', + tiebreaker: null, value: 'EB4E81DD7C55BA9715652ECF5647FB8877E55A8F', }, node: { - __typename: 'TlsNode', _id: 'EB4E81DD7C55BA9715652ECF5647FB8877E55A8F', subjects: [ 'CN=*.cdn.mozilla.net,OU=Cloud Services,O=Mozilla Corporation,L=Mountain View,ST=California,C=US', @@ -83,7 +72,6 @@ const expectedOverviewSourceResult = { }, ], pageInfo: { - __typename: 'PageInfoPaginated', activePage: 0, fakeTotalCount: 3, showMorePagesIndicator: false, @@ -93,76 +81,71 @@ const expectedOverviewSourceResult = { export default function ({ getService }: FtrProviderContext) { const esArchiver = getService('esArchiver'); - const client = getService('securitySolutionGraphQLClient'); + const supertest = getService('supertest'); + describe('Tls Test with Packetbeat', () => { describe('Tls Test', () => { before(() => esArchiver.load('packetbeat/tls')); after(() => esArchiver.unload('packetbeat/tls')); - it('Ensure data is returned for FlowTarget.Source', () => { - return client - .query({ - query: tlsQuery, - variables: { - sourceId: 'default', - timerange: { - interval: '12h', - to: TO, - from: FROM, - }, - ip: SOURCE_IP, - flowTarget: FlowTarget.source, - sort: { field: TlsFields._id, direction: Direction.desc }, - pagination: { - activePage: 0, - cursorStart: 0, - fakePossibleCount: 30, - querySize: 10, - }, - defaultIndex: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'], - docValueFields: [], - inspect: false, + it('Ensure data is returned for FlowTarget.Source', async () => { + const { body: tls } = await supertest + .post('/internal/search/securitySolutionSearchStrategy/') + .set('kbn-xsrf', 'true') + .send({ + factoryQueryType: NetworkQueries.tls, + timerange: { + interval: '12h', + to: TO, + from: FROM, + }, + ip: SOURCE_IP, + flowTarget: FlowTarget.source, + sort: { field: NetworkTlsFields._id, direction: Direction.desc }, + pagination: { + activePage: 0, + cursorStart: 0, + fakePossibleCount: 30, + querySize: 10, }, + defaultIndex: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'], + docValueFields: [], + inspect: false, }) - .then((resp) => { - const tls = resp.data.source.Tls; - expect(tls.edges.length).to.be(1); - expect(tls.totalCount).to.be(1); - expect(tls.edges[0].node).to.eql(expectedResult); - }); + .expect(200); + expect(tls.edges.length).to.be(1); + expect(tls.totalCount).to.be(1); + expect(tls.edges[0].node).to.eql(expectedResult); }); - it('Ensure data is returned for FlowTarget.Destination', () => { - return client - .query({ - query: tlsQuery, - variables: { - sourceId: 'default', - timerange: { - interval: '12h', - to: TO, - from: FROM, - }, - ip: DESTINATION_IP, - flowTarget: FlowTarget.destination, - sort: { field: TlsFields._id, direction: Direction.desc }, - pagination: { - activePage: 0, - cursorStart: 0, - fakePossibleCount: 30, - querySize: 10, - }, - defaultIndex: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'], - docValueFields: [], - inspect: false, + it('Ensure data is returned for FlowTarget.Destination', async () => { + const { body: tls } = await supertest + .post('/internal/search/securitySolutionSearchStrategy/') + .set('kbn-xsrf', 'true') + .send({ + factoryQueryType: NetworkQueries.tls, + timerange: { + interval: '12h', + to: TO, + from: FROM, }, + ip: DESTINATION_IP, + flowTarget: FlowTarget.destination, + sort: { field: NetworkTlsFields._id, direction: Direction.desc }, + pagination: { + activePage: 0, + cursorStart: 0, + fakePossibleCount: 30, + querySize: 10, + }, + defaultIndex: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'], + docValueFields: [], + inspect: false, }) - .then((resp) => { - const tls = resp.data.source.Tls; - expect(tls.edges.length).to.be(1); - expect(tls.totalCount).to.be(1); - expect(tls.edges[0].node).to.eql(expectedResult); - }); + .expect(200); + expect(tls.edges.length).to.be(1); + expect(tls.totalCount).to.be(1); + expect(tls.edges[0].node).to.eql(expectedResult); }); }); @@ -170,68 +153,62 @@ export default function ({ getService }: FtrProviderContext) { before(() => esArchiver.load('packetbeat/tls')); after(() => esArchiver.unload('packetbeat/tls')); - it('Ensure data is returned for FlowTarget.Source', () => { - return client - .query({ - query: tlsQuery, - variables: { - sourceId: 'default', - timerange: { - interval: '12h', - to: TO, - from: FROM, - }, - ip: '', - flowTarget: FlowTarget.source, - sort: { field: TlsFields._id, direction: Direction.desc }, - pagination: { - activePage: 0, - cursorStart: 0, - fakePossibleCount: 30, - querySize: 10, - }, - defaultIndex: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'], - docValueFields: [], - inspect: false, + it('Ensure data is returned for FlowTarget.Source', async () => { + const { body: tls } = await supertest + .post('/internal/search/securitySolutionSearchStrategy/') + .set('kbn-xsrf', 'true') + .send({ + factoryQueryType: NetworkQueries.tls, + timerange: { + interval: '12h', + to: TO, + from: FROM, + }, + ip: '', + flowTarget: FlowTarget.source, + sort: { field: NetworkTlsFields._id, direction: Direction.desc }, + pagination: { + activePage: 0, + cursorStart: 0, + fakePossibleCount: 30, + querySize: 10, }, + defaultIndex: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'], + docValueFields: [], + inspect: false, }) - .then((resp) => { - const tls = resp.data.source.Tls; - expect(tls.pageInfo).to.eql(expectedOverviewSourceResult.pageInfo); - expect(tls.edges[0]).to.eql(expectedOverviewSourceResult.edges[0]); - }); + .expect(200); + expect(tls.pageInfo).to.eql(expectedOverviewSourceResult.pageInfo); + expect(tls.edges[0]).to.eql(expectedOverviewSourceResult.edges[0]); }); - it('Ensure data is returned for FlowTarget.Destination', () => { - return client - .query({ - query: tlsQuery, - variables: { - sourceId: 'default', - timerange: { - interval: '12h', - to: TO, - from: FROM, - }, - ip: '', - flowTarget: FlowTarget.destination, - sort: { field: TlsFields._id, direction: Direction.desc }, - pagination: { - activePage: 0, - cursorStart: 0, - fakePossibleCount: 30, - querySize: 10, - }, - defaultIndex: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'], - docValueFields: [], - inspect: false, + it('Ensure data is returned for FlowTarget.Destination', async () => { + const { body: tls } = await supertest + .post('/internal/search/securitySolutionSearchStrategy/') + .set('kbn-xsrf', 'true') + .send({ + factoryQueryType: NetworkQueries.tls, + timerange: { + interval: '12h', + to: TO, + from: FROM, + }, + ip: '', + flowTarget: FlowTarget.destination, + sort: { field: NetworkTlsFields._id, direction: Direction.desc }, + pagination: { + activePage: 0, + cursorStart: 0, + fakePossibleCount: 30, + querySize: 10, }, + defaultIndex: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'], + docValueFields: [], + inspect: false, }) - .then((resp) => { - const tls = resp.data.source.Tls; - expect(tls.pageInfo).to.eql(expectedOverviewDestinationResult.pageInfo); - expect(tls.edges[0]).to.eql(expectedOverviewDestinationResult.edges[0]); - }); + .expect(200); + expect(tls.pageInfo).to.eql(expectedOverviewDestinationResult.pageInfo); + expect(tls.edges[0]).to.eql(expectedOverviewDestinationResult.edges[0]); }); }); }); diff --git a/x-pack/test/api_integration/apis/security_solution/uncommon_processes.ts b/x-pack/test/api_integration/apis/security_solution/uncommon_processes.ts index 1ed9a03ecf87e..3eb1ada8da459 100644 --- a/x-pack/test/api_integration/apis/security_solution/uncommon_processes.ts +++ b/x-pack/test/api_integration/apis/security_solution/uncommon_processes.ts @@ -6,10 +6,7 @@ import expect from '@kbn/expect'; -// @ts-expect-error -import { uncommonProcessesQuery } from '../../../../plugins/security_solution/public/hosts/containers/uncommon_processes/index.gql_query'; -// @ts-expect-error -import { GetUncommonProcessesQuery } from '../../../../plugins/security_solution/public/graphql/types'; +import { HostsQueries } from '../../../../plugins/security_solution/common/search_strategy'; import { FtrProviderContext } from '../../ftr_provider_context'; const FROM = '2000-01-01T00:00:00.000Z'; @@ -20,20 +17,18 @@ const TOTAL_COUNT = 3; export default function ({ getService }: FtrProviderContext) { const esArchiver = getService('esArchiver'); - const client = getService('securitySolutionGraphQLClient'); + const supertest = getService('supertest'); describe('uncommon_processes', () => { before(() => esArchiver.load('auditbeat/hosts')); after(() => esArchiver.unload('auditbeat/hosts')); it('should return an edge of length 1 when given a pagination of length 1', async () => { - const { - data: { - source: { UncommonProcesses }, - }, - } = await client.query({ - query: uncommonProcessesQuery, - variables: { + const { body: UncommonProcesses } = await supertest + .post('/internal/search/securitySolutionSearchStrategy/') + .set('kbn-xsrf', 'true') + .send({ + factoryQueryType: HostsQueries.uncommonProcesses, sourceId: 'default', timerange: { interval: '12h', @@ -49,19 +44,17 @@ export default function ({ getService }: FtrProviderContext) { defaultIndex: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'], docValueFields: [], inspect: false, - }, - }); + }) + .expect(200); expect(UncommonProcesses.edges.length).to.be(1); }); it('should return an edge of length 2 when given a pagination of length 2', async () => { - const { - data: { - source: { UncommonProcesses }, - }, - } = await client.query({ - query: uncommonProcessesQuery, - variables: { + const { body: UncommonProcesses } = await supertest + .post('/internal/search/securitySolutionSearchStrategy/') + .set('kbn-xsrf', 'true') + .send({ + factoryQueryType: HostsQueries.uncommonProcesses, sourceId: 'default', timerange: { interval: '12h', @@ -77,19 +70,18 @@ export default function ({ getService }: FtrProviderContext) { defaultIndex: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'], docValueFields: [], inspect: false, - }, - }); + }) + .expect(200); + expect(UncommonProcesses.edges.length).to.be(2); }); it('should return a total count of elements', async () => { - const { - data: { - source: { UncommonProcesses }, - }, - } = await client.query({ - query: uncommonProcessesQuery, - variables: { + const { body: UncommonProcesses } = await supertest + .post('/internal/search/securitySolutionSearchStrategy/') + .set('kbn-xsrf', 'true') + .send({ + factoryQueryType: HostsQueries.uncommonProcesses, sourceId: 'default', timerange: { interval: '12h', @@ -105,19 +97,18 @@ export default function ({ getService }: FtrProviderContext) { defaultIndex: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'], docValueFields: [], inspect: false, - }, - }); + }) + .expect(200); + expect(UncommonProcesses.totalCount).to.be(TOTAL_COUNT); }); it('should return a single data set with pagination of 1', async () => { - const { - data: { - source: { UncommonProcesses }, - }, - } = await client.query({ - query: uncommonProcessesQuery, - variables: { + const { body: UncommonProcesses } = await supertest + .post('/internal/search/securitySolutionSearchStrategy/') + .set('kbn-xsrf', 'true') + .send({ + factoryQueryType: HostsQueries.uncommonProcesses, sourceId: 'default', timerange: { interval: '12h', @@ -133,28 +124,26 @@ export default function ({ getService }: FtrProviderContext) { defaultIndex: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'], docValueFields: [], inspect: false, - }, - }); - const expected: GetUncommonProcessesQuery.Node = { + }) + .expect(200); + + const expected = { _id: 'HCFxB2kBR346wHgnL4ik', instances: 1, process: { args: [], name: ['kworker/u2:0'], - __typename: 'ProcessEcsFields', }, user: { id: ['0'], name: ['root'], - __typename: 'UserEcsFields', }, hosts: [ { + id: ['zeek-sensor-san-francisco'], name: ['zeek-sensor-san-francisco'], - __typename: 'HostEcsFields', }, ], - __typename: 'UncommonProcessItem', }; expect(UncommonProcesses.edges[0].node).to.eql(expected); }); diff --git a/x-pack/test/api_integration/apis/security_solution/users.ts b/x-pack/test/api_integration/apis/security_solution/users.ts index 9d42fc0b9788b..1b5b3604cb34f 100644 --- a/x-pack/test/api_integration/apis/security_solution/users.ts +++ b/x-pack/test/api_integration/apis/security_solution/users.ts @@ -5,16 +5,13 @@ */ import expect from '@kbn/expect'; -// @ts-expect-error -import { usersQuery } from '../../../../plugins/security_solution/public/network/containers/users/index.gql_query'; import { + NetworkQueries, Direction, - // @ts-expect-error - UsersFields, + NetworkUsersFields, FlowTarget, - // @ts-expect-error - GetUsersQuery, -} from '../../../../plugins/security_solution/public/graphql/types'; +} from '../../../../plugins/security_solution/common/search_strategy'; + import { FtrProviderContext } from '../../ftr_provider_context'; const FROM = '2000-01-01T00:00:00.000Z'; @@ -23,47 +20,46 @@ const IP = '0.0.0.0'; export default function ({ getService }: FtrProviderContext) { const esArchiver = getService('esArchiver'); - const client = getService('securitySolutionGraphQLClient'); + const supertest = getService('supertest'); describe('Users', () => { describe('With auditbeat', () => { before(() => esArchiver.load('auditbeat/default')); after(() => esArchiver.unload('auditbeat/default')); - it('Ensure data is returned from auditbeat', () => { - return client - .query({ - query: usersQuery, - variables: { - sourceId: 'default', - timerange: { - interval: '12h', - to: TO, - from: FROM, - }, - defaultIndex: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'], - docValueFields: [], - ip: IP, - flowTarget: FlowTarget.destination, - sort: { field: UsersFields.name, direction: Direction.asc }, - pagination: { - activePage: 0, - cursorStart: 0, - fakePossibleCount: 30, - querySize: 10, - }, - inspect: false, + it('Ensure data is returned from auditbeat', async () => { + const { body: users } = await supertest + .post('/internal/search/securitySolutionSearchStrategy/') + .set('kbn-xsrf', 'true') + .send({ + factoryQueryType: NetworkQueries.users, + sourceId: 'default', + timerange: { + interval: '12h', + to: TO, + from: FROM, + }, + defaultIndex: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'], + docValueFields: [], + ip: IP, + flowTarget: FlowTarget.destination, + sort: { field: NetworkUsersFields.name, direction: Direction.asc }, + pagination: { + activePage: 0, + cursorStart: 0, + fakePossibleCount: 30, + querySize: 10, }, + inspect: false, }) - .then((resp) => { - const users = resp.data.source.Users; - expect(users.edges.length).to.be(1); - expect(users.totalCount).to.be(1); - expect(users.edges[0].node.user!.id).to.eql(['0']); - expect(users.edges[0].node.user!.name).to.be('root'); - expect(users.edges[0].node.user!.groupId).to.eql(['0']); - expect(users.edges[0].node.user!.groupName).to.eql(['root']); - expect(users.edges[0].node.user!.count).to.be(1); - }); + .expect(200); + + expect(users.edges.length).to.be(1); + expect(users.totalCount).to.be(1); + expect(users.edges[0].node.user!.id).to.eql(['0']); + expect(users.edges[0].node.user!.name).to.be('root'); + expect(users.edges[0].node.user!.groupId).to.eql(['0']); + expect(users.edges[0].node.user!.groupName).to.eql(['root']); + expect(users.edges[0].node.user!.count).to.be(1); }); }); }); diff --git a/x-pack/test/functional/es_archives/filebeat/default/data.json.gz b/x-pack/test/functional/es_archives/filebeat/default/data.json.gz index bd73f4946575ba6170d1e890ebc3b22a49743a0d..1886818971deed4699a429d6496ff3e7dfa8bace 100644 GIT binary patch delta 142078 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

    + +

    + + + - 0} - name="user" - readOnly={readOnly} - value={user || ''} - data-test-subj="emailUserInput" - onChange={(e) => { - editActionSecrets('user', nullableString(e.target.value)); - }} - /> - - - - 0} - label={i18n.translate( - 'xpack.triggersActionsUI.sections.builtinActionTypes.emailAction.passwordFieldLabel', - { - defaultMessage: 'Password', + disabled={readOnly} + checked={hasAuth} + onChange={(e) => { + editActionConfig('hasAuth', e.target.checked); + if (!e.target.checked) { + editActionSecrets('user', null); + editActionSecrets('password', null); } - )} - > - 0} - name="password" - value={password || ''} - data-test-subj="emailPasswordInput" - onChange={(e) => { - editActionSecrets('password', nullableString(e.target.value)); - }} - /> - + }} + /> + {hasAuth ? ( + <> + {action.id ? ( + <> + + + + + ) : null} + + + 0 && user !== undefined} + label={i18n.translate( + 'xpack.triggersActionsUI.sections.builtinActionTypes.emailAction.userTextFieldLabel', + { + defaultMessage: 'Username', + } + )} + > + 0 && user !== undefined} + name="user" + readOnly={readOnly} + value={user || ''} + data-test-subj="emailUserInput" + onChange={(e) => { + editActionSecrets('user', nullableString(e.target.value)); + }} + onBlur={() => { + if (!user) { + editActionSecrets('user', ''); + } + }} + /> + + + + 0 && password !== undefined} + label={i18n.translate( + 'xpack.triggersActionsUI.sections.builtinActionTypes.emailAction.passwordFieldLabel', + { + defaultMessage: 'Password', + } + )} + > + 0 && password !== undefined} + name="password" + value={password || ''} + data-test-subj="emailPasswordInput" + onChange={(e) => { + editActionSecrets('password', nullableString(e.target.value)); + }} + onBlur={() => { + if (!password) { + editActionSecrets('password', ''); + } + }} + /> + + + + + ) : null} ); }; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/types.ts b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/types.ts index f6bb08148b3cb..958d77a11c883 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/types.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/types.ts @@ -69,6 +69,7 @@ export interface EmailConfig { host: string; port: number; secure?: boolean; + hasAuth: boolean; } export interface EmailSecrets { diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_connector_form.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_connector_form.tsx index ef6621f98fac2..f91bd7382b61c 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_connector_form.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_connector_form.tsx @@ -15,6 +15,7 @@ import { EuiLoadingSpinner, EuiFlexGroup, EuiFlexItem, + EuiTitle, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; @@ -169,26 +170,37 @@ export const ActionConnectorForm = ({ {FieldsComponent !== null ? ( - - - - - - } - > - - + <> + +

    + +

    +
    + + + + + + + } + > + + + ) : null} ); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/email.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/email.ts index 329bd3433d388..f6b0f06a6722e 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/email.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/email.ts @@ -25,6 +25,7 @@ export default function emailTest({ getService }: FtrProviderContext) { config: { service: '__json', from: 'bob@example.com', + hasAuth: true, }, secrets: { user: 'bob', @@ -41,6 +42,7 @@ export default function emailTest({ getService }: FtrProviderContext) { actionTypeId: '.email', config: { service: '__json', + hasAuth: true, host: null, port: null, secure: null, @@ -62,6 +64,7 @@ export default function emailTest({ getService }: FtrProviderContext) { config: { from: 'bob@example.com', service: '__json', + hasAuth: true, host: null, port: null, secure: null, From 7211f78ce195f1925ebace43905b1301bbf82577 Mon Sep 17 00:00:00 2001 From: Tyler Smalley Date: Thu, 1 Oct 2020 14:38:51 -0700 Subject: [PATCH 17/50] Bumps Jest related packages (#78720) Signed-off-by: Tyler Smalley --- package.json | 14 +- .../elastic-eslint-config-kibana/package.json | 2 +- .../src/integration_tests/cluster.test.js | 2 +- packages/kbn-i18n/src/core/i18n.test.ts | 2 +- packages/kbn-optimizer/package.json | 2 +- packages/kbn-spec-to-console/package.json | 2 +- .../server/logging/rotate/log_rotator.test.ts | 6 +- .../listing/dashboard_listing.test.js | 2 +- .../step_time_field/step_time_field.test.tsx | 2 +- .../number_list/number_list.test.tsx | 8 +- .../components/splits/terms.test.js | 12 +- x-pack/package.json | 12 +- .../alerts/server/alerts_client.test.ts | 4 +- .../components/__tests__/app.test.tsx | 2 +- .../settings/__tests__/settings.test.tsx | 2 +- .../event_log/server/lib/ready_signal.test.ts | 27 +- .../plugins/licensing/public/plugin.test.ts | 32 +- .../services/ml_server_info.test.ts | 9 +- .../new_job_capabilities._service.test.ts | 11 +- .../capabilities/check_capabilities.test.ts | 21 +- .../annotation_service/annotation.test.ts | 15 +- .../new_job_caps/new_job_caps.test.ts | 12 +- .../public/lib/ensure_minimum_time.test.js | 9 +- .../monitoring/public/lib/setup_mode.test.js | 91 +- .../monitoring/public/lib/setup_mode.tsx | 2 +- .../lib/authorized_user_pre_routing.test.ts | 2 +- .../detail_panel/detail_panel.test.js | 2 +- .../sections/job_list/job_list.test.js | 2 +- .../job_list/job_table/job_table.test.js | 2 +- .../job_create_review.test.js | 2 +- .../test/client_integration/job_list.test.js | 4 +- .../client_integration/job_list_clone.test.js | 2 +- .../flow_target_select.test.tsx.snap | 16 +- .../properties/new_template_timeline.test.tsx | 12 +- .../server/lib/bulk_operation_buffer.test.ts | 33 +- .../task_manager/server/task_store.test.ts | 198 ++- .../public/app/hooks/use_index_data.test.tsx | 10 +- .../step_define/step_define_form.test.tsx | 7 +- .../step_define/step_define_summary.test.tsx | 3 +- .../public/custom_time_range_action.test.ts | 56 +- .../public/custom_time_range_badge.test.ts | 20 +- yarn.lock | 1236 +++++++++-------- 42 files changed, 978 insertions(+), 932 deletions(-) diff --git a/package.json b/package.json index 26a7fef9cfc18..0eda8dd9f4114 100644 --- a/package.json +++ b/package.json @@ -291,7 +291,7 @@ "@types/hjson": "^2.4.2", "@types/hoek": "^4.1.3", "@types/inert": "^5.1.2", - "@types/jest": "^25.2.3", + "@types/jest": "^26.0.14", "@types/jest-when": "^2.7.1", "@types/joi": "^13.4.2", "@types/jquery": "^3.3.31", @@ -337,7 +337,7 @@ "@types/supertest-as-promised": "^2.0.38", "@types/tapable": "^1.0.6", "@types/tar": "^4.0.3", - "@types/testing-library__jest-dom": "^5.9.2", + "@types/testing-library__jest-dom": "^5.9.3", "@types/testing-library__react-hooks": "^3.4.0", "@types/type-detect": "^4.0.1", "@types/uuid": "^3.4.4", @@ -356,7 +356,7 @@ "archiver": "^3.1.1", "axe-core": "^4.0.2", "babel-eslint": "^10.0.3", - "babel-jest": "^25.5.1", + "babel-jest": "^26.3.0", "babel-plugin-istanbul": "^6.0.0", "backport": "5.6.0", "brace": "0.11.1", @@ -382,7 +382,7 @@ "eslint-plugin-cypress": "^2.8.1", "eslint-plugin-eslint-comments": "^3.2.0", "eslint-plugin-import": "^2.19.1", - "eslint-plugin-jest": "^23.10.0", + "eslint-plugin-jest": "^24.0.2", "eslint-plugin-jsx-a11y": "^6.2.3", "eslint-plugin-mocha": "^6.2.2", "eslint-plugin-no-unsanitized": "^3.0.2", @@ -411,10 +411,10 @@ "iedriver": "^3.14.2", "immer": "^1.5.0", "intl-messageformat-parser": "^1.4.0", - "jest": "^25.5.4", + "jest": "^26.4.2", "jest-canvas-mock": "^2.2.0", - "jest-circus": "^25.5.4", - "jest-cli": "^25.5.4", + "jest-circus": "^26.4.2", + "jest-cli": "^26.4.2", "jest-environment-jsdom-thirteen": "^1.0.1", "jest-raw-loader": "^1.0.1", "jest-when": "^2.7.2", diff --git a/packages/elastic-eslint-config-kibana/package.json b/packages/elastic-eslint-config-kibana/package.json index a4bb8d5449ee8..3f2c6e9edb261 100644 --- a/packages/elastic-eslint-config-kibana/package.json +++ b/packages/elastic-eslint-config-kibana/package.json @@ -24,7 +24,7 @@ "eslint-plugin-jsx-a11y": "^6.2.3", "eslint-plugin-eslint-comments": "^3.2.0", "eslint-plugin-import": "^2.19.1", - "eslint-plugin-jest": "^23.10.0", + "eslint-plugin-jest": "^24.0.2", "eslint-plugin-mocha": "^6.2.2", "eslint-plugin-no-unsanitized": "^3.0.2", "eslint-plugin-prefer-object-spread": "^1.2.1", diff --git a/packages/kbn-es/src/integration_tests/cluster.test.js b/packages/kbn-es/src/integration_tests/cluster.test.js index 0ae0ac0aac27a..6229a8add0d24 100644 --- a/packages/kbn-es/src/integration_tests/cluster.test.js +++ b/packages/kbn-es/src/integration_tests/cluster.test.js @@ -60,7 +60,7 @@ async function ensureResolve(promise) { function mockEsBin({ exitCode, start }) { execa.mockImplementationOnce((cmd, args, options) => - require.requireActual('execa')( + jest.requireActual('execa')( process.execPath, [ require.resolve('./__fixtures__/es_bin.js'), diff --git a/packages/kbn-i18n/src/core/i18n.test.ts b/packages/kbn-i18n/src/core/i18n.test.ts index ec08c82b502db..3364f20879c2a 100644 --- a/packages/kbn-i18n/src/core/i18n.test.ts +++ b/packages/kbn-i18n/src/core/i18n.test.ts @@ -25,7 +25,7 @@ describe('I18n engine', () => { let i18n: typeof i18nModule; beforeEach(() => { - i18n = require.requireActual('./i18n'); + i18n = jest.requireActual('./i18n'); }); afterEach(() => { diff --git a/packages/kbn-optimizer/package.json b/packages/kbn-optimizer/package.json index f90fcaec79fe0..5871c81f48aea 100644 --- a/packages/kbn-optimizer/package.json +++ b/packages/kbn-optimizer/package.json @@ -24,7 +24,7 @@ "execa": "^4.0.2", "file-loader": "^4.2.0", "istanbul-instrumenter-loader": "^3.0.1", - "jest-diff": "^25.5.0", + "jest-diff": "^26.4.2", "json-stable-stringify": "^1.0.1", "loader-utils": "^1.2.3", "node-sass": "^4.13.1", diff --git a/packages/kbn-spec-to-console/package.json b/packages/kbn-spec-to-console/package.json index 0c80c949c1d11..557f38ec740fc 100644 --- a/packages/kbn-spec-to-console/package.json +++ b/packages/kbn-spec-to-console/package.json @@ -17,7 +17,7 @@ }, "homepage": "https://github.com/jbudz/spec-to-console#readme", "devDependencies": { - "jest": "^25.5.4", + "jest": "^26.4.2", "prettier": "^2.1.1" }, "dependencies": { diff --git a/src/legacy/server/logging/rotate/log_rotator.test.ts b/src/legacy/server/logging/rotate/log_rotator.test.ts index 70842d42f5e1f..8f67b47f6949e 100644 --- a/src/legacy/server/logging/rotate/log_rotator.test.ts +++ b/src/legacy/server/logging/rotate/log_rotator.test.ts @@ -22,6 +22,7 @@ import fs, { existsSync, mkdirSync, statSync, writeFileSync } from 'fs'; import { LogRotator } from './log_rotator'; import { tmpdir } from 'os'; import { dirname, join } from 'path'; +import lodash from 'lodash'; const mockOn = jest.fn(); jest.mock('chokidar', () => ({ @@ -31,10 +32,7 @@ jest.mock('chokidar', () => ({ })), })); -jest.mock('lodash', () => ({ - ...require.requireActual('lodash'), - throttle: (fn: any) => fn, -})); +lodash.throttle = (fn: any) => fn; const tempDir = join(tmpdir(), 'kbn_log_rotator_test'); const testFilePath = join(tempDir, 'log_rotator_test_log_file.log'); diff --git a/src/plugins/dashboard/public/application/listing/dashboard_listing.test.js b/src/plugins/dashboard/public/application/listing/dashboard_listing.test.js index 6acb491f9a20c..99b1ebf047d74 100644 --- a/src/plugins/dashboard/public/application/listing/dashboard_listing.test.js +++ b/src/plugins/dashboard/public/application/listing/dashboard_listing.test.js @@ -20,7 +20,7 @@ jest.mock( 'lodash', () => ({ - ...require.requireActual('lodash'), + ...jest.requireActual('lodash'), // mock debounce to fire immediately with no internal timer debounce: (func) => { function debounced(...args) { diff --git a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_time_field/step_time_field.test.tsx b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_time_field/step_time_field.test.tsx index aec010d2dd3f8..4d1033d12d2b8 100644 --- a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_time_field/step_time_field.test.tsx +++ b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_time_field/step_time_field.test.tsx @@ -30,7 +30,7 @@ jest.mock('./components/time_field', () => ({ TimeField: 'TimeField' })); jest.mock('./components/advanced_options', () => ({ AdvancedOptions: 'AdvancedOptions' })); jest.mock('./components/action_buttons', () => ({ ActionButtons: 'ActionButtons' })); jest.mock('./../../lib', () => ({ - extractTimeFields: require.requireActual('./../../lib').extractTimeFields, + extractTimeFields: jest.requireActual('./../../lib').extractTimeFields, ensureMinimumTime: async (fields: IFieldType) => Promise.resolve(fields), })); diff --git a/src/plugins/vis_default_editor/public/components/controls/components/number_list/number_list.test.tsx b/src/plugins/vis_default_editor/public/components/controls/components/number_list/number_list.test.tsx index 82d4b9142fb76..7964da23d8f50 100644 --- a/src/plugins/vis_default_editor/public/components/controls/components/number_list/number_list.test.tsx +++ b/src/plugins/vis_default_editor/public/components/controls/components/number_list/number_list.test.tsx @@ -33,10 +33,10 @@ jest.mock('@elastic/eui', () => ({ let counter = 1; return () => `12${counter++}`; }), - EuiSpacer: require.requireActual('@elastic/eui').EuiSpacer, - EuiFlexItem: require.requireActual('@elastic/eui').EuiFlexItem, - EuiButtonEmpty: require.requireActual('@elastic/eui').EuiButtonEmpty, - EuiFormErrorText: require.requireActual('@elastic/eui').EuiFormErrorText, + EuiSpacer: jest.requireActual('@elastic/eui').EuiSpacer, + EuiFlexItem: jest.requireActual('@elastic/eui').EuiFlexItem, + EuiButtonEmpty: jest.requireActual('@elastic/eui').EuiButtonEmpty, + EuiFormErrorText: jest.requireActual('@elastic/eui').EuiFormErrorText, })); describe('NumberList', () => { diff --git a/src/plugins/vis_type_timeseries/public/application/components/splits/terms.test.js b/src/plugins/vis_type_timeseries/public/application/components/splits/terms.test.js index 4d322cd7b7e61..da840adb75cd3 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/splits/terms.test.js +++ b/src/plugins/vis_type_timeseries/public/application/components/splits/terms.test.js @@ -23,12 +23,12 @@ import { SplitByTermsUI } from './terms'; jest.mock('@elastic/eui', () => ({ htmlIdGenerator: jest.fn(() => () => '42'), - EuiFlexGroup: require.requireActual('@elastic/eui').EuiFlexGroup, - EuiFlexItem: require.requireActual('@elastic/eui').EuiFlexItem, - EuiFormRow: require.requireActual('@elastic/eui').EuiFormRow, - EuiFieldNumber: require.requireActual('@elastic/eui').EuiFieldNumber, - EuiComboBox: require.requireActual('@elastic/eui').EuiComboBox, - EuiFieldText: require.requireActual('@elastic/eui').EuiFieldText, + EuiFlexGroup: jest.requireActual('@elastic/eui').EuiFlexGroup, + EuiFlexItem: jest.requireActual('@elastic/eui').EuiFlexItem, + EuiFormRow: jest.requireActual('@elastic/eui').EuiFormRow, + EuiFieldNumber: jest.requireActual('@elastic/eui').EuiFieldNumber, + EuiComboBox: jest.requireActual('@elastic/eui').EuiComboBox, + EuiFieldText: jest.requireActual('@elastic/eui').EuiFieldText, })); describe('src/legacy/core_plugins/metrics/public/components/splits/terms.test.js', () => { diff --git a/x-pack/package.json b/x-pack/package.json index 6c18902c77366..f9b193bb4da06 100644 --- a/x-pack/package.json +++ b/x-pack/package.json @@ -88,7 +88,7 @@ "@types/hoist-non-react-statics": "^3.3.1", "@types/http-proxy": "^1.17.4", "@types/http-proxy-agent": "^2.0.2", - "@types/jest": "^25.2.3", + "@types/jest": "^26.0.14", "@types/jest-specific-snapshot": "^0.5.4", "@types/joi": "^13.4.2", "@types/js-search": "^1.4.0", @@ -127,7 +127,7 @@ "@types/styled-components": "^5.1.0", "@types/supertest": "^2.0.5", "@types/tar-fs": "^1.16.1", - "@types/testing-library__jest-dom": "^5.9.2", + "@types/testing-library__jest-dom": "^5.9.3", "@types/testing-library__react-hooks": "^3.4.0", "@types/tinycolor2": "^1.4.1", "@types/use-resize-observer": "^6.0.0", @@ -143,7 +143,7 @@ "apollo-link-error": "^1.1.7", "apollo-link-state": "^0.4.1", "autoprefixer": "^9.7.4", - "babel-jest": "^25.5.1", + "babel-jest": "^26.3.0", "babel-loader": "^8.0.6", "babel-plugin-require-context-hook": "npm:babel-plugin-require-context-hook-babel7@1.0.0", "base64-js": "^1.3.1", @@ -188,9 +188,9 @@ "hoist-non-react-statics": "^3.3.2", "i18n-iso-countries": "^4.3.1", "icalendar": "0.7.1", - "jest": "^25.5.4", - "jest-circus": "^25.5.4", - "jest-cli": "^25.5.4", + "jest": "^26.4.2", + "jest-circus": "^26.4.2", + "jest-cli": "^26.4.2", "jest-styled-components": "^7.0.2", "js-search": "^1.4.3", "jsdom": "13.1.0", diff --git a/x-pack/plugins/alerts/server/alerts_client.test.ts b/x-pack/plugins/alerts/server/alerts_client.test.ts index a5846cd1060c5..088390c3cb6e7 100644 --- a/x-pack/plugins/alerts/server/alerts_client.test.ts +++ b/x-pack/plugins/alerts/server/alerts_client.test.ts @@ -4130,14 +4130,13 @@ describe('update()', () => { expect(taskManager.runNow).not.toHaveBeenCalled(); }); - test('updating the alert should not wait for the rerun the task to complete', async (done) => { + test('updating the alert should not wait for the rerun the task to complete', async () => { const alertId = uuid.v4(); const taskId = uuid.v4(); mockApiCalls(alertId, taskId, { interval: '10s' }, { interval: '30s' }); const resolveAfterAlertUpdatedCompletes = resolvable<{ id: string }>(); - resolveAfterAlertUpdatedCompletes.then(() => done()); taskManager.runNow.mockReset(); taskManager.runNow.mockReturnValue(resolveAfterAlertUpdatedCompletes); @@ -4165,7 +4164,6 @@ describe('update()', () => { }); expect(taskManager.runNow).toHaveBeenCalled(); - resolveAfterAlertUpdatedCompletes.resolve({ id: alertId }); }); diff --git a/x-pack/plugins/canvas/shareable_runtime/components/__tests__/app.test.tsx b/x-pack/plugins/canvas/shareable_runtime/components/__tests__/app.test.tsx index 2ec3cfde8bd68..eaf45db0a0b93 100644 --- a/x-pack/plugins/canvas/shareable_runtime/components/__tests__/app.test.tsx +++ b/x-pack/plugins/canvas/shareable_runtime/components/__tests__/app.test.tsx @@ -40,7 +40,7 @@ jest.mock('@elastic/eui/lib/components/portal/portal', () => { // Local constants are not supported in Jest mocks-- they must be // imported within the mock. // eslint-disable-next-line no-shadow - const React = require.requireActual('react'); + const React = jest.requireActual('react'); return { EuiPortal: (props: any) =>
    {props.children}
    , }; diff --git a/x-pack/plugins/canvas/shareable_runtime/components/footer/settings/__tests__/settings.test.tsx b/x-pack/plugins/canvas/shareable_runtime/components/footer/settings/__tests__/settings.test.tsx index 34dacc7956253..28aa6ef90aedb 100644 --- a/x-pack/plugins/canvas/shareable_runtime/components/footer/settings/__tests__/settings.test.tsx +++ b/x-pack/plugins/canvas/shareable_runtime/components/footer/settings/__tests__/settings.test.tsx @@ -26,7 +26,7 @@ jest.mock('@elastic/eui/lib/services/accessibility', () => { }); jest.mock('@elastic/eui/lib/components/portal/portal', () => { // eslint-disable-next-line no-shadow - const React = require.requireActual('react'); + const React = jest.requireActual('react'); return { EuiPortal: (props: any) =>
    {props.children}
    , }; diff --git a/x-pack/plugins/event_log/server/lib/ready_signal.test.ts b/x-pack/plugins/event_log/server/lib/ready_signal.test.ts index c216651ee94b1..d23d81861acc4 100644 --- a/x-pack/plugins/event_log/server/lib/ready_signal.test.ts +++ b/x-pack/plugins/event_log/server/lib/ready_signal.test.ts @@ -13,28 +13,9 @@ describe('ReadySignal', () => { readySignal = createReadySignal(); }); - test('works as expected', async (done) => { - let value = 41; - - timeoutSet(100, async () => { - expect(value).toBe(41); - }); - - timeoutSet(250, async () => readySignal.signal(42)); - - timeoutSet(400, async () => { - expect(value).toBe(42); - - const innerValue = await readySignal.wait(); - expect(innerValue).toBe(42); - done(); - }); - - value = await readySignal.wait(); - expect(value).toBe(42); + test('works as expected', async () => { + readySignal.signal(42); + const ready = await readySignal.wait(); + expect(ready).toBe(42); }); }); - -function timeoutSet(ms: number, fn: () => Promise): void { - setTimeout(fn, ms); -} diff --git a/x-pack/plugins/licensing/public/plugin.test.ts b/x-pack/plugins/licensing/public/plugin.test.ts index c20563dd15913..ce3fcdb042326 100644 --- a/x-pack/plugins/licensing/public/plugin.test.ts +++ b/x-pack/plugins/licensing/public/plugin.test.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { take } from 'rxjs/operators'; +import { take, toArray } from 'rxjs/operators'; import { mountExpiredBannerMock } from './plugin.test.mocks'; import { LicenseType } from '../common/types'; @@ -92,7 +92,7 @@ describe('licensing plugin', () => { expect(sessionStorage.getItem).toHaveBeenCalledWith(licensingSessionStorageKey); }); - it('observable receives updated licenses', async (done) => { + it('observable receives updated licenses', async () => { const types: LicenseType[] = ['gold', 'platinum']; const sessionStorage = coreMock.createStorage(); @@ -104,27 +104,17 @@ describe('licensing plugin', () => { Promise.resolve(licenseMock.createLicense({ license: { type: types.shift() } })) ); - await plugin.setup(coreSetup); + plugin.setup(coreSetup); const { refresh, license$ } = await plugin.start(coreStart); + const promise = license$.pipe(take(3), toArray()).toPromise(); - let i = 0; - license$.subscribe((value) => { - i++; - if (i === 1) { - expect(value.type).toBe('basic'); - refresh(); - } else if (i === 2) { - expect(value.type).toBe('gold'); - // since this is a synchronous subscription, we need to give the exhaustMap a chance - // to mark the subscription as complete before emitting another value on the Subject - process.nextTick(() => refresh()); - } else if (i === 3) { - expect(value.type).toBe('platinum'); - done(); - } else { - throw new Error('unreachable'); - } - }); + await refresh(); + await refresh(); + + const licenses = await promise; + expect(licenses[0].type).toBe('basic'); + expect(licenses[1].type).toBe('gold'); + expect(licenses[2].type).toBe('platinum'); }); it('saved fetched license & signature in session storage', async () => { diff --git a/x-pack/plugins/ml/public/application/services/ml_server_info.test.ts b/x-pack/plugins/ml/public/application/services/ml_server_info.test.ts index cd0f10bb7f577..e935d443f9857 100644 --- a/x-pack/plugins/ml/public/application/services/ml_server_info.test.ts +++ b/x-pack/plugins/ml/public/application/services/ml_server_info.test.ts @@ -28,9 +28,8 @@ describe('ml_server_info initial state', () => { }); describe('ml_server_info', () => { - beforeEach(async (done) => { + beforeEach(async () => { await loadMlServerInfo(); - done(); }); describe('cloud information', () => { @@ -41,23 +40,21 @@ describe('ml_server_info', () => { }); describe('defaults', () => { - it('should get defaults', async (done) => { + it('should get defaults', async () => { const defaults = getNewJobDefaults(); expect(defaults.anomaly_detectors.model_memory_limit).toBe('128mb'); expect(defaults.anomaly_detectors.categorization_examples_limit).toBe(4); expect(defaults.anomaly_detectors.model_snapshot_retention_days).toBe(1); expect(defaults.datafeeds.scroll_size).toBe(1000); - done(); }); }); describe('limits', () => { - it('should get limits', async (done) => { + it('should get limits', async () => { const limits = getNewJobLimits(); expect(limits.max_model_memory_limit).toBe('128mb'); - done(); }); }); diff --git a/x-pack/plugins/ml/public/application/services/new_job_capabilities._service.test.ts b/x-pack/plugins/ml/public/application/services/new_job_capabilities._service.test.ts index 81f05065b5139..471a55061617b 100644 --- a/x-pack/plugins/ml/public/application/services/new_job_capabilities._service.test.ts +++ b/x-pack/plugins/ml/public/application/services/new_job_capabilities._service.test.ts @@ -26,7 +26,7 @@ const indexPattern = ({ describe('new_job_capabilities_service', () => { describe('cloudwatch newJobCaps()', () => { - it('can construct job caps objects from endpoint json', async (done) => { + it('can construct job caps objects from endpoint json', async () => { await newJobCapsService.initializeFromIndexPattern(indexPattern); const { fields, aggs } = await newJobCapsService.newJobCaps; @@ -43,27 +43,22 @@ describe('new_job_capabilities_service', () => { expect(meanAgg.fields).toHaveLength(7); expect(distinctCountAgg.fields).toHaveLength(10); - done(); }); - it('job caps including text fields', async (done) => { + it('job caps including text fields', async () => { await newJobCapsService.initializeFromIndexPattern(indexPattern, true, false); const { fields, aggs } = await newJobCapsService.newJobCaps; expect(fields).toHaveLength(13); // one more field expect(aggs).toHaveLength(35); - - done(); }); - it('job caps excluding event rate', async (done) => { + it('job caps excluding event rate', async () => { await newJobCapsService.initializeFromIndexPattern(indexPattern, false, true); const { fields, aggs } = await newJobCapsService.newJobCaps; expect(fields).toHaveLength(11); // one less field expect(aggs).toHaveLength(35); - - done(); }); }); }); diff --git a/x-pack/plugins/ml/server/lib/capabilities/check_capabilities.test.ts b/x-pack/plugins/ml/server/lib/capabilities/check_capabilities.test.ts index 4dd17f8cf4889..a436bcdebde4b 100644 --- a/x-pack/plugins/ml/server/lib/capabilities/check_capabilities.test.ts +++ b/x-pack/plugins/ml/server/lib/capabilities/check_capabilities.test.ts @@ -49,7 +49,7 @@ const mlClusterClientUpgrade = ({ describe('check_capabilities', () => { describe('getCapabilities() - right number of capabilities', () => { - test('kibana capabilities count', async (done) => { + test('kibana capabilities count', async () => { const { getCapabilities } = capabilitiesProvider( mlClusterClientNonUpgrade, getAdminCapabilities(), @@ -59,12 +59,11 @@ describe('check_capabilities', () => { const { capabilities } = await getCapabilities(); const count = Object.keys(capabilities).length; expect(count).toBe(28); - done(); }); }); describe('getCapabilities() with security', () => { - test('ml_user capabilities only', async (done) => { + test('ml_user capabilities only', async () => { const { getCapabilities } = capabilitiesProvider( mlClusterClientNonUpgrade, getUserCapabilities(), @@ -110,10 +109,9 @@ describe('check_capabilities', () => { expect(capabilities.canDeleteDataFrameAnalytics).toBe(false); expect(capabilities.canCreateDataFrameAnalytics).toBe(false); expect(capabilities.canStartStopDataFrameAnalytics).toBe(false); - done(); }); - test('full capabilities', async (done) => { + test('full capabilities', async () => { const { getCapabilities } = capabilitiesProvider( mlClusterClientNonUpgrade, getAdminCapabilities(), @@ -159,10 +157,9 @@ describe('check_capabilities', () => { expect(capabilities.canDeleteDataFrameAnalytics).toBe(true); expect(capabilities.canCreateDataFrameAnalytics).toBe(true); expect(capabilities.canStartStopDataFrameAnalytics).toBe(true); - done(); }); - test('upgrade in progress with full capabilities', async (done) => { + test('upgrade in progress with full capabilities', async () => { const { getCapabilities } = capabilitiesProvider( mlClusterClientUpgrade, getAdminCapabilities(), @@ -208,10 +205,9 @@ describe('check_capabilities', () => { expect(capabilities.canDeleteDataFrameAnalytics).toBe(false); expect(capabilities.canCreateDataFrameAnalytics).toBe(false); expect(capabilities.canStartStopDataFrameAnalytics).toBe(false); - done(); }); - test('upgrade in progress with partial capabilities', async (done) => { + test('upgrade in progress with partial capabilities', async () => { const { getCapabilities } = capabilitiesProvider( mlClusterClientUpgrade, getUserCapabilities(), @@ -257,10 +253,9 @@ describe('check_capabilities', () => { expect(capabilities.canDeleteDataFrameAnalytics).toBe(false); expect(capabilities.canCreateDataFrameAnalytics).toBe(false); expect(capabilities.canStartStopDataFrameAnalytics).toBe(false); - done(); }); - test('full capabilities, ml disabled in space', async (done) => { + test('full capabilities, ml disabled in space', async () => { const { getCapabilities } = capabilitiesProvider( mlClusterClientNonUpgrade, getDefaultCapabilities(), @@ -306,11 +301,10 @@ describe('check_capabilities', () => { expect(capabilities.canDeleteDataFrameAnalytics).toBe(false); expect(capabilities.canCreateDataFrameAnalytics).toBe(false); expect(capabilities.canStartStopDataFrameAnalytics).toBe(false); - done(); }); }); - test('full capabilities, basic license, ml disabled in space', async (done) => { + test('full capabilities, basic license, ml disabled in space', async () => { const { getCapabilities } = capabilitiesProvider( mlClusterClientNonUpgrade, getDefaultCapabilities(), @@ -357,6 +351,5 @@ describe('check_capabilities', () => { expect(capabilities.canDeleteDataFrameAnalytics).toBe(false); expect(capabilities.canCreateDataFrameAnalytics).toBe(false); expect(capabilities.canStartStopDataFrameAnalytics).toBe(false); - done(); }); }); diff --git a/x-pack/plugins/ml/server/models/annotation_service/annotation.test.ts b/x-pack/plugins/ml/server/models/annotation_service/annotation.test.ts index 4c511b567615d..3d90cb0984391 100644 --- a/x-pack/plugins/ml/server/models/annotation_service/annotation.test.ts +++ b/x-pack/plugins/ml/server/models/annotation_service/annotation.test.ts @@ -35,7 +35,7 @@ describe('annotation_service', () => { }); describe('deleteAnnotation()', () => { - it('should delete annotation', async (done) => { + it('should delete annotation', async () => { const { deleteAnnotation } = annotationServiceProvider(mlClusterClientSpy); const mockFunct = mlClusterClientSpy; @@ -50,12 +50,11 @@ describe('annotation_service', () => { expect(mockFunct.asInternalUser.delete.mock.calls[0][0]).toStrictEqual(deleteParamsMock); expect(response).toBe(acknowledgedResponseMock); - done(); }); }); describe('getAnnotation()', () => { - it('should get annotations for specific job', async (done) => { + it('should get annotations for specific job', async () => { const { getAnnotations } = annotationServiceProvider(mlClusterClientSpy); const mockFunct = mlClusterClientSpy; @@ -74,7 +73,6 @@ describe('annotation_service', () => { expect(Object.keys(response.annotations)).toHaveLength(1); expect(response.annotations[jobIdMock]).toHaveLength(2); expect(isAnnotations(response.annotations[jobIdMock])).toBeTruthy(); - done(); }); it('should throw and catch an error', async () => { @@ -106,7 +104,7 @@ describe('annotation_service', () => { }); describe('indexAnnotation()', () => { - it('should index annotation', async (done) => { + it('should index annotation', async () => { const { indexAnnotation } = annotationServiceProvider(mlClusterClientSpy); const mockFunct = mlClusterClientSpy; @@ -129,10 +127,9 @@ describe('annotation_service', () => { expect(typeof annotation.modified_time).toBe('number'); expect(response).toBe(acknowledgedResponseMock); - done(); }); - it('should remove ._id and .key before updating annotation', async (done) => { + it('should remove ._id and .key before updating annotation', async () => { const { indexAnnotation } = annotationServiceProvider(mlClusterClientSpy); const mockFunct = mlClusterClientSpy; @@ -159,10 +156,9 @@ describe('annotation_service', () => { expect(typeof annotation.key).toBe('undefined'); expect(response).toBe(acknowledgedResponseMock); - done(); }); - it('should update annotation text and the username for modified_username', async (done) => { + it('should update annotation text and the username for modified_username', async () => { const { getAnnotations, indexAnnotation } = annotationServiceProvider(mlClusterClientSpy); const mockFunct = mlClusterClientSpy; @@ -196,7 +192,6 @@ describe('annotation_service', () => { expect(modifiedAnnotation.modified_username).toBe(modifiedUsernameMock); expect(typeof modifiedAnnotation.create_time).toBe('number'); expect(typeof modifiedAnnotation.modified_time).toBe('number'); - done(); }); }); }); diff --git a/x-pack/plugins/ml/server/models/job_service/new_job_caps/new_job_caps.test.ts b/x-pack/plugins/ml/server/models/job_service/new_job_caps/new_job_caps.test.ts index 891cb2e0d1e64..1169123e93ea3 100644 --- a/x-pack/plugins/ml/server/models/job_service/new_job_caps/new_job_caps.test.ts +++ b/x-pack/plugins/ml/server/models/job_service/new_job_caps/new_job_caps.test.ts @@ -48,42 +48,38 @@ describe('job_service - job_caps', () => { }); describe('farequote newJobCaps()', () => { - it('can get job caps for index pattern', async (done) => { + it('can get job caps for index pattern', async () => { const indexPattern = 'farequote-*'; const isRollup = false; const { newJobCaps } = newJobCapsProvider(mlClusterClientNonRollupMock); const response = await newJobCaps(indexPattern, isRollup, savedObjectsClientMock); expect(response).toEqual(farequoteJobCaps); - done(); }); - it('can get rollup job caps for non rollup index pattern', async (done) => { + it('can get rollup job caps for non rollup index pattern', async () => { const indexPattern = 'farequote-*'; const isRollup = true; const { newJobCaps } = newJobCapsProvider(mlClusterClientNonRollupMock); const response = await newJobCaps(indexPattern, isRollup, savedObjectsClientMock); expect(response).toEqual(farequoteJobCapsEmpty); - done(); }); }); describe('cloudwatch newJobCaps()', () => { - it('can get rollup job caps for rollup index pattern', async (done) => { + it('can get rollup job caps for rollup index pattern', async () => { const indexPattern = 'cloud_roll_index'; const isRollup = true; const { newJobCaps } = newJobCapsProvider(mlClusterClientRollupMock); const response = await newJobCaps(indexPattern, isRollup, savedObjectsClientMock); expect(response).toEqual(cloudwatchJobCaps); - done(); }); - it('can get non rollup job caps for rollup index pattern', async (done) => { + it('can get non rollup job caps for rollup index pattern', async () => { const indexPattern = 'cloud_roll_index'; const isRollup = false; const { newJobCaps } = newJobCapsProvider(mlClusterClientRollupMock); const response = await newJobCaps(indexPattern, isRollup, savedObjectsClientMock); expect(response).not.toEqual(cloudwatchJobCaps); - done(); }); }); }); diff --git a/x-pack/plugins/monitoring/public/lib/ensure_minimum_time.test.js b/x-pack/plugins/monitoring/public/lib/ensure_minimum_time.test.js index f37dbe3283d29..eda9c17db4e39 100644 --- a/x-pack/plugins/monitoring/public/lib/ensure_minimum_time.test.js +++ b/x-pack/plugins/monitoring/public/lib/ensure_minimum_time.test.js @@ -7,28 +7,25 @@ import { ensureMinimumTime } from './ensure_minimum_time'; describe('ensureMinimumTime', () => { - it('resolves single promise', async (done) => { + it('resolves single promise', async () => { const promiseA = new Promise((resolve) => resolve('a')); const a = await ensureMinimumTime(promiseA, 0); expect(a).toBe('a'); - done(); }); - it('resolves multiple promises', async (done) => { + it('resolves multiple promises', async () => { const promiseA = new Promise((resolve) => resolve('a')); const promiseB = new Promise((resolve) => resolve('b')); const [a, b] = await ensureMinimumTime([promiseA, promiseB], 0); expect(a).toBe('a'); expect(b).toBe('b'); - done(); }); - it('resolves in the amount of time provided, at minimum', async (done) => { + it('resolves in the amount of time provided, at minimum', async () => { const startTime = new Date().getTime(); const promise = new Promise((resolve) => resolve()); await ensureMinimumTime(promise, 100); const endTime = new Date().getTime(); expect(endTime - startTime).toBeGreaterThanOrEqual(100); - done(); }); }); diff --git a/x-pack/plugins/monitoring/public/lib/setup_mode.test.js b/x-pack/plugins/monitoring/public/lib/setup_mode.test.js index 9aa5a6bdc0496..424da9d27ff0c 100644 --- a/x-pack/plugins/monitoring/public/lib/setup_mode.test.js +++ b/x-pack/plugins/monitoring/public/lib/setup_mode.test.js @@ -23,7 +23,13 @@ jest.mock('react-dom', () => ({ jest.mock('../legacy_shims', () => { return { Legacy: { - shims: { getAngularInjector: () => ({ get: () => ({ get: () => 'utc' }) }) }, + shims: { + getAngularInjector: () => ({ get: () => ({ get: () => 'utc' }) }), + toastNotifications: { + addDanger: jest.fn(), + }, + I18nContext: '
    ', + }, }, }; }); @@ -59,9 +65,6 @@ const angularStateMock = { // We are no longer waiting for setup mode data to be fetched when enabling // so we need to wait for the next tick for the async action to finish -function waitForSetupModeData(action) { - process.nextTick(action); -} function setModulesAndMocks() { jest.clearAllMocks().resetModules(); @@ -75,6 +78,10 @@ function setModulesAndMocks() { setSetupModeMenuItem = setupMode.setSetupModeMenuItem; } +function waitForSetupModeData() { + return new Promise((resolve) => process.nextTick(resolve)); +} + describe('setup_mode', () => { beforeEach(async () => { setModulesAndMocks(); @@ -96,22 +103,22 @@ describe('setup_mode', () => { }); it('should enable toggle mode', async () => { - initSetupModeState(angularStateMock.scope, angularStateMock.injector); - await toggleSetupMode(true); + await initSetupModeState(angularStateMock.scope, angularStateMock.injector); + toggleSetupMode(true); expect(injectorModulesMock.globalState.inSetupMode).toBe(true); }); it('should disable toggle mode', async () => { - initSetupModeState(angularStateMock.scope, angularStateMock.injector); - await toggleSetupMode(false); + await initSetupModeState(angularStateMock.scope, angularStateMock.injector); + toggleSetupMode(false); expect(injectorModulesMock.globalState.inSetupMode).toBe(false); }); it('should set top nav config', async () => { const render = require('react-dom').render; - initSetupModeState(angularStateMock.scope, angularStateMock.injector); + await initSetupModeState(angularStateMock.scope, angularStateMock.injector); setSetupModeMenuItem(); - await toggleSetupMode(true); + toggleSetupMode(true); expect(render.mock.calls.length).toBe(2); }); }); @@ -121,7 +128,7 @@ describe('setup_mode', () => { data = {}; }); - it('should not fetch data if the user does not have sufficient permissions', async (done) => { + it('should not fetch data if the user does not have sufficient permissions', async () => { const addDanger = jest.fn(); jest.doMock('../legacy_shims', () => ({ Legacy: { @@ -129,6 +136,7 @@ describe('setup_mode', () => { toastNotifications: { addDanger, }, + I18nContext: '
    ', }, }, })); @@ -138,20 +146,19 @@ describe('setup_mode', () => { }, }; setModulesAndMocks(); - initSetupModeState(angularStateMock.scope, angularStateMock.injector); - await toggleSetupMode(true); - waitForSetupModeData(() => { - const state = getSetupModeState(); - expect(state.enabled).toBe(false); - expect(addDanger).toHaveBeenCalledWith({ - title: 'Setup mode is not available', - text: 'You do not have the necessary permissions to do this.', - }); - done(); + await initSetupModeState(angularStateMock.scope, angularStateMock.injector); + toggleSetupMode(true); + await waitForSetupModeData(); + + const state = getSetupModeState(); + expect(state.enabled).toBe(false); + expect(addDanger).toHaveBeenCalledWith({ + title: 'Setup mode is not available', + text: 'You do not have the necessary permissions to do this.', }); }); - it('should set the newly discovered cluster uuid', async (done) => { + it('should set the newly discovered cluster uuid', async () => { const clusterUuid = '1ajy'; data = { _meta: { @@ -166,15 +173,14 @@ describe('setup_mode', () => { }, }, }; - initSetupModeState(angularStateMock.scope, angularStateMock.injector); - await toggleSetupMode(true); - waitForSetupModeData(() => { - expect(injectorModulesMock.globalState.cluster_uuid).toBe(clusterUuid); - done(); - }); + await initSetupModeState(angularStateMock.scope, angularStateMock.injector); + toggleSetupMode(true); + await waitForSetupModeData(); + + expect(injectorModulesMock.globalState.cluster_uuid).toBe(clusterUuid); }); - it('should fetch data for a given cluster', async (done) => { + it('should fetch data for a given cluster', async () => { const clusterUuid = '1ajy'; data = { _meta: { @@ -190,22 +196,23 @@ describe('setup_mode', () => { }, }; - initSetupModeState(angularStateMock.scope, angularStateMock.injector); - await toggleSetupMode(true); - waitForSetupModeData(() => { - expect(injectorModulesMock.$http.post).toHaveBeenCalledWith( - `../api/monitoring/v1/setup/collection/cluster/${clusterUuid}`, - { - ccs: undefined, - } - ); - done(); - }); + await initSetupModeState(angularStateMock.scope, angularStateMock.injector); + toggleSetupMode(true); + await waitForSetupModeData(); + + expect(injectorModulesMock.$http.post).toHaveBeenCalledWith( + `../api/monitoring/v1/setup/collection/cluster/${clusterUuid}`, + { + ccs: undefined, + } + ); }); it('should fetch data for a single node', async () => { - initSetupModeState(angularStateMock.scope, angularStateMock.injector); - await toggleSetupMode(true); + await initSetupModeState(angularStateMock.scope, angularStateMock.injector); + toggleSetupMode(true); + await waitForSetupModeData(); + injectorModulesMock.$http.post.mockClear(); await updateSetupModeData('45asd'); expect(injectorModulesMock.$http.post).toHaveBeenCalledWith( diff --git a/x-pack/plugins/monitoring/public/lib/setup_mode.tsx b/x-pack/plugins/monitoring/public/lib/setup_mode.tsx index 3e555c843a0bb..6b956ce71c009 100644 --- a/x-pack/plugins/monitoring/public/lib/setup_mode.tsx +++ b/x-pack/plugins/monitoring/public/lib/setup_mode.tsx @@ -206,7 +206,7 @@ export const initSetupModeState = async ($scope: any, $injector: any, callback?: const globalState = $injector.get('globalState'); if (globalState.inSetupMode) { - await toggleSetupMode(true); + toggleSetupMode(true); } }; diff --git a/x-pack/plugins/reporting/server/routes/lib/authorized_user_pre_routing.test.ts b/x-pack/plugins/reporting/server/routes/lib/authorized_user_pre_routing.test.ts index 932ebfdd22bbc..cee8a88000e29 100644 --- a/x-pack/plugins/reporting/server/routes/lib/authorized_user_pre_routing.test.ts +++ b/x-pack/plugins/reporting/server/routes/lib/authorized_user_pre_routing.test.ts @@ -130,7 +130,7 @@ describe('authorized_user_pre_routing', function () { ).toMatchObject({ body: `Sorry, you don't have access to Reporting` }); }); - it('should return from handler when security is enabled and user has explicitly allowed role', async function (done) { + it('should return from handler when security is enabled and user has explicitly allowed role', function (done) { mockCore.getPluginSetupDeps = () => (({ // @ts-ignore diff --git a/x-pack/plugins/rollup/public/crud_app/sections/job_list/detail_panel/detail_panel.test.js b/x-pack/plugins/rollup/public/crud_app/sections/job_list/detail_panel/detail_panel.test.js index f9f3cda6f2c20..3ac2ee5f5aadb 100644 --- a/x-pack/plugins/rollup/public/crud_app/sections/job_list/detail_panel/detail_panel.test.js +++ b/x-pack/plugins/rollup/public/crud_app/sections/job_list/detail_panel/detail_panel.test.js @@ -18,7 +18,7 @@ import { } from '../../components'; jest.mock('../../../../kibana_services', () => { - const services = require.requireActual('../../../../kibana_services'); + const services = jest.requireActual('../../../../kibana_services'); return { ...services, trackUiMetric: jest.fn(), diff --git a/x-pack/plugins/rollup/public/crud_app/sections/job_list/job_list.test.js b/x-pack/plugins/rollup/public/crud_app/sections/job_list/job_list.test.js index e0fb73ef9c3bb..ea70bdb3fbc41 100644 --- a/x-pack/plugins/rollup/public/crud_app/sections/job_list/job_list.test.js +++ b/x-pack/plugins/rollup/public/crud_app/sections/job_list/job_list.test.js @@ -14,7 +14,7 @@ import { coreMock } from '../../../../../../../src/core/public/mocks'; const startMock = coreMock.createStart(); jest.mock('../../services', () => { - const services = require.requireActual('../../services'); + const services = jest.requireActual('../../services'); return { ...services, getRouterLinkProps: (link) => ({ href: link }), diff --git a/x-pack/plugins/rollup/public/crud_app/sections/job_list/job_table/job_table.test.js b/x-pack/plugins/rollup/public/crud_app/sections/job_list/job_table/job_table.test.js index 481c419403754..462742bee978f 100644 --- a/x-pack/plugins/rollup/public/crud_app/sections/job_list/job_table/job_table.test.js +++ b/x-pack/plugins/rollup/public/crud_app/sections/job_list/job_table/job_table.test.js @@ -12,7 +12,7 @@ import { rollupJobsStore } from '../../../store'; import { JobTable } from './job_table'; jest.mock('../../../../kibana_services', () => { - const services = require.requireActual('../../../../kibana_services'); + const services = jest.requireActual('../../../../kibana_services'); return { ...services, trackUiMetric: jest.fn(), diff --git a/x-pack/plugins/rollup/public/test/client_integration/job_create_review.test.js b/x-pack/plugins/rollup/public/test/client_integration/job_create_review.test.js index 87fdabae18240..d50a718e5c529 100644 --- a/x-pack/plugins/rollup/public/test/client_integration/job_create_review.test.js +++ b/x-pack/plugins/rollup/public/test/client_integration/job_create_review.test.js @@ -16,7 +16,7 @@ jest.mock('lodash', () => ({ })); jest.mock('../../kibana_services', () => { - const services = require.requireActual('../../kibana_services'); + const services = jest.requireActual('../../kibana_services'); return { ...services, getUiStatsReporter: jest.fn(() => () => {}), diff --git a/x-pack/plugins/rollup/public/test/client_integration/job_list.test.js b/x-pack/plugins/rollup/public/test/client_integration/job_list.test.js index f05e9fd1decd6..4091f79052b23 100644 --- a/x-pack/plugins/rollup/public/test/client_integration/job_list.test.js +++ b/x-pack/plugins/rollup/public/test/client_integration/job_list.test.js @@ -10,7 +10,7 @@ import { JOBS } from './helpers/constants'; import { coreMock } from '../../../../../../src/core/public/mocks'; jest.mock('../../crud_app/services', () => { - const services = require.requireActual('../../crud_app/services'); + const services = jest.requireActual('../../crud_app/services'); return { ...services, getRouterLinkProps: (link) => ({ href: link }), @@ -18,7 +18,7 @@ jest.mock('../../crud_app/services', () => { }); jest.mock('../../kibana_services', () => { - const services = require.requireActual('../../kibana_services'); + const services = jest.requireActual('../../kibana_services'); return { ...services, getUiStatsReporter: jest.fn(() => () => {}), diff --git a/x-pack/plugins/rollup/public/test/client_integration/job_list_clone.test.js b/x-pack/plugins/rollup/public/test/client_integration/job_list_clone.test.js index 76be39a2c0e09..7513e88a01fc8 100644 --- a/x-pack/plugins/rollup/public/test/client_integration/job_list_clone.test.js +++ b/x-pack/plugins/rollup/public/test/client_integration/job_list_clone.test.js @@ -16,7 +16,7 @@ jest.mock('lodash', () => ({ })); jest.mock('../../kibana_services', () => { - const services = require.requireActual('../../kibana_services'); + const services = jest.requireActual('../../kibana_services'); return { ...services, getUiStatsReporter: jest.fn(() => () => {}), diff --git a/x-pack/plugins/security_solution/public/network/components/flow_controls/__snapshots__/flow_target_select.test.tsx.snap b/x-pack/plugins/security_solution/public/network/components/flow_controls/__snapshots__/flow_target_select.test.tsx.snap index 6e38b5eeff5f6..efc4d4be9e957 100644 --- a/x-pack/plugins/security_solution/public/network/components/flow_controls/__snapshots__/flow_target_select.test.tsx.snap +++ b/x-pack/plugins/security_solution/public/network/components/flow_controls/__snapshots__/flow_target_select.test.tsx.snap @@ -7,21 +7,7 @@ exports[`FlowTargetSelect Component rendering it renders the FlowTargetSelect 1` hasDividers={false} isInvalid={false} isLoading={false} - onChange={ - [MockFunction] { - "calls": Array [ - Array [ - "destination", - ], - ], - "results": Array [ - Object { - "type": "return", - "value": undefined, - }, - ], - } - } + onChange={[MockFunction]} options={ Array [ Object { diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/properties/new_template_timeline.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/properties/new_template_timeline.test.tsx index b142484872813..b6e921ae9c001 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/properties/new_template_timeline.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/properties/new_template_timeline.test.tsx @@ -38,6 +38,10 @@ describe('NewTemplateTimeline', () => { const mockTitle = 'NEW_TIMELINE'; let wrapper: ReactWrapper; + beforeEach(() => { + jest.clearAllMocks(); + }); + describe('render if CRUD', () => { beforeAll(() => { (useKibana as jest.Mock).mockReturnValue({ @@ -52,10 +56,6 @@ describe('NewTemplateTimeline', () => { }, }); - afterAll(() => { - (useKibana as jest.Mock).mockReset(); - }); - wrapper = mount( @@ -100,10 +100,6 @@ describe('NewTemplateTimeline', () => { ); }); - afterAll(() => { - (useKibana as jest.Mock).mockReset(); - }); - test('no render', () => { expect( wrapper.find('[data-test-subj="template-timeline-new-with-border"]').exists() diff --git a/x-pack/plugins/task_manager/server/lib/bulk_operation_buffer.test.ts b/x-pack/plugins/task_manager/server/lib/bulk_operation_buffer.test.ts index 25abd92b32a26..c007b32338496 100644 --- a/x-pack/plugins/task_manager/server/lib/bulk_operation_buffer.test.ts +++ b/x-pack/plugins/task_manager/server/lib/bulk_operation_buffer.test.ts @@ -161,7 +161,7 @@ describe('Bulk Operation Buffer', () => { }); }); - test('handles both resolutions and rejections at individual task level', async (done) => { + test('handles both resolutions and rejections at individual task level', async () => { const bulkUpdate: jest.Mocked> = jest.fn( ([task1, task2, task3]) => { return Promise.resolve([ @@ -178,7 +178,7 @@ describe('Bulk Operation Buffer', () => { const task2 = createTask(); const task3 = createTask(); - return Promise.all([ + await Promise.all([ expect(bufferedUpdate(task1)).resolves.toMatchObject(incrementAttempts(task1)), expect(bufferedUpdate(task2)).rejects.toMatchObject( mapErr( @@ -187,13 +187,12 @@ describe('Bulk Operation Buffer', () => { ) ), expect(bufferedUpdate(task3)).resolves.toMatchObject(incrementAttempts(task3)), - ]).then(() => { - expect(bulkUpdate).toHaveBeenCalledTimes(1); - done(); - }); + ]); + + expect(bulkUpdate).toHaveBeenCalledTimes(1); }); - test('handles bulkUpdate failure', async (done) => { + test('handles bulkUpdate failure', async () => { const bulkUpdate: jest.Mocked> = jest.fn(() => { return Promise.reject(new Error('bulkUpdate is an illusion')); }); @@ -204,7 +203,7 @@ describe('Bulk Operation Buffer', () => { const task2 = createTask(); const task3 = createTask(); - return Promise.all([ + await Promise.all([ expect(bufferedUpdate(task1)).rejects.toMatchInlineSnapshot(` Object { "error": [Error: bulkUpdate is an illusion], @@ -223,13 +222,12 @@ describe('Bulk Operation Buffer', () => { "tag": "err", } `), - ]).then(() => { - expect(bulkUpdate).toHaveBeenCalledTimes(1); - done(); - }); + ]); + + expect(bulkUpdate).toHaveBeenCalledTimes(1); }); - test('logs unknown bulk operation results', async (done) => { + test('logs unknown bulk operation results', async () => { const bulkUpdate: jest.Mocked> = jest.fn( ([task1, task2, task3]) => { return Promise.resolve([ @@ -248,7 +246,7 @@ describe('Bulk Operation Buffer', () => { const task2 = createTask(); const task3 = createTask(); - return Promise.all([ + await Promise.all([ expect(bufferedUpdate(task1)).resolves.toMatchObject(incrementAttempts(task1)), expect(bufferedUpdate(task2)).rejects.toMatchObject( asErr(new Error(`Unhandled buffered operation for entity: ${task2.id}`)) @@ -256,10 +254,9 @@ describe('Bulk Operation Buffer', () => { expect(bufferedUpdate(task3)).rejects.toMatchObject( asErr(new Error(`Unhandled buffered operation for entity: ${task3.id}`)) ), - ]).then(() => { - expect(logger.warn).toHaveBeenCalledTimes(2); - done(); - }); + ]); + + expect(logger.warn).toHaveBeenCalledTimes(2); }); }); }); diff --git a/x-pack/plugins/task_manager/server/task_store.test.ts b/x-pack/plugins/task_manager/server/task_store.test.ts index 45c41b4d1d69d..f5fafe83748d9 100644 --- a/x-pack/plugins/task_manager/server/task_store.test.ts +++ b/x-pack/plugins/task_manager/server/task_store.test.ts @@ -7,7 +7,7 @@ import _ from 'lodash'; import sinon from 'sinon'; import uuid from 'uuid'; -import { filter } from 'rxjs/operators'; +import { filter, take } from 'rxjs/operators'; import { Option, some, none } from 'fp-ts/lib/Option'; import { @@ -1242,7 +1242,7 @@ if (doc['task.runAt'].size()!=0) { return { taskManagerId, runAt, tasks }; } - test('emits an event when a task is succesfully claimed by id', async (done) => { + test('emits an event when a task is succesfully claimed by id', async () => { const { taskManagerId, runAt, tasks } = generateTasks(); const callCluster = sinon.spy(async (name: string, params?: unknown) => name === 'updateByQuery' @@ -1262,49 +1262,47 @@ if (doc['task.runAt'].size()!=0) { index: '', }); - const sub = store.events + const promise = store.events .pipe( filter( (event: TaskEvent>) => event.id === 'claimed-by-id' - ) + ), + take(1) ) - .subscribe({ - next: (event: TaskEvent>) => { - expect(event).toMatchObject( - asTaskClaimEvent( - 'claimed-by-id', - asOk({ - id: 'claimed-by-id', - runAt, - taskType: 'foo', - schedule: undefined, - attempts: 0, - status: 'claiming' as TaskStatus, - params: { hello: 'world' }, - state: { baby: 'Henhen' }, - user: 'jimbo', - scope: ['reporting'], - ownerId: taskManagerId, - startedAt: null, - retryAt: null, - scheduledAt: new Date(), - }) - ) - ); - sub.unsubscribe(); - done(); - }, - }); + .toPromise(); await store.claimAvailableTasks({ claimTasksById: ['claimed-by-id'], claimOwnershipUntil: new Date(), size: 10, }); + + const event = await promise; + expect(event).toMatchObject( + asTaskClaimEvent( + 'claimed-by-id', + asOk({ + id: 'claimed-by-id', + runAt, + taskType: 'foo', + schedule: undefined, + attempts: 0, + status: 'claiming' as TaskStatus, + params: { hello: 'world' }, + state: { baby: 'Henhen' }, + user: 'jimbo', + scope: ['reporting'], + ownerId: taskManagerId, + startedAt: null, + retryAt: null, + scheduledAt: new Date(), + }) + ) + ); }); - test('emits an event when a task is succesfully by scheduling', async (done) => { + test('emits an event when a task is succesfully by scheduling', async () => { const { taskManagerId, runAt, tasks } = generateTasks(); const callCluster = sinon.spy(async (name: string, params?: unknown) => name === 'updateByQuery' @@ -1324,49 +1322,47 @@ if (doc['task.runAt'].size()!=0) { index: '', }); - const sub = store.events + const promise = store.events .pipe( filter( (event: TaskEvent>) => event.id === 'claimed-by-schedule' - ) + ), + take(1) ) - .subscribe({ - next: (event: TaskEvent>) => { - expect(event).toMatchObject( - asTaskClaimEvent( - 'claimed-by-schedule', - asOk({ - id: 'claimed-by-schedule', - runAt, - taskType: 'bar', - schedule: { interval: '5m' }, - attempts: 2, - status: 'claiming' as TaskStatus, - params: { shazm: 1 }, - state: { henry: 'The 8th' }, - user: 'dabo', - scope: ['reporting', 'ceo'], - ownerId: taskManagerId, - startedAt: null, - retryAt: null, - scheduledAt: new Date(), - }) - ) - ); - sub.unsubscribe(); - done(); - }, - }); + .toPromise(); await store.claimAvailableTasks({ claimTasksById: ['claimed-by-id'], claimOwnershipUntil: new Date(), size: 10, }); + + const event = await promise; + expect(event).toMatchObject( + asTaskClaimEvent( + 'claimed-by-schedule', + asOk({ + id: 'claimed-by-schedule', + runAt, + taskType: 'bar', + schedule: { interval: '5m' }, + attempts: 2, + status: 'claiming' as TaskStatus, + params: { shazm: 1 }, + state: { henry: 'The 8th' }, + user: 'dabo', + scope: ['reporting', 'ceo'], + ownerId: taskManagerId, + startedAt: null, + retryAt: null, + scheduledAt: new Date(), + }) + ) + ); }); - test('emits an event when the store fails to claim a required task by id', async (done) => { + test('emits an event when the store fails to claim a required task by id', async () => { const { taskManagerId, runAt, tasks } = generateTasks(); const callCluster = sinon.spy(async (name: string, params?: unknown) => name === 'updateByQuery' @@ -1386,51 +1382,49 @@ if (doc['task.runAt'].size()!=0) { index: '', }); - const sub = store.events + const promise = store.events .pipe( filter( (event: TaskEvent>) => event.id === 'already-running' - ) + ), + take(1) ) - .subscribe({ - next: (event: TaskEvent>) => { - expect(event).toMatchObject( - asTaskClaimEvent( - 'already-running', - asErr( - some({ - id: 'already-running', - runAt, - taskType: 'bar', - schedule: { interval: '5m' }, - attempts: 2, - status: 'running' as TaskStatus, - params: { shazm: 1 }, - state: { henry: 'The 8th' }, - user: 'dabo', - scope: ['reporting', 'ceo'], - ownerId: taskManagerId, - startedAt: null, - retryAt: null, - scheduledAt: new Date(), - }) - ) - ) - ); - sub.unsubscribe(); - done(); - }, - }); + .toPromise(); await store.claimAvailableTasks({ claimTasksById: ['already-running'], claimOwnershipUntil: new Date(), size: 10, }); + + const event = await promise; + expect(event).toMatchObject( + asTaskClaimEvent( + 'already-running', + asErr( + some({ + id: 'already-running', + runAt, + taskType: 'bar', + schedule: { interval: '5m' }, + attempts: 2, + status: 'running' as TaskStatus, + params: { shazm: 1 }, + state: { henry: 'The 8th' }, + user: 'dabo', + scope: ['reporting', 'ceo'], + ownerId: taskManagerId, + startedAt: null, + retryAt: null, + scheduledAt: new Date(), + }) + ) + ) + ); }); - test('emits an event when the store fails to find a task which was required by id', async (done) => { + test('emits an event when the store fails to find a task which was required by id', async () => { const { taskManagerId, tasks } = generateTasks(); const callCluster = sinon.spy(async (name: string, params?: unknown) => name === 'updateByQuery' @@ -1450,26 +1444,24 @@ if (doc['task.runAt'].size()!=0) { index: '', }); - const sub = store.events + const promise = store.events .pipe( filter( (event: TaskEvent>) => event.id === 'unknown-task' - ) + ), + take(1) ) - .subscribe({ - next: (event: TaskEvent>) => { - expect(event).toMatchObject(asTaskClaimEvent('unknown-task', asErr(none))); - sub.unsubscribe(); - done(); - }, - }); + .toPromise(); await store.claimAvailableTasks({ claimTasksById: ['unknown-task'], claimOwnershipUntil: new Date(), size: 10, }); + + const event = await promise; + expect(event).toMatchObject(asTaskClaimEvent('unknown-task', asErr(none))); }); }); }); diff --git a/x-pack/plugins/transform/public/app/hooks/use_index_data.test.tsx b/x-pack/plugins/transform/public/app/hooks/use_index_data.test.tsx index 4d752ee65fbfd..8b514b3e06519 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_index_data.test.tsx +++ b/x-pack/plugins/transform/public/app/hooks/use_index_data.test.tsx @@ -6,7 +6,7 @@ import React, { FC } from 'react'; -import { render, wait } from '@testing-library/react'; +import { render } from '@testing-library/react'; import { renderHook } from '@testing-library/react-hooks'; import { CoreSetup } from 'src/core/public'; @@ -33,7 +33,7 @@ const query: SimpleQuery = { }; describe('Transform: useIndexData()', () => { - test('indexPattern set triggers loading', async (done) => { + test('indexPattern set triggers loading', async () => { const mlShared = await getMlSharedImports(); const wrapper: FC = ({ children }) => ( {children} @@ -58,13 +58,11 @@ describe('Transform: useIndexData()', () => { expect(IndexObj.errorMessage).toBe(''); expect(IndexObj.status).toBe(1); expect(IndexObj.tableItems).toEqual([]); - done(); }); }); describe('Transform: with useIndexData()', () => { - // Using the async/await wait()/done() pattern to avoid act() errors. - test('Minimal initialization', async (done) => { + test('Minimal initialization', async () => { // Arrange const indexPattern = { title: 'the-index-pattern-title', @@ -97,7 +95,5 @@ describe('Transform: with useIndexData()', () => { // Act // Assert expect(getByText('the-index-preview-title')).toBeInTheDocument(); - await wait(); - done(); }); }); diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_form.test.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_form.test.tsx index cf1bfda6128ef..a03ce841a09ad 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_form.test.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_form.test.tsx @@ -5,7 +5,7 @@ */ import React from 'react'; -import { render, wait } from '@testing-library/react'; +import { render } from '@testing-library/react'; import { I18nProvider } from '@kbn/i18n/react'; @@ -51,8 +51,7 @@ const createMockStorage = () => ({ }); describe('Transform: ', () => { - // Using the async/await wait()/done() pattern to avoid act() errors. - test('Minimal initialization', async (done) => { + test('Minimal initialization', async () => { // Arrange const mlSharedImports = await getMlSharedImports(); @@ -85,8 +84,6 @@ describe('Transform: ', () => { // Assert expect(getByText('Index pattern')).toBeInTheDocument(); expect(getByText(searchItems.indexPattern.title)).toBeInTheDocument(); - await wait(); - done(); }); }); diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_summary.test.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_summary.test.tsx index 7aed0568e6efc..b3cd8a2937952 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_summary.test.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_summary.test.tsx @@ -27,7 +27,7 @@ import { getMlSharedImports } from '../../../../../shared_imports'; describe('Transform: ', () => { // Using the async/await wait()/done() pattern to avoid act() errors. - test('Minimal initialization', async (done) => { + test('Minimal initialization', async () => { // Arrange const mlSharedImports = await getMlSharedImports(); @@ -72,6 +72,5 @@ describe('Transform: ', () => { expect(getByText('Group by')).toBeInTheDocument(); expect(getByText('Aggregations')).toBeInTheDocument(); await wait(); - done(); }); }); diff --git a/x-pack/plugins/ui_actions_enhanced/public/custom_time_range_action.test.ts b/x-pack/plugins/ui_actions_enhanced/public/custom_time_range_action.test.ts index 9af79c9ac5259..99971c42e5512 100644 --- a/x-pack/plugins/ui_actions_enhanced/public/custom_time_range_action.test.ts +++ b/x-pack/plugins/ui_actions_enhanced/public/custom_time_range_action.test.ts @@ -5,7 +5,7 @@ */ import { findTestSubject } from '@elastic/eui/lib/test'; -import { skip } from 'rxjs/operators'; +import { skip, take } from 'rxjs/operators'; import * as Rx from 'rxjs'; import { mount } from 'enzyme'; @@ -27,7 +27,7 @@ const createOpenModalMock = () => { return mock; }; -test('Custom time range action prevents embeddable from using container time', async (done) => { +test('Custom time range action prevents embeddable from using container time', async () => { const container = new TimeRangeContainer( { timeRange: { from: 'now-15m', to: 'now' }, @@ -79,19 +79,19 @@ test('Custom time range action prevents embeddable from using container time', a findTestSubject(wrapper, 'addPerPanelTimeRangeButton').simulate('click'); - const subscription = Rx.merge(container.getOutput$(), container.getInput$()) - .pipe(skip(2)) - .subscribe(() => { - expect(child1.getInput().timeRange).toEqual({ from: 'now-30days', to: 'now-29days' }); - expect(child2.getInput().timeRange).toEqual({ from: 'now-30m', to: 'now-1m' }); - subscription.unsubscribe(); - done(); - }); + const promise = Rx.merge(container.getOutput$(), container.getOutput$(), container.getInput$()) + .pipe(skip(2), take(1)) + .toPromise(); container.updateInput({ timeRange: { from: 'now-30m', to: 'now-1m' } }); + + await promise; + + expect(child1.getInput().timeRange).toEqual({ from: 'now-30days', to: 'now-29days' }); + expect(child2.getInput().timeRange).toEqual({ from: 'now-30m', to: 'now-1m' }); }); -test('Removing custom time range action resets embeddable back to container time', async (done) => { +test('Removing custom time range action resets embeddable back to container time', async () => { const container = new TimeRangeContainer( { timeRange: { from: 'now-15m', to: 'now' }, @@ -153,19 +153,19 @@ test('Removing custom time range action resets embeddable back to container time const wrapper2 = mount(openModal2); findTestSubject(wrapper2, 'removePerPanelTimeRangeButton').simulate('click'); - const subscription = Rx.merge(container.getOutput$(), container.getInput$()) - .pipe(skip(2)) - .subscribe(() => { - expect(child1.getInput().timeRange).toEqual({ from: 'now-10m', to: 'now-5m' }); - expect(child2.getInput().timeRange).toEqual({ from: 'now-10m', to: 'now-5m' }); - subscription.unsubscribe(); - done(); - }); + const promise = Rx.merge(container.getOutput$(), container.getOutput$(), container.getInput$()) + .pipe(skip(2), take(1)) + .toPromise(); container.updateInput({ timeRange: { from: 'now-10m', to: 'now-5m' } }); + + await promise; + + expect(child1.getInput().timeRange).toEqual({ from: 'now-10m', to: 'now-5m' }); + expect(child2.getInput().timeRange).toEqual({ from: 'now-10m', to: 'now-5m' }); }); -test('Cancelling custom time range action leaves state alone', async (done) => { +test('Cancelling custom time range action leaves state alone', async () => { const container = new TimeRangeContainer( { timeRange: { from: 'now-15m', to: 'now' }, @@ -212,16 +212,16 @@ test('Cancelling custom time range action leaves state alone', async (done) => { findTestSubject(wrapper, 'cancelPerPanelTimeRangeButton').simulate('click'); - const subscription = Rx.merge(container.getOutput$(), container.getInput$()) - .pipe(skip(2)) - .subscribe(() => { - expect(child1.getInput().timeRange).toEqual({ from: '1', to: '2' }); - expect(child2.getInput().timeRange).toEqual({ from: 'now-30m', to: 'now-1m' }); - subscription.unsubscribe(); - done(); - }); + const promise = Rx.merge(container.getOutput$(), container.getOutput$(), container.getInput$()) + .pipe(skip(2), take(1)) + .toPromise(); container.updateInput({ timeRange: { from: 'now-30m', to: 'now-1m' } }); + + await promise; + + expect(child1.getInput().timeRange).toEqual({ from: '1', to: '2' }); + expect(child2.getInput().timeRange).toEqual({ from: 'now-30m', to: 'now-1m' }); }); test(`badge is compatible with embeddable that inherits from parent`, async () => { diff --git a/x-pack/plugins/ui_actions_enhanced/public/custom_time_range_badge.test.ts b/x-pack/plugins/ui_actions_enhanced/public/custom_time_range_badge.test.ts index 03fb80c3ce75b..a839079137905 100644 --- a/x-pack/plugins/ui_actions_enhanced/public/custom_time_range_badge.test.ts +++ b/x-pack/plugins/ui_actions_enhanced/public/custom_time_range_badge.test.ts @@ -5,7 +5,7 @@ */ import { findTestSubject } from '@elastic/eui/lib/test'; -import { skip } from 'rxjs/operators'; +import { skip, take } from 'rxjs/operators'; import * as Rx from 'rxjs'; import { mount } from 'enzyme'; import { TimeRangeEmbeddable, TimeRangeContainer, TIME_RANGE_EMBEDDABLE } from './test_helpers'; @@ -13,7 +13,7 @@ import { CustomTimeRangeBadge } from './custom_time_range_badge'; import { ReactElement } from 'react'; import { nextTick } from 'test_utils/enzyme_helpers'; -test('Removing custom time range from badge resets embeddable back to container time', async (done) => { +test('Removing custom time range from badge resets embeddable back to container time', async () => { const container = new TimeRangeContainer( { timeRange: { from: 'now-15m', to: 'now' }, @@ -60,16 +60,16 @@ test('Removing custom time range from badge resets embeddable back to container const wrapper = mount(openModal); findTestSubject(wrapper, 'removePerPanelTimeRangeButton').simulate('click'); - const subscription = Rx.merge(child1.getInput$(), container.getOutput$(), container.getInput$()) - .pipe(skip(4)) - .subscribe(() => { - expect(child1.getInput().timeRange).toEqual({ from: 'now-10m', to: 'now-5m' }); - expect(child2.getInput().timeRange).toEqual({ from: 'now-10m', to: 'now-5m' }); - subscription.unsubscribe(); - done(); - }); + const promise = Rx.merge(child1.getInput$(), container.getOutput$(), container.getInput$()) + .pipe(skip(4), take(1)) + .toPromise(); container.updateInput({ timeRange: { from: 'now-10m', to: 'now-5m' } }); + + await promise; + + expect(child1.getInput().timeRange).toEqual({ from: 'now-10m', to: 'now-5m' }); + expect(child2.getInput().timeRange).toEqual({ from: 'now-10m', to: 'now-5m' }); }); test(`badge is not compatible with embeddable that inherits from parent`, async () => { diff --git a/yarn.lock b/yarn.lock index 876f938cfce88..77e3a399c4313 100644 --- a/yarn.lock +++ b/yarn.lock @@ -514,6 +514,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.10.4" +"@babel/plugin-syntax-import-meta@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" + integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-json-strings@^7.8.0", "@babel/plugin-syntax-json-strings@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" @@ -1650,59 +1657,61 @@ chalk "^2.0.1" slash "^2.0.0" -"@jest/console@^25.5.0": - version "25.5.0" - resolved "https://registry.yarnpkg.com/@jest/console/-/console-25.5.0.tgz#770800799d510f37329c508a9edd0b7b447d9abb" - integrity sha512-T48kZa6MK1Y6k4b89sexwmSF4YLeZS/Udqg3Jj3jG/cHH+N/sLFCEoXEDMOKugJQ9FxPN1osxIknvKkxt6MKyw== +"@jest/console@^26.3.0": + version "26.3.0" + resolved "https://registry.yarnpkg.com/@jest/console/-/console-26.3.0.tgz#ed04063efb280c88ba87388b6f16427c0a85c856" + integrity sha512-/5Pn6sJev0nPUcAdpJHMVIsA8sKizL2ZkcKPE5+dJrCccks7tcM7c9wbgHudBJbxXLoTbqsHkG1Dofoem4F09w== dependencies: - "@jest/types" "^25.5.0" - chalk "^3.0.0" - jest-message-util "^25.5.0" - jest-util "^25.5.0" + "@jest/types" "^26.3.0" + "@types/node" "*" + chalk "^4.0.0" + jest-message-util "^26.3.0" + jest-util "^26.3.0" slash "^3.0.0" -"@jest/core@^25.5.4": - version "25.5.4" - resolved "https://registry.yarnpkg.com/@jest/core/-/core-25.5.4.tgz#3ef7412f7339210f003cdf36646bbca786efe7b4" - integrity sha512-3uSo7laYxF00Dg/DMgbn4xMJKmDdWvZnf89n8Xj/5/AeQ2dOQmn6b6Hkj/MleyzZWXpwv+WSdYWl4cLsy2JsoA== +"@jest/core@^26.4.2": + version "26.4.2" + resolved "https://registry.yarnpkg.com/@jest/core/-/core-26.4.2.tgz#85d0894f31ac29b5bab07aa86806d03dd3d33edc" + integrity sha512-sDva7YkeNprxJfepOctzS8cAk9TOekldh+5FhVuXS40+94SHbiicRO1VV2tSoRtgIo+POs/Cdyf8p76vPTd6dg== dependencies: - "@jest/console" "^25.5.0" - "@jest/reporters" "^25.5.1" - "@jest/test-result" "^25.5.0" - "@jest/transform" "^25.5.1" - "@jest/types" "^25.5.0" + "@jest/console" "^26.3.0" + "@jest/reporters" "^26.4.1" + "@jest/test-result" "^26.3.0" + "@jest/transform" "^26.3.0" + "@jest/types" "^26.3.0" + "@types/node" "*" ansi-escapes "^4.2.1" - chalk "^3.0.0" + chalk "^4.0.0" exit "^0.1.2" graceful-fs "^4.2.4" - jest-changed-files "^25.5.0" - jest-config "^25.5.4" - jest-haste-map "^25.5.1" - jest-message-util "^25.5.0" - jest-regex-util "^25.2.6" - jest-resolve "^25.5.1" - jest-resolve-dependencies "^25.5.4" - jest-runner "^25.5.4" - jest-runtime "^25.5.4" - jest-snapshot "^25.5.1" - jest-util "^25.5.0" - jest-validate "^25.5.0" - jest-watcher "^25.5.0" + jest-changed-files "^26.3.0" + jest-config "^26.4.2" + jest-haste-map "^26.3.0" + jest-message-util "^26.3.0" + jest-regex-util "^26.0.0" + jest-resolve "^26.4.0" + jest-resolve-dependencies "^26.4.2" + jest-runner "^26.4.2" + jest-runtime "^26.4.2" + jest-snapshot "^26.4.2" + jest-util "^26.3.0" + jest-validate "^26.4.2" + jest-watcher "^26.3.0" micromatch "^4.0.2" p-each-series "^2.1.0" - realpath-native "^2.0.0" rimraf "^3.0.0" slash "^3.0.0" strip-ansi "^6.0.0" -"@jest/environment@^25.5.0": - version "25.5.0" - resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-25.5.0.tgz#aa33b0c21a716c65686638e7ef816c0e3a0c7b37" - integrity sha512-U2VXPEqL07E/V7pSZMSQCvV5Ea4lqOlT+0ZFijl/i316cRMHvZ4qC+jBdryd+lmRetjQo0YIQr6cVPNxxK87mA== +"@jest/environment@^26.3.0": + version "26.3.0" + resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-26.3.0.tgz#e6953ab711ae3e44754a025f838bde1a7fd236a0" + integrity sha512-EW+MFEo0DGHahf83RAaiqQx688qpXgl99wdb8Fy67ybyzHwR1a58LHcO376xQJHfmoXTu89M09dH3J509cx2AA== dependencies: - "@jest/fake-timers" "^25.5.0" - "@jest/types" "^25.5.0" - jest-mock "^25.5.0" + "@jest/fake-timers" "^26.3.0" + "@jest/types" "^26.3.0" + "@types/node" "*" + jest-mock "^26.3.0" "@jest/fake-timers@^24.9.0": version "24.9.0" @@ -1713,57 +1722,58 @@ jest-message-util "^24.9.0" jest-mock "^24.9.0" -"@jest/fake-timers@^25.5.0": - version "25.5.0" - resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-25.5.0.tgz#46352e00533c024c90c2bc2ad9f2959f7f114185" - integrity sha512-9y2+uGnESw/oyOI3eww9yaxdZyHq7XvprfP/eeoCsjqKYts2yRlsHS/SgjPDV8FyMfn2nbMy8YzUk6nyvdLOpQ== +"@jest/fake-timers@^26.3.0": + version "26.3.0" + resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-26.3.0.tgz#f515d4667a6770f60ae06ae050f4e001126c666a" + integrity sha512-ZL9ytUiRwVP8ujfRepffokBvD2KbxbqMhrXSBhSdAhISCw3gOkuntisiSFv+A6HN0n0fF4cxzICEKZENLmW+1A== dependencies: - "@jest/types" "^25.5.0" - jest-message-util "^25.5.0" - jest-mock "^25.5.0" - jest-util "^25.5.0" - lolex "^5.0.0" + "@jest/types" "^26.3.0" + "@sinonjs/fake-timers" "^6.0.1" + "@types/node" "*" + jest-message-util "^26.3.0" + jest-mock "^26.3.0" + jest-util "^26.3.0" -"@jest/globals@^25.5.2": - version "25.5.2" - resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-25.5.2.tgz#5e45e9de8d228716af3257eeb3991cc2e162ca88" - integrity sha512-AgAS/Ny7Q2RCIj5kZ+0MuKM1wbF0WMLxbCVl/GOMoCNbODRdJ541IxJ98xnZdVSZXivKpJlNPIWa3QmY0l4CXA== +"@jest/globals@^26.4.2": + version "26.4.2" + resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-26.4.2.tgz#73c2a862ac691d998889a241beb3dc9cada40d4a" + integrity sha512-Ot5ouAlehhHLRhc+sDz2/9bmNv9p5ZWZ9LE1pXGGTCXBasmi5jnYjlgYcYt03FBwLmZXCZ7GrL29c33/XRQiow== dependencies: - "@jest/environment" "^25.5.0" - "@jest/types" "^25.5.0" - expect "^25.5.0" + "@jest/environment" "^26.3.0" + "@jest/types" "^26.3.0" + expect "^26.4.2" -"@jest/reporters@^25.5.1": - version "25.5.1" - resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-25.5.1.tgz#cb686bcc680f664c2dbaf7ed873e93aa6811538b" - integrity sha512-3jbd8pPDTuhYJ7vqiHXbSwTJQNavczPs+f1kRprRDxETeE3u6srJ+f0NPuwvOmk+lmunZzPkYWIFZDLHQPkviw== +"@jest/reporters@^26.4.1": + version "26.4.1" + resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-26.4.1.tgz#3b4d6faf28650f3965f8b97bc3d114077fb71795" + integrity sha512-aROTkCLU8++yiRGVxLsuDmZsQEKO6LprlrxtAuzvtpbIFl3eIjgIf3EUxDKgomkS25R9ZzwGEdB5weCcBZlrpQ== dependencies: "@bcoe/v8-coverage" "^0.2.3" - "@jest/console" "^25.5.0" - "@jest/test-result" "^25.5.0" - "@jest/transform" "^25.5.1" - "@jest/types" "^25.5.0" - chalk "^3.0.0" + "@jest/console" "^26.3.0" + "@jest/test-result" "^26.3.0" + "@jest/transform" "^26.3.0" + "@jest/types" "^26.3.0" + chalk "^4.0.0" collect-v8-coverage "^1.0.0" exit "^0.1.2" glob "^7.1.2" graceful-fs "^4.2.4" istanbul-lib-coverage "^3.0.0" - istanbul-lib-instrument "^4.0.0" + istanbul-lib-instrument "^4.0.3" istanbul-lib-report "^3.0.0" istanbul-lib-source-maps "^4.0.0" istanbul-reports "^3.0.2" - jest-haste-map "^25.5.1" - jest-resolve "^25.5.1" - jest-util "^25.5.0" - jest-worker "^25.5.0" + jest-haste-map "^26.3.0" + jest-resolve "^26.4.0" + jest-util "^26.3.0" + jest-worker "^26.3.0" slash "^3.0.0" source-map "^0.6.0" - string-length "^3.1.0" + string-length "^4.0.1" terminal-link "^2.0.0" - v8-to-istanbul "^4.1.3" + v8-to-istanbul "^5.0.1" optionalDependencies: - node-notifier "^6.0.0" + node-notifier "^8.0.0" "@jest/source-map@^24.9.0": version "24.9.0" @@ -1774,10 +1784,10 @@ graceful-fs "^4.1.15" source-map "^0.6.0" -"@jest/source-map@^25.5.0": - version "25.5.0" - resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-25.5.0.tgz#df5c20d6050aa292c2c6d3f0d2c7606af315bd1b" - integrity sha512-eIGx0xN12yVpMcPaVpjXPnn3N30QGJCJQSkEDUt9x1fI1Gdvb07Ml6K5iN2hG7NmMP6FDmtPEssE3z6doOYUwQ== +"@jest/source-map@^26.3.0": + version "26.3.0" + resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-26.3.0.tgz#0e646e519883c14c551f7b5ae4ff5f1bfe4fc3d9" + integrity sha512-hWX5IHmMDWe1kyrKl7IhFwqOuAreIwHhbe44+XH2ZRHjrKIh0LO5eLQ/vxHFeAfRwJapmxuqlGAEYLadDq6ZGQ== dependencies: callsites "^3.0.0" graceful-fs "^4.2.4" @@ -1792,50 +1802,28 @@ "@jest/types" "^24.9.0" "@types/istanbul-lib-coverage" "^2.0.0" -"@jest/test-result@^25.5.0": - version "25.5.0" - resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-25.5.0.tgz#139a043230cdeffe9ba2d8341b27f2efc77ce87c" - integrity sha512-oV+hPJgXN7IQf/fHWkcS99y0smKLU2czLBJ9WA0jHITLst58HpQMtzSYxzaBvYc6U5U6jfoMthqsUlUlbRXs0A== +"@jest/test-result@^26.3.0": + version "26.3.0" + resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-26.3.0.tgz#46cde01fa10c0aaeb7431bf71e4a20d885bc7fdb" + integrity sha512-a8rbLqzW/q7HWheFVMtghXV79Xk+GWwOK1FrtimpI5n1la2SY0qHri3/b0/1F0Ve0/yJmV8pEhxDfVwiUBGtgg== dependencies: - "@jest/console" "^25.5.0" - "@jest/types" "^25.5.0" + "@jest/console" "^26.3.0" + "@jest/types" "^26.3.0" "@types/istanbul-lib-coverage" "^2.0.0" collect-v8-coverage "^1.0.0" -"@jest/test-sequencer@^25.5.4": - version "25.5.4" - resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-25.5.4.tgz#9b4e685b36954c38d0f052e596d28161bdc8b737" - integrity sha512-pTJGEkSeg1EkCO2YWq6hbFvKNXk8ejqlxiOg1jBNLnWrgXOkdY6UmqZpwGFXNnRt9B8nO1uWMzLLZ4eCmhkPNA== - dependencies: - "@jest/test-result" "^25.5.0" - graceful-fs "^4.2.4" - jest-haste-map "^25.5.1" - jest-runner "^25.5.4" - jest-runtime "^25.5.4" - -"@jest/transform@^25.5.1": - version "25.5.1" - resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-25.5.1.tgz#0469ddc17699dd2bf985db55fa0fb9309f5c2db3" - integrity sha512-Y8CEoVwXb4QwA6Y/9uDkn0Xfz0finGkieuV0xkdF9UtZGJeLukD5nLkaVrVsODB1ojRWlaoD0AJZpVHCSnJEvg== +"@jest/test-sequencer@^26.4.2": + version "26.4.2" + resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-26.4.2.tgz#58a3760a61eec758a2ce6080201424580d97cbba" + integrity sha512-83DRD8N3M0tOhz9h0bn6Kl6dSp+US6DazuVF8J9m21WAp5x7CqSMaNycMP0aemC/SH/pDQQddbsfHRTBXVUgog== dependencies: - "@babel/core" "^7.1.0" - "@jest/types" "^25.5.0" - babel-plugin-istanbul "^6.0.0" - chalk "^3.0.0" - convert-source-map "^1.4.0" - fast-json-stable-stringify "^2.0.0" + "@jest/test-result" "^26.3.0" graceful-fs "^4.2.4" - jest-haste-map "^25.5.1" - jest-regex-util "^25.2.6" - jest-util "^25.5.0" - micromatch "^4.0.2" - pirates "^4.0.1" - realpath-native "^2.0.0" - slash "^3.0.0" - source-map "^0.6.1" - write-file-atomic "^3.0.0" + jest-haste-map "^26.3.0" + jest-runner "^26.4.2" + jest-runtime "^26.4.2" -"@jest/transform@^26.0.0": +"@jest/transform@^26.0.0", "@jest/transform@^26.3.0": version "26.3.0" resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-26.3.0.tgz#c393e0e01459da8a8bfc6d2a7c2ece1a13e8ba55" integrity sha512-Isj6NB68QorGoFWvcOjlUhpkT56PqNIsXKR7XfvoDlCANn/IANlh8DrKAA2l2JKC3yWSMH5wS0GwuQM20w3b2A== @@ -2841,6 +2829,13 @@ dependencies: type-detect "4.0.8" +"@sinonjs/fake-timers@^6.0.1": + version "6.0.1" + resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz#293674fccb3262ac782c7aadfdeca86b10c75c40" + integrity sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA== + dependencies: + "@sinonjs/commons" "^1.7.0" + "@sinonjs/formatio@^3.2.1": version "3.2.2" resolved "https://registry.yarnpkg.com/@sinonjs/formatio/-/formatio-3.2.2.tgz#771c60dfa75ea7f2d68e3b94c7e888a78781372c" @@ -3753,6 +3748,17 @@ resolved "https://registry.yarnpkg.com/@types/babel-types/-/babel-types-7.0.4.tgz#bfd5b0d0d1ba13e351dff65b6e52783b816826c8" integrity sha512-WiZhq3SVJHFRgRYLXvpf65XnV6ipVHhnNaNvE8yCimejrGglkg38kEj0JcizqwSHxmPSjcTlig/6JouxLGEhGw== +"@types/babel__core@^7.0.0": + version "7.1.10" + resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.10.tgz#ca58fc195dd9734e77e57c6f2df565623636ab40" + integrity sha512-x8OM8XzITIMyiwl5Vmo2B1cR1S1Ipkyv4mdlbJjMa1lmuKvKY9FrBbEANIaMlnWn5Rf7uO+rC/VgYabNkE17Hw== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + "@types/babel__generator" "*" + "@types/babel__template" "*" + "@types/babel__traverse" "*" + "@types/babel__core@^7.1.2": version "7.1.2" resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.2.tgz#608c74f55928033fce18b99b213c16be4b3d114f" @@ -4374,7 +4380,7 @@ dependencies: "@types/jest" "*" -"@types/jest@*", "@types/jest@^25.1.1", "@types/jest@^25.2.3": +"@types/jest@*", "@types/jest@^25.1.1": version "25.2.3" resolved "https://registry.yarnpkg.com/@types/jest/-/jest-25.2.3.tgz#33d27e4c4716caae4eced355097a47ad363fdcaf" integrity sha512-JXc1nK/tXHiDhV55dvfzqtmP4S3sy3T3ouV2tkViZgxY/zeUkcpQcQPGRlgF4KmWzWW5oiWYSZwtCB+2RsE4Fw== @@ -4382,6 +4388,14 @@ jest-diff "^25.2.1" pretty-format "^25.2.1" +"@types/jest@^26.0.14": + version "26.0.14" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-26.0.14.tgz#078695f8f65cb55c5a98450d65083b2b73e5a3f3" + integrity sha512-Hz5q8Vu0D288x3iWXePSn53W7hAjP0H7EQ6QvDO9c7t46mR0lNOLlfuwQ+JkVxuhygHzlzPX+0jKdA3ZgSh+Vg== + dependencies: + jest-diff "^25.2.1" + pretty-format "^25.2.1" + "@types/joi@*", "@types/joi@^13.4.2": version "13.6.1" resolved "https://registry.yarnpkg.com/@types/joi/-/joi-13.6.1.tgz#325486a397504f8e22c8c551dc8b0e1d41d5d5ae" @@ -4768,11 +4782,6 @@ resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-1.16.1.tgz#328d1c9b54402e44119398bcb6a31b7bbd606d59" integrity sha512-db6pZL5QY3JrlCHBhYQzYDci0xnoDuxfseUuguLRr3JNk+bnCfpkK6p8quiUDyO8A0vbpBKkk59Fw125etrNeA== -"@types/prettier@^1.19.0": - version "1.19.1" - resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-1.19.1.tgz#33509849f8e679e4add158959fdb086440e9553f" - integrity sha512-5qOlnZscTn4xxM5MeGXAMOsIOIKIbh9e85zJWfBRVPlRMEVawzoPhINYbRGkBZCI8LxvBe7tJCdWiarA99OZfQ== - "@types/prettier@^2.0.0", "@types/prettier@^2.0.2": version "2.0.2" resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.0.2.tgz#5bb52ee68d0f8efa9cc0099920e56be6cc4e37f3" @@ -5166,13 +5175,20 @@ resolved "https://registry.yarnpkg.com/@types/tempy/-/tempy-0.2.0.tgz#8b7a93f6912aef25cc0b8d8a80ff974151478685" integrity sha512-YaX74QljqR45Xu7dd22wMvzTS+ItUiSyDl9XJl6WTgYNE09r2TF+mV2FDjWRM5Sdzf9C9dXRTUdz9J5SoEYxXg== -"@types/testing-library__jest-dom@^5.9.1", "@types/testing-library__jest-dom@^5.9.2": +"@types/testing-library__jest-dom@^5.9.1": version "5.9.2" resolved "https://registry.yarnpkg.com/@types/testing-library__jest-dom/-/testing-library__jest-dom-5.9.2.tgz#59e4771a1cf87d51e89a5cc8195cd3b647cba322" integrity sha512-K7nUSpH/5i8i0NagTJ+uFUDRueDlnMNhJtMjMwTGPPSqyImbWC/hgKPDCKt6Phu2iMJg2kWqlax+Ucj2DKMwpA== dependencies: "@types/jest" "*" +"@types/testing-library__jest-dom@^5.9.3": + version "5.9.3" + resolved "https://registry.yarnpkg.com/@types/testing-library__jest-dom/-/testing-library__jest-dom-5.9.3.tgz#574039e210140a536c6ec891063289fb742a75eb" + integrity sha512-5YxiCFA2vk0cxq2LIxYgHBpFlnJvMH9bkUIVNin+1GXT+LZgVOgXBeEyyo2ZrGXMO/KWe1ZV3p7Kb6LJAvJasw== + dependencies: + "@types/jest" "*" + "@types/testing-library__react-hooks@^3.3.0", "@types/testing-library__react-hooks@^3.4.0": version "3.4.0" resolved "https://registry.yarnpkg.com/@types/testing-library__react-hooks/-/testing-library__react-hooks-3.4.0.tgz#be148b7fa7d19cd3349c4ef9d9534486bc582fcc" @@ -5409,14 +5425,17 @@ eslint-scope "^5.0.0" eslint-utils "^2.0.0" -"@typescript-eslint/experimental-utils@^2.5.0": - version "2.15.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-2.15.0.tgz#41e35313bfaef91650ddb5380846d1c78a780070" - integrity sha512-Qkxu5zndY5hqlcQkmA88gfLvqQulMpX/TN91XC7OuXsRf4XG5xLGie0sbpX97o/oeccjeZYRMipIsjKk/tjDHA== +"@typescript-eslint/experimental-utils@^4.0.1": + version "4.3.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.3.0.tgz#3f3c6c508e01b8050d51b016e7f7da0e3aefcb87" + integrity sha512-cmmIK8shn3mxmhpKfzMMywqiEheyfXLV/+yPDnOTvQX/ztngx7Lg/OD26J8gTZfkLKUmaEBxO2jYP3keV7h2OQ== dependencies: "@types/json-schema" "^7.0.3" - "@typescript-eslint/typescript-estree" "2.15.0" + "@typescript-eslint/scope-manager" "4.3.0" + "@typescript-eslint/types" "4.3.0" + "@typescript-eslint/typescript-estree" "4.3.0" eslint-scope "^5.0.0" + eslint-utils "^2.0.0" "@typescript-eslint/parser@^3.10.0": version "3.10.0" @@ -5429,23 +5448,23 @@ "@typescript-eslint/typescript-estree" "3.10.0" eslint-visitor-keys "^1.1.0" +"@typescript-eslint/scope-manager@4.3.0": + version "4.3.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.3.0.tgz#c743227e087545968080d2362cfb1273842cb6a7" + integrity sha512-cTeyP5SCNE8QBRfc+Lgh4Xpzje46kNUhXYfc3pQWmJif92sjrFuHT9hH4rtOkDTo/si9Klw53yIr+djqGZS1ig== + dependencies: + "@typescript-eslint/types" "4.3.0" + "@typescript-eslint/visitor-keys" "4.3.0" + "@typescript-eslint/types@3.10.0": version "3.10.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-3.10.0.tgz#b81906674eca94a884345ba0bc1aaf6cd4da912a" integrity sha512-ktUWSa75heQNwH85GRM7qP/UUrXqx9d6yIdw0iLO9/uE1LILW+i+3+B64dUodUS2WFWLzKTlwfi9giqrODibWg== -"@typescript-eslint/typescript-estree@2.15.0": - version "2.15.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-2.15.0.tgz#79ae52eed8701b164d91e968a65d85a9105e76d3" - integrity sha512-L6Pog+w3VZzXkAdyqA0VlwybF8WcwZX+mufso86CMxSdWmcizJ38lgBdpqTbc9bo92iyi0rOvmATKiwl+amjxg== - dependencies: - debug "^4.1.1" - eslint-visitor-keys "^1.1.0" - glob "^7.1.6" - is-glob "^4.0.1" - lodash.unescape "4.0.1" - semver "^6.3.0" - tsutils "^3.17.1" +"@typescript-eslint/types@4.3.0": + version "4.3.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.3.0.tgz#1f0b2d5e140543e2614f06d48fb3ae95193c6ddf" + integrity sha512-Cx9TpRvlRjOppGsU6Y6KcJnUDOelja2NNCX6AZwtVHRzaJkdytJWMuYiqi8mS35MRNA3cJSwDzXePfmhU6TANw== "@typescript-eslint/typescript-estree@3.10.0": version "3.10.0" @@ -5461,6 +5480,20 @@ semver "^7.3.2" tsutils "^3.17.1" +"@typescript-eslint/typescript-estree@4.3.0": + version "4.3.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.3.0.tgz#0edc1068e6b2e4c7fdc54d61e329fce76241cee8" + integrity sha512-ZAI7xjkl+oFdLV/COEz2tAbQbR3XfgqHEGy0rlUXzfGQic6EBCR4s2+WS3cmTPG69aaZckEucBoTxW9PhzHxxw== + dependencies: + "@typescript-eslint/types" "4.3.0" + "@typescript-eslint/visitor-keys" "4.3.0" + debug "^4.1.1" + globby "^11.0.1" + is-glob "^4.0.1" + lodash "^4.17.15" + semver "^7.3.2" + tsutils "^3.17.1" + "@typescript-eslint/typescript-estree@^1.9.0": version "1.9.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-1.9.0.tgz#5d6d49be936e96fb0f859673480f89b070a5dd9b" @@ -5476,6 +5509,14 @@ dependencies: eslint-visitor-keys "^1.1.0" +"@typescript-eslint/visitor-keys@4.3.0": + version "4.3.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.3.0.tgz#0e5ab0a09552903edeae205982e8521e17635ae0" + integrity sha512-xZxkuR7XLM6RhvLkgv9yYlTcBHnTULzfnw4i6+z2TGBLy9yljAypQaZl9c3zFvy7PNI7fYWyvKYtohyF8au3cw== + dependencies: + "@typescript-eslint/types" "4.3.0" + eslint-visitor-keys "^2.0.0" + "@webassemblyjs/ast@1.8.5": version "1.8.5" resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.8.5.tgz#51b1c5fe6576a34953bf4b253df9f0d490d9e359" @@ -5844,6 +5885,11 @@ abab@^2.0.0: resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.0.tgz#aba0ab4c5eee2d4c79d3487d85450fb2376ebb0f" integrity sha512-sY5AXXVZv4Y1VACTtR11UJCPHHudgY5i26Qj5TypE6DKlIApbwb5uqhXcJ5UUGbvZNRh7EeIoW+LrJumBsKp7w== +abab@^2.0.3: + version "2.0.5" + resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.5.tgz#c0b678fb32d60fc1219c784d6a826fe385aeb79a" + integrity sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q== + abbrev@1: version "1.1.1" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" @@ -5885,7 +5931,7 @@ accepts@~1.3.7: mime-types "~2.1.24" negotiator "0.6.2" -acorn-globals@^4.3.0, acorn-globals@^4.3.2: +acorn-globals@^4.3.0: version "4.3.4" resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-4.3.4.tgz#9fa1926addc11c97308c4e66d7add0d40c3272e7" integrity sha512-clfQEh21R+D0leSbUdWf3OcfqyaCSAQ8Ryq00bofSekfr9W8u1jyYZo6ir0xu9Gtcf7BjcHJpnbZH7JOCpP60A== @@ -5893,6 +5939,14 @@ acorn-globals@^4.3.0, acorn-globals@^4.3.2: acorn "^6.0.1" acorn-walk "^6.0.1" +acorn-globals@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-6.0.0.tgz#46cdd39f0f8ff08a876619b55f5ac8a6dc770b45" + integrity sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg== + dependencies: + acorn "^7.1.1" + acorn-walk "^7.1.1" + acorn-jsx@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b" @@ -5924,6 +5978,11 @@ acorn-walk@^7.0.0: resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.1.1.tgz#345f0dffad5c735e7373d2fec9a1023e6a44b83e" integrity sha512-wdlPY2tm/9XBr7QkKlq0WQVgiuGTX6YWPyRyBviSoScBuLfTVQhvwg6wJ369GJ/1nPfTLMfnrFIfjqVg6d+jQQ== +acorn-walk@^7.1.1: + version "7.2.0" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc" + integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA== + acorn@5.X, acorn@^5.0.3, acorn@^5.5.0: version "5.7.4" resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.4.tgz#3e8d8a9947d0599a1796d10225d7432f4a4acf5e" @@ -5949,6 +6008,11 @@ acorn@^7.1.0: resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.1.1.tgz#e35668de0b402f359de515c5482a1ab9f89a69bf" integrity sha512-add7dgA5ppRPxCFJoAGfMDi7PIBXq1RtGo7BhbLaxwrXPOmw8gq48Y9ozT01hUKy9byMjlR20EJhu5zlkErEkg== +acorn@^7.1.1: + version "7.4.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.0.tgz#e1ad486e6c54501634c6c397c5c121daa383607c" + integrity sha512-+G7P8jJmCHr+S+cLfQxygbWhXy+8YTVGzAkpEbcLo2mLoL7tij/VG41QSHACSf5QgYRhMZYHuNc6drJaO0Da+w== + address@1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/address/-/address-1.1.2.tgz#bf1116c9c758c51b7a933d296b72c221ed9428b6" @@ -7030,7 +7094,7 @@ async-foreach@^0.1.3: resolved "https://registry.yarnpkg.com/async-foreach/-/async-foreach-0.1.3.tgz#36121f845c0578172de419a97dbeb1d16ec34542" integrity sha1-NhIfhFwFeBct5Bmpfb6x0W7DRUI= -async-limiter@^1.0.0, async-limiter@~1.0.0: +async-limiter@~1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ== @@ -7270,17 +7334,17 @@ babel-helper-to-multiple-sequence-expressions@^0.5.0: resolved "https://registry.yarnpkg.com/babel-helper-to-multiple-sequence-expressions/-/babel-helper-to-multiple-sequence-expressions-0.5.0.tgz#a3f924e3561882d42fcf48907aa98f7979a4588d" integrity sha512-m2CvfDW4+1qfDdsrtf4dwOslQC3yhbgyBFptncp4wvtdrDHqueW7slsYv4gArie056phvQFhT2nRcGS4bnm6mA== -babel-jest@^25.5.1: - version "25.5.1" - resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-25.5.1.tgz#bc2e6101f849d6f6aec09720ffc7bc5332e62853" - integrity sha512-9dA9+GmMjIzgPnYtkhBg73gOo/RHqPmLruP3BaGL4KEX3Dwz6pI8auSN8G8+iuEG90+GSswyKvslN+JYSaacaQ== +babel-jest@^26.3.0: + version "26.3.0" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-26.3.0.tgz#10d0ca4b529ca3e7d1417855ef7d7bd6fc0c3463" + integrity sha512-sxPnQGEyHAOPF8NcUsD0g7hDCnvLL2XyblRBcgrzTWBB/mAIpWow3n1bEL+VghnnZfreLhFSBsFluRoK2tRK4g== dependencies: - "@jest/transform" "^25.5.1" - "@jest/types" "^25.5.0" + "@jest/transform" "^26.3.0" + "@jest/types" "^26.3.0" "@types/babel__core" "^7.1.7" babel-plugin-istanbul "^6.0.0" - babel-preset-jest "^25.5.0" - chalk "^3.0.0" + babel-preset-jest "^26.3.0" + chalk "^4.0.0" graceful-fs "^4.2.4" slash "^3.0.0" @@ -7378,13 +7442,14 @@ babel-plugin-istanbul@^6.0.0: istanbul-lib-instrument "^4.0.0" test-exclude "^6.0.0" -babel-plugin-jest-hoist@^25.5.0: - version "25.5.0" - resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-25.5.0.tgz#129c80ba5c7fc75baf3a45b93e2e372d57ca2677" - integrity sha512-u+/W+WAjMlvoocYGTwthAiQSxDcJAyHpQ6oWlHdFZaaN+Rlk8Q7iiwDPg2lN/FyJtAYnKjFxbn7xus4HCFkg5g== +babel-plugin-jest-hoist@^26.2.0: + version "26.2.0" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-26.2.0.tgz#bdd0011df0d3d513e5e95f76bd53b51147aca2dd" + integrity sha512-B/hVMRv8Nh1sQ1a3EY8I0n4Y1Wty3NrR5ebOyVT302op+DOAau+xNEImGMsUWOC3++ZlMooCytKz+NgN8aKGbA== dependencies: "@babel/template" "^7.3.3" "@babel/types" "^7.3.3" + "@types/babel__core" "^7.0.0" "@types/babel__traverse" "^7.0.6" babel-plugin-macros@^2.0.0: @@ -7588,14 +7653,15 @@ babel-polyfill@^6.26.0: core-js "^2.5.0" regenerator-runtime "^0.10.5" -babel-preset-current-node-syntax@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-0.1.2.tgz#fb4a4c51fe38ca60fede1dc74ab35eb843cb41d6" - integrity sha512-u/8cS+dEiK1SFILbOC8/rUI3ml9lboKuuMvZ/4aQnQmhecQAgPw5ew066C1ObnEAUmlx7dv/s2z52psWEtLNiw== +babel-preset-current-node-syntax@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-0.1.3.tgz#b4b547acddbf963cba555ba9f9cbbb70bfd044da" + integrity sha512-uyexu1sVwcdFnyq9o8UQYsXwXflIh8LvrF5+cKrYam93ned1CStffB3+BEcsxGSgagoA3GEyjDqO4a/58hyPYQ== dependencies: "@babel/plugin-syntax-async-generators" "^7.8.4" "@babel/plugin-syntax-bigint" "^7.8.3" "@babel/plugin-syntax-class-properties" "^7.8.3" + "@babel/plugin-syntax-import-meta" "^7.8.3" "@babel/plugin-syntax-json-strings" "^7.8.3" "@babel/plugin-syntax-logical-assignment-operators" "^7.8.3" "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" @@ -7604,13 +7670,13 @@ babel-preset-current-node-syntax@^0.1.2: "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" "@babel/plugin-syntax-optional-chaining" "^7.8.3" -babel-preset-jest@^25.5.0: - version "25.5.0" - resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-25.5.0.tgz#c1d7f191829487a907764c65307faa0e66590b49" - integrity sha512-8ZczygctQkBU+63DtSOKGh7tFL0CeCuz+1ieud9lJ1WPQ9O6A1a/r+LGn6Y705PA6whHQ3T1XuB/PmpfNYf8Fw== +babel-preset-jest@^26.3.0: + version "26.3.0" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-26.3.0.tgz#ed6344506225c065fd8a0b53e191986f74890776" + integrity sha512-5WPdf7nyYi2/eRxCbVrE1kKCWxgWY4RsPEbdJWFm7QsesFGqjdkyLeu1zRkwM1cxK6EPIlNd6d2AxLk7J+t4pw== dependencies: - babel-plugin-jest-hoist "^25.5.0" - babel-preset-current-node-syntax "^0.1.2" + babel-plugin-jest-hoist "^26.2.0" + babel-preset-current-node-syntax "^0.1.3" "babel-preset-minify@^0.5.0 || 0.6.0-alpha.5": version "0.5.0" @@ -8143,6 +8209,11 @@ browser-process-hrtime@^0.1.2: resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-0.1.2.tgz#425d68a58d3447f02a04aa894187fce8af8b7b8e" integrity sha1-Ql1opY00R/AqBKqJQYf86K+Le44= +browser-process-hrtime@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626" + integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow== + browser-resolve@^1.11.3, browser-resolve@^1.8.1: version "1.11.3" resolved "https://registry.yarnpkg.com/browser-resolve/-/browser-resolve-1.11.3.tgz#9b7cbb3d0f510e4cb86bdbd796124d28b5890af6" @@ -8851,6 +8922,11 @@ change-emitter@^0.1.2: resolved "https://registry.yarnpkg.com/change-emitter/-/change-emitter-0.1.6.tgz#e8b2fe3d7f1ab7d69a32199aff91ea6931409515" integrity sha1-6LL+PX8at9aaMhma/5HqaTFAlRU= +char-regex@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" + integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== + character-entities-html4@^1.0.0: version "1.1.4" resolved "https://registry.yarnpkg.com/character-entities-html4/-/character-entities-html4-1.1.4.tgz#0e64b0a3753ddbf1fdc044c5fd01d0199a02e125" @@ -10451,7 +10527,7 @@ cssom@0.3.x, cssom@^0.3.4, cssom@~0.3.6: resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a" integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg== -cssom@^0.4.1: +cssom@^0.4.4: version "0.4.4" resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.4.4.tgz#5a66cf93d2d0b661d80bf6a44fb65f5c2e4e0a10" integrity sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw== @@ -10463,10 +10539,10 @@ cssstyle@^1.1.1: dependencies: cssom "0.3.x" -cssstyle@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-2.2.0.tgz#e4c44debccd6b7911ed617a4395e5754bba59992" - integrity sha512-sEb3XFPx3jNnCAMtqrXPDeSgQr+jojtCeNf8cvMNMh1cG970+lljssvQDzPq6lmmJu2Vhqood/gtEomBiHOGnA== +cssstyle@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-2.3.0.tgz#ff665a0ddbdc31864b09647f34163443d90b0852" + integrity sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A== dependencies: cssom "~0.3.6" @@ -10875,6 +10951,15 @@ data-urls@^1.1.0: whatwg-mimetype "^2.2.0" whatwg-url "^7.0.0" +data-urls@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-2.0.0.tgz#156485a72963a970f5d5821aaf642bef2bf2db9b" + integrity sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ== + dependencies: + abab "^2.0.3" + whatwg-mimetype "^2.3.0" + whatwg-url "^8.0.0" + date-fns@^1.27.2: version "1.29.0" resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-1.29.0.tgz#12e609cdcb935127311d04d33334e2960a2a54e6" @@ -10965,6 +11050,11 @@ decamelize@^1.0.0, decamelize@^1.1.0, decamelize@^1.1.1, decamelize@^1.1.2, deca resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= +decimal.js@^10.2.0: + version "10.2.1" + resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.2.1.tgz#238ae7b0f0c793d3e3cea410108b35a2c01426a3" + integrity sha512-KaL7+6Fw6i5A2XSnsbhm/6B+NuEA7TZ4vqxnd5tXz9sbKtrN9Srj8ab4vKVdK8YAqZO9P1kg45Y6YLoduPf+kw== + decode-uri-component@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" @@ -11641,6 +11731,13 @@ domexception@^1.0.1: dependencies: webidl-conversions "^4.0.2" +domexception@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/domexception/-/domexception-2.0.1.tgz#fb44aefba793e1574b0af6aed2801d057529f304" + integrity sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg== + dependencies: + webidl-conversions "^5.0.0" + domhandler@2.1: version "2.1.0" resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.1.0.tgz#d2646f5e57f6c3bab11cf6cb05d3c0acf7412594" @@ -11992,6 +12089,11 @@ elliptic@^6.0.0: minimalistic-assert "^1.0.0" minimalistic-crypto-utils "^1.0.0" +emittery@^0.7.1: + version "0.7.1" + resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.7.1.tgz#c02375a927a40948c0345cc903072597f5270451" + integrity sha512-d34LN4L6h18Bzz9xpoku2nPwKxCPlPMr3EEKTkoEBi+1/+b0lcRkRJ1UVyyZaKNeqGR3swcGl6s390DNO4YVgQ== + "emoji-regex@>=6.0.0 <=6.1.1": version "6.1.1" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-6.1.1.tgz#c6cd0ec1b0642e2a3c67a1137efc5e796da4f88e" @@ -12481,7 +12583,7 @@ escodegen@^1.11.1: optionalDependencies: source-map "~0.6.1" -escodegen@^1.12.0: +escodegen@^1.12.0, escodegen@^1.14.1: version "1.14.3" resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.14.3.tgz#4e7b81fba61581dc97582ed78cab7f0e8d63f503" integrity sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw== @@ -12644,12 +12746,12 @@ eslint-plugin-import@^2.19.1: read-pkg-up "^2.0.0" resolve "^1.12.0" -eslint-plugin-jest@^23.10.0: - version "23.10.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-23.10.0.tgz#4738c7ca9e6513da50f4e99d7b161c1f82fa8e8f" - integrity sha512-cHC//nesojSO1MLxVmFJR/bUaQQG7xvMHQD8YLbsQzevR41WKm8paKDUv2wMHlUy5XLZUmNcWuflOi4apS8D+Q== +eslint-plugin-jest@^24.0.2: + version "24.0.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-24.0.2.tgz#4bf0fcdc86289d702a7dacb430b4363482af773b" + integrity sha512-DSBLNpkKDOpUJQkTGSs5sVJWsu0nDyQ2rYxkr0Eh7nrkc5bMUr/dlDbtTj3l8y6UaCVsem6rryF1OZrKnz1S5g== dependencies: - "@typescript-eslint/experimental-utils" "^2.5.0" + "@typescript-eslint/experimental-utils" "^4.0.1" eslint-plugin-jsx-a11y@^6.2.3: version "6.2.3" @@ -12779,6 +12881,11 @@ eslint-visitor-keys@^1.1.0: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz#e2a82cea84ff246ad6fb57f9bde5b46621459ec2" integrity sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A== +eslint-visitor-keys@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz#21fdc8fbcd9c795cc0321f0563702095751511a8" + integrity sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ== + eslint@^2.7.0: version "2.13.1" resolved "https://registry.yarnpkg.com/eslint/-/eslint-2.13.1.tgz#e4cc8fa0f009fb829aaae23855a29360be1f6c11" @@ -13055,10 +13162,10 @@ execa@^1.0.0: signal-exit "^3.0.0" strip-eof "^1.0.0" -execa@^3.2.0: - version "3.4.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-3.4.0.tgz#c08ed4550ef65d858fac269ffc8572446f37eb89" - integrity sha512-r9vdGQk4bmCuK1yKQu1KTwcT2zwfWdbdaXfCtAh+5nU/4fSX+JAb7vZGvI5naJrQlvONrEB20jeruESI69530g== +execa@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/execa/-/execa-4.0.3.tgz#0a34dabbad6d66100bd6f2c576c8669403f317f2" + integrity sha512-WFDXGHckXPWZX19t1kCsXzOpqX9LWYNqn4C+HqZlk/V0imTkzJZqf87ZBhvpHaftERYknpk0fjSylnXVlVgI0A== dependencies: cross-spawn "^7.0.0" get-stream "^5.0.0" @@ -13067,7 +13174,6 @@ execa@^3.2.0: merge-stream "^2.0.0" npm-run-path "^4.0.0" onetime "^5.1.0" - p-finally "^2.0.0" signal-exit "^3.0.2" strip-final-newline "^2.0.0" @@ -13152,18 +13258,6 @@ expect@^24.8.0, expect@^24.9.0: jest-message-util "^24.9.0" jest-regex-util "^24.9.0" -expect@^25.5.0: - version "25.5.0" - resolved "https://registry.yarnpkg.com/expect/-/expect-25.5.0.tgz#f07f848712a2813bb59167da3fb828ca21f58bba" - integrity sha512-w7KAXo0+6qqZZhovCaBVPSIqQp7/UTcx4M9uKt2m6pd2VB1voyC8JizLRqeEqud3AAVP02g+hbErDu5gu64tlA== - dependencies: - "@jest/types" "^25.5.0" - ansi-styles "^4.0.0" - jest-get-type "^25.2.6" - jest-matcher-utils "^25.5.0" - jest-message-util "^25.5.0" - jest-regex-util "^25.2.6" - expect@^26.4.0: version "26.4.0" resolved "https://registry.yarnpkg.com/expect/-/expect-26.4.0.tgz#34a0aae523343b0931ff1cf0aa972dfe40edfab4" @@ -13176,6 +13270,18 @@ expect@^26.4.0: jest-message-util "^26.3.0" jest-regex-util "^26.0.0" +expect@^26.4.2: + version "26.4.2" + resolved "https://registry.yarnpkg.com/expect/-/expect-26.4.2.tgz#36db120928a5a2d7d9736643032de32f24e1b2a1" + integrity sha512-IlJ3X52Z0lDHm7gjEp+m76uX46ldH5VpqmU0006vqDju/285twh7zaWMRhs67VpQhBwjjMchk+p5aA0VkERCAA== + dependencies: + "@jest/types" "^26.3.0" + ansi-styles "^4.0.0" + jest-get-type "^26.3.0" + jest-matcher-utils "^26.4.2" + jest-message-util "^26.3.0" + jest-regex-util "^26.0.0" + expiry-js@0.1.7: version "0.1.7" resolved "https://registry.yarnpkg.com/expiry-js/-/expiry-js-0.1.7.tgz#76be8c05e572bf936df40c1766448d0b3b2f555f" @@ -16085,6 +16191,13 @@ html-encoding-sniffer@^1.0.2: dependencies: whatwg-encoding "^1.0.1" +html-encoding-sniffer@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz#42a6dc4fd33f00281176e8b23759ca4e4fa185f3" + integrity sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ== + dependencies: + whatwg-encoding "^1.0.5" + html-entities@^1.2.0, html-entities@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.3.1.tgz#fb9a1a4b5b14c5daba82d3e34c6ae4fe701a0e44" @@ -17499,6 +17612,11 @@ is-plain-object@^5.0.0: resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344" integrity sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q== +is-potential-custom-element-name@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.0.tgz#0c52e54bcca391bb2c494b21e8626d7336c6e397" + integrity sha1-DFLlS8yjkbssSUsh6GJtczbG45c= + is-promise@^2.1, is-promise@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" @@ -17726,6 +17844,13 @@ is-wsl@^2.1.1: resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.1.1.tgz#4a1c152d429df3d441669498e2486d3596ebaf1d" integrity sha512-umZHcSrwlDHo2TGMXv0DZ8dIUGunZ2Iv68YZnrmCiBPkZ4aaOhtv7pXJKeki9k3qJ3RJr0cDyitcl5wEH3AYog== +is-wsl@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" + integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== + dependencies: + is-docker "^2.0.0" + is-yarn-global@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/is-yarn-global/-/is-yarn-global-0.3.0.tgz#d502d3382590ea3004893746754c89139973e232" @@ -17860,6 +17985,16 @@ istanbul-lib-instrument@^4.0.0: istanbul-lib-coverage "^3.0.0" semver "^6.3.0" +istanbul-lib-instrument@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz#873c6fff897450118222774696a3f28902d77c1d" + integrity sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ== + dependencies: + "@babel/core" "^7.7.5" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-coverage "^3.0.0" + semver "^6.3.0" + istanbul-lib-processinfo@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.2.tgz#e1426514662244b2f25df728e8fd1ba35fe53b9c" @@ -17962,82 +18097,83 @@ jest-canvas-mock@^2.2.0: cssfontparser "^1.2.1" parse-color "^1.0.0" -jest-changed-files@^25.5.0: - version "25.5.0" - resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-25.5.0.tgz#141cc23567ceb3f534526f8614ba39421383634c" - integrity sha512-EOw9QEqapsDT7mKF162m8HFzRPbmP8qJQny6ldVOdOVBz3ACgPm/1nAn5fPQ/NDaYhX/AHkrGwwkCncpAVSXcw== +jest-changed-files@^26.3.0: + version "26.3.0" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-26.3.0.tgz#68fb2a7eb125f50839dab1f5a17db3607fe195b1" + integrity sha512-1C4R4nijgPltX6fugKxM4oQ18zimS7LqQ+zTTY8lMCMFPrxqBFb7KJH0Z2fRQJvw2Slbaipsqq7s1mgX5Iot+g== dependencies: - "@jest/types" "^25.5.0" - execa "^3.2.0" + "@jest/types" "^26.3.0" + execa "^4.0.0" throat "^5.0.0" -jest-circus@^25.5.4: - version "25.5.4" - resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-25.5.4.tgz#d5578346f53d5604b7b1d1e5e56be48b1c73c61d" - integrity sha512-nOLJXZjWuV2i8yQ2w+MZ8NhFuqrbgpPAa4mh+DWPYmNI377YYpDKvDUrLMW8U1sa2iGt5mjKQbmJz2SK9AYjWg== +jest-circus@^26.4.2: + version "26.4.2" + resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-26.4.2.tgz#f84487d2ea635cadf1feb269b14ad0602135ad17" + integrity sha512-gzxoteivskdUTNxT7Jx6hrANsEm+x1wh8jaXmQCtzC7zoNWirk9chYdSosHFC4tJlfDZa0EsPreVAxLicLsV0w== dependencies: "@babel/traverse" "^7.1.0" - "@jest/environment" "^25.5.0" - "@jest/test-result" "^25.5.0" - "@jest/types" "^25.5.0" - chalk "^3.0.0" + "@jest/environment" "^26.3.0" + "@jest/test-result" "^26.3.0" + "@jest/types" "^26.3.0" + "@types/node" "*" + chalk "^4.0.0" co "^4.6.0" - expect "^25.5.0" + dedent "^0.7.0" + expect "^26.4.2" is-generator-fn "^2.0.0" - jest-each "^25.5.0" - jest-matcher-utils "^25.5.0" - jest-message-util "^25.5.0" - jest-runtime "^25.5.4" - jest-snapshot "^25.5.1" - jest-util "^25.5.0" - pretty-format "^25.5.0" - stack-utils "^1.0.1" + jest-each "^26.4.2" + jest-matcher-utils "^26.4.2" + jest-message-util "^26.3.0" + jest-runner "^26.4.2" + jest-runtime "^26.4.2" + jest-snapshot "^26.4.2" + jest-util "^26.3.0" + pretty-format "^26.4.2" + stack-utils "^2.0.2" throat "^5.0.0" -jest-cli@^25.5.4: - version "25.5.4" - resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-25.5.4.tgz#b9f1a84d1301a92c5c217684cb79840831db9f0d" - integrity sha512-rG8uJkIiOUpnREh1768/N3n27Cm+xPFkSNFO91tgg+8o2rXeVLStz+vkXkGr4UtzH6t1SNbjwoiswd7p4AhHTw== +jest-cli@^26.4.2: + version "26.4.2" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-26.4.2.tgz#24afc6e4dfc25cde4c7ec4226fb7db5f157c21da" + integrity sha512-zb+lGd/SfrPvoRSC/0LWdaWCnscXc1mGYW//NP4/tmBvRPT3VntZ2jtKUONsRi59zc5JqmsSajA9ewJKFYp8Cw== dependencies: - "@jest/core" "^25.5.4" - "@jest/test-result" "^25.5.0" - "@jest/types" "^25.5.0" - chalk "^3.0.0" + "@jest/core" "^26.4.2" + "@jest/test-result" "^26.3.0" + "@jest/types" "^26.3.0" + chalk "^4.0.0" exit "^0.1.2" graceful-fs "^4.2.4" import-local "^3.0.2" is-ci "^2.0.0" - jest-config "^25.5.4" - jest-util "^25.5.0" - jest-validate "^25.5.0" + jest-config "^26.4.2" + jest-util "^26.3.0" + jest-validate "^26.4.2" prompts "^2.0.1" - realpath-native "^2.0.0" yargs "^15.3.1" -jest-config@^25.5.4: - version "25.5.4" - resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-25.5.4.tgz#38e2057b3f976ef7309b2b2c8dcd2a708a67f02c" - integrity sha512-SZwR91SwcdK6bz7Gco8qL7YY2sx8tFJYzvg216DLihTWf+LKY/DoJXpM9nTzYakSyfblbqeU48p/p7Jzy05Atg== +jest-config@^26.4.2: + version "26.4.2" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-26.4.2.tgz#da0cbb7dc2c131ffe831f0f7f2a36256e6086558" + integrity sha512-QBf7YGLuToiM8PmTnJEdRxyYy3mHWLh24LJZKVdXZ2PNdizSe1B/E8bVm+HYcjbEzGuVXDv/di+EzdO/6Gq80A== dependencies: "@babel/core" "^7.1.0" - "@jest/test-sequencer" "^25.5.4" - "@jest/types" "^25.5.0" - babel-jest "^25.5.1" - chalk "^3.0.0" + "@jest/test-sequencer" "^26.4.2" + "@jest/types" "^26.3.0" + babel-jest "^26.3.0" + chalk "^4.0.0" deepmerge "^4.2.2" glob "^7.1.1" graceful-fs "^4.2.4" - jest-environment-jsdom "^25.5.0" - jest-environment-node "^25.5.0" - jest-get-type "^25.2.6" - jest-jasmine2 "^25.5.4" - jest-regex-util "^25.2.6" - jest-resolve "^25.5.1" - jest-util "^25.5.0" - jest-validate "^25.5.0" + jest-environment-jsdom "^26.3.0" + jest-environment-node "^26.3.0" + jest-get-type "^26.3.0" + jest-jasmine2 "^26.4.2" + jest-regex-util "^26.0.0" + jest-resolve "^26.4.0" + jest-util "^26.3.0" + jest-validate "^26.4.2" micromatch "^4.0.2" - pretty-format "^25.5.0" - realpath-native "^2.0.0" + pretty-format "^26.4.2" jest-diff@^24.9.0: version "24.9.0" @@ -18049,7 +18185,7 @@ jest-diff@^24.9.0: jest-get-type "^24.9.0" pretty-format "^24.9.0" -jest-diff@^25.2.1, jest-diff@^25.5.0: +jest-diff@^25.2.1: version "25.5.0" resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-25.5.0.tgz#1dd26ed64f96667c068cef026b677dfa01afcfa9" integrity sha512-z1kygetuPiREYdNIumRpAHY6RXiGmp70YHptjdaxTWGmA085W3iCnXNx0DhflK3vwrKmrRWyY1wUpkPMVxMK7A== @@ -18069,23 +18205,33 @@ jest-diff@^26.4.0: jest-get-type "^26.3.0" pretty-format "^26.4.0" -jest-docblock@^25.3.0: - version "25.3.0" - resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-25.3.0.tgz#8b777a27e3477cd77a168c05290c471a575623ef" - integrity sha512-aktF0kCar8+zxRHxQZwxMy70stc9R1mOmrLsT5VO3pIT0uzGRSDAXxSlz4NqQWpuLjPpuMhPRl7H+5FRsvIQAg== +jest-diff@^26.4.2: + version "26.4.2" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-26.4.2.tgz#a1b7b303bcc534aabdb3bd4a7caf594ac059f5aa" + integrity sha512-6T1XQY8U28WH0Z5rGpQ+VqZSZz8EN8rZcBtfvXaOkbwxIEeRre6qnuZQlbY1AJ4MKDxQF8EkrCvK+hL/VkyYLQ== + dependencies: + chalk "^4.0.0" + diff-sequences "^26.3.0" + jest-get-type "^26.3.0" + pretty-format "^26.4.2" + +jest-docblock@^26.0.0: + version "26.0.0" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-26.0.0.tgz#3e2fa20899fc928cb13bd0ff68bd3711a36889b5" + integrity sha512-RDZ4Iz3QbtRWycd8bUEPxQsTlYazfYn/h5R65Fc6gOfwozFhoImx+affzky/FFBuqISPTqjXomoIGJVKBWoo0w== dependencies: detect-newline "^3.0.0" -jest-each@^25.5.0: - version "25.5.0" - resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-25.5.0.tgz#0c3c2797e8225cb7bec7e4d249dcd96b934be516" - integrity sha512-QBogUxna3D8vtiItvn54xXde7+vuzqRrEeaw8r1s+1TG9eZLVJE5ZkKoSUlqFwRjnlaA4hyKGiu9OlkFIuKnjA== +jest-each@^26.4.2: + version "26.4.2" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-26.4.2.tgz#bb14f7f4304f2bb2e2b81f783f989449b8b6ffae" + integrity sha512-p15rt8r8cUcRY0Mvo1fpkOGYm7iI8S6ySxgIdfh3oOIv+gHwrHTy5VWCGOecWUhDsit4Nz8avJWdT07WLpbwDA== dependencies: - "@jest/types" "^25.5.0" - chalk "^3.0.0" - jest-get-type "^25.2.6" - jest-util "^25.5.0" - pretty-format "^25.5.0" + "@jest/types" "^26.3.0" + chalk "^4.0.0" + jest-get-type "^26.3.0" + jest-util "^26.3.0" + pretty-format "^26.4.2" jest-environment-jsdom-thirteen@^1.0.1: version "1.0.1" @@ -18096,29 +18242,30 @@ jest-environment-jsdom-thirteen@^1.0.1: jest-util "^24.0.0" jsdom "^13.0.0" -jest-environment-jsdom@^25.5.0: - version "25.5.0" - resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-25.5.0.tgz#dcbe4da2ea997707997040ecf6e2560aec4e9834" - integrity sha512-7Jr02ydaq4jaWMZLY+Skn8wL5nVIYpWvmeatOHL3tOcV3Zw8sjnPpx+ZdeBfc457p8jCR9J6YCc+Lga0oIy62A== +jest-environment-jsdom@^26.3.0: + version "26.3.0" + resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-26.3.0.tgz#3b749ba0f3a78e92ba2c9ce519e16e5dd515220c" + integrity sha512-zra8He2btIMJkAzvLaiZ9QwEPGEetbxqmjEBQwhH3CA+Hhhu0jSiEJxnJMbX28TGUvPLxBt/zyaTLrOPF4yMJA== dependencies: - "@jest/environment" "^25.5.0" - "@jest/fake-timers" "^25.5.0" - "@jest/types" "^25.5.0" - jest-mock "^25.5.0" - jest-util "^25.5.0" - jsdom "^15.2.1" + "@jest/environment" "^26.3.0" + "@jest/fake-timers" "^26.3.0" + "@jest/types" "^26.3.0" + "@types/node" "*" + jest-mock "^26.3.0" + jest-util "^26.3.0" + jsdom "^16.2.2" -jest-environment-node@^25.5.0: - version "25.5.0" - resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-25.5.0.tgz#0f55270d94804902988e64adca37c6ce0f7d07a1" - integrity sha512-iuxK6rQR2En9EID+2k+IBs5fCFd919gVVK5BeND82fYeLWPqvRcFNPKu9+gxTwfB5XwBGBvZ0HFQa+cHtIoslA== +jest-environment-node@^26.3.0: + version "26.3.0" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-26.3.0.tgz#56c6cfb506d1597f94ee8d717072bda7228df849" + integrity sha512-c9BvYoo+FGcMj5FunbBgtBnbR5qk3uky8PKyRVpSfe2/8+LrNQMiXX53z6q2kY+j15SkjQCOSL/6LHnCPLVHNw== dependencies: - "@jest/environment" "^25.5.0" - "@jest/fake-timers" "^25.5.0" - "@jest/types" "^25.5.0" - jest-mock "^25.5.0" - jest-util "^25.5.0" - semver "^6.3.0" + "@jest/environment" "^26.3.0" + "@jest/fake-timers" "^26.3.0" + "@jest/types" "^26.3.0" + "@types/node" "*" + jest-mock "^26.3.0" + jest-util "^26.3.0" jest-get-type@^24.9.0: version "24.9.0" @@ -18135,26 +18282,6 @@ jest-get-type@^26.3.0: resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-26.3.0.tgz#e97dc3c3f53c2b406ca7afaed4493b1d099199e0" integrity sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig== -jest-haste-map@^25.5.1: - version "25.5.1" - resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-25.5.1.tgz#1df10f716c1d94e60a1ebf7798c9fb3da2620943" - integrity sha512-dddgh9UZjV7SCDQUrQ+5t9yy8iEgKc1AKqZR9YDww8xsVOtzPQSMVLDChc21+g29oTRexb9/B0bIlZL+sWmvAQ== - dependencies: - "@jest/types" "^25.5.0" - "@types/graceful-fs" "^4.1.2" - anymatch "^3.0.3" - fb-watchman "^2.0.0" - graceful-fs "^4.2.4" - jest-serializer "^25.5.0" - jest-util "^25.5.0" - jest-worker "^25.5.0" - micromatch "^4.0.2" - sane "^4.0.3" - walker "^1.0.7" - which "^2.0.2" - optionalDependencies: - fsevents "^2.1.2" - jest-haste-map@^26.3.0: version "26.3.0" resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-26.3.0.tgz#c51a3b40100d53ab777bfdad382d2e7a00e5c726" @@ -18176,36 +18303,37 @@ jest-haste-map@^26.3.0: optionalDependencies: fsevents "^2.1.2" -jest-jasmine2@^25.5.4: - version "25.5.4" - resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-25.5.4.tgz#66ca8b328fb1a3c5364816f8958f6970a8526968" - integrity sha512-9acbWEfbmS8UpdcfqnDO+uBUgKa/9hcRh983IHdM+pKmJPL77G0sWAAK0V0kr5LK3a8cSBfkFSoncXwQlRZfkQ== +jest-jasmine2@^26.4.2: + version "26.4.2" + resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-26.4.2.tgz#18a9d5bec30904267ac5e9797570932aec1e2257" + integrity sha512-z7H4EpCldHN1J8fNgsja58QftxBSL+JcwZmaXIvV9WKIM+x49F4GLHu/+BQh2kzRKHAgaN/E82od+8rTOBPyPA== dependencies: "@babel/traverse" "^7.1.0" - "@jest/environment" "^25.5.0" - "@jest/source-map" "^25.5.0" - "@jest/test-result" "^25.5.0" - "@jest/types" "^25.5.0" - chalk "^3.0.0" + "@jest/environment" "^26.3.0" + "@jest/source-map" "^26.3.0" + "@jest/test-result" "^26.3.0" + "@jest/types" "^26.3.0" + "@types/node" "*" + chalk "^4.0.0" co "^4.6.0" - expect "^25.5.0" + expect "^26.4.2" is-generator-fn "^2.0.0" - jest-each "^25.5.0" - jest-matcher-utils "^25.5.0" - jest-message-util "^25.5.0" - jest-runtime "^25.5.4" - jest-snapshot "^25.5.1" - jest-util "^25.5.0" - pretty-format "^25.5.0" + jest-each "^26.4.2" + jest-matcher-utils "^26.4.2" + jest-message-util "^26.3.0" + jest-runtime "^26.4.2" + jest-snapshot "^26.4.2" + jest-util "^26.3.0" + pretty-format "^26.4.2" throat "^5.0.0" -jest-leak-detector@^25.5.0: - version "25.5.0" - resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-25.5.0.tgz#2291c6294b0ce404241bb56fe60e2d0c3e34f0bb" - integrity sha512-rV7JdLsanS8OkdDpZtgBf61L5xZ4NnYLBq72r6ldxahJWWczZjXawRsoHyXzibM5ed7C2QRjpp6ypgwGdKyoVA== +jest-leak-detector@^26.4.2: + version "26.4.2" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-26.4.2.tgz#c73e2fa8757bf905f6f66fb9e0070b70fa0f573f" + integrity sha512-akzGcxwxtE+9ZJZRW+M2o+nTNnmQZxrHJxX/HjgDaU5+PLmY1qnQPnMjgADPGCRPhB+Yawe1iij0REe+k/aHoA== dependencies: - jest-get-type "^25.2.6" - pretty-format "^25.5.0" + jest-get-type "^26.3.0" + pretty-format "^26.4.2" jest-matcher-utils@^24.9.0: version "24.9.0" @@ -18217,16 +18345,6 @@ jest-matcher-utils@^24.9.0: jest-get-type "^24.9.0" pretty-format "^24.9.0" -jest-matcher-utils@^25.5.0: - version "25.5.0" - resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-25.5.0.tgz#fbc98a12d730e5d2453d7f1ed4a4d948e34b7867" - integrity sha512-VWI269+9JS5cpndnpCwm7dy7JtGQT30UHfrnM3mXl22gHGt/b7NkjBqXfbhZ8V4B7ANUsjK18PlSBmG0YH7gjw== - dependencies: - chalk "^3.0.0" - jest-diff "^25.5.0" - jest-get-type "^25.2.6" - pretty-format "^25.5.0" - jest-matcher-utils@^26.4.0: version "26.4.0" resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-26.4.0.tgz#2bce9a939e008b894faf1bd4b5bb58facd00c252" @@ -18237,6 +18355,16 @@ jest-matcher-utils@^26.4.0: jest-get-type "^26.3.0" pretty-format "^26.4.0" +jest-matcher-utils@^26.4.2: + version "26.4.2" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-26.4.2.tgz#fa81f3693f7cb67e5fc1537317525ef3b85f4b06" + integrity sha512-KcbNqWfWUG24R7tu9WcAOKKdiXiXCbMvQYT6iodZ9k1f7065k0keUOW6XpJMMvah+hTfqkhJhRXmA3r3zMAg0Q== + dependencies: + chalk "^4.0.0" + jest-diff "^26.4.2" + jest-get-type "^26.3.0" + pretty-format "^26.4.2" + jest-message-util@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-24.9.0.tgz#527f54a1e380f5e202a8d1149b0ec872f43119e3" @@ -18251,20 +18379,6 @@ jest-message-util@^24.9.0: slash "^2.0.0" stack-utils "^1.0.1" -jest-message-util@^25.5.0: - version "25.5.0" - resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-25.5.0.tgz#ea11d93204cc7ae97456e1d8716251185b8880ea" - integrity sha512-ezddz3YCT/LT0SKAmylVyWWIGYoKHOFOFXx3/nA4m794lfVUskMcwhip6vTgdVrOtYdjeQeis2ypzes9mZb4EA== - dependencies: - "@babel/code-frame" "^7.0.0" - "@jest/types" "^25.5.0" - "@types/stack-utils" "^1.0.1" - chalk "^3.0.0" - graceful-fs "^4.2.4" - micromatch "^4.0.2" - slash "^3.0.0" - stack-utils "^1.0.1" - jest-message-util@^26.3.0: version "26.3.0" resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-26.3.0.tgz#3bdb538af27bb417f2d4d16557606fd082d5841a" @@ -18286,12 +18400,13 @@ jest-mock@^24.0.0, jest-mock@^24.9.0: dependencies: "@jest/types" "^24.9.0" -jest-mock@^25.5.0: - version "25.5.0" - resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-25.5.0.tgz#a91a54dabd14e37ecd61665d6b6e06360a55387a" - integrity sha512-eXWuTV8mKzp/ovHc5+3USJMYsTBhyQ+5A1Mak35dey/RG8GlM4YWVylZuGgVXinaW6tpvk/RSecmF37FKUlpXA== +jest-mock@^26.3.0: + version "26.3.0" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-26.3.0.tgz#ee62207c3c5ebe5f35b760e1267fee19a1cfdeba" + integrity sha512-PeaRrg8Dc6mnS35gOo/CbZovoDPKAeB1FICZiuagAgGvbWdNNyjQjkOaGUa/3N3JtpQ/Mh9P4A2D4Fv51NnP8Q== dependencies: - "@jest/types" "^25.5.0" + "@jest/types" "^26.3.0" + "@types/node" "*" jest-pnp-resolver@^1.2.1: version "1.2.1" @@ -18313,24 +18428,19 @@ jest-regex-util@^24.9.0: resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-24.9.0.tgz#c13fb3380bde22bf6575432c493ea8fe37965636" integrity sha512-05Cmb6CuxaA+Ys6fjr3PhvV3bGQmO+2p2La4hFbU+W5uOc479f7FdLXUWXw4pYMAhhSZIuKHwSXSu6CsSBAXQA== -jest-regex-util@^25.2.6: - version "25.2.6" - resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-25.2.6.tgz#d847d38ba15d2118d3b06390056028d0f2fd3964" - integrity sha512-KQqf7a0NrtCkYmZZzodPftn7fL1cq3GQAFVMn5Hg8uKx/fIenLEobNanUxb7abQ1sjADHBseG/2FGpsv/wr+Qw== - jest-regex-util@^26.0.0: version "26.0.0" resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-26.0.0.tgz#d25e7184b36e39fd466c3bc41be0971e821fee28" integrity sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A== -jest-resolve-dependencies@^25.5.4: - version "25.5.4" - resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-25.5.4.tgz#85501f53957c8e3be446e863a74777b5a17397a7" - integrity sha512-yFmbPd+DAQjJQg88HveObcGBA32nqNZ02fjYmtL16t1xw9bAttSn5UGRRhzMHIQbsep7znWvAvnD4kDqOFM0Uw== +jest-resolve-dependencies@^26.4.2: + version "26.4.2" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-26.4.2.tgz#739bdb027c14befb2fe5aabbd03f7bab355f1dc5" + integrity sha512-ADHaOwqEcVc71uTfySzSowA/RdxUpCxhxa2FNLiin9vWLB1uLPad3we+JSSROq5+SrL9iYPdZZF8bdKM7XABTQ== dependencies: - "@jest/types" "^25.5.0" - jest-regex-util "^25.2.6" - jest-snapshot "^25.5.1" + "@jest/types" "^26.3.0" + jest-regex-util "^26.0.0" + jest-snapshot "^26.4.2" jest-resolve@^24.9.0: version "24.9.0" @@ -18343,21 +18453,6 @@ jest-resolve@^24.9.0: jest-pnp-resolver "^1.2.1" realpath-native "^1.1.0" -jest-resolve@^25.5.1: - version "25.5.1" - resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-25.5.1.tgz#0e6fbcfa7c26d2a5fe8f456088dc332a79266829" - integrity sha512-Hc09hYch5aWdtejsUZhA+vSzcotf7fajSlPA6EZPE1RmPBAD39XtJhvHWFStid58iit4IPDLI/Da4cwdDmAHiQ== - dependencies: - "@jest/types" "^25.5.0" - browser-resolve "^1.11.3" - chalk "^3.0.0" - graceful-fs "^4.2.4" - jest-pnp-resolver "^1.2.1" - read-pkg-up "^7.0.1" - realpath-native "^2.0.0" - resolve "^1.17.0" - slash "^3.0.0" - jest-resolve@^26.4.0: version "26.4.0" resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-26.4.0.tgz#6dc0af7fb93e65b73fec0368ca2b76f3eb59a6d7" @@ -18372,70 +18467,64 @@ jest-resolve@^26.4.0: resolve "^1.17.0" slash "^3.0.0" -jest-runner@^25.5.4: - version "25.5.4" - resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-25.5.4.tgz#ffec5df3875da5f5c878ae6d0a17b8e4ecd7c71d" - integrity sha512-V/2R7fKZo6blP8E9BL9vJ8aTU4TH2beuqGNxHbxi6t14XzTb+x90B3FRgdvuHm41GY8ch4xxvf0ATH4hdpjTqg== +jest-runner@^26.4.2: + version "26.4.2" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-26.4.2.tgz#c3ec5482c8edd31973bd3935df5a449a45b5b853" + integrity sha512-FgjDHeVknDjw1gRAYaoUoShe1K3XUuFMkIaXbdhEys+1O4bEJS8Avmn4lBwoMfL8O5oFTdWYKcf3tEJyyYyk8g== dependencies: - "@jest/console" "^25.5.0" - "@jest/environment" "^25.5.0" - "@jest/test-result" "^25.5.0" - "@jest/types" "^25.5.0" - chalk "^3.0.0" + "@jest/console" "^26.3.0" + "@jest/environment" "^26.3.0" + "@jest/test-result" "^26.3.0" + "@jest/types" "^26.3.0" + "@types/node" "*" + chalk "^4.0.0" + emittery "^0.7.1" exit "^0.1.2" graceful-fs "^4.2.4" - jest-config "^25.5.4" - jest-docblock "^25.3.0" - jest-haste-map "^25.5.1" - jest-jasmine2 "^25.5.4" - jest-leak-detector "^25.5.0" - jest-message-util "^25.5.0" - jest-resolve "^25.5.1" - jest-runtime "^25.5.4" - jest-util "^25.5.0" - jest-worker "^25.5.0" + jest-config "^26.4.2" + jest-docblock "^26.0.0" + jest-haste-map "^26.3.0" + jest-leak-detector "^26.4.2" + jest-message-util "^26.3.0" + jest-resolve "^26.4.0" + jest-runtime "^26.4.2" + jest-util "^26.3.0" + jest-worker "^26.3.0" source-map-support "^0.5.6" throat "^5.0.0" -jest-runtime@^25.5.4: - version "25.5.4" - resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-25.5.4.tgz#dc981fe2cb2137abcd319e74ccae7f7eeffbfaab" - integrity sha512-RWTt8LeWh3GvjYtASH2eezkc8AehVoWKK20udV6n3/gC87wlTbE1kIA+opCvNWyyPeBs6ptYsc6nyHUb1GlUVQ== - dependencies: - "@jest/console" "^25.5.0" - "@jest/environment" "^25.5.0" - "@jest/globals" "^25.5.2" - "@jest/source-map" "^25.5.0" - "@jest/test-result" "^25.5.0" - "@jest/transform" "^25.5.1" - "@jest/types" "^25.5.0" +jest-runtime@^26.4.2: + version "26.4.2" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-26.4.2.tgz#94ce17890353c92e4206580c73a8f0c024c33c42" + integrity sha512-4Pe7Uk5a80FnbHwSOk7ojNCJvz3Ks2CNQWT5Z7MJo4tX0jb3V/LThKvD9tKPNVNyeMH98J/nzGlcwc00R2dSHQ== + dependencies: + "@jest/console" "^26.3.0" + "@jest/environment" "^26.3.0" + "@jest/fake-timers" "^26.3.0" + "@jest/globals" "^26.4.2" + "@jest/source-map" "^26.3.0" + "@jest/test-result" "^26.3.0" + "@jest/transform" "^26.3.0" + "@jest/types" "^26.3.0" "@types/yargs" "^15.0.0" - chalk "^3.0.0" + chalk "^4.0.0" collect-v8-coverage "^1.0.0" exit "^0.1.2" glob "^7.1.3" graceful-fs "^4.2.4" - jest-config "^25.5.4" - jest-haste-map "^25.5.1" - jest-message-util "^25.5.0" - jest-mock "^25.5.0" - jest-regex-util "^25.2.6" - jest-resolve "^25.5.1" - jest-snapshot "^25.5.1" - jest-util "^25.5.0" - jest-validate "^25.5.0" - realpath-native "^2.0.0" + jest-config "^26.4.2" + jest-haste-map "^26.3.0" + jest-message-util "^26.3.0" + jest-mock "^26.3.0" + jest-regex-util "^26.0.0" + jest-resolve "^26.4.0" + jest-snapshot "^26.4.2" + jest-util "^26.3.0" + jest-validate "^26.4.2" slash "^3.0.0" strip-bom "^4.0.0" yargs "^15.3.1" -jest-serializer@^25.5.0: - version "25.5.0" - resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-25.5.0.tgz#a993f484e769b4ed54e70e0efdb74007f503072b" - integrity sha512-LxD8fY1lByomEPflwur9o4e2a5twSQ7TaVNLlFUuToIdoJuBt8tzHfCsZ42Ok6LkKXWzFWf3AGmheuLAA7LcCA== - dependencies: - graceful-fs "^4.2.4" - jest-serializer@^26.3.0: version "26.3.0" resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-26.3.0.tgz#1c9d5e1b74d6e5f7e7f9627080fa205d976c33ef" @@ -18463,27 +18552,6 @@ jest-snapshot@^24.1.0: pretty-format "^24.9.0" semver "^6.2.0" -jest-snapshot@^25.5.1: - version "25.5.1" - resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-25.5.1.tgz#1a2a576491f9961eb8d00c2e5fd479bc28e5ff7f" - integrity sha512-C02JE1TUe64p2v1auUJ2ze5vcuv32tkv9PyhEb318e8XOKF7MOyXdJ7kdjbvrp3ChPLU2usI7Rjxs97Dj5P0uQ== - dependencies: - "@babel/types" "^7.0.0" - "@jest/types" "^25.5.0" - "@types/prettier" "^1.19.0" - chalk "^3.0.0" - expect "^25.5.0" - graceful-fs "^4.2.4" - jest-diff "^25.5.0" - jest-get-type "^25.2.6" - jest-matcher-utils "^25.5.0" - jest-message-util "^25.5.0" - jest-resolve "^25.5.1" - make-dir "^3.0.0" - natural-compare "^1.4.0" - pretty-format "^25.5.0" - semver "^6.3.0" - jest-snapshot@^26.3.0: version "26.4.0" resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-26.4.0.tgz#efd42eef09bcb33e9a3eb98e229f2368c73c9235" @@ -18505,6 +18573,27 @@ jest-snapshot@^26.3.0: pretty-format "^26.4.0" semver "^7.3.2" +jest-snapshot@^26.4.2: + version "26.4.2" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-26.4.2.tgz#87d3ac2f2bd87ea8003602fbebd8fcb9e94104f6" + integrity sha512-N6Uub8FccKlf5SBFnL2Ri/xofbaA68Cc3MGjP/NuwgnsvWh+9hLIR/DhrxbSiKXMY9vUW5dI6EW1eHaDHqe9sg== + dependencies: + "@babel/types" "^7.0.0" + "@jest/types" "^26.3.0" + "@types/prettier" "^2.0.0" + chalk "^4.0.0" + expect "^26.4.2" + graceful-fs "^4.2.4" + jest-diff "^26.4.2" + jest-get-type "^26.3.0" + jest-haste-map "^26.3.0" + jest-matcher-utils "^26.4.2" + jest-message-util "^26.3.0" + jest-resolve "^26.4.0" + natural-compare "^1.4.0" + pretty-format "^26.4.2" + semver "^7.3.2" + jest-specific-snapshot@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/jest-specific-snapshot/-/jest-specific-snapshot-2.0.0.tgz#425fe524b25df154aa39f97fa6fe9726faaac273" @@ -18544,17 +18633,6 @@ jest-util@^24.0.0: slash "^2.0.0" source-map "^0.6.0" -jest-util@^25.5.0: - version "25.5.0" - resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-25.5.0.tgz#31c63b5d6e901274d264a4fec849230aa3fa35b0" - integrity sha512-KVlX+WWg1zUTB9ktvhsg2PXZVdkI1NBevOJSkTKYAyXyH4QSvh+Lay/e/v+bmaFfrkfx43xD8QTfgobzlEXdIA== - dependencies: - "@jest/types" "^25.5.0" - chalk "^3.0.0" - graceful-fs "^4.2.4" - is-ci "^2.0.0" - make-dir "^3.0.0" - jest-util@^26.3.0: version "26.3.0" resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-26.3.0.tgz#a8974b191df30e2bf523ebbfdbaeb8efca535b3e" @@ -18567,29 +18645,30 @@ jest-util@^26.3.0: is-ci "^2.0.0" micromatch "^4.0.2" -jest-validate@^25.5.0: - version "25.5.0" - resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-25.5.0.tgz#fb4c93f332c2e4cf70151a628e58a35e459a413a" - integrity sha512-okUFKqhZIpo3jDdtUXUZ2LxGUZJIlfdYBvZb1aczzxrlyMlqdnnws9MOxezoLGhSaFc2XYaHNReNQfj5zPIWyQ== +jest-validate@^26.4.2: + version "26.4.2" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-26.4.2.tgz#e871b0dfe97747133014dcf6445ee8018398f39c" + integrity sha512-blft+xDX7XXghfhY0mrsBCYhX365n8K5wNDC4XAcNKqqjEzsRUSXP44m6PL0QJEW2crxQFLLztVnJ4j7oPlQrQ== dependencies: - "@jest/types" "^25.5.0" - camelcase "^5.3.1" - chalk "^3.0.0" - jest-get-type "^25.2.6" + "@jest/types" "^26.3.0" + camelcase "^6.0.0" + chalk "^4.0.0" + jest-get-type "^26.3.0" leven "^3.1.0" - pretty-format "^25.5.0" + pretty-format "^26.4.2" -jest-watcher@^25.5.0: - version "25.5.0" - resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-25.5.0.tgz#d6110d101df98badebe435003956fd4a465e8456" - integrity sha512-XrSfJnVASEl+5+bb51V0Q7WQx65dTSk7NL4yDdVjPnRNpM0hG+ncFmDYJo9O8jaSRcAitVbuVawyXCRoxGrT5Q== +jest-watcher@^26.3.0: + version "26.3.0" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-26.3.0.tgz#f8ef3068ddb8af160ef868400318dc4a898eed08" + integrity sha512-XnLdKmyCGJ3VoF6G/p5ohbJ04q/vv5aH9ENI+i6BL0uu9WWB6Z7Z2lhQQk0d2AVZcRGp1yW+/TsoToMhBFPRdQ== dependencies: - "@jest/test-result" "^25.5.0" - "@jest/types" "^25.5.0" + "@jest/test-result" "^26.3.0" + "@jest/types" "^26.3.0" + "@types/node" "*" ansi-escapes "^4.2.1" - chalk "^3.0.0" - jest-util "^25.5.0" - string-length "^3.1.0" + chalk "^4.0.0" + jest-util "^26.3.0" + string-length "^4.0.1" jest-when@^2.7.2: version "2.7.2" @@ -18599,7 +18678,7 @@ jest-when@^2.7.2: bunyan "^1.8.12" expect "^24.8.0" -jest-worker@^25.4.0, jest-worker@^25.5.0: +jest-worker@^25.4.0: version "25.5.0" resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-25.5.0.tgz#2611d071b79cea0f43ee57a3d118593ac1547db1" integrity sha512-/dsSmUkIy5EBGfv/IjjqmFxrNAUpBERfGs1oHROyD7yxjG/w+t0GOJDX8O1k32ySmd7+a5IhnJU2qQFcJ4n1vw== @@ -18616,14 +18695,14 @@ jest-worker@^26.2.1, jest-worker@^26.3.0: merge-stream "^2.0.0" supports-color "^7.0.0" -jest@^25.5.4: - version "25.5.4" - resolved "https://registry.yarnpkg.com/jest/-/jest-25.5.4.tgz#f21107b6489cfe32b076ce2adcadee3587acb9db" - integrity sha512-hHFJROBTqZahnO+X+PMtT6G2/ztqAZJveGqz//FnWWHurizkD05PQGzRZOhF3XP6z7SJmL+5tCfW8qV06JypwQ== +jest@^26.4.2: + version "26.4.2" + resolved "https://registry.yarnpkg.com/jest/-/jest-26.4.2.tgz#7e8bfb348ec33f5459adeaffc1a25d5752d9d312" + integrity sha512-LLCjPrUh98Ik8CzW8LLVnSCfLaiY+wbK53U7VxnFSX7Q+kWC4noVeDvGWIFw0Amfq1lq2VfGm7YHWSLBV62MJw== dependencies: - "@jest/core" "^25.5.4" + "@jest/core" "^26.4.2" import-local "^3.0.2" - jest-cli "^25.5.4" + jest-cli "^26.4.2" jimp@^0.14.0: version "0.14.0" @@ -18750,36 +18829,36 @@ jsdom@13.1.0, jsdom@^13.0.0: ws "^6.1.2" xml-name-validator "^3.0.0" -jsdom@^15.2.1: - version "15.2.1" - resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-15.2.1.tgz#d2feb1aef7183f86be521b8c6833ff5296d07ec5" - integrity sha512-fAl1W0/7T2G5vURSyxBzrJ1LSdQn6Tr5UX/xD4PXDx/PDgwygedfW6El/KIj3xJ7FU61TTYnc/l/B7P49Eqt6g== - dependencies: - abab "^2.0.0" - acorn "^7.1.0" - acorn-globals "^4.3.2" - array-equal "^1.0.0" - cssom "^0.4.1" - cssstyle "^2.0.0" - data-urls "^1.1.0" - domexception "^1.0.1" - escodegen "^1.11.1" - html-encoding-sniffer "^1.0.2" +jsdom@^16.2.2: + version "16.4.0" + resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-16.4.0.tgz#36005bde2d136f73eee1a830c6d45e55408edddb" + integrity sha512-lYMm3wYdgPhrl7pDcRmvzPhhrGVBeVhPIqeHjzeiHN3DFmD1RBpbExbi8vU7BJdH8VAZYovR8DMt0PNNDM7k8w== + dependencies: + abab "^2.0.3" + acorn "^7.1.1" + acorn-globals "^6.0.0" + cssom "^0.4.4" + cssstyle "^2.2.0" + data-urls "^2.0.0" + decimal.js "^10.2.0" + domexception "^2.0.1" + escodegen "^1.14.1" + html-encoding-sniffer "^2.0.1" + is-potential-custom-element-name "^1.0.0" nwsapi "^2.2.0" - parse5 "5.1.0" - pn "^1.1.0" - request "^2.88.0" - request-promise-native "^1.0.7" - saxes "^3.1.9" - symbol-tree "^3.2.2" + parse5 "5.1.1" + request "^2.88.2" + request-promise-native "^1.0.8" + saxes "^5.0.0" + symbol-tree "^3.2.4" tough-cookie "^3.0.1" - w3c-hr-time "^1.0.1" - w3c-xmlserializer "^1.1.2" - webidl-conversions "^4.0.2" + w3c-hr-time "^1.0.2" + w3c-xmlserializer "^2.0.0" + webidl-conversions "^6.1.0" whatwg-encoding "^1.0.5" whatwg-mimetype "^2.3.0" - whatwg-url "^7.0.0" - ws "^7.0.0" + whatwg-url "^8.0.0" + ws "^7.2.3" xml-name-validator "^3.0.0" jsesc@^1.3.0: @@ -20011,7 +20090,7 @@ lolex@^4.2.0: resolved "https://registry.yarnpkg.com/lolex/-/lolex-4.2.0.tgz#ddbd7f6213ca1ea5826901ab1222b65d714b3cd7" integrity sha512-gKO5uExCXvSm6zbF562EvM+rd1kQDnB9AZBbiQVzf1ZmdDpxUSvpnAaVOP83N/31mRK8Ml8/VE8DMvsAZQ+7wg== -lolex@^5.0.0, lolex@^5.0.1: +lolex@^5.0.1: version "5.1.2" resolved "https://registry.yarnpkg.com/lolex/-/lolex-5.1.2.tgz#953694d098ce7c07bc5ed6d0e42bc6c0c6d5a367" integrity sha512-h4hmjAvHTmd+25JSwrtTIuwbKdwg5NzZVRMLn9saij4SZaepCrTCxPr35H/3bjwfMJtN+t3CX8672UIkglz28A== @@ -21653,16 +21732,17 @@ node-modules-regexp@^1.0.0: resolved "https://registry.yarnpkg.com/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz#8d9dbe28964a4ac5712e9131642107c71e90ec40" integrity sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA= -node-notifier@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-6.0.0.tgz#cea319e06baa16deec8ce5cd7f133c4a46b68e12" - integrity sha512-SVfQ/wMw+DesunOm5cKqr6yDcvUTDl/yc97ybGHMrteNEY6oekXpNpS3lZwgLlwz0FLgHoiW28ZpmBHUDg37cw== +node-notifier@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-8.0.0.tgz#a7eee2d51da6d0f7ff5094bc7108c911240c1620" + integrity sha512-46z7DUmcjoYdaWyXouuFNNfUo6eFa94t23c53c+lG/9Cvauk4a98rAUp9672X5dxGdQmLpPzTxzu8f/OeEPaFA== dependencies: growly "^1.3.0" - is-wsl "^2.1.1" - semver "^6.3.0" + is-wsl "^2.2.0" + semver "^7.3.2" shellwords "^0.1.1" - which "^1.3.1" + uuid "^8.3.0" + which "^2.0.2" node-pre-gyp@^0.11.0: version "0.11.0" @@ -22583,11 +22663,6 @@ p-finally@^1.0.0: resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= -p-finally@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-2.0.1.tgz#bd6fcaa9c559a096b680806f4d657b3f0f240561" - integrity sha512-vpm09aKwq6H9phqRQzecoDpD8TmVyGw70qmWlyq5onxY7tqyTTFVvxMykxQSQKILBSFlbXpypIw2T1Ml7+DDtw== - p-is-promise@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-1.1.0.tgz#9c9456989e9f6588017b0434d56097675c3da05e" @@ -22977,6 +23052,11 @@ parse5@5.1.0: resolved "https://registry.yarnpkg.com/parse5/-/parse5-5.1.0.tgz#c59341c9723f414c452975564c7c00a68d58acd2" integrity sha512-fxNG2sQjHvlVAYmzBZS9YlDp6PTSSDwa98vkD4QgVDDCAo84z5X1t5XyJQ62ImdLXx5NdIIfihey6xpum9/gRQ== +parse5@5.1.1, parse5@^5.0.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-5.1.1.tgz#f68e4e5ba1852ac2cadc00f4555fff6c2abb6178" + integrity sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug== + parse5@^3.0.1: version "3.0.3" resolved "https://registry.yarnpkg.com/parse5/-/parse5-3.0.3.tgz#042f792ffdd36851551cf4e9e066b3874ab45b5c" @@ -22984,11 +23064,6 @@ parse5@^3.0.1: dependencies: "@types/node" "*" -parse5@^5.0.0: - version "5.1.1" - resolved "https://registry.yarnpkg.com/parse5/-/parse5-5.1.1.tgz#f68e4e5ba1852ac2cadc00f4555fff6c2abb6178" - integrity sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug== - parse5@^6.0.0: version "6.0.1" resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" @@ -25249,11 +25324,6 @@ realpath-native@^1.1.0: dependencies: util.promisify "^1.0.0" -realpath-native@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/realpath-native/-/realpath-native-2.0.0.tgz#7377ac429b6e1fd599dc38d08ed942d0d7beb866" - integrity sha512-v1SEYUOXXdbBZK8ZuNgO4TBjamPsiSgcFr0aP+tEKpQZK8vooEUqV6nm6Cv502mX4NF2EfsnVqtNAHG+/6Ur1Q== - recast@^0.14.7: version "0.14.7" resolved "https://registry.yarnpkg.com/recast/-/recast-0.14.7.tgz#4f1497c2b5826d42a66e8e3c9d80c512983ff61d" @@ -25874,7 +25944,14 @@ request-promise-core@1.1.3: dependencies: lodash "^4.17.15" -request-promise-native@^1.0.5, request-promise-native@^1.0.7: +request-promise-core@1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/request-promise-core/-/request-promise-core-1.1.4.tgz#3eedd4223208d419867b78ce815167d10593a22f" + integrity sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw== + dependencies: + lodash "^4.17.19" + +request-promise-native@^1.0.5: version "1.0.8" resolved "https://registry.yarnpkg.com/request-promise-native/-/request-promise-native-1.0.8.tgz#a455b960b826e44e2bf8999af64dff2bfe58cb36" integrity sha512-dapwLGqkHtwL5AEbfenuzjTYg35Jd6KPytsC2/TLkVMz8rm+tNt72MGUWT1RP/aYawMpN6HqbNGBQaRcBtjQMQ== @@ -25883,6 +25960,15 @@ request-promise-native@^1.0.5, request-promise-native@^1.0.7: stealthy-require "^1.1.1" tough-cookie "^2.3.3" +request-promise-native@^1.0.8: + version "1.0.9" + resolved "https://registry.yarnpkg.com/request-promise-native/-/request-promise-native-1.0.9.tgz#e407120526a5efdc9a39b28a5679bf47b9d9dc28" + integrity sha512-wcW+sIUiWnKgNY0dqCpOZkUbF/I+YPi+f09JZIDa39Ec+q82CpSYniDp+ISgTTbKmnpJWASeJBPZmoxH84wt3g== + dependencies: + request-promise-core "1.1.4" + stealthy-require "^1.1.1" + tough-cookie "^2.3.3" + request-promise@^4.2.2: version "4.2.4" resolved "https://registry.yarnpkg.com/request-promise/-/request-promise-4.2.4.tgz#1c5ed0d71441e38ad58c7ce4ea4ea5b06d54b310" @@ -26531,13 +26617,20 @@ sax@>=0.6.0, sax@^1.2.4, sax@~1.2.4: resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== -saxes@^3.1.4, saxes@^3.1.9: +saxes@^3.1.4: version "3.1.11" resolved "https://registry.yarnpkg.com/saxes/-/saxes-3.1.11.tgz#d59d1fd332ec92ad98a2e0b2ee644702384b1c5b" integrity sha512-Ydydq3zC+WYDJK1+gRxRapLIED9PWeSuuS41wqyoRmzvhhh9nc+QQrVMKJYzJFULazeGhzSV0QleN2wD3boh2g== dependencies: xmlchars "^2.1.1" +saxes@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/saxes/-/saxes-5.0.1.tgz#eebab953fa3b7608dbe94e5dadb15c888fa6696d" + integrity sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw== + dependencies: + xmlchars "^2.2.0" + scheduler@^0.18.0: version "0.18.0" resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.18.0.tgz#5901ad6659bc1d8f3fdaf36eb7a67b0d6746b1c4" @@ -27693,13 +27786,13 @@ string-length@^2.0.0: astral-regex "^1.0.0" strip-ansi "^4.0.0" -string-length@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/string-length/-/string-length-3.1.0.tgz#107ef8c23456e187a8abd4a61162ff4ac6e25837" - integrity sha512-Ttp5YvkGm5v9Ijagtaz1BnN+k9ObpvS0eIBblPMp2YWL8FBmi9qblQ9fexc2k/CXFgrTIteU3jAw3payCnwSTA== +string-length@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.1.tgz#4a973bf31ef77c4edbceadd6af2611996985f8a1" + integrity sha512-PKyXUd0LK0ePjSOnWn34V2uD6acUWev9uy0Ft05k0E8xRW+SKcA0F7eMr7h5xlzfn+4O3N+55rduYyet3Jk+jw== dependencies: - astral-regex "^1.0.0" - strip-ansi "^5.2.0" + char-regex "^1.0.2" + strip-ansi "^6.0.0" string-replace-loader@^2.2.0: version "2.2.0" @@ -28270,6 +28363,11 @@ symbol-tree@^3.2.2: resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.2.tgz#ae27db38f660a7ae2e1c3b7d1bc290819b8519e6" integrity sha1-rifbOPZgp64uHDt9G8KQgZuFGeY= +symbol-tree@^3.2.4: + version "3.2.4" + resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" + integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== + symbol.prototype.description@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/symbol.prototype.description/-/symbol.prototype.description-1.0.0.tgz#6e355660eb1e44ca8ad53a68fdb72ef131ca4b12" @@ -29029,6 +29127,13 @@ tr46@^1.0.1: dependencies: punycode "^2.1.0" +tr46@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-2.0.2.tgz#03273586def1595ae08fedb38d7733cee91d2479" + integrity sha512-3n1qG+/5kg+jrbTzwAykB5yRYtQCTqOGKq5U5PE3b0a1/mzo6snDhjGS0zJVJunO0NrT3Dg1MLy5TjWP/UJppg== + dependencies: + punycode "^2.1.1" + traceparent@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/traceparent/-/traceparent-1.0.0.tgz#9b14445cdfe5c19f023f1c04d249c3d8e003a5ce" @@ -30143,10 +30248,10 @@ v8-compile-cache@^2.0.3: resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz#e14de37b31a6d194f5690d67efc4e7f6fc6ab30e" integrity sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g== -v8-to-istanbul@^4.1.3: - version "4.1.3" - resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-4.1.3.tgz#22fe35709a64955f49a08a7c7c959f6520ad6f20" - integrity sha512-sAjOC+Kki6aJVbUOXJbcR0MnbfjvBzwKZazEJymA2IX49uoOdEdk+4fBq5cXgYgiyKtAyrrJNtBZdOeDIF+Fng== +v8-to-istanbul@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-5.0.1.tgz#0608f5b49a481458625edb058488607f25498ba5" + integrity sha512-mbDNjuDajqYe3TXFk5qxcQy8L1msXNE37WTlLoqqpBfRsimbNcrlhQlDPntmECEcUvdC+AQ8CyMMf6EUx1r74Q== dependencies: "@types/istanbul-lib-coverage" "^2.0.1" convert-source-map "^1.6.0" @@ -30823,7 +30928,14 @@ w3c-hr-time@^1.0.1: dependencies: browser-process-hrtime "^0.1.2" -w3c-xmlserializer@^1.0.1, w3c-xmlserializer@^1.1.2: +w3c-hr-time@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd" + integrity sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ== + dependencies: + browser-process-hrtime "^1.0.0" + +w3c-xmlserializer@^1.0.1: version "1.1.2" resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-1.1.2.tgz#30485ca7d70a6fd052420a3d12fd90e6339ce794" integrity sha512-p10l/ayESzrBMYWRID6xbuCKh2Fp77+sA0doRuGn4tTIMrrZVeqfpKjXHY+oDh3K4nLdPgNwMTVP6Vp4pvqbNg== @@ -30832,6 +30944,13 @@ w3c-xmlserializer@^1.0.1, w3c-xmlserializer@^1.1.2: webidl-conversions "^4.0.2" xml-name-validator "^3.0.0" +w3c-xmlserializer@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz#3e7104a05b75146cc60f564380b7f683acf1020a" + integrity sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA== + dependencies: + xml-name-validator "^3.0.0" + walk@2.3.x: version "2.3.9" resolved "https://registry.yarnpkg.com/walk/-/walk-2.3.9.tgz#31b4db6678f2ae01c39ea9fb8725a9031e558a7b" @@ -30937,6 +31056,16 @@ webidl-conversions@^4.0.2: resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" integrity sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg== +webidl-conversions@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-5.0.0.tgz#ae59c8a00b121543a2acc65c0434f57b0fc11aff" + integrity sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA== + +webidl-conversions@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-6.1.0.tgz#9111b4d7ea80acd40f5270d666621afa78b69514" + integrity sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w== + webpack-cli@^3.3.10: version "3.3.10" resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-3.3.10.tgz#17b279267e9b4fb549023fae170da8e6e766da13" @@ -31193,6 +31322,15 @@ whatwg-url@^7.0.0: tr46 "^1.0.1" webidl-conversions "^4.0.2" +whatwg-url@^8.0.0: + version "8.2.2" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-8.2.2.tgz#85e7f9795108b53d554cec640b2e8aee2a0d4bfd" + integrity sha512-PcVnO6NiewhkmzV0qn7A+UZ9Xx4maNTI+O+TShmfE4pqjoCMwUMjkvoNhNHPTvgR7QH9Xt3R13iHuWy2sToFxQ== + dependencies: + lodash.sortby "^4.7.0" + tr46 "^2.0.2" + webidl-conversions "^6.1.0" + which-boxed-primitive@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.1.tgz#cbe8f838ebe91ba2471bb69e9edbda67ab5a5ec1" @@ -31535,12 +31673,10 @@ ws@^6.1.2, ws@^6.2.1: dependencies: async-limiter "~1.0.0" -ws@^7.0.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.2.0.tgz#422eda8c02a4b5dba7744ba66eebbd84bcef0ec7" - integrity sha512-+SqNqFbwTm/0DC18KYzIsMTnEWpLwJsiasW/O17la4iDRRIO9uaHbvKiAS3AHgTiuuWerK/brj4O6MYZkei9xg== - dependencies: - async-limiter "^1.0.0" +ws@^7.2.3: + version "7.3.1" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.3.1.tgz#d0547bf67f7ce4f12a72dfe31262c68d7dc551c8" + integrity sha512-D3RuNkynyHmEJIpD2qrgVkc9DQ23OrN/moAwZX4L8DfvszsJxpjQuUq3LMx6HoYji9fbIOBY18XWBsAux1ZZUA== x-is-function@^1.0.4: version "1.0.4" @@ -31634,7 +31770,7 @@ xmlbuilder@~9.0.1: resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-9.0.4.tgz#519cb4ca686d005a8420d3496f3f0caeecca580f" integrity sha1-UZy0ymhtAFqEINNJbz8MruzKWA8= -xmlchars@^2.1.1: +xmlchars@^2.1.1, xmlchars@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== From 5f187307c2e20ea1c8057a0e65c7b5801a4467f6 Mon Sep 17 00:00:00 2001 From: Jen Huang Date: Thu, 1 Oct 2020 14:50:03 -0700 Subject: [PATCH 18/50] Fix condition for filtering to installed packages (#79205) --- .../ingest_manager/server/services/epm/packages/get.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/ingest_manager/server/services/epm/packages/get.ts b/x-pack/plugins/ingest_manager/server/services/epm/packages/get.ts index c4232247cc4bd..2d11b6157804f 100644 --- a/x-pack/plugins/ingest_manager/server/services/epm/packages/get.ts +++ b/x-pack/plugins/ingest_manager/server/services/epm/packages/get.ts @@ -51,14 +51,14 @@ export async function getPackages( } // Get package names for packages which cannot have more than one package policy on an agent policy -// Assume packages only export one config template for now +// Assume packages only export one policy template for now export async function getLimitedPackages(options: { savedObjectsClient: SavedObjectsClientContract; }): Promise { const { savedObjectsClient } = options; const allPackages = await getPackages({ savedObjectsClient, experimental: true }); const installedPackages = allPackages.filter( - (pkg) => (pkg.status = InstallationStatus.installed) + (pkg) => pkg.status === InstallationStatus.installed ); const installedPackagesInfo = await Promise.all( installedPackages.map((pkgInstall) => { From 117b5771dcee1b3ee00e56d9c7bb025e459fec14 Mon Sep 17 00:00:00 2001 From: Patrick Mueller Date: Thu, 1 Oct 2020 18:06:26 -0400 Subject: [PATCH 19/50] [Alerting] formalize alert status and add status fields to alert saved object (#75553) resolves https://github.com/elastic/kibana/issues/51099 This formalizes the concept of "alert status", in terms of it's execution, with some new fields in the alert saved object and types used with the alert client and http APIs. These fields are read-only from the client point-of-view; they are provided in the alert structures, but are only updated by the alerting framework itself. The values will be updated after each run of the alert type executor. The data is added to the alert as the `executionStatus` field, with the following shape: ```ts interface AlertExecutionStatus { status: 'ok' | 'active' | 'error' | 'pending' | 'unknown'; lastExecutionDate: Date; error?: { reason: 'read' | 'decrypt' | 'execute' | 'unknown'; message: string; }; } ``` --- x-pack/plugins/alerts/common/alert.ts | 23 ++ .../alerts/server/alerts_client.test.ts | 20 ++ x-pack/plugins/alerts/server/alerts_client.ts | 21 +- .../server/lib/alert_execution_status.test.ts | 185 ++++++++++ .../server/lib/alert_execution_status.ts | 66 ++++ ...rt_instance_summary_from_event_log.test.ts | 4 + .../server/lib/error_with_reason.test.ts | 28 ++ .../alerts/server/lib/error_with_reason.ts | 29 ++ x-pack/plugins/alerts/server/lib/index.ts | 7 + .../lib/is_alert_not_found_error.test.ts | 22 +- .../server/lib/is_alert_not_found_error.ts | 8 +- x-pack/plugins/alerts/server/plugin.ts | 1 + .../alerts/server/routes/create.test.ts | 7 +- .../plugins/alerts/server/routes/get.test.ts | 7 +- .../alerts/server/saved_objects/index.ts | 13 +- .../alerts/server/saved_objects/mappings.json | 20 ++ .../server/saved_objects/migrations.test.ts | 30 +- .../alerts/server/saved_objects/migrations.ts | 23 +- .../saved_objects/partially_update_alert.ts | 4 +- .../task_runner/alert_task_instance.test.ts | 4 + .../server/task_runner/task_runner.test.ts | 15 +- .../alerts/server/task_runner/task_runner.ts | 59 +++- .../task_runner/task_runner_factory.test.ts | 6 +- .../server/task_runner/task_runner_factory.ts | 3 +- x-pack/plugins/alerts/server/types.ts | 15 + .../routes/__mocks__/request_responses.ts | 8 + .../rules/patch_rules.mock.ts | 4 + .../public/application/lib/alert_api.test.ts | 8 + .../public/application/lib/alert_api.ts | 5 +- .../components/alert_details.test.tsx | 4 + .../components/alert_details_route.test.tsx | 4 + .../components/alert_instances.test.tsx | 4 + .../components/alert_instances_route.test.tsx | 4 + .../components/view_in_app.test.tsx | 4 + .../sections/alert_form/alert_edit.test.tsx | 9 +- .../with_bulk_alert_api_operations.test.tsx | 4 + .../common/lib/test_assertions.ts | 18 + .../tests/alerting/create.ts | 1 + .../tests/alerting/execution_status.ts | 87 +++++ .../tests/alerting/find.ts | 81 +++++ .../security_and_spaces/tests/alerting/get.ts | 1 + .../tests/alerting/index.ts | 1 + .../tests/alerting/update.ts | 5 + .../spaces_only/tests/alerting/create.ts | 1 + .../tests/alerting/execution_status.ts | 333 ++++++++++++++++++ .../spaces_only/tests/alerting/find.ts | 1 + .../spaces_only/tests/alerting/get.ts | 1 + .../spaces_only/tests/alerting/index.ts | 1 + .../spaces_only/tests/alerting/update.ts | 1 + .../detection_engine_api_integration/utils.ts | 13 +- 50 files changed, 1176 insertions(+), 47 deletions(-) create mode 100644 x-pack/plugins/alerts/server/lib/alert_execution_status.test.ts create mode 100644 x-pack/plugins/alerts/server/lib/alert_execution_status.ts create mode 100644 x-pack/plugins/alerts/server/lib/error_with_reason.test.ts create mode 100644 x-pack/plugins/alerts/server/lib/error_with_reason.ts create mode 100644 x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/execution_status.ts create mode 100644 x-pack/test/alerting_api_integration/spaces_only/tests/alerting/execution_status.ts diff --git a/x-pack/plugins/alerts/common/alert.ts b/x-pack/plugins/alerts/common/alert.ts index 3ff7ed742e810..4ebe66f7b7c9f 100644 --- a/x-pack/plugins/alerts/common/alert.ts +++ b/x-pack/plugins/alerts/common/alert.ts @@ -15,6 +15,28 @@ export interface IntervalSchedule extends SavedObjectAttributes { interval: string; } +// for the `typeof ThingValues[number]` types below, become string types that +// only accept the values in the associated string arrays +export const AlertExecutionStatusValues = ['ok', 'active', 'error', 'pending', 'unknown'] as const; +export type AlertExecutionStatuses = typeof AlertExecutionStatusValues[number]; + +export const AlertExecutionStatusErrorReasonValues = [ + 'read', + 'decrypt', + 'execute', + 'unknown', +] as const; +export type AlertExecutionStatusErrorReasons = typeof AlertExecutionStatusErrorReasonValues[number]; + +export interface AlertExecutionStatus { + status: AlertExecutionStatuses; + lastExecutionDate: Date; + error?: { + reason: AlertExecutionStatusErrorReasons; + message: string; + }; +} + export type AlertActionParams = SavedObjectAttributes; export interface AlertAction { @@ -44,6 +66,7 @@ export interface Alert { throttle: string | null; muteAll: boolean; mutedInstanceIds: string[]; + executionStatus: AlertExecutionStatus; } export type SanitizedAlert = Omit; diff --git a/x-pack/plugins/alerts/server/alerts_client.test.ts b/x-pack/plugins/alerts/server/alerts_client.test.ts index 088390c3cb6e7..b20018fcc26f7 100644 --- a/x-pack/plugins/alerts/server/alerts_client.test.ts +++ b/x-pack/plugins/alerts/server/alerts_client.test.ts @@ -393,6 +393,11 @@ describe('create()', () => { "createdAt": "2019-02-12T21:01:22.479Z", "createdBy": "elastic", "enabled": true, + "executionStatus": Object { + "error": null, + "lastExecutionDate": "2019-02-12T21:01:22.479Z", + "status": "pending", + }, "meta": Object { "versionApiKeyLastmodified": "v7.10.0", }, @@ -1034,6 +1039,11 @@ describe('create()', () => { muteAll: false, mutedInstanceIds: [], tags: ['foo'], + executionStatus: { + lastExecutionDate: '2019-02-12T21:01:22.479Z', + status: 'pending', + error: null, + }, }, { references: [ @@ -1150,6 +1160,11 @@ describe('create()', () => { muteAll: false, mutedInstanceIds: [], tags: ['foo'], + executionStatus: { + lastExecutionDate: '2019-02-12T21:01:22.479Z', + status: 'pending', + error: null, + }, }, { references: [ @@ -2506,6 +2521,11 @@ const BaseAlertInstanceSummarySavedObject: SavedObject = { throttle: null, muteAll: false, mutedInstanceIds: [], + executionStatus: { + status: 'unknown', + lastExecutionDate: '2020-08-20T19:23:38Z', + error: null, + }, }, references: [], }; diff --git a/x-pack/plugins/alerts/server/alerts_client.ts b/x-pack/plugins/alerts/server/alerts_client.ts index bcc3c9bcf7e55..bd278d39c6229 100644 --- a/x-pack/plugins/alerts/server/alerts_client.ts +++ b/x-pack/plugins/alerts/server/alerts_client.ts @@ -28,7 +28,7 @@ import { AlertTaskState, AlertInstanceSummary, } from './types'; -import { validateAlertTypeParams } from './lib'; +import { validateAlertTypeParams, alertExecutionStatusFromRaw } from './lib'; import { InvalidateAPIKeyParams, GrantAPIKeyResult as SecurityPluginGrantAPIKeyResult, @@ -122,6 +122,7 @@ export interface CreateOptions { | 'muteAll' | 'mutedInstanceIds' | 'actions' + | 'executionStatus' > & { actions: NormalizedAlertAction[] }; options?: { migrationVersion?: Record; @@ -228,6 +229,11 @@ export class AlertsClient { params: validatedAlertTypeParams as RawAlert['params'], muteAll: false, mutedInstanceIds: [], + executionStatus: { + status: 'pending', + lastExecutionDate: new Date().toISOString(), + error: null, + }, }; let createdAlert: SavedObject; try { @@ -978,9 +984,19 @@ export class AlertsClient { updatedAt: SavedObject['updated_at'] = createdAt, references: SavedObjectReference[] | undefined ): PartialAlert { + // Not the prettiest code here, but if we want to use most of the + // alert fields from the rawAlert using `...rawAlert` kind of access, we + // need to specifically delete the executionStatus as it's a different type + // in RawAlert and Alert. Probably next time we need to do something similar + // here, we should look at redesigning the implementation of this method. + const rawAlertWithoutExecutionStatus: Partial> = { + ...rawAlert, + }; + delete rawAlertWithoutExecutionStatus.executionStatus; + const executionStatus = alertExecutionStatusFromRaw(this.logger, id, rawAlert.executionStatus); return { id, - ...rawAlert, + ...rawAlertWithoutExecutionStatus, // we currently only support the Interval Schedule type // Once we support additional types, this type signature will likely change schedule: rawAlert.schedule as IntervalSchedule, @@ -990,6 +1006,7 @@ export class AlertsClient { ...(updatedAt ? { updatedAt: new Date(updatedAt) } : {}), ...(createdAt ? { createdAt: new Date(createdAt) } : {}), ...(scheduledTaskId ? { scheduledTaskId } : {}), + ...(executionStatus ? { executionStatus } : {}), }; } diff --git a/x-pack/plugins/alerts/server/lib/alert_execution_status.test.ts b/x-pack/plugins/alerts/server/lib/alert_execution_status.test.ts new file mode 100644 index 0000000000000..3372d19cd4090 --- /dev/null +++ b/x-pack/plugins/alerts/server/lib/alert_execution_status.test.ts @@ -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; + * you may not use this file except in compliance with the Elastic License. + */ + +import { loggingSystemMock } from '../../../../../src/core/server/mocks'; +import { AlertExecutionStatusErrorReasons } from '../types'; +import { + executionStatusFromState, + executionStatusFromError, + alertExecutionStatusToRaw, + alertExecutionStatusFromRaw, +} from './alert_execution_status'; +import { ErrorWithReason } from './error_with_reason'; + +const MockLogger = loggingSystemMock.create().get(); + +describe('AlertExecutionStatus', () => { + beforeEach(() => { + jest.resetAllMocks(); + }); + + describe('executionStatusFromState()', () => { + test('empty task state', () => { + const status = executionStatusFromState({}); + checkDateIsNearNow(status.lastExecutionDate); + expect(status.status).toBe('ok'); + expect(status.error).toBe(undefined); + }); + + test('task state with no instances', () => { + const status = executionStatusFromState({ alertInstances: {} }); + checkDateIsNearNow(status.lastExecutionDate); + expect(status.status).toBe('ok'); + expect(status.error).toBe(undefined); + }); + + test('task state with one instance', () => { + const status = executionStatusFromState({ alertInstances: { a: {} } }); + checkDateIsNearNow(status.lastExecutionDate); + expect(status.status).toBe('active'); + expect(status.error).toBe(undefined); + }); + }); + + describe('executionStatusFromError()', () => { + test('error with no reason', () => { + const status = executionStatusFromError(new Error('boo!')); + expect(status.status).toBe('error'); + expect(status.error).toMatchInlineSnapshot(` + Object { + "message": "boo!", + "reason": "unknown", + } + `); + }); + + test('error with a reason', () => { + const status = executionStatusFromError(new ErrorWithReason('execute', new Error('hoo!'))); + expect(status.status).toBe('error'); + expect(status.error).toMatchInlineSnapshot(` + Object { + "message": "hoo!", + "reason": "execute", + } + `); + }); + }); + + describe('alertExecutionStatusToRaw()', () => { + const date = new Date('2020-09-03T16:26:58Z'); + const status = 'ok'; + const reason: AlertExecutionStatusErrorReasons = 'decrypt'; + const error = { reason, message: 'wops' }; + + test('status without an error', () => { + expect(alertExecutionStatusToRaw({ lastExecutionDate: date, status })).toMatchInlineSnapshot(` + Object { + "error": null, + "lastExecutionDate": "2020-09-03T16:26:58.000Z", + "status": "ok", + } + `); + }); + + test('status with an error', () => { + expect(alertExecutionStatusToRaw({ lastExecutionDate: date, status, error })) + .toMatchInlineSnapshot(` + Object { + "error": Object { + "message": "wops", + "reason": "decrypt", + }, + "lastExecutionDate": "2020-09-03T16:26:58.000Z", + "status": "ok", + } + `); + }); + }); + + describe('alertExecutionStatusFromRaw()', () => { + const date = new Date('2020-09-03T16:26:58Z').toISOString(); + const status = 'active'; + const reason: AlertExecutionStatusErrorReasons = 'execute'; + const error = { reason, message: 'wops' }; + + test('no input', () => { + const result = alertExecutionStatusFromRaw(MockLogger, 'alert-id'); + expect(result).toBe(undefined); + }); + + test('undefined input', () => { + const result = alertExecutionStatusFromRaw(MockLogger, 'alert-id', undefined); + expect(result).toBe(undefined); + }); + + test('null input', () => { + const result = alertExecutionStatusFromRaw(MockLogger, 'alert-id', null); + expect(result).toBe(undefined); + }); + + test('invalid date', () => { + const result = alertExecutionStatusFromRaw(MockLogger, 'alert-id', { + lastExecutionDate: 'an invalid date', + })!; + checkDateIsNearNow(result.lastExecutionDate); + expect(result.status).toBe('unknown'); + expect(result.error).toBe(undefined); + expect(MockLogger.debug).toBeCalledWith( + 'invalid alertExecutionStatus lastExecutionDate "an invalid date" in raw alert alert-id' + ); + }); + + test('valid date', () => { + const result = alertExecutionStatusFromRaw(MockLogger, 'alert-id', { + lastExecutionDate: date, + }); + expect(result).toMatchInlineSnapshot(` + Object { + "lastExecutionDate": 2020-09-03T16:26:58.000Z, + "status": "unknown", + } + `); + }); + + test('valid status and date', () => { + const result = alertExecutionStatusFromRaw(MockLogger, 'alert-id', { + status, + lastExecutionDate: date, + }); + expect(result).toMatchInlineSnapshot(` + Object { + "lastExecutionDate": 2020-09-03T16:26:58.000Z, + "status": "active", + } + `); + }); + + test('valid status, date and error', () => { + const result = alertExecutionStatusFromRaw(MockLogger, 'alert-id', { + status, + lastExecutionDate: date, + error, + }); + expect(result).toMatchInlineSnapshot(` + Object { + "error": Object { + "message": "wops", + "reason": "execute", + }, + "lastExecutionDate": 2020-09-03T16:26:58.000Z, + "status": "active", + } + `); + }); + }); +}); + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +function checkDateIsNearNow(date: any) { + expect(date instanceof Date).toBe(true); + // allow for lots of slop in the time difference + expect(Date.now() - date.valueOf()).toBeLessThanOrEqual(10000); +} diff --git a/x-pack/plugins/alerts/server/lib/alert_execution_status.ts b/x-pack/plugins/alerts/server/lib/alert_execution_status.ts new file mode 100644 index 0000000000000..9eb0c8817f28c --- /dev/null +++ b/x-pack/plugins/alerts/server/lib/alert_execution_status.ts @@ -0,0 +1,66 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { Logger } from 'src/core/server'; +import { AlertTaskState, AlertExecutionStatus, RawAlertExecutionStatus } from '../types'; +import { getReasonFromError } from './error_with_reason'; + +export function executionStatusFromState(state: AlertTaskState): AlertExecutionStatus { + const instanceIds = Object.keys(state.alertInstances ?? {}); + return { + lastExecutionDate: new Date(), + status: instanceIds.length === 0 ? 'ok' : 'active', + }; +} + +export function executionStatusFromError(error: Error): AlertExecutionStatus { + return { + lastExecutionDate: new Date(), + status: 'error', + error: { + reason: getReasonFromError(error), + message: error.message, + }, + }; +} + +export function alertExecutionStatusToRaw({ + lastExecutionDate, + status, + error, +}: AlertExecutionStatus): RawAlertExecutionStatus { + return { + lastExecutionDate: lastExecutionDate.toISOString(), + status, + // explicitly setting to null (in case undefined) due to partial update concerns + error: error ?? null, + }; +} + +export function alertExecutionStatusFromRaw( + logger: Logger, + alertId: string, + rawAlertExecutionStatus?: Partial | null | undefined +): AlertExecutionStatus | undefined { + if (!rawAlertExecutionStatus) return undefined; + + const { lastExecutionDate, status = 'unknown', error } = rawAlertExecutionStatus; + + let parsedDateMillis = lastExecutionDate ? Date.parse(lastExecutionDate) : Date.now(); + if (isNaN(parsedDateMillis)) { + logger.debug( + `invalid alertExecutionStatus lastExecutionDate "${lastExecutionDate}" in raw alert ${alertId}` + ); + parsedDateMillis = Date.now(); + } + + const parsedDate = new Date(parsedDateMillis); + if (error) { + return { lastExecutionDate: parsedDate, status, error }; + } else { + return { lastExecutionDate: parsedDate, status }; + } +} diff --git a/x-pack/plugins/alerts/server/lib/alert_instance_summary_from_event_log.test.ts b/x-pack/plugins/alerts/server/lib/alert_instance_summary_from_event_log.test.ts index b5936cf3577b3..566a1770c0658 100644 --- a/x-pack/plugins/alerts/server/lib/alert_instance_summary_from_event_log.test.ts +++ b/x-pack/plugins/alerts/server/lib/alert_instance_summary_from_event_log.test.ts @@ -511,4 +511,8 @@ const BaseAlert: SanitizedAlert = { createdAt: new Date(), updatedAt: new Date(), apiKeyOwner: null, + executionStatus: { + status: 'unknown', + lastExecutionDate: new Date('2020-08-20T19:23:38Z'), + }, }; diff --git a/x-pack/plugins/alerts/server/lib/error_with_reason.test.ts b/x-pack/plugins/alerts/server/lib/error_with_reason.test.ts new file mode 100644 index 0000000000000..f31f584400308 --- /dev/null +++ b/x-pack/plugins/alerts/server/lib/error_with_reason.test.ts @@ -0,0 +1,28 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { ErrorWithReason, getReasonFromError, isErrorWithReason } from './error_with_reason'; + +describe('ErrorWithReason', () => { + const plainError = new Error('well, actually'); + const errorWithReason = new ErrorWithReason('decrypt', plainError); + + test('ErrorWithReason class', () => { + expect(errorWithReason.message).toBe(plainError.message); + expect(errorWithReason.error).toBe(plainError); + expect(errorWithReason.reason).toBe('decrypt'); + }); + + test('getReasonFromError()', () => { + expect(getReasonFromError(plainError)).toBe('unknown'); + expect(getReasonFromError(errorWithReason)).toBe('decrypt'); + }); + + test('isErrorWithReason()', () => { + expect(isErrorWithReason(plainError)).toBe(false); + expect(isErrorWithReason(errorWithReason)).toBe(true); + }); +}); diff --git a/x-pack/plugins/alerts/server/lib/error_with_reason.ts b/x-pack/plugins/alerts/server/lib/error_with_reason.ts new file mode 100644 index 0000000000000..29eb666e64427 --- /dev/null +++ b/x-pack/plugins/alerts/server/lib/error_with_reason.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; + * you may not use this file except in compliance with the Elastic License. + */ + +import { AlertExecutionStatusErrorReasons } from '../types'; + +export class ErrorWithReason extends Error { + public readonly reason: AlertExecutionStatusErrorReasons; + public readonly error: Error; + + constructor(reason: AlertExecutionStatusErrorReasons, error: Error) { + super(error.message); + this.error = error; + this.reason = reason; + } +} + +export function getReasonFromError(error: Error): AlertExecutionStatusErrorReasons { + if (isErrorWithReason(error)) { + return error.reason; + } + return 'unknown'; +} + +export function isErrorWithReason(error: Error | ErrorWithReason): error is ErrorWithReason { + return error instanceof ErrorWithReason; +} diff --git a/x-pack/plugins/alerts/server/lib/index.ts b/x-pack/plugins/alerts/server/lib/index.ts index 2f610aafd8c31..32047ae5cbfa8 100644 --- a/x-pack/plugins/alerts/server/lib/index.ts +++ b/x-pack/plugins/alerts/server/lib/index.ts @@ -7,3 +7,10 @@ export { parseDuration, validateDurationSchema } from '../../common/parse_duration'; export { LicenseState } from './license_state'; export { validateAlertTypeParams } from './validate_alert_type_params'; +export { ErrorWithReason, getReasonFromError, isErrorWithReason } from './error_with_reason'; +export { + executionStatusFromState, + executionStatusFromError, + alertExecutionStatusToRaw, + alertExecutionStatusFromRaw, +} from './alert_execution_status'; diff --git a/x-pack/plugins/alerts/server/lib/is_alert_not_found_error.test.ts b/x-pack/plugins/alerts/server/lib/is_alert_not_found_error.test.ts index 46ceee3ce420b..b570957d82de4 100644 --- a/x-pack/plugins/alerts/server/lib/is_alert_not_found_error.test.ts +++ b/x-pack/plugins/alerts/server/lib/is_alert_not_found_error.test.ts @@ -5,27 +5,27 @@ */ import { isAlertSavedObjectNotFoundError } from './is_alert_not_found_error'; +import { ErrorWithReason } from './error_with_reason'; import { SavedObjectsErrorHelpers } from '../../../../../src/core/server'; import uuid from 'uuid'; describe('isAlertSavedObjectNotFoundError', () => { + const id = uuid.v4(); + const errorSONF = SavedObjectsErrorHelpers.createGenericNotFoundError('alert', id); + test('identifies SavedObjects Not Found errors', () => { - const id = uuid.v4(); // ensure the error created by SO parses as a string with the format we expect - expect( - `${SavedObjectsErrorHelpers.createGenericNotFoundError('alert', id)}`.includes(`alert/${id}`) - ).toBe(true); - - const errorBySavedObjectsHelper = SavedObjectsErrorHelpers.createGenericNotFoundError( - 'alert', - id - ); + expect(`${errorSONF}`.includes(`alert/${id}`)).toBe(true); - expect(isAlertSavedObjectNotFoundError(errorBySavedObjectsHelper, id)).toBe(true); + expect(isAlertSavedObjectNotFoundError(errorSONF, id)).toBe(true); }); test('identifies generic errors', () => { - const id = uuid.v4(); expect(isAlertSavedObjectNotFoundError(new Error(`not found`), id)).toBe(false); }); + + test('identifies SavedObjects Not Found errors wrapped in an ErrorWithReason', () => { + const error = new ErrorWithReason('read', errorSONF); + expect(isAlertSavedObjectNotFoundError(error, id)).toBe(true); + }); }); diff --git a/x-pack/plugins/alerts/server/lib/is_alert_not_found_error.ts b/x-pack/plugins/alerts/server/lib/is_alert_not_found_error.ts index 0aa83ad0e883c..038e234586688 100644 --- a/x-pack/plugins/alerts/server/lib/is_alert_not_found_error.ts +++ b/x-pack/plugins/alerts/server/lib/is_alert_not_found_error.ts @@ -5,7 +5,13 @@ */ import { SavedObjectsErrorHelpers } from '../../../../../src/core/server'; +import { isErrorWithReason } from './error_with_reason'; export function isAlertSavedObjectNotFoundError(err: Error, alertId: string) { - return SavedObjectsErrorHelpers.isNotFoundError(err) && `${err}`.includes(alertId); + // if this is an error with a reason, the actual error needs to be extracted + const actualError = isErrorWithReason(err) ? err.error : err; + + return ( + SavedObjectsErrorHelpers.isNotFoundError(actualError) && `${actualError}`.includes(alertId) + ); } diff --git a/x-pack/plugins/alerts/server/plugin.ts b/x-pack/plugins/alerts/server/plugin.ts index e9caf4b78e627..4cdcac4c9e889 100644 --- a/x-pack/plugins/alerts/server/plugin.ts +++ b/x-pack/plugins/alerts/server/plugin.ts @@ -264,6 +264,7 @@ export class AlertingPlugin { encryptedSavedObjectsClient, getBasePath: this.getBasePath, eventLogger: this.eventLogger!, + internalSavedObjectsRepository: core.savedObjects.createInternalRepository(['alert']), }); this.eventLogService!.registerSavedObjectProvider('alert', (request) => { diff --git a/x-pack/plugins/alerts/server/routes/create.test.ts b/x-pack/plugins/alerts/server/routes/create.test.ts index 274acaf01c475..51c5d2525631d 100644 --- a/x-pack/plugins/alerts/server/routes/create.test.ts +++ b/x-pack/plugins/alerts/server/routes/create.test.ts @@ -10,6 +10,7 @@ import { mockLicenseState } from '../lib/license_state.mock'; import { verifyApiAccess } from '../lib/license_api_access'; import { mockHandlerArguments } from './_mock_handler_arguments'; import { alertsClientMock } from '../alerts_client.mock'; +import { Alert } from '../../common/alert'; const alertsClient = alertsClientMock.create(); @@ -46,7 +47,7 @@ describe('createAlertRoute', () => { ], }; - const createResult = { + const createResult: Alert = { ...mockedAlert, enabled: true, muteAll: false, @@ -64,6 +65,10 @@ describe('createAlertRoute', () => { actionTypeId: 'test', }, ], + executionStatus: { + status: 'unknown', + lastExecutionDate: new Date('2020-08-20T19:23:38Z'), + }, }; it('creates an alert with proper parameters', async () => { diff --git a/x-pack/plugins/alerts/server/routes/get.test.ts b/x-pack/plugins/alerts/server/routes/get.test.ts index 8c4b06adf70f7..c60177e90b79d 100644 --- a/x-pack/plugins/alerts/server/routes/get.test.ts +++ b/x-pack/plugins/alerts/server/routes/get.test.ts @@ -10,6 +10,7 @@ import { mockLicenseState } from '../lib/license_state.mock'; import { verifyApiAccess } from '../lib/license_api_access'; import { mockHandlerArguments } from './_mock_handler_arguments'; import { alertsClientMock } from '../alerts_client.mock'; +import { Alert } from '../../common'; const alertsClient = alertsClientMock.create(); jest.mock('../lib/license_api_access.ts', () => ({ @@ -21,7 +22,7 @@ beforeEach(() => { }); describe('getAlertRoute', () => { - const mockedAlert = { + const mockedAlert: Alert = { id: '1', alertTypeId: '1', schedule: { interval: '10s' }, @@ -51,6 +52,10 @@ describe('getAlertRoute', () => { apiKeyOwner: '', throttle: '30s', mutedInstanceIds: [], + executionStatus: { + status: 'unknown', + lastExecutionDate: new Date('2020-08-20T19:23:38Z'), + }, }; it('gets an alert with proper parameters', async () => { diff --git a/x-pack/plugins/alerts/server/saved_objects/index.ts b/x-pack/plugins/alerts/server/saved_objects/index.ts index 51ac68b589977..9aa1f86676eaa 100644 --- a/x-pack/plugins/alerts/server/saved_objects/index.ts +++ b/x-pack/plugins/alerts/server/saved_objects/index.ts @@ -16,15 +16,19 @@ export const AlertAttributesExcludedFromAAD = [ 'muteAll', 'mutedInstanceIds', 'updatedBy', + 'executionStatus', ]; // useful for Pick which is a // type which is a subset of RawAlert with just attributes excluded from AAD + +// useful for Pick export type AlertAttributesExcludedFromAADType = | 'scheduledTaskId' | 'muteAll' | 'mutedInstanceIds' - | 'updatedBy'; + | 'updatedBy' + | 'executionStatus'; export function setupSavedObjects( savedObjects: SavedObjectsServiceSetup, @@ -42,11 +46,6 @@ export function setupSavedObjects( encryptedSavedObjects.registerType({ type: 'alert', attributesToEncrypt: new Set(['apiKey']), - attributesToExcludeFromAAD: new Set([ - 'scheduledTaskId', - 'muteAll', - 'mutedInstanceIds', - 'updatedBy', - ]), + attributesToExcludeFromAAD: new Set(AlertAttributesExcludedFromAAD), }); } diff --git a/x-pack/plugins/alerts/server/saved_objects/mappings.json b/x-pack/plugins/alerts/server/saved_objects/mappings.json index 8440b963975ff..a6c92080f18be 100644 --- a/x-pack/plugins/alerts/server/saved_objects/mappings.json +++ b/x-pack/plugins/alerts/server/saved_objects/mappings.json @@ -83,6 +83,26 @@ "type": "keyword" } } + }, + "executionStatus": { + "properties": { + "status": { + "type": "keyword" + }, + "lastExecutionDate": { + "type": "date" + }, + "error": { + "properties": { + "reason": { + "type": "keyword" + }, + "message": { + "type": "keyword" + } + } + } + } } } } diff --git a/x-pack/plugins/alerts/server/saved_objects/migrations.test.ts b/x-pack/plugins/alerts/server/saved_objects/migrations.test.ts index 10e1a9ae421b7..8c9d10769b18a 100644 --- a/x-pack/plugins/alerts/server/saved_objects/migrations.test.ts +++ b/x-pack/plugins/alerts/server/saved_objects/migrations.test.ts @@ -177,7 +177,7 @@ describe('7.10.0', () => { }, ], }); - expect(migration710(alert, { log })).toEqual({ + expect(migration710(alert, { log })).toMatchObject({ ...alert, attributes: { ...alert.attributes, @@ -199,6 +199,32 @@ describe('7.10.0', () => { }, }); }); + + test('creates execution status', () => { + const migration710 = getMigrations(encryptedSavedObjectsSetup)['7.10.0']; + const alert = getMockData(); + const dateStart = Date.now(); + const migratedAlert = migration710(alert, { log }); + const dateStop = Date.now(); + const dateExecutionStatus = Date.parse( + migratedAlert.attributes.executionStatus.lastExecutionDate + ); + + expect(dateStart).toBeLessThanOrEqual(dateExecutionStatus); + expect(dateStop).toBeGreaterThanOrEqual(dateExecutionStatus); + + expect(migratedAlert).toMatchObject({ + ...alert, + attributes: { + ...alert.attributes, + executionStatus: { + lastExecutionDate: migratedAlert.attributes.executionStatus.lastExecutionDate, + status: 'pending', + error: null, + }, + }, + }); + }); }); describe('7.10.0 migrates with failure', () => { @@ -237,7 +263,7 @@ describe('7.10.0 migrates with failure', () => { function getMockData( overwrites: Record = {} -): SavedObjectUnsanitizedDoc { +): SavedObjectUnsanitizedDoc> { return { attributes: { enabled: true, diff --git a/x-pack/plugins/alerts/server/saved_objects/migrations.ts b/x-pack/plugins/alerts/server/saved_objects/migrations.ts index 537c21e85c0bd..0b2c86b84f67b 100644 --- a/x-pack/plugins/alerts/server/saved_objects/migrations.ts +++ b/x-pack/plugins/alerts/server/saved_objects/migrations.ts @@ -30,7 +30,11 @@ export function getMigrations( // migrate all documents in 7.10 in order to add the "meta" RBAC field return true; }, - pipeMigrations(markAsLegacyAndChangeConsumer, setAlertIdAsDefaultDedupkeyOnPagerDutyActions) + pipeMigrations( + markAsLegacyAndChangeConsumer, + setAlertIdAsDefaultDedupkeyOnPagerDutyActions, + initializeExecutionStatus + ) ); return { @@ -110,6 +114,23 @@ function setAlertIdAsDefaultDedupkeyOnPagerDutyActions( }; } +function initializeExecutionStatus( + doc: SavedObjectUnsanitizedDoc +): SavedObjectUnsanitizedDoc { + const { attributes } = doc; + return { + ...doc, + attributes: { + ...attributes, + executionStatus: { + status: 'pending', + lastExecutionDate: new Date().toISOString(), + error: null, + }, + }, + }; +} + function pipeMigrations(...migrations: AlertMigration[]): AlertMigration { return (doc: SavedObjectUnsanitizedDoc) => migrations.reduce((migratedDoc, nextMigration) => nextMigration(migratedDoc), doc); diff --git a/x-pack/plugins/alerts/server/saved_objects/partially_update_alert.ts b/x-pack/plugins/alerts/server/saved_objects/partially_update_alert.ts index cc25aaba35798..b829a6788a3dd 100644 --- a/x-pack/plugins/alerts/server/saved_objects/partially_update_alert.ts +++ b/x-pack/plugins/alerts/server/saved_objects/partially_update_alert.ts @@ -15,7 +15,9 @@ import { import { AlertAttributesExcludedFromAAD, AlertAttributesExcludedFromAADType } from './index'; -export type PartiallyUpdateableAlertAttributes = Pick; +export type PartiallyUpdateableAlertAttributes = Partial< + Pick +>; export interface PartiallyUpdateAlertSavedObjectOptions { version?: string; diff --git a/x-pack/plugins/alerts/server/task_runner/alert_task_instance.test.ts b/x-pack/plugins/alerts/server/task_runner/alert_task_instance.test.ts index efac4c5dcdc01..cf0dd9d135e27 100644 --- a/x-pack/plugins/alerts/server/task_runner/alert_task_instance.test.ts +++ b/x-pack/plugins/alerts/server/task_runner/alert_task_instance.test.ts @@ -29,6 +29,10 @@ const alert: SanitizedAlert = { throttle: null, muteAll: false, mutedInstanceIds: [], + executionStatus: { + status: 'unknown', + lastExecutionDate: new Date('2020-08-20T19:23:38Z'), + }, }; describe('Alert Task Instance', () => { diff --git a/x-pack/plugins/alerts/server/task_runner/task_runner.test.ts b/x-pack/plugins/alerts/server/task_runner/task_runner.test.ts index 801d30b6406ee..d9af3d0ae6d5b 100644 --- a/x-pack/plugins/alerts/server/task_runner/task_runner.test.ts +++ b/x-pack/plugins/alerts/server/task_runner/task_runner.test.ts @@ -11,14 +11,17 @@ import { ConcreteTaskInstance, TaskStatus } from '../../../task_manager/server'; import { TaskRunnerContext } from './task_runner_factory'; import { TaskRunner } from './task_runner'; import { encryptedSavedObjectsMock } from '../../../encrypted_saved_objects/server/mocks'; -import { loggingSystemMock } from '../../../../../src/core/server/mocks'; +import { + loggingSystemMock, + savedObjectsRepositoryMock, +} from '../../../../../src/core/server/mocks'; import { PluginStartContract as ActionsPluginStart } from '../../../actions/server'; import { actionsMock, actionsClientMock } from '../../../actions/server/mocks'; import { alertsMock, alertsClientMock } from '../mocks'; import { eventLoggerMock } from '../../../event_log/server/event_logger.mock'; import { IEventLogger } from '../../../event_log/server'; import { SavedObjectsErrorHelpers } from '../../../../../src/core/server'; - +import { Alert } from '../../common'; const alertType = { id: 'test', name: 'My test alert', @@ -71,9 +74,10 @@ describe('Task Runner', () => { spaceIdToNamespace: jest.fn().mockReturnValue(undefined), getBasePath: jest.fn().mockReturnValue(undefined), eventLogger: eventLoggerMock.create(), + internalSavedObjectsRepository: savedObjectsRepositoryMock.create(), }; - const mockedAlertTypeSavedObject = { + const mockedAlertTypeSavedObject: Alert = { id: '1', consumer: 'bar', createdAt: new Date('2019-02-12T21:01:22.479Z'), @@ -82,6 +86,7 @@ describe('Task Runner', () => { muteAll: false, enabled: true, alertTypeId: '123', + apiKey: '', apiKeyOwner: 'elastic', schedule: { interval: '10s' }, name: 'alert-name', @@ -102,6 +107,10 @@ describe('Task Runner', () => { }, }, ], + executionStatus: { + status: 'unknown', + lastExecutionDate: new Date('2020-08-20T19:23:38Z'), + }, }; beforeEach(() => { diff --git a/x-pack/plugins/alerts/server/task_runner/task_runner.ts b/x-pack/plugins/alerts/server/task_runner/task_runner.ts index 7ea3f83d747c0..1ccf14a3a5334 100644 --- a/x-pack/plugins/alerts/server/task_runner/task_runner.ts +++ b/x-pack/plugins/alerts/server/task_runner/task_runner.ts @@ -11,7 +11,13 @@ import { ConcreteTaskInstance } from '../../../task_manager/server'; import { createExecutionHandler } from './create_execution_handler'; import { AlertInstance, createAlertInstanceFactory } from '../alert_instance'; import { getNextRunAt } from './get_next_run_at'; -import { validateAlertTypeParams } from '../lib'; +import { + validateAlertTypeParams, + executionStatusFromState, + executionStatusFromError, + alertExecutionStatusToRaw, + ErrorWithReason, +} from '../lib'; import { AlertType, RawAlert, @@ -22,6 +28,7 @@ import { Alert, AlertExecutorOptions, SanitizedAlert, + AlertExecutionStatus, } from '../types'; import { promiseResult, map, Resultable, asOk, asErr, resolveErr } from '../lib/result_type'; import { taskInstanceToAlertTaskInstance } from './alert_task_instance'; @@ -29,6 +36,7 @@ import { EVENT_LOG_ACTIONS } from '../plugin'; import { IEvent, IEventLogger, SAVED_OBJECT_REL_PRIMARY } from '../../../event_log/server'; import { isAlertSavedObjectNotFoundError } from '../lib/is_alert_not_found_error'; import { AlertsClient } from '../alerts_client'; +import { partiallyUpdateAlert } from '../saved_objects'; const FALLBACK_RETRY_INTERVAL: IntervalSchedule = { interval: '5m' }; @@ -204,7 +212,7 @@ export class TaskRunner { event.event = event.event || {}; event.event.outcome = 'failure'; eventLogger.logEvent(event); - throw err; + throw new ErrorWithReason('execute', err); } eventLogger.stopTiming(event); @@ -278,15 +286,22 @@ export class TaskRunner { const { params: { alertId, spaceId }, } = this.taskInstance; + let apiKey: string | null; + try { + apiKey = await this.getApiKeyForAlertPermissions(alertId, spaceId); + } catch (err) { + throw new ErrorWithReason('decrypt', err); + } + const [services, alertsClient] = this.getServicesWithSpaceLevelPermissions(spaceId, apiKey); - const apiKey = await this.getApiKeyForAlertPermissions(alertId, spaceId); - const [services, alertsClient] = await this.getServicesWithSpaceLevelPermissions( - spaceId, - apiKey - ); + let alert: SanitizedAlert; // Ensure API key is still valid and user has access - const alert = await alertsClient.get({ id: alertId }); + try { + alert = await alertsClient.get({ id: alertId }); + } catch (err) { + throw new ErrorWithReason('read', err); + } return { state: await promiseResult( @@ -306,12 +321,38 @@ export class TaskRunner { async run(): Promise { const { - params: { alertId }, + params: { alertId, spaceId }, startedAt: previousStartedAt, state: originalState, } = this.taskInstance; const { state, runAt } = await errorAsAlertTaskRunResult(this.loadAlertAttributesAndRun()); + const namespace = spaceId === 'default' ? undefined : spaceId; + + const executionStatus: AlertExecutionStatus = map( + state, + (alertTaskState: AlertTaskState) => executionStatusFromState(alertTaskState), + (err: Error) => executionStatusFromError(err) + ); + this.logger.debug( + `alertExecutionStatus for ${this.alertType.id}:${alertId}: ${JSON.stringify(executionStatus)}` + ); + + const client = this.context.internalSavedObjectsRepository; + const attributes = { + executionStatus: alertExecutionStatusToRaw(executionStatus), + }; + + try { + await partiallyUpdateAlert(client, alertId, attributes, { + ignore404: true, + namespace, + }); + } catch (err) { + this.logger.error( + `error updating alert execution status for ${this.alertType.id}:${alertId} ${err.message}` + ); + } return { state: map( diff --git a/x-pack/plugins/alerts/server/task_runner/task_runner_factory.test.ts b/x-pack/plugins/alerts/server/task_runner/task_runner_factory.test.ts index 9af7d9ddc44eb..5da8e4296f4dd 100644 --- a/x-pack/plugins/alerts/server/task_runner/task_runner_factory.test.ts +++ b/x-pack/plugins/alerts/server/task_runner/task_runner_factory.test.ts @@ -8,7 +8,10 @@ import sinon from 'sinon'; import { ConcreteTaskInstance, TaskStatus } from '../../../task_manager/server'; import { TaskRunnerContext, TaskRunnerFactory } from './task_runner_factory'; import { encryptedSavedObjectsMock } from '../../../encrypted_saved_objects/server/mocks'; -import { loggingSystemMock } from '../../../../../src/core/server/mocks'; +import { + loggingSystemMock, + savedObjectsRepositoryMock, +} from '../../../../../src/core/server/mocks'; import { actionsMock } from '../../../actions/server/mocks'; import { alertsMock, alertsClientMock } from '../mocks'; import { eventLoggerMock } from '../../../event_log/server/event_logger.mock'; @@ -63,6 +66,7 @@ describe('Task Runner Factory', () => { spaceIdToNamespace: jest.fn().mockReturnValue(undefined), getBasePath: jest.fn().mockReturnValue(undefined), eventLogger: eventLoggerMock.create(), + internalSavedObjectsRepository: savedObjectsRepositoryMock.create(), }; beforeEach(() => { diff --git a/x-pack/plugins/alerts/server/task_runner/task_runner_factory.ts b/x-pack/plugins/alerts/server/task_runner/task_runner_factory.ts index 6f83e34cdbe03..944c4dc64ce7a 100644 --- a/x-pack/plugins/alerts/server/task_runner/task_runner_factory.ts +++ b/x-pack/plugins/alerts/server/task_runner/task_runner_factory.ts @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import { Logger, KibanaRequest } from '../../../../../src/core/server'; +import { Logger, KibanaRequest, ISavedObjectsRepository } from '../../../../../src/core/server'; import { RunContext } from '../../../task_manager/server'; import { EncryptedSavedObjectsClient } from '../../../encrypted_saved_objects/server'; import { PluginStartContract as ActionsPluginStartContract } from '../../../actions/server'; @@ -26,6 +26,7 @@ export interface TaskRunnerContext { encryptedSavedObjectsClient: EncryptedSavedObjectsClient; spaceIdToNamespace: SpaceIdToNamespaceFunction; getBasePath: GetBasePathFunction; + internalSavedObjectsRepository: ISavedObjectsRepository; } export class TaskRunnerFactory { diff --git a/x-pack/plugins/alerts/server/types.ts b/x-pack/plugins/alerts/server/types.ts index 8d568e8b7ecd1..03d41724213ce 100644 --- a/x-pack/plugins/alerts/server/types.ts +++ b/x-pack/plugins/alerts/server/types.ts @@ -24,6 +24,8 @@ import { AlertTypeState, AlertInstanceContext, AlertInstanceState, + AlertExecutionStatuses, + AlertExecutionStatusErrorReasons, } from '../common'; export type WithoutQueryAndParams = Pick>; @@ -115,6 +117,18 @@ export interface AlertMeta extends SavedObjectAttributes { versionApiKeyLastmodified?: string; } +// note that the `error` property is "null-able", as we're doing a partial +// update on the alert when we update this data, but need to ensure we +// delete any previous error if the current status has no error +export interface RawAlertExecutionStatus extends SavedObjectAttributes { + status: AlertExecutionStatuses; + lastExecutionDate: string; + error: null | { + reason: AlertExecutionStatusErrorReasons; + message: string; + }; +} + export type PartialAlert = Pick & Partial>; export interface RawAlert extends SavedObjectAttributes { @@ -136,6 +150,7 @@ export interface RawAlert extends SavedObjectAttributes { muteAll: boolean; mutedInstanceIds: string[]; meta?: AlertMeta; + executionStatus: RawAlertExecutionStatus; } export type AlertInfoParams = Pick< 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 5d9cfb4bb4492..9081831c45497 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 @@ -419,6 +419,10 @@ export const getResult = (): RuleAlertType => ({ muteAll: false, mutedInstanceIds: [], scheduledTaskId: '2dabe330-0702-11ea-8b50-773b89126888', + executionStatus: { + status: 'unknown', + lastExecutionDate: new Date('2020-08-20T19:23:38Z'), + }, }); export const getMlResult = (): RuleAlertType => { @@ -630,6 +634,10 @@ export const getNotificationResult = (): RuleNotificationAlertType => ({ mutedInstanceIds: [], scheduledTaskId: '62b3a130-6b70-11ea-9ce9-6b9818c4cbd7', updatedAt: new Date('2020-03-21T12:37:08.730Z'), + executionStatus: { + status: 'unknown', + lastExecutionDate: new Date('2020-08-20T19:23:38Z'), + }, }); export const getFindNotificationsResultWithSingleHit = (): FindHit => ({ diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/patch_rules.mock.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/patch_rules.mock.ts index aeb136a969aa1..8672c85f98426 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/patch_rules.mock.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/patch_rules.mock.ts @@ -110,6 +110,10 @@ const rule: SanitizedAlert = { muteAll: false, mutedInstanceIds: [], scheduledTaskId: '2dabe330-0702-11ea-8b50-773b89126888', + executionStatus: { + status: 'unknown', + lastExecutionDate: new Date('2020-08-20T19:23:38Z'), + }, }; export const getPatchRulesOptionsMock = (): PatchRulesOptions => ({ diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/alert_api.test.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/alert_api.test.ts index fc5d301cb7cd0..f6cefb77a240e 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/lib/alert_api.test.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/lib/alert_api.test.ts @@ -398,6 +398,10 @@ describe('createAlert', () => { updatedBy: null, muteAll: false, mutedInstanceIds: [], + executionStatus: { + status: 'unknown', + lastExecutionDate: new Date('2020-08-20T19:23:38Z'), + }, }; http.post.mockResolvedValueOnce(resolvedValue); @@ -440,6 +444,10 @@ describe('updateAlert', () => { updatedBy: null, muteAll: false, mutedInstanceIds: [], + executionStatus: { + status: 'unknown', + lastExecutionDate: new Date('2020-08-20T19:23:38Z'), + }, }; http.put.mockResolvedValueOnce(resolvedValue); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/alert_api.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/alert_api.ts index 97feea6ba8a0f..d5711a3e8c919 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/lib/alert_api.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/lib/alert_api.ts @@ -136,7 +136,10 @@ export async function createAlert({ alert, }: { http: HttpSetup; - alert: Omit; + alert: Omit< + AlertWithoutId, + 'createdBy' | 'updatedBy' | 'muteAll' | 'mutedInstanceIds' | 'executionStatus' + >; }): Promise { return await http.post(`${BASE_ALERT_API_PATH}/alert`, { body: JSON.stringify(alert), diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.test.tsx index 16d1a5c7c9c65..5c9969221cfc3 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.test.tsx @@ -757,6 +757,10 @@ function mockAlert(overloads: Partial = {}): Alert { throttle: null, muteAll: false, mutedInstanceIds: [], + executionStatus: { + status: 'unknown', + lastExecutionDate: new Date('2020-08-20T19:23:38Z'), + }, ...overloads, }; } diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details_route.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details_route.test.tsx index 7a40104e97d9f..5ed924c37fe7a 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details_route.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details_route.test.tsx @@ -404,6 +404,10 @@ function mockAlert(overloads: Partial = {}): Alert { throttle: null, muteAll: false, mutedInstanceIds: [], + executionStatus: { + status: 'unknown', + lastExecutionDate: new Date('2020-08-20T19:23:38Z'), + }, ...overloads, }; } diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_instances.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_instances.test.tsx index f59b836a7936e..2c1020ff1d5b3 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_instances.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_instances.test.tsx @@ -254,6 +254,10 @@ function mockAlert(overloads: Partial = {}): Alert { throttle: null, muteAll: false, mutedInstanceIds: [], + executionStatus: { + status: 'unknown', + lastExecutionDate: new Date('2020-08-20T19:23:38Z'), + }, ...overloads, }; } diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_instances_route.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_instances_route.test.tsx index d92148a8fea53..603f06d0bbae4 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_instances_route.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_instances_route.test.tsx @@ -132,6 +132,10 @@ function mockAlert(overloads: Partial = {}): Alert { throttle: null, muteAll: false, mutedInstanceIds: [], + executionStatus: { + status: 'unknown', + lastExecutionDate: new Date('2020-08-20T19:23:38Z'), + }, ...overloads, }; } diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/view_in_app.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/view_in_app.test.tsx index 54d335aaba5aa..7e43fd22ff8c8 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/view_in_app.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/view_in_app.test.tsx @@ -105,6 +105,10 @@ function mockAlert(overloads: Partial = {}): Alert { throttle: null, muteAll: false, mutedInstanceIds: [], + executionStatus: { + status: 'unknown', + lastExecutionDate: new Date('2020-08-20T19:23:38Z'), + }, ...overloads, }; } diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_edit.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_edit.test.tsx index e408c7fcb8144..24eb7aabb9549 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_edit.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_edit.test.tsx @@ -8,7 +8,7 @@ import { mountWithIntl, nextTick } from 'test_utils/enzyme_helpers'; import { act } from 'react-dom/test-utils'; import { coreMock } from '../../../../../../../src/core/public/mocks'; import { actionTypeRegistryMock } from '../../action_type_registry.mock'; -import { ValidationResult } from '../../../types'; +import { ValidationResult, Alert } from '../../../types'; import { AlertsContextProvider } from '../../context/alerts_context'; import { alertTypeRegistryMock } from '../../alert_type_registry.mock'; import { ReactWrapper } from 'enzyme'; @@ -73,7 +73,7 @@ describe('alert_edit', () => { actionParamsFields: null, }; - const alert = { + const alert: Alert = { id: 'ab5661e0-197e-45ee-b477-302d89193b5e', params: { aggType: 'average', @@ -93,7 +93,6 @@ describe('alert_edit', () => { actionTypeId: 'my-action-type', group: 'threshold met', params: { message: 'Alert [{{ctx.metadata.name}}] has exceeded the threshold' }, - message: 'Alert [{{ctx.metadata.name}}] has exceeded the threshold', id: '917f5d41-fbc4-4056-a8ad-ac592f7dcee2', }, ], @@ -107,6 +106,10 @@ describe('alert_edit', () => { muteAll: false, mutedInstanceIds: [], updatedAt: new Date(), + executionStatus: { + status: 'unknown', + lastExecutionDate: new Date('2020-08-20T19:23:38Z'), + }, }; actionTypeRegistry.get.mockReturnValueOnce(actionTypeModel); actionTypeRegistry.has.mockReturnValue(true); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/with_bulk_alert_api_operations.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/with_bulk_alert_api_operations.test.tsx index 074e2d5147b5e..72d4f8857a610 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/with_bulk_alert_api_operations.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/with_bulk_alert_api_operations.test.tsx @@ -264,6 +264,10 @@ function mockAlert(overloads: Partial = {}): Alert { throttle: null, muteAll: false, mutedInstanceIds: [], + executionStatus: { + status: 'unknown', + lastExecutionDate: new Date('2020-08-20T19:23:38Z'), + }, ...overloads, }; } diff --git a/x-pack/test/alerting_api_integration/common/lib/test_assertions.ts b/x-pack/test/alerting_api_integration/common/lib/test_assertions.ts index 9495dd4cfae82..6124a5fb7c358 100644 --- a/x-pack/test/alerting_api_integration/common/lib/test_assertions.ts +++ b/x-pack/test/alerting_api_integration/common/lib/test_assertions.ts @@ -15,3 +15,21 @@ export function ensureDatetimeIsWithinRange( expect(diff).to.be.greaterThan(expectedDiff - buffer); expect(diff).to.be.lessThan(expectedDiff + buffer); } + +export function ensureDatetimesAreOrdered(dates: Array) { + const dateStrings = dates.map(normalizeDate); + const sortedDateStrings = dateStrings.slice().sort(); + expect(dateStrings).to.eql(sortedDateStrings); +} + +function normalizeDate(date: Date | string | number): string { + if (typeof date === 'number') return new Date(date).toISOString(); + if (date instanceof Date) return date.toISOString(); + + const dateString = `${date}`; + const dateNumber = Date.parse(dateString); + if (isNaN(dateNumber)) { + throw new Error(`invalid date string: "${dateString}"`); + } + return new Date(dateNumber).toISOString(); +} diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/create.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/create.ts index 983f87405a1a6..19d90378e8b7a 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/create.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/create.ts @@ -119,6 +119,7 @@ export default function createAlertTests({ getService }: FtrProviderContext) { apiKeyOwner: user.username, muteAll: false, mutedInstanceIds: [], + executionStatus: response.body.executionStatus, }); expect(typeof response.body.scheduledTaskId).to.be('string'); expect(Date.parse(response.body.createdAt)).to.be.greaterThan(0); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/execution_status.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/execution_status.ts new file mode 100644 index 0000000000000..8fb89042e4a90 --- /dev/null +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/execution_status.ts @@ -0,0 +1,87 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import expect from '@kbn/expect'; +import { Spaces } from '../../scenarios'; +import { getUrlPrefix, getTestAlertData, ObjectRemover } from '../../../common/lib'; +import { FtrProviderContext } from '../../../common/ftr_provider_context'; + +// eslint-disable-next-line import/no-default-export +export default function executionStatusAlertTests({ getService }: FtrProviderContext) { + const supertest = getService('supertest'); + const spaceId = Spaces[0].id; + + // the only tests here are those that can't be run in spaces_only + describe('executionStatus', () => { + const objectRemover = new ObjectRemover(supertest); + + after(async () => await objectRemover.removeAll()); + + it('should eventually have error reason "decrypt" when appropriate', async () => { + const response = await supertest + .post(`${getUrlPrefix(spaceId)}/api/alerts/alert`) + .set('kbn-xsrf', 'foo') + .send( + getTestAlertData({ + alertTypeId: 'test.noop', + schedule: { interval: '1s' }, + }) + ); + expect(response.status).to.eql(200); + const alertId = response.body.id; + objectRemover.add(spaceId, alertId, 'alert', 'alerts'); + + let executionStatus = await waitForStatus(alertId, new Set(['ok']), 10000); + + // break AAD + await supertest + .put(`${getUrlPrefix(spaceId)}/api/alerts_fixture/saved_object/alert/${alertId}`) + .set('kbn-xsrf', 'foo') + .send({ + attributes: { + name: 'bar', + }, + }) + .expect(200); + + executionStatus = await waitForStatus(alertId, new Set(['error'])); + expect(executionStatus.error).to.be.ok(); + expect(executionStatus.error.reason).to.be('decrypt'); + expect(executionStatus.error.message).to.be('Unable to decrypt attribute "apiKey"'); + }); + }); + + const WaitForStatusIncrement = 500; + + async function waitForStatus( + id: string, + statuses: Set, + waitMillis: number = 10000 + ): Promise> { + if (waitMillis < 0) { + expect().fail(`waiting for alert ${id} statuses ${Array.from(statuses)} timed out`); + } + + const response = await supertest.get(`${getUrlPrefix(spaceId)}/api/alerts/alert/${id}`); + expect(response.status).to.eql(200); + const { status } = response.body.executionStatus; + if (statuses.has(status)) return response.body.executionStatus; + + // eslint-disable-next-line no-console + console.log( + `waitForStatus(${Array.from(statuses)}): got ${JSON.stringify( + response.body.executionStatus + )}, retrying` + ); + + await delay(WaitForStatusIncrement); + return await waitForStatus(id, statuses, waitMillis - WaitForStatusIncrement); + } +} + +async function delay(millis: number): Promise { + await new Promise((resolve) => setTimeout(resolve, millis)); +} diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/find.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/find.ts index 268212d4294d0..adfe5cd27b33a 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/find.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/find.ts @@ -79,6 +79,7 @@ export default function createFindTests({ getService }: FtrProviderContext) { apiKeyOwner: 'elastic', muteAll: false, mutedInstanceIds: [], + executionStatus: match.executionStatus, }); expect(Date.parse(match.createdAt)).to.be.greaterThan(0); expect(Date.parse(match.updatedAt)).to.be.greaterThan(0); @@ -273,6 +274,7 @@ export default function createFindTests({ getService }: FtrProviderContext) { mutedInstanceIds: [], createdAt: match.createdAt, updatedAt: match.updatedAt, + executionStatus: match.executionStatus, }); expect(Date.parse(match.createdAt)).to.be.greaterThan(0); expect(Date.parse(match.updatedAt)).to.be.greaterThan(0); @@ -359,6 +361,85 @@ export default function createFindTests({ getService }: FtrProviderContext) { } }); + it('should handle find alert request with executionStatus field appropriately', async () => { + const myTag = uuid.v4(); + const { body: createdAlert } = await supertest + .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .set('kbn-xsrf', 'foo') + .send( + getTestAlertData({ + enabled: false, + tags: [myTag], + alertTypeId: 'test.restricted-noop', + consumer: 'alertsRestrictedFixture', + }) + ) + .expect(200); + objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); + + // create another type with same tag + const { body: createdSecondAlert } = await supertest + .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .set('kbn-xsrf', 'foo') + .send( + getTestAlertData({ + tags: [myTag], + alertTypeId: 'test.restricted-noop', + consumer: 'alertsRestrictedFixture', + }) + ) + .expect(200); + objectRemover.add(space.id, createdSecondAlert.id, 'alert', 'alerts'); + + const response = await supertestWithoutAuth + .get( + `${getUrlPrefix( + space.id + )}/api/alerts/_find?filter=alert.attributes.alertTypeId:test.restricted-noop&fields=["tags","executionStatus"]&sort_field=createdAt` + ) + .auth(user.username, user.password); + + switch (scenario.id) { + case 'no_kibana_privileges at space1': + case 'space_1_all at space2': + expect(response.statusCode).to.eql(403); + expect(response.body).to.eql({ + error: 'Forbidden', + message: `Unauthorized to find any alert types`, + statusCode: 403, + }); + break; + case 'space_1_all at space1': + case 'space_1_all_alerts_none_actions at space1': + expect(response.statusCode).to.eql(200); + expect(response.body.data).to.eql([]); + break; + case 'global_read at space1': + case 'superuser at space1': + case 'space_1_all_with_restricted_fixture at space1': + expect(response.statusCode).to.eql(200); + expect(response.body.page).to.equal(1); + expect(response.body.perPage).to.be.greaterThan(0); + expect(response.body.total).to.be.greaterThan(0); + const [matchFirst, matchSecond] = response.body.data; + expect(omit(matchFirst, 'updatedAt')).to.eql({ + id: createdAlert.id, + actions: [], + tags: [myTag], + executionStatus: matchFirst.executionStatus, + }); + expect(omit(matchSecond, 'updatedAt')).to.eql({ + id: createdSecondAlert.id, + actions: [], + tags: [myTag], + executionStatus: matchSecond.executionStatus, + }); + break; + default: + throw new Error(`Scenario untested: ${JSON.stringify(scenario)}`); + } + }); + it(`shouldn't find alert from another space`, async () => { const { body: createdAlert } = await supertest .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/get.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/get.ts index 1043ece08a2ac..93e9be771ab5c 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/get.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/get.ts @@ -75,6 +75,7 @@ export default function createGetTests({ getService }: FtrProviderContext) { apiKeyOwner: 'elastic', muteAll: false, mutedInstanceIds: [], + executionStatus: response.body.executionStatus, }); expect(Date.parse(response.body.createdAt)).to.be.greaterThan(0); expect(Date.parse(response.body.updatedAt)).to.be.greaterThan(0); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/index.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/index.ts index fa0130780cb69..1fbee9e18fdaa 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/index.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/index.ts @@ -14,6 +14,7 @@ export default function alertingTests({ loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./delete')); loadTestFile(require.resolve('./disable')); loadTestFile(require.resolve('./enable')); + loadTestFile(require.resolve('./execution_status')); loadTestFile(require.resolve('./get')); loadTestFile(require.resolve('./get_alert_state')); loadTestFile(require.resolve('./get_alert_instance_summary')); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/update.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/update.ts index 48269cc1c4498..d75aa868253de 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/update.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/update.ts @@ -129,6 +129,7 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { scheduledTaskId: createdAlert.scheduledTaskId, createdAt: response.body.createdAt, updatedAt: response.body.updatedAt, + executionStatus: response.body.executionStatus, }); expect(Date.parse(response.body.createdAt)).to.be.greaterThan(0); expect(Date.parse(response.body.updatedAt)).to.be.greaterThan(0); @@ -211,6 +212,7 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { scheduledTaskId: createdAlert.scheduledTaskId, createdAt: response.body.createdAt, updatedAt: response.body.updatedAt, + executionStatus: response.body.executionStatus, }); expect(Date.parse(response.body.createdAt)).to.be.greaterThan(0); expect(Date.parse(response.body.updatedAt)).to.be.greaterThan(0); @@ -304,6 +306,7 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { scheduledTaskId: createdAlert.scheduledTaskId, createdAt: response.body.createdAt, updatedAt: response.body.updatedAt, + executionStatus: response.body.executionStatus, }); expect(Date.parse(response.body.createdAt)).to.be.greaterThan(0); expect(Date.parse(response.body.updatedAt)).to.be.greaterThan(0); @@ -397,6 +400,7 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { scheduledTaskId: createdAlert.scheduledTaskId, createdAt: response.body.createdAt, updatedAt: response.body.updatedAt, + executionStatus: response.body.executionStatus, }); expect(Date.parse(response.body.createdAt)).to.be.greaterThan(0); expect(Date.parse(response.body.updatedAt)).to.be.greaterThan(0); @@ -486,6 +490,7 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { scheduledTaskId: createdAlert.scheduledTaskId, createdAt: response.body.createdAt, updatedAt: response.body.updatedAt, + executionStatus: response.body.executionStatus, }); expect(Date.parse(response.body.createdAt)).to.be.greaterThan(0); expect(Date.parse(response.body.updatedAt)).to.be.greaterThan(0); 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 86775f77a7671..41f6b66c30aaf 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 @@ -87,6 +87,7 @@ export default function createAlertTests({ getService }: FtrProviderContext) { mutedInstanceIds: [], createdAt: response.body.createdAt, updatedAt: response.body.updatedAt, + executionStatus: response.body.executionStatus, }); expect(Date.parse(response.body.createdAt)).to.be.greaterThan(0); expect(Date.parse(response.body.updatedAt)).to.be.greaterThan(0); diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/execution_status.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/execution_status.ts new file mode 100644 index 0000000000000..ac63fe8faadc7 --- /dev/null +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/execution_status.ts @@ -0,0 +1,333 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import expect from '@kbn/expect'; +import { Spaces } from '../../scenarios'; +import { + checkAAD, + getUrlPrefix, + getTestAlertData, + ObjectRemover, + ensureDatetimesAreOrdered, +} from '../../../common/lib'; +import { FtrProviderContext } from '../../../common/ftr_provider_context'; + +// eslint-disable-next-line import/no-default-export +export default function executionStatusAlertTests({ getService }: FtrProviderContext) { + const supertest = getService('supertest'); + + describe('executionStatus', () => { + const objectRemover = new ObjectRemover(supertest); + + after(async () => await objectRemover.removeAll()); + + it('should be "pending" for newly created alert', async () => { + const dateStart = Date.now(); + const response = await supertest + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert`) + .set('kbn-xsrf', 'foo') + .send(getTestAlertData()); + const dateEnd = Date.now(); + expect(response.status).to.eql(200); + objectRemover.add(Spaces.space1.id, response.body.id, 'alert', 'alerts'); + + expect(response.body.executionStatus).to.be.ok(); + const { status, lastExecutionDate, error } = response.body.executionStatus; + expect(status).to.be('pending'); + ensureDatetimesAreOrdered([dateStart, lastExecutionDate, dateEnd]); + expect(error).not.to.be.ok(); + + // Ensure AAD isn't broken + await checkAAD({ + supertest, + spaceId: Spaces.space1.id, + type: 'alert', + id: response.body.id, + }); + }); + + it('should eventually be "ok" for no-op alert', async () => { + const dates = []; + dates.push(Date.now()); + const response = await supertest + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert`) + .set('kbn-xsrf', 'foo') + .send( + getTestAlertData({ + alertTypeId: 'test.noop', + schedule: { interval: '1s' }, + }) + ); + expect(response.status).to.eql(200); + const alertId = response.body.id; + dates.push(response.body.executionStatus.lastExecutionDate); + dates.push(Date.now()); + objectRemover.add(Spaces.space1.id, alertId, 'alert', 'alerts'); + + const executionStatus = await waitForStatus(alertId, new Set(['ok'])); + dates.push(executionStatus.lastExecutionDate); + dates.push(Date.now()); + ensureDatetimesAreOrdered(dates); + + // Ensure AAD isn't broken + await checkAAD({ + supertest, + spaceId: Spaces.space1.id, + type: 'alert', + id: response.body.id, + }); + }); + + it('should eventually be "active" for firing alert', async () => { + const dates = []; + dates.push(Date.now()); + const response = await supertest + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert`) + .set('kbn-xsrf', 'foo') + .send( + getTestAlertData({ + alertTypeId: 'test.patternFiring', + schedule: { interval: '1s' }, + params: { + pattern: { instance: trues(100) }, + }, + }) + ); + expect(response.status).to.eql(200); + const alertId = response.body.id; + dates.push(response.body.executionStatus.lastExecutionDate); + dates.push(Date.now()); + objectRemover.add(Spaces.space1.id, alertId, 'alert', 'alerts'); + + const executionStatus = await waitForStatus(alertId, new Set(['active'])); + dates.push(executionStatus.lastExecutionDate); + dates.push(Date.now()); + ensureDatetimesAreOrdered(dates); + + // Ensure AAD isn't broken + await checkAAD({ + supertest, + spaceId: Spaces.space1.id, + type: 'alert', + id: response.body.id, + }); + }); + + it('should eventually be "error" for an error alert', async () => { + const dates = []; + dates.push(Date.now()); + const response = await supertest + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert`) + .set('kbn-xsrf', 'foo') + .send( + getTestAlertData({ + alertTypeId: 'test.throw', + schedule: { interval: '1s' }, + }) + ); + expect(response.status).to.eql(200); + const alertId = response.body.id; + dates.push(response.body.executionStatus.lastExecutionDate); + dates.push(Date.now()); + objectRemover.add(Spaces.space1.id, alertId, 'alert', 'alerts'); + + const executionStatus = await waitForStatus(alertId, new Set(['error'])); + dates.push(executionStatus.lastExecutionDate); + dates.push(Date.now()); + ensureDatetimesAreOrdered(dates); + + // Ensure AAD isn't broken + await checkAAD({ + supertest, + spaceId: Spaces.space1.id, + type: 'alert', + id: response.body.id, + }); + }); + + // not sure how to test the read error reason! + + // note the decrypt error reason is tested in security_and_spaces, can't be tested + // without security on + + it('should eventually have error reason "execute" when appropriate', async () => { + const response = await supertest + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert`) + .set('kbn-xsrf', 'foo') + .send( + getTestAlertData({ + alertTypeId: 'test.throw', + schedule: { interval: '1s' }, + }) + ); + expect(response.status).to.eql(200); + const alertId = response.body.id; + objectRemover.add(Spaces.space1.id, alertId, 'alert', 'alerts'); + + const executionStatus = await waitForStatus(alertId, new Set(['error'])); + expect(executionStatus.error).to.be.ok(); + expect(executionStatus.error.reason).to.be('execute'); + expect(executionStatus.error.message).to.be('this alert is intended to fail'); + }); + + it('should eventually have error reason "unknown" when appropriate', async () => { + const response = await supertest + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert`) + .set('kbn-xsrf', 'foo') + .send( + getTestAlertData({ + alertTypeId: 'test.validation', + schedule: { interval: '1s' }, + params: { param1: 'valid now, but will change to a number soon!' }, + }) + ); + expect(response.status).to.eql(200); + const alertId = response.body.id; + objectRemover.add(Spaces.space1.id, alertId, 'alert', 'alerts'); + + let executionStatus = await waitForStatus(alertId, new Set(['ok'])); + + // break the validation of the params + await supertest + .put(`${getUrlPrefix(Spaces.space1.id)}/api/alerts_fixture/saved_object/alert/${alertId}`) + .set('kbn-xsrf', 'foo') + .send({ + attributes: { + params: { param1: 42 }, + }, + }) + .expect(200); + + executionStatus = await waitForStatus(alertId, new Set(['error'])); + expect(executionStatus.error).to.be.ok(); + expect(executionStatus.error.reason).to.be('unknown'); + + const message = 'params invalid: [param1]: expected value of type [string] but got [number]'; + expect(executionStatus.error.message).to.be(message); + }); + + it('should be able to find over all the fields', async () => { + const startDate = Date.now(); + const createResponse = await supertest + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert`) + .set('kbn-xsrf', 'foo') + .send( + getTestAlertData({ + alertTypeId: 'test.throw', + schedule: { interval: '1s' }, + }) + ); + expect(createResponse.status).to.eql(200); + const alertId = createResponse.body.id; + objectRemover.add(Spaces.space1.id, alertId, 'alert', 'alerts'); + + await waitForStatus(alertId, new Set(['error'])); + + let filter = `lastExecutionDate>${startDate}`; + let executionStatus = await waitForFindStatus(alertId, new Set(['error']), filter); + expectErrorExecutionStatus(executionStatus, startDate); + + filter = `status:error`; + executionStatus = await waitForFindStatus(alertId, new Set(['error']), filter); + expectErrorExecutionStatus(executionStatus, startDate); + + filter = `error.message:*intended*`; + executionStatus = await waitForFindStatus(alertId, new Set(['error']), filter); + expectErrorExecutionStatus(executionStatus, startDate); + + filter = `error.reason:execute`; + executionStatus = await waitForFindStatus(alertId, new Set(['error']), filter); + expectErrorExecutionStatus(executionStatus, startDate); + }); + }); + + const WaitForStatusIncrement = 500; + + async function waitForStatus( + id: string, + statuses: Set, + waitMillis: number = 10000 + ): Promise> { + if (waitMillis < 0) { + expect().fail(`waiting for alert ${id} statuses ${Array.from(statuses)} timed out`); + } + + const response = await supertest.get( + `${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert/${id}` + ); + expect(response.status).to.eql(200); + const { status } = response.body.executionStatus; + + const message = `waitForStatus(${Array.from(statuses)}): got ${JSON.stringify( + response.body.executionStatus + )}`; + + if (statuses.has(status)) { + return response.body.executionStatus; + } + + // eslint-disable-next-line no-console + console.log(`${message}, retrying`); + + await delay(WaitForStatusIncrement); + return await waitForStatus(id, statuses, waitMillis - WaitForStatusIncrement); + } + + async function waitForFindStatus( + id: string, + statuses: Set, + filter: string, + waitMillis: number = 10000 + ): Promise> { + if (waitMillis < 0) { + expect().fail(`waiting for find alert ${id} statuses ${Array.from(statuses)} timed out`); + } + + const findUri = getFindUri(filter); + const response = await supertest.get(`${getUrlPrefix(Spaces.space1.id)}/${findUri}`); + + expect(response.status).to.eql(200); + const { executionStatus } = response.body.data.find((obj: any) => obj.id === id); + + const message = `waitForFindStatus(${Array.from(statuses)}): got ${JSON.stringify( + executionStatus + )}`; + + if (statuses.has(executionStatus.status)) { + return executionStatus; + } + + // eslint-disable-next-line no-console + console.log(`${message}, retrying`); + + await delay(WaitForStatusIncrement); + return await waitForStatus(id, statuses, waitMillis - WaitForStatusIncrement); + } +} + +function expectErrorExecutionStatus(executionStatus: Record, startDate: number) { + expect(executionStatus.status).to.equal('error'); + + const statusDate = Date.parse(executionStatus.lastExecutionDate); + const stopDate = Date.now(); + expect(startDate).to.be.lessThan(statusDate); + expect(stopDate).to.be.greaterThan(statusDate); + + expect(executionStatus.error.message).to.equal('this alert is intended to fail'); + expect(executionStatus.error.reason).to.equal('execute'); +} + +function getFindUri(filter: string) { + return `api/alerts/_find?filter=alert.attributes.executionStatus.${filter}`; +} + +function trues(length: number): boolean[] { + return new Array(length).fill(true); +} + +async function delay(millis: number): Promise { + await new Promise((resolve) => setTimeout(resolve, millis)); +} diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/find.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/find.ts index b28ce89b30472..850ec24789f5b 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/find.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/find.ts @@ -56,6 +56,7 @@ export default function createFindTests({ getService }: FtrProviderContext) { mutedInstanceIds: [], createdAt: match.createdAt, updatedAt: match.updatedAt, + executionStatus: match.executionStatus, }); expect(Date.parse(match.createdAt)).to.be.greaterThan(0); expect(Date.parse(match.updatedAt)).to.be.greaterThan(0); diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/get.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/get.ts index 165eaa09126a8..14a57f57c9237 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/get.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/get.ts @@ -50,6 +50,7 @@ export default function createGetTests({ getService }: FtrProviderContext) { mutedInstanceIds: [], createdAt: response.body.createdAt, updatedAt: response.body.updatedAt, + executionStatus: response.body.executionStatus, }); expect(Date.parse(response.body.createdAt)).to.be.greaterThan(0); expect(Date.parse(response.body.updatedAt)).to.be.greaterThan(0); diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/index.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/index.ts index 1907eed728053..a80970788e517 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/index.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/index.ts @@ -23,6 +23,7 @@ export default function alertingTests({ loadTestFile, getService }: FtrProviderC loadTestFile(require.resolve('./get_alert_instance_summary')); loadTestFile(require.resolve('./list_alert_types')); loadTestFile(require.resolve('./event_log')); + loadTestFile(require.resolve('./execution_status')); loadTestFile(require.resolve('./mute_all')); loadTestFile(require.resolve('./mute_instance')); loadTestFile(require.resolve('./unmute_all')); diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/update.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/update.ts index 9c8e6f6b8d94c..f44a7d7131879 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/update.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/update.ts @@ -57,6 +57,7 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { scheduledTaskId: createdAlert.scheduledTaskId, createdAt: response.body.createdAt, updatedAt: response.body.updatedAt, + executionStatus: response.body.executionStatus, }); expect(Date.parse(response.body.createdAt)).to.be.greaterThan(0); expect(Date.parse(response.body.updatedAt)).to.be.greaterThan(0); diff --git a/x-pack/test/detection_engine_api_integration/utils.ts b/x-pack/test/detection_engine_api_integration/utils.ts index 1dba1a154373b..5d82eed41d3c5 100644 --- a/x-pack/test/detection_engine_api_integration/utils.ts +++ b/x-pack/test/detection_engine_api_integration/utils.ts @@ -248,16 +248,25 @@ export const getSimpleMlRuleOutput = (ruleId = 'rule-1'): Partial = export const deleteAllAlerts = async (es: Client, retryCount = 20): Promise => { if (retryCount > 0) { try { - await es.deleteByQuery({ + const result = await es.deleteByQuery({ index: '.kibana', q: 'type:alert', wait_for_completion: true, refresh: true, + conflicts: 'proceed', body: {}, }); + // deleteByQuery will cause version conflicts as alerts are being updated + // by background processes; the code below accounts for that + if (result.body.version_conflicts !== 0) { + throw new Error(`Version conflicts for ${result.body.version_conflicts} alerts`); + } } catch (err) { // eslint-disable-next-line no-console - console.log(`Failure trying to deleteAllAlerts, retries left are: ${retryCount - 1}`, err); + console.log(`Error in deleteAllAlerts(), retries left: ${retryCount - 1}`, err); + + // retry, counting down, and delay a bit before + await new Promise((resolve) => setTimeout(resolve, 250)); await deleteAllAlerts(es, retryCount - 1); } } else { From d6c712842d86482d23534298315d3f849384496d Mon Sep 17 00:00:00 2001 From: Frank Hassanabad Date: Thu, 1 Oct 2020 16:31:00 -0600 Subject: [PATCH 20/50] [Security Solution][Detection Engine] Adds threat matching to the rule creator (#78955) ## Summary This adds threat matching rule type to the rule creator. Screen shot of creating a threat match Screen Shot 2020-09-30 at 3 31 09 PM --- Screen shot of the description after creating one Screen Shot 2020-09-30 at 3 29 32 PM --- Screen shot of first creating a threat match without values filled out Screen Shot 2020-09-30 at 3 27 29 PM Additions and bug fixes: * Changes the threat index to be an array * Adds a threat_language to the REST schema so that we can use KQL, Lucene, (others in the future) * Adds plumbing for threat_list to work with the other REST endpoints such as PUT, PATCH, etc... * Adds the AND, OR dialog and user interface **Usage** If you are a team member using the team servers you can skip this usage section of creating threat index. Otherwise if you want to know how to create a mock threat index, instructions are below. Go to the folder: ```ts /kibana/x-pack/plugins/security_solution/server/lib/detection_engine/scripts ``` And post a small ECS threat mapping to the index called `mock-threat-list`: ```ts ./create_threat_mapping.sh ``` Then to post a small number of threats that represent simple port numbers you can run: ```ts ./create_threat_data.sh ``` However, feel free to also manually create them directly in your dev tools like so: ```ts # Posts a threat list item called some-name with an IP but change these out for valid data in your system PUT mock-threat-list-1/_doc/9999 { "@timestamp": "2020-09-09T20:30:45.725Z", "host": { "name": "some-name", "ip": "127.0.0.1" } } ``` ```ts # Posts a destination port number to watch PUT mock-threat-list-1/_doc/10000 { "@timestamp": "2020-09-08T20:30:45.725Z", "destination": { "port": "443" } } ``` ```ts # Posts a source port number to watch PUT mock-threat-list-1/_doc/10001 { "@timestamp": "2020-09-08T20:30:45.725Z", "source": { "port": "443" } } ``` ### Checklist - [x] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/master/packages/kbn-i18n/README.md) - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [ ] This was checked for [keyboard-only and screenreader accessibility](https://developer.mozilla.org/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Accessibility#Accessibility_testing_checklist) - [ ] This renders correctly on smaller devices using a responsive layout. (You can test this [in your browser](https://www.browserstack.com/guide/responsive-testing-on-local-server) - [ ] This was checked for [cross-browser compatibility](https://www.elastic.co/support/matrix#matrix_browsers) --- .../add_prepackaged_rules_schema.mock.ts | 4 +- .../request/add_prepackaged_rules_schema.ts | 2 + .../request/create_rules_schema.mock.ts | 4 +- .../schemas/request/create_rules_schema.ts | 2 + .../request/import_rules_schema.mock.ts | 4 +- .../schemas/request/import_rules_schema.ts | 2 + .../schemas/request/patch_rules_schema.ts | 12 + .../schemas/request/update_rules_schema.ts | 12 + .../schemas/response/rules_schema.mocks.ts | 2 +- .../schemas/response/rules_schema.test.ts | 4 +- .../schemas/response/rules_schema.ts | 3 + .../detection_engine/schemas/types/index.ts | 1 + .../schemas/types/threat_mapping.ts | 40 +- .../threat_match/and_badge.test.tsx | 46 +++ .../components/threat_match/and_badge.tsx | 50 +++ .../threat_match/entry_delete_button.test.tsx | 123 ++++++ .../threat_match/entry_delete_button.tsx | 67 +++ .../threat_match/entry_item.test.tsx | 130 ++++++ .../components/threat_match/entry_item.tsx | 131 ++++++ .../components/threat_match/helpers.test.tsx | 225 +++++++++++ .../components/threat_match/helpers.tsx | 171 ++++++++ .../components/threat_match/index.test.tsx | 304 ++++++++++++++ .../common/components/threat_match/index.tsx | 220 ++++++++++ .../threat_match/list_item.test.tsx | 382 ++++++++++++++++++ .../components/threat_match/list_item.tsx | 120 ++++++ .../threat_match/logic_buttons.stories.tsx | 49 +++ .../threat_match/logic_buttons.test.tsx | 90 +++++ .../components/threat_match/logic_buttons.tsx | 55 +++ .../components/threat_match/reducer.test.ts | 101 +++++ .../common/components/threat_match/reducer.ts | 51 +++ .../components/threat_match/translations.ts | 37 ++ .../common/components/threat_match/types.ts | 26 ++ .../rules/description_step/helpers.tsx | 42 +- .../rules/description_step/index.tsx | 22 +- .../rules/description_step/translations.tsx | 7 + .../rules/description_step/types.ts | 1 + .../rules/select_rule_type/index.tsx | 23 ++ .../rules/select_rule_type/translations.ts | 14 + .../rules/step_define_rule/index.tsx | 63 ++- .../rules/step_define_rule/schema.tsx | 136 ++++++- .../rules/step_define_rule/translations.tsx | 21 + .../rules/threatmatch_input/index.tsx | 114 ++++++ .../rules/threatmatch_input/translations.ts | 14 + .../detection_engine/rules/types.ts | 14 +- .../rules/all/__mocks__/mock.ts | 3 + .../detection_engine/rules/create/helpers.ts | 80 +++- .../detection_engine/rules/create/index.tsx | 8 +- .../detection_engine/rules/helpers.test.tsx | 30 ++ .../pages/detection_engine/rules/helpers.tsx | 8 +- .../pages/detection_engine/rules/types.ts | 9 +- .../routes/__mocks__/request_responses.ts | 1 + .../routes/rules/create_rules_bulk_route.ts | 2 + .../routes/rules/create_rules_route.ts | 2 + .../routes/rules/import_rules_route.ts | 9 +- .../routes/rules/patch_rules_bulk_route.ts | 10 + .../routes/rules/patch_rules_route.ts | 10 + .../routes/rules/update_rules_bulk_route.ts | 10 + .../routes/rules/update_rules_route.ts | 10 + .../routes/rules/utils.test.ts | 4 +- .../detection_engine/routes/rules/utils.ts | 1 + .../rules/create_rules.mock.ts | 2 + .../detection_engine/rules/create_rules.ts | 2 + .../rules/install_prepacked_rules.ts | 2 + .../rules/patch_rules.mock.ts | 10 + .../lib/detection_engine/rules/patch_rules.ts | 15 + .../lib/detection_engine/rules/types.ts | 12 + .../rules/update_prepacked_rules.ts | 10 + .../rules/update_rules.mock.ts | 10 + .../detection_engine/rules/update_rules.ts | 15 + .../lib/detection_engine/rules/utils.test.ts | 15 + .../lib/detection_engine/rules/utils.ts | 14 +- .../queries/query_with_threat_mapping.json | 2 +- .../signals/__mocks__/es_results.ts | 1 + .../detection_engine/signals/build_rule.ts | 1 + .../signals/signal_params_schema.ts | 3 +- .../signals/signal_rule_alert_type.ts | 2 + .../threat_mapping/create_threat_signal.ts | 4 +- .../threat_mapping/create_threat_signals.ts | 5 +- .../signals/threat_mapping/get_threat_list.ts | 9 +- .../signals/threat_mapping/types.ts | 9 +- .../server/lib/detection_engine/types.ts | 2 + 81 files changed, 3224 insertions(+), 59 deletions(-) create mode 100644 x-pack/plugins/security_solution/public/common/components/threat_match/and_badge.test.tsx create mode 100644 x-pack/plugins/security_solution/public/common/components/threat_match/and_badge.tsx create mode 100644 x-pack/plugins/security_solution/public/common/components/threat_match/entry_delete_button.test.tsx create mode 100644 x-pack/plugins/security_solution/public/common/components/threat_match/entry_delete_button.tsx create mode 100644 x-pack/plugins/security_solution/public/common/components/threat_match/entry_item.test.tsx create mode 100644 x-pack/plugins/security_solution/public/common/components/threat_match/entry_item.tsx create mode 100644 x-pack/plugins/security_solution/public/common/components/threat_match/helpers.test.tsx create mode 100644 x-pack/plugins/security_solution/public/common/components/threat_match/helpers.tsx create mode 100644 x-pack/plugins/security_solution/public/common/components/threat_match/index.test.tsx create mode 100644 x-pack/plugins/security_solution/public/common/components/threat_match/index.tsx create mode 100644 x-pack/plugins/security_solution/public/common/components/threat_match/list_item.test.tsx create mode 100644 x-pack/plugins/security_solution/public/common/components/threat_match/list_item.tsx create mode 100644 x-pack/plugins/security_solution/public/common/components/threat_match/logic_buttons.stories.tsx create mode 100644 x-pack/plugins/security_solution/public/common/components/threat_match/logic_buttons.test.tsx create mode 100644 x-pack/plugins/security_solution/public/common/components/threat_match/logic_buttons.tsx create mode 100644 x-pack/plugins/security_solution/public/common/components/threat_match/reducer.test.ts create mode 100644 x-pack/plugins/security_solution/public/common/components/threat_match/reducer.ts create mode 100644 x-pack/plugins/security_solution/public/common/components/threat_match/translations.ts create mode 100644 x-pack/plugins/security_solution/public/common/components/threat_match/types.ts create mode 100644 x-pack/plugins/security_solution/public/detections/components/rules/threatmatch_input/index.tsx create mode 100644 x-pack/plugins/security_solution/public/detections/components/rules/threatmatch_input/translations.ts diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/add_prepackaged_rules_schema.mock.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/add_prepackaged_rules_schema.mock.ts index 777256ff961f9..c033e0adccf0f 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/add_prepackaged_rules_schema.mock.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/add_prepackaged_rules_schema.mock.ts @@ -60,7 +60,7 @@ export const getAddPrepackagedThreatMatchRulesSchemaMock = (): AddPrepackagedRul rule_id: 'rule-1', version: 1, threat_query: '*:*', - threat_index: 'list-index', + threat_index: ['list-index'], threat_mapping: [ { entries: [ @@ -118,7 +118,7 @@ export const getAddPrepackagedThreatMatchRulesSchemaDecodedMock = (): AddPrepack exceptions_list: [], rule_id: 'rule-1', threat_query: '*:*', - threat_index: 'list-index', + threat_index: ['list-index'], threat_mapping: [ { entries: [ diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/add_prepackaged_rules_schema.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/add_prepackaged_rules_schema.ts index 3f338c57dd930..6ffbf4e4c8d4c 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/add_prepackaged_rules_schema.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/add_prepackaged_rules_schema.ts @@ -51,6 +51,7 @@ import { threat_query, threat_filters, threat_mapping, + threat_language, } from '../types/threat_mapping'; import { @@ -128,6 +129,7 @@ export const addPrepackagedRulesSchema = t.intersection([ threat_mapping, // defaults to "undefined" if not set during decode threat_query, // defaults to "undefined" if not set during decode threat_index, // defaults to "undefined" if not set during decode + threat_language, // defaults "undefined" if not set during decode }) ), ]); diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/create_rules_schema.mock.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/create_rules_schema.mock.ts index 32299be500b45..94dd1215d8026 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/create_rules_schema.mock.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/create_rules_schema.mock.ts @@ -66,7 +66,7 @@ export const getCreateThreatMatchRulesSchemaMock = (ruleId = 'rule-1'): CreateRu language: 'kuery', rule_id: ruleId, threat_query: '*:*', - threat_index: 'list-index', + threat_index: ['list-index'], threat_mapping: [ { entries: [ @@ -124,7 +124,7 @@ export const getCreateThreatMatchRulesSchemaDecodedMock = (): CreateRulesSchemaD exceptions_list: [], rule_id: 'rule-1', threat_query: '*:*', - threat_index: 'list-index', + threat_index: ['list-index'], threat_mapping: [ { entries: [ diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/create_rules_schema.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/create_rules_schema.ts index 2489210a26c8f..d8e7614fcb840 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/create_rules_schema.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/create_rules_schema.ts @@ -52,6 +52,7 @@ import { threat_query, threat_filters, threat_mapping, + threat_language, } from '../types/threat_mapping'; import { @@ -124,6 +125,7 @@ export const createRulesSchema = t.intersection([ threat_query, // defaults to "undefined" if not set during decode threat_filters, // defaults to "undefined" if not set during decode threat_index, // defaults to "undefined" if not set during decode + threat_language, // defaults "undefined" if not set during decode }) ), ]); diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/import_rules_schema.mock.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/import_rules_schema.mock.ts index 160dbb92b74cd..2eea9ac0f30c7 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/import_rules_schema.mock.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/import_rules_schema.mock.ts @@ -86,7 +86,7 @@ export const getImportThreatMatchRulesSchemaMock = (ruleId = 'rule-1'): ImportRu risk_score: 55, language: 'kuery', rule_id: ruleId, - threat_index: 'index-123', + threat_index: ['index-123'], threat_mapping: [{ entries: [{ field: 'host.name', type: 'mapping', value: 'host.name' }] }], threat_query: '*:*', threat_filters: [ @@ -136,7 +136,7 @@ export const getImportThreatMatchRulesSchemaDecodedMock = (): ImportRulesSchemaD rule_id: 'rule-1', immutable: false, threat_query: '*:*', - threat_index: 'index-123', + threat_index: ['index-123'], threat_mapping: [ { entries: [ diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/import_rules_schema.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/import_rules_schema.ts index a411b3d439a1f..852394b74767b 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/import_rules_schema.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/import_rules_schema.ts @@ -58,6 +58,7 @@ import { threat_query, threat_filters, threat_mapping, + threat_language, } from '../types/threat_mapping'; import { @@ -147,6 +148,7 @@ export const importRulesSchema = t.intersection([ threat_mapping, // defaults to "undefined" if not set during decode threat_query, // defaults to "undefined" if not set during decode threat_index, // defaults to "undefined" if not set during decode + threat_language, // defaults "undefined" if not set during decode }) ), ]); diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/patch_rules_schema.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/patch_rules_schema.ts index 40e79d96a9e6b..f4dce5c7ac05f 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/patch_rules_schema.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/patch_rules_schema.ts @@ -48,6 +48,13 @@ import { severity_mapping, event_category_override, } from '../common/schemas'; +import { + threat_index, + threat_query, + threat_filters, + threat_mapping, + threat_language, +} from '../types/threat_mapping'; import { listArrayOrUndefined } from '../types/lists'; /** @@ -97,6 +104,11 @@ export const patchRulesSchema = t.exact( note, version, exceptions_list: listArrayOrUndefined, + threat_index, + threat_query, + threat_filters, + threat_mapping, + threat_language, }) ); diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/update_rules_schema.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/update_rules_schema.ts index 8a13dd2f4e908..b0cd8b1c53688 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/update_rules_schema.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/update_rules_schema.ts @@ -49,6 +49,13 @@ import { SeverityMapping, event_category_override, } from '../common/schemas'; +import { + threat_index, + threat_query, + threat_filters, + threat_mapping, + threat_language, +} from '../types/threat_mapping'; import { DefaultStringArray, @@ -122,6 +129,11 @@ export const updateRulesSchema = t.intersection([ note, // defaults to "undefined" if not set during decode version, // defaults to "undefined" if not set during decode exceptions_list: DefaultListArray, // defaults to empty array if not set during decode + threat_mapping, // defaults to "undefined" if not set during decode + threat_query, // defaults to "undefined" if not set during decode + threat_filters, // defaults to "undefined" if not set during decode + threat_index, // defaults to "undefined" if not set during decode + threat_language, // defaults "undefined" if not set during decode }) ), ]); diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/response/rules_schema.mocks.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/response/rules_schema.mocks.ts index aaa246c82d9d7..340f93150ce5c 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/response/rules_schema.mocks.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/schemas/response/rules_schema.mocks.ts @@ -87,7 +87,7 @@ export const getThreatMatchingSchemaMock = (anchorDate: string = ANCHOR_DATE): R return { ...getRulesSchemaMock(anchorDate), type: 'threat_match', - threat_index: 'index-123', + threat_index: ['index-123'], threat_mapping: [{ entries: [{ field: 'host.name', type: 'mapping', value: 'host.name' }] }], threat_query: '*:*', threat_filters: [ diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/response/rules_schema.test.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/response/rules_schema.test.ts index c5bad3c55066b..82675768a11b7 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/response/rules_schema.test.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/schemas/response/rules_schema.test.ts @@ -626,7 +626,7 @@ describe('rules_schema', () => { const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual([ - 'invalid keys "threat_index,threat_mapping,[{"entries":[{"field":"host.name","type":"mapping","value":"host.name"}]}],threat_query,threat_filters,[{"bool":{"must":[{"query_string":{"query":"host.name: linux","analyze_wildcard":true,"time_zone":"Zulu"}}],"filter":[],"should":[],"must_not":[]}}]"', + 'invalid keys "threat_index,["index-123"],threat_mapping,[{"entries":[{"field":"host.name","type":"mapping","value":"host.name"}]}],threat_query,threat_filters,[{"bool":{"must":[{"query_string":{"query":"host.name: linux","analyze_wildcard":true,"time_zone":"Zulu"}}],"filter":[],"should":[],"must_not":[]}}]"', ]); expect(message.schema).toEqual({}); }); @@ -764,7 +764,7 @@ describe('rules_schema', () => { test('should return 5 fields for a rule of type "threat_match"', () => { const fields = addThreatMatchFields({ type: 'threat_match' }); - expect(fields.length).toEqual(5); + expect(fields.length).toEqual(6); }); }); diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/response/rules_schema.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/response/rules_schema.ts index 908425a7496d0..e85beddf0e51e 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/response/rules_schema.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/schemas/response/rules_schema.ts @@ -66,6 +66,7 @@ import { threat_query, threat_filters, threat_mapping, + threat_language, } from '../types/threat_mapping'; import { DefaultListArray } from '../types/lists_default_array'; @@ -144,6 +145,7 @@ export const dependentRulesSchema = t.partial({ threat_index, threat_query, threat_mapping, + threat_language, }); /** @@ -277,6 +279,7 @@ export const addThreatMatchFields = (typeAndTimelineOnly: TypeAndTimelineOnly): t.exact(t.type({ threat_query: dependentRulesSchema.props.threat_query })), t.exact(t.type({ threat_index: dependentRulesSchema.props.threat_index })), t.exact(t.type({ threat_mapping: dependentRulesSchema.props.threat_mapping })), + t.exact(t.partial({ threat_language: dependentRulesSchema.props.threat_language })), t.exact(t.partial({ threat_filters: dependentRulesSchema.props.threat_filters })), t.exact(t.partial({ saved_id: dependentRulesSchema.props.saved_id })), ]; diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/types/index.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/types/index.ts index aab9a550d25e7..28a66d2948a92 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/types/index.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/schemas/types/index.ts @@ -33,4 +33,5 @@ export * from './positive_integer'; export * from './positive_integer_greater_than_zero'; export * from './references_default_array'; export * from './risk_score'; +export * from './threat_mapping'; export * from './uuid'; diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/types/threat_mapping.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/types/threat_mapping.ts index f2b4754c2d113..a1be6485f596b 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/types/threat_mapping.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/schemas/types/threat_mapping.ts @@ -7,6 +7,7 @@ /* eslint-disable @typescript-eslint/naming-convention */ import * as t from 'io-ts'; +import { language } from '../common/schemas'; import { NonEmptyString } from './non_empty_string'; export const threat_query = t.string; @@ -19,29 +20,38 @@ export type ThreatFilters = t.TypeOf; export const threatFiltersOrUndefined = t.union([threat_filters, t.undefined]); export type ThreatFiltersOrUndefined = t.TypeOf; -export const threatMappingEntries = t.array( - t.exact( - t.type({ - field: NonEmptyString, - type: t.keyof({ mapping: null }), - value: NonEmptyString, - }) - ) +export const threatMapEntry = t.exact( + t.type({ + field: NonEmptyString, + type: t.keyof({ mapping: null }), + value: NonEmptyString, + }) ); + +export type ThreatMapEntry = t.TypeOf; + +export const threatMappingEntries = t.array(threatMapEntry); export type ThreatMappingEntries = t.TypeOf; -export const threat_mapping = t.array( - t.exact( - t.type({ - entries: threatMappingEntries, - }) - ) +export const threatMap = t.exact( + t.type({ + entries: threatMappingEntries, + }) ); +export type ThreatMap = t.TypeOf; + +export const threat_mapping = t.array(threatMap); export type ThreatMapping = t.TypeOf; export const threatMappingOrUndefined = t.union([threat_mapping, t.undefined]); export type ThreatMappingOrUndefined = t.TypeOf; -export const threat_index = t.string; +export const threat_index = t.array(t.string); +export type ThreatIndex = t.TypeOf; export const threatIndexOrUndefined = t.union([threat_index, t.undefined]); export type ThreatIndexOrUndefined = t.TypeOf; + +export const threat_language = t.union([language, t.undefined]); +export type ThreatLanguage = t.TypeOf; +export const threatLanguageOrUndefined = t.union([threat_language, t.undefined]); +export type ThreatLanguageOrUndefined = t.TypeOf; diff --git a/x-pack/plugins/security_solution/public/common/components/threat_match/and_badge.test.tsx b/x-pack/plugins/security_solution/public/common/components/threat_match/and_badge.test.tsx new file mode 100644 index 0000000000000..87d2b5ede7d67 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/threat_match/and_badge.test.tsx @@ -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; + * you may not use this file except in compliance with the Elastic License. + */ + +import React from 'react'; +import { ThemeProvider } from 'styled-components'; +import { mount } from 'enzyme'; +import euiLightVars from '@elastic/eui/dist/eui_theme_light.json'; + +import { AndBadgeComponent } from './and_badge'; + +describe('AndBadgeComponent', () => { + test('it renders entryItemIndexItemEntryFirstRowAndBadge for very first item', () => { + const wrapper = mount( + ({ eui: euiLightVars, darkMode: false })}> + + + ); + + expect(wrapper.find('[data-test-subj="entryItemEntryFirstRowAndBadge"]').exists()).toBeTruthy(); + }); + + test('it renders entryItemEntryInvisibleAndBadge if "entriesLength" is 1 or less', () => { + const wrapper = mount( + ({ eui: euiLightVars, darkMode: false })}> + + + ); + + expect( + wrapper.find('[data-test-subj="entryItemEntryInvisibleAndBadge"]').exists() + ).toBeTruthy(); + }); + + test('it renders regular "and" badge if item is not the first one and includes more than one entry', () => { + const wrapper = mount( + ({ eui: euiLightVars, darkMode: false })}> + + + ); + + expect(wrapper.find('[data-test-subj="entryItemEntryAndBadge"]').exists()).toBeTruthy(); + }); +}); diff --git a/x-pack/plugins/security_solution/public/common/components/threat_match/and_badge.tsx b/x-pack/plugins/security_solution/public/common/components/threat_match/and_badge.tsx new file mode 100644 index 0000000000000..fd8d3f08e5de3 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/threat_match/and_badge.tsx @@ -0,0 +1,50 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React from 'react'; +import { EuiFlexItem } from '@elastic/eui'; +import styled from 'styled-components'; + +import { AndOrBadge } from '../and_or_badge'; + +const MyInvisibleAndBadge = styled(EuiFlexItem)` + visibility: hidden; +`; + +const MyFirstRowContainer = styled(EuiFlexItem)` + padding-top: 20px; +`; + +interface AndBadgeProps { + entriesLength: number; + entryItemIndex: number; +} + +export const AndBadgeComponent = React.memo(({ entriesLength, entryItemIndex }) => { + const badge = ; + + if (entriesLength > 1 && entryItemIndex === 0) { + return ( + + {badge} + + ); + } else if (entriesLength <= 1) { + return ( + + {badge} + + ); + } else { + return ( + + {badge} + + ); + } +}); + +AndBadgeComponent.displayName = 'AndBadge'; diff --git a/x-pack/plugins/security_solution/public/common/components/threat_match/entry_delete_button.test.tsx b/x-pack/plugins/security_solution/public/common/components/threat_match/entry_delete_button.test.tsx new file mode 100644 index 0000000000000..063499902094c --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/threat_match/entry_delete_button.test.tsx @@ -0,0 +1,123 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { mount } from 'enzyme'; +import React from 'react'; +import { ThreatMappingEntries } from '../../../../common/detection_engine/schemas/types'; + +import { EntryDeleteButtonComponent } from './entry_delete_button'; + +const entries: ThreatMappingEntries = [ + { + field: 'field.one', + type: 'mapping', + value: 'field.one', + }, +]; + +describe('EntryDeleteButtonComponent', () => { + test('it renders firstRowDeleteButton for very first entry', () => { + const wrapper = mount( + + ); + + expect(wrapper.find('[data-test-subj="firstRowDeleteButton"] button')).toHaveLength(1); + }); + + test('it does not render firstRowDeleteButton if entryIndex is not 0', () => { + const wrapper = mount( + + ); + + expect(wrapper.find('[data-test-subj="firstRowDeleteButton"]')).toHaveLength(0); + expect(wrapper.find('[data-test-subj="deleteButton"] button')).toHaveLength(1); + }); + + test('it does not render firstRowDeleteButton if itemIndex is not 0', () => { + const wrapper = mount( + + ); + + expect(wrapper.find('[data-test-subj="firstRowDeleteButton"]')).toHaveLength(0); + expect(wrapper.find('[data-test-subj="deleteButton"] button')).toHaveLength(1); + }); + + test('it invokes "onDelete" when button is clicked', () => { + const onDelete = jest.fn(); + + const wrapper = mount( + + ); + wrapper.find('[data-test-subj="deleteButton"] button').simulate('click'); + + expect(onDelete).toHaveBeenCalledTimes(1); + expect(onDelete).toHaveBeenCalledWith(0); + }); + + test('it disables button if it is the only entry left and no field has been selected', () => { + const emptyEntries: ThreatMappingEntries = [ + { + field: '', + type: 'mapping', + value: 'field.one', + }, + ]; + + const wrapper = mount( + + ); + + const button = wrapper.find('[data-test-subj="firstRowDeleteButton"] button').at(0); + + expect(button.prop('disabled')).toBeTruthy(); + }); + + test('it does not disable button if it is the only entry left and field has been selected', () => { + const wrapper = mount( + + ); + + const button = wrapper.find('[data-test-subj="deleteButton"] button').at(0); + + expect(button.prop('disabled')).toBeFalsy(); + }); +}); diff --git a/x-pack/plugins/security_solution/public/common/components/threat_match/entry_delete_button.tsx b/x-pack/plugins/security_solution/public/common/components/threat_match/entry_delete_button.tsx new file mode 100644 index 0000000000000..10a82855bb0a3 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/threat_match/entry_delete_button.tsx @@ -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; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { useCallback } from 'react'; +import { EuiButtonIcon, EuiFlexItem } from '@elastic/eui'; +import styled from 'styled-components'; + +import { Entry } from './types'; + +const MyFirstRowContainer = styled(EuiFlexItem)` + padding-top: 20px; +`; + +interface EntryDeleteButtonProps { + entries: Entry[]; + isOnlyItem: boolean; + entryIndex: number; + itemIndex: number; + onDelete: (item: number) => void; +} + +export const EntryDeleteButtonComponent = React.memo( + ({ entries, isOnlyItem, entryIndex, itemIndex, onDelete }) => { + const isDisabled: boolean = + isOnlyItem && + entries.length === 1 && + itemIndex === 0 && + (entries[0].field == null || entries[0].field === ''); + + const handleDelete = useCallback((): void => { + onDelete(entryIndex); + }, [onDelete, entryIndex]); + + const button = ( + + ); + + if (entryIndex === 0 && itemIndex === 0) { + // This logic was added to work around it including the field + // labels in centering the delete icon for the first row + return ( + + {button} + + ); + } else { + return ( + + {button} + + ); + } + } +); + +EntryDeleteButtonComponent.displayName = 'EntryDeleteButton'; diff --git a/x-pack/plugins/security_solution/public/common/components/threat_match/entry_item.test.tsx b/x-pack/plugins/security_solution/public/common/components/threat_match/entry_item.test.tsx new file mode 100644 index 0000000000000..36033c358766d --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/threat_match/entry_item.test.tsx @@ -0,0 +1,130 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { mount } from 'enzyme'; +import React from 'react'; +import { EuiComboBox, EuiComboBoxOptionOption } from '@elastic/eui'; + +import { EntryItem } from './entry_item'; +import { + fields, + getField, +} from '../../../../../../../src/plugins/data/common/index_patterns/fields/fields.mocks'; +import { IndexPattern } from 'src/plugins/data/public'; + +jest.mock('../../../common/lib/kibana'); + +describe('EntryItem', () => { + test('it renders field labels if "showLabel" is "true"', () => { + const wrapper = mount( + + ); + + expect(wrapper.find('[data-test-subj="threatFieldInputFormRow"]')).not.toEqual(0); + }); + + test('it invokes "onChange" when new field is selected and resets value fields', () => { + const mockOnChange = jest.fn(); + const wrapper = mount( + + ); + + ((wrapper.find(EuiComboBox).at(0).props() as unknown) as { + onChange: (a: EuiComboBoxOptionOption[]) => void; + }).onChange([{ label: 'machine.os' }]); + + expect(mockOnChange).toHaveBeenCalledWith( + { + field: 'machine.os', + type: 'mapping', + value: 'ip', + }, + 0 + ); + }); + + test('it invokes "onChange" when new value is selected', () => { + const mockOnChange = jest.fn(); + const wrapper = mount( + + ); + + ((wrapper.find(EuiComboBox).at(1).props() as unknown) as { + onChange: (a: EuiComboBoxOptionOption[]) => void; + }).onChange([{ label: 'is not' }]); + + expect(mockOnChange).toHaveBeenCalledWith({ field: 'ip', type: 'mapping', value: '' }, 0); + }); +}); diff --git a/x-pack/plugins/security_solution/public/common/components/threat_match/entry_item.tsx b/x-pack/plugins/security_solution/public/common/components/threat_match/entry_item.tsx new file mode 100644 index 0000000000000..c99e63ff4eda0 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/threat_match/entry_item.tsx @@ -0,0 +1,131 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import React, { useCallback, useMemo } from 'react'; +import { EuiFormRow, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import styled from 'styled-components'; + +import { IFieldType, IndexPattern } from '../../../../../../../src/plugins/data/common'; +import { FieldComponent } from '../autocomplete/field'; +import { FormattedEntry, Entry } from './types'; +import * as i18n from './translations'; +import { getEntryOnFieldChange, getEntryOnThreatFieldChange } from './helpers'; + +interface EntryItemProps { + entry: FormattedEntry; + indexPattern: IndexPattern; + threatIndexPatterns: IndexPattern; + showLabel: boolean; + onChange: (arg: Entry, i: number) => void; +} + +const FlexItemWithLabel = styled(EuiFlexItem)` + padding-top: 20px; + text-align: center; +`; + +const FlexItemWithoutLabel = styled(EuiFlexItem)` + text-align: center; +`; + +export const EntryItem: React.FC = ({ + entry, + indexPattern, + threatIndexPatterns, + showLabel, + onChange, +}): JSX.Element => { + const handleFieldChange = useCallback( + ([newField]: IFieldType[]): void => { + const { updatedEntry, index } = getEntryOnFieldChange(entry, newField); + onChange(updatedEntry, index); + }, + [onChange, entry] + ); + + const handleThreatFieldChange = useCallback( + ([newField]: IFieldType[]): void => { + const { updatedEntry, index } = getEntryOnThreatFieldChange(entry, newField); + onChange(updatedEntry, index); + }, + [onChange, entry] + ); + + const renderFieldInput = useMemo(() => { + const comboBox = ( + + ); + + if (showLabel) { + return ( + + {comboBox} + + ); + } else { + return comboBox; + } + }, [handleFieldChange, indexPattern, entry, showLabel]); + + const renderThreatFieldInput = useMemo(() => { + const comboBox = ( + + ); + + if (showLabel) { + return ( + + {comboBox} + + ); + } else { + return comboBox; + } + }, [handleThreatFieldChange, threatIndexPatterns, entry, showLabel]); + + return ( + + {renderFieldInput} + + + {showLabel ? ( + {i18n.MATCHES} + ) : ( + {i18n.MATCHES} + )} + + + {renderThreatFieldInput} + + ); +}; + +EntryItem.displayName = 'EntryItem'; diff --git a/x-pack/plugins/security_solution/public/common/components/threat_match/helpers.test.tsx b/x-pack/plugins/security_solution/public/common/components/threat_match/helpers.test.tsx new file mode 100644 index 0000000000000..7bab8e93ea9db --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/threat_match/helpers.test.tsx @@ -0,0 +1,225 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { + fields, + getField, +} from '../../../../../../../src/plugins/data/common/index_patterns/fields/fields.mocks'; +import { Entry, EmptyEntry, ThreatMapEntries, FormattedEntry } from './types'; +import { IndexPattern } from '../../../../../../../src/plugins/data/common'; +import moment from 'moment-timezone'; + +import { + filterItems, + getEntryOnFieldChange, + getFormattedEntries, + getFormattedEntry, + getUpdatedEntriesOnDelete, +} from './helpers'; +import { ThreatMapEntry } from '../../../../common/detection_engine/schemas/types'; + +const getMockIndexPattern = (): IndexPattern => + ({ + id: '1234', + title: 'logstash-*', + fields, + } as IndexPattern); + +const getMockEntry = (): FormattedEntry => ({ + field: getField('ip'), + value: getField('ip'), + type: 'mapping', + entryIndex: 0, +}); + +describe('Helpers', () => { + beforeEach(() => { + moment.tz.setDefault('UTC'); + }); + + afterEach(() => { + moment.tz.setDefault('Browser'); + }); + + describe('#getFormattedEntry', () => { + test('it returns entry with a value when "item.field" is of type "text" and matching keyword field exists', () => { + const payloadIndexPattern: IndexPattern = { + ...getMockIndexPattern(), + fields: [ + ...fields, + { + name: 'machine.os.raw.text', + type: 'string', + esTypes: ['text'], + count: 0, + scripted: false, + searchable: false, + aggregatable: false, + readFromDocValues: true, + }, + ], + } as IndexPattern; + const payloadItem: Entry = { + field: 'machine.os.raw.text', + type: 'mapping', + value: 'some os', + }; + const output = getFormattedEntry(payloadIndexPattern, payloadItem, 0); + const expected: FormattedEntry = { + entryIndex: 0, + field: { + name: 'machine.os.raw.text', + type: 'string', + esTypes: ['text'], + count: 0, + scripted: false, + searchable: false, + aggregatable: false, + readFromDocValues: true, + }, + type: 'mapping', + value: undefined, + }; + expect(output).toEqual(expected); + }); + }); + + describe('#getFormattedEntries', () => { + test('it returns formatted entry with fields undefined if it unable to find a matching index pattern field', () => { + const payloadIndexPattern: IndexPattern = getMockIndexPattern(); + const payloadItems: Entry[] = [{ field: 'field.one', type: 'mapping', value: 'field.one' }]; + const output = getFormattedEntries(payloadIndexPattern, payloadItems); + const expected: FormattedEntry[] = [ + { + entryIndex: 0, + field: undefined, + value: undefined, + type: 'mapping', + }, + ]; + expect(output).toEqual(expected); + }); + + test('it returns formatted entries', () => { + const payloadIndexPattern: IndexPattern = getMockIndexPattern(); + const payloadItems: Entry[] = [ + { field: 'machine.os', type: 'mapping', value: 'machine.os' }, + { field: 'ip', type: 'mapping', value: 'ip' }, + ]; + const output = getFormattedEntries(payloadIndexPattern, payloadItems); + const expected: FormattedEntry[] = [ + { + field: { + name: 'machine.os', + type: 'string', + esTypes: ['text'], + count: 0, + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: false, + }, + type: 'mapping', + value: { + name: 'machine.os', + type: 'string', + esTypes: ['text'], + count: 0, + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: false, + }, + entryIndex: 0, + }, + { + field: { + name: 'ip', + type: 'ip', + esTypes: ['ip'], + count: 0, + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: true, + }, + type: 'mapping', + value: { + name: 'ip', + type: 'ip', + esTypes: ['ip'], + count: 0, + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: true, + }, + entryIndex: 1, + }, + ]; + expect(output).toEqual(expected); + }); + }); + + describe('#getUpdatedEntriesOnDelete', () => { + test('it removes entry corresponding to "entryIndex"', () => { + const payloadItem: ThreatMapEntries = { + entries: [ + { field: 'field.one', type: 'mapping', value: 'field.one' }, + { field: 'field.two', type: 'mapping', value: 'field.two' }, + ], + }; + const output = getUpdatedEntriesOnDelete(payloadItem, 0); + const expected: ThreatMapEntries = { + entries: [ + { + field: 'field.two', + type: 'mapping', + value: 'field.two', + }, + ], + }; + expect(output).toEqual(expected); + }); + }); + + describe('#getEntryOnFieldChange', () => { + test('it returns field of type "match" with updated field', () => { + const payloadItem = getMockEntry(); + const payloadIFieldType = getField('ip'); + const output = getEntryOnFieldChange(payloadItem, payloadIFieldType); + const expected: { updatedEntry: Entry; index: number } = { + index: 0, + updatedEntry: { + field: 'ip', + type: 'mapping', + value: 'ip', + }, + }; + expect(output).toEqual(expected); + }); + }); + + describe('#filterItems', () => { + test('it removes entry items with "value" of "undefined"', () => { + const entry: ThreatMapEntry = { field: 'host.name', type: 'mapping', value: 'host.name' }; + const mockEmpty: EmptyEntry = { + field: 'host.name', + type: 'mapping', + value: undefined, + }; + const items = filterItems([ + { + entries: [entry], + }, + { + entries: [mockEmpty], + }, + ]); + expect(items).toEqual([{ entries: [entry] }]); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/public/common/components/threat_match/helpers.tsx b/x-pack/plugins/security_solution/public/common/components/threat_match/helpers.tsx new file mode 100644 index 0000000000000..9b155e1d568a8 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/threat_match/helpers.tsx @@ -0,0 +1,171 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { + ThreatMap, + threatMap, + ThreatMapping, +} from '../../../../common/detection_engine/schemas/types'; + +import { IndexPattern, IFieldType } from '../../../../../../../src/plugins/data/common'; +import { Entry, FormattedEntry, ThreatMapEntries, EmptyEntry } from './types'; + +/** + * Formats the entry into one that is easily usable for the UI. + * + * @param patterns IndexPattern containing available fields on rule index + * @param item item entry + * @param itemIndex entry index + */ +export const getFormattedEntry = ( + indexPattern: IndexPattern, + item: Entry, + itemIndex: number +): FormattedEntry => { + const { fields } = indexPattern; + const field = item.field; + const threatField = item.value; + const [foundField] = fields.filter(({ name }) => field != null && field === name); + const [threatFoundField] = fields.filter( + ({ name }) => threatField != null && threatField === name + ); + return { + field: foundField, + type: 'mapping', + value: threatFoundField, + entryIndex: itemIndex, + }; +}; + +/** + * Formats the entries to be easily usable for the UI + * + * @param patterns IndexPattern containing available fields on rule index + * @param entries item entries + */ +export const getFormattedEntries = ( + indexPattern: IndexPattern, + entries: Entry[] +): FormattedEntry[] => { + return entries.reduce((acc, item, index) => { + const newItemEntry = getFormattedEntry(indexPattern, item, index); + return [...acc, newItemEntry]; + }, []); +}; + +/** + * Determines whether an entire entry or item need to be removed + * + * @param item + * @param entryIndex index of given entry + * + */ +export const getUpdatedEntriesOnDelete = ( + item: ThreatMapEntries, + entryIndex: number +): ThreatMapEntries => { + return { + ...item, + entries: [...item.entries.slice(0, entryIndex), ...item.entries.slice(entryIndex + 1)], + }; +}; + +/** + * Determines proper entry update when user selects new field + * + * @param item - current item entry values + * @param newField - newly selected field + * + */ +export const getEntryOnFieldChange = ( + item: FormattedEntry, + newField: IFieldType +): { updatedEntry: Entry; index: number } => { + const { entryIndex } = item; + return { + updatedEntry: { + field: newField != null ? newField.name : '', + type: 'mapping', + value: item.value != null ? item.value.name : '', + }, + index: entryIndex, + }; +}; + +/** + * Determines proper entry update when user selects new field + * + * @param item - current item entry values + * @param newField - newly selected field + * + */ +export const getEntryOnThreatFieldChange = ( + item: FormattedEntry, + newField: IFieldType +): { updatedEntry: Entry; index: number } => { + const { entryIndex } = item; + return { + updatedEntry: { + field: item.field != null ? item.field.name : '', + type: 'mapping', + value: newField != null ? newField.name : '', + }, + index: entryIndex, + }; +}; + +export const getDefaultEmptyEntry = (): EmptyEntry => ({ + field: '', + type: 'mapping', + value: '', +}); + +export const getNewItem = (): ThreatMap => { + return { + entries: [ + { + field: '', + type: 'mapping', + value: '', + }, + ], + }; +}; + +export const filterItems = (items: ThreatMapEntries[]): ThreatMapping => { + return items.reduce((acc, item) => { + const newItem = { ...item, entries: item.entries }; + if (threatMap.is(newItem)) { + return [...acc, newItem]; + } else { + return acc; + } + }, []); +}; + +/** + * Given a list of items checks each one to see if any of them have an empty field + * or an empty value. + * @param items The items to check if we have an empty entries. + */ +export const containsInvalidItems = (items: ThreatMapEntries[]): boolean => { + return items.some((item) => + item.entries.some((subEntry) => subEntry.field === '' || subEntry.value === '') + ); +}; + +/** + * Given a list of items checks if we have a single empty entry and if we do returns true. + * @param items The items to check if we have a single empty entry. + */ +export const singleEntryThreat = (items: ThreatMapEntries[]): boolean => { + return ( + items.length === 1 && + items[0].entries.length === 1 && + items[0].entries[0].field === '' && + items[0].entries[0].value === '' + ); +}; diff --git a/x-pack/plugins/security_solution/public/common/components/threat_match/index.test.tsx b/x-pack/plugins/security_solution/public/common/components/threat_match/index.test.tsx new file mode 100644 index 0000000000000..14bc64c90a661 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/threat_match/index.test.tsx @@ -0,0 +1,304 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React from 'react'; +import { ThemeProvider } from 'styled-components'; +import { mount } from 'enzyme'; +import euiLightVars from '@elastic/eui/dist/eui_theme_light.json'; +import { waitFor } from '@testing-library/react'; + +import { fields } from '../../../../../../../src/plugins/data/common/index_patterns/fields/fields.mocks'; + +import { useKibana } from '../../../common/lib/kibana'; + +import { ThreatMatchComponent } from './'; +import { ThreatMapEntries } from './types'; +import { IndexPattern } from 'src/plugins/data/public'; + +jest.mock('../../../common/lib/kibana'); + +const getPayLoad = (): ThreatMapEntries[] => [ + { entries: [{ field: 'host.name', type: 'mapping', value: 'host.name' }] }, +]; + +const getDoublePayLoad = (): ThreatMapEntries[] => [ + { entries: [{ field: 'host.name', type: 'mapping', value: 'host.name' }] }, + { entries: [{ field: 'host.name', type: 'mapping', value: 'host.name' }] }, +]; + +describe('ThreatMatchComponent', () => { + const getValueSuggestionsMock = jest.fn().mockResolvedValue(['value 1', 'value 2']); + + beforeEach(() => { + (useKibana as jest.Mock).mockReturnValue({ + services: { + data: { + autocomplete: { + getValueSuggestions: getValueSuggestionsMock, + }, + }, + }, + }); + }); + + afterEach(() => { + getValueSuggestionsMock.mockClear(); + }); + + test('it displays empty entry if no "listItems" are passed in', () => { + const wrapper = mount( + ({ eui: euiLightVars, darkMode: false })}> + + + ); + + expect(wrapper.find('EuiFlexGroup[data-test-subj="itemEntryContainer"]')).toHaveLength(1); + expect(wrapper.find('[data-test-subj="entryField"]').text()).toEqual('Search'); + expect(wrapper.find('[data-test-subj="threatEntryField"]').text()).toEqual('Search'); + }); + + test('it displays "Search" for "listItems" that are passed in', async () => { + const wrapper = mount( + ({ eui: euiLightVars, darkMode: false })}> + + + ); + expect(wrapper.find('EuiFlexGroup[data-test-subj="itemEntryContainer"]')).toHaveLength(1); + expect(wrapper.find('[data-test-subj="entryField"]').at(0).text()).toEqual('Search'); + + wrapper.unmount(); + }); + + test('it displays "or", "and" enabled', () => { + const wrapper = mount( + ({ eui: euiLightVars, darkMode: false })}> + + + ); + + expect(wrapper.find('[data-test-subj="andButton"] button').prop('disabled')).toBeFalsy(); + expect(wrapper.find('[data-test-subj="orButton"] button').prop('disabled')).toBeFalsy(); + }); + + test('it adds an entry when "and" clicked', async () => { + const wrapper = mount( + ({ eui: euiLightVars, darkMode: false })}> + + + ); + + expect(wrapper.find('EuiFlexGroup[data-test-subj="itemEntryContainer"]')).toHaveLength(1); + + wrapper.find('[data-test-subj="andButton"] button').simulate('click'); + + await waitFor(() => { + expect(wrapper.find('EuiFlexGroup[data-test-subj="itemEntryContainer"]')).toHaveLength(2); + expect(wrapper.find('[data-test-subj="entryField"]').at(0).text()).toEqual('Search'); + expect(wrapper.find('[data-test-subj="threatEntryField"]').at(0).text()).toEqual('Search'); + expect(wrapper.find('[data-test-subj="entryField"]').at(1).text()).toEqual('Search'); + expect(wrapper.find('[data-test-subj="threatEntryField"]').at(1).text()).toEqual('Search'); + }); + }); + + test('it adds an item when "or" clicked', async () => { + const wrapper = mount( + ({ eui: euiLightVars, darkMode: false })}> + + + ); + + expect(wrapper.find('EuiFlexGroup[data-test-subj="entriesContainer"]')).toHaveLength(1); + + wrapper.find('[data-test-subj="orButton"] button').simulate('click'); + + await waitFor(() => { + expect(wrapper.find('EuiFlexGroup[data-test-subj="entriesContainer"]')).toHaveLength(2); + expect(wrapper.find('[data-test-subj="entryField"]').at(0).text()).toEqual('Search'); + expect(wrapper.find('[data-test-subj="threatEntryField"]').at(0).text()).toEqual('Search'); + expect(wrapper.find('[data-test-subj="entryField"]').at(1).text()).toEqual('Search'); + expect(wrapper.find('[data-test-subj="threatEntryField"]').at(1).text()).toEqual('Search'); + }); + }); + + test('it removes one row if user deletes a row', () => { + const wrapper = mount( + ({ eui: euiLightVars, darkMode: false })}> + + + ); + + expect(wrapper.find('[data-test-subj="entriesContainer"]').length).toEqual(4); + wrapper.find('[data-test-subj="firstRowDeleteButton"] button').simulate('click'); + expect(wrapper.find('[data-test-subj="entriesContainer"]').length).toEqual(2); + wrapper.unmount(); + }); + + test('it displays "and" badge if at least one item includes more than one entry', () => { + const wrapper = mount( + ({ eui: euiLightVars, darkMode: false })}> + + + ); + + expect(wrapper.find('[data-test-subj="entryItemEntryFirstRowAndBadge"]').exists()).toBeFalsy(); + + wrapper.find('[data-test-subj="andButton"] button').simulate('click'); + + expect(wrapper.find('[data-test-subj="entryItemEntryFirstRowAndBadge"]').exists()).toBeTruthy(); + }); + + test('it does not display "and" badge if none of the items include more than one entry', () => { + const wrapper = mount( + ({ eui: euiLightVars, darkMode: false })}> + + + ); + + wrapper.find('[data-test-subj="orButton"] button').simulate('click'); + + expect(wrapper.find('[data-test-subj="entryItemEntryFirstRowAndBadge"]').exists()).toBeFalsy(); + + wrapper.find('[data-test-subj="orButton"] button').simulate('click'); + + expect(wrapper.find('[data-test-subj="entryItemEntryFirstRowAndBadge"]').exists()).toBeFalsy(); + }); +}); diff --git a/x-pack/plugins/security_solution/public/common/components/threat_match/index.tsx b/x-pack/plugins/security_solution/public/common/components/threat_match/index.tsx new file mode 100644 index 0000000000000..d3936e10bd877 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/threat_match/index.tsx @@ -0,0 +1,220 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import React, { useCallback, useEffect, useReducer } from 'react'; +import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import styled from 'styled-components'; + +import { ThreatMapping } from '../../../../common/detection_engine/schemas/types'; +import { ListItemComponent } from './list_item'; +import { IndexPattern } from '../../../../../../../src/plugins/data/common'; +import { AndOrBadge } from '../and_or_badge'; +import { LogicButtons } from './logic_buttons'; +import { ThreatMapEntries } from './types'; +import { State, reducer } from './reducer'; +import { getDefaultEmptyEntry, getNewItem, filterItems } from './helpers'; + +const MyInvisibleAndBadge = styled(EuiFlexItem)` + visibility: hidden; +`; + +const MyAndBadge = styled(AndOrBadge)` + & > .euiFlexItem { + margin: 0; + } +`; + +const MyButtonsContainer = styled(EuiFlexItem)` + margin: 16px 0; +`; + +const initialState: State = { + andLogicIncluded: false, + entries: [], + entriesToDelete: [], +}; + +interface OnChangeProps { + entryItems: ThreatMapping; + entriesToDelete: ThreatMapEntries[]; +} + +interface ThreatMatchComponentProps { + listItems: ThreatMapEntries[]; + indexPatterns: IndexPattern; + threatIndexPatterns: IndexPattern; + onChange: (arg: OnChangeProps) => void; +} + +export const ThreatMatchComponent = ({ + listItems, + indexPatterns, + threatIndexPatterns, + onChange, +}: ThreatMatchComponentProps) => { + const [{ entries, entriesToDelete, andLogicIncluded }, dispatch] = useReducer(reducer(), { + ...initialState, + }); + + const setUpdateEntries = useCallback( + (items: ThreatMapEntries[]): void => { + dispatch({ + type: 'setEntries', + entries: items, + }); + }, + [dispatch] + ); + + const setDefaultEntries = useCallback( + (item: ThreatMapEntries): void => { + dispatch({ + type: 'setDefault', + initialState, + lastEntry: item, + }); + }, + [dispatch] + ); + + const handleEntryItemChange = useCallback( + (item: ThreatMapEntries, index: number): void => { + const updatedEntries = [ + ...entries.slice(0, index), + { + ...item, + }, + ...entries.slice(index + 1), + ]; + + setUpdateEntries(updatedEntries); + }, + [setUpdateEntries, entries] + ); + + const handleDeleteEntryItem = useCallback( + (item: ThreatMapEntries, itemIndex: number): void => { + if (item.entries.length === 0) { + const updatedEntries = [...entries.slice(0, itemIndex), ...entries.slice(itemIndex + 1)]; + // if it's the only item left, don't delete it just add a default entry to it + if (updatedEntries.length === 0) { + setDefaultEntries(item); + } else { + setUpdateEntries([...entries.slice(0, itemIndex), ...entries.slice(itemIndex + 1)]); + } + } else { + handleEntryItemChange(item, itemIndex); + } + }, + [handleEntryItemChange, setUpdateEntries, entries, setDefaultEntries] + ); + + const handleAddNewEntryItemEntry = useCallback((): void => { + const lastEntry = entries[entries.length - 1]; + const { entries: innerEntries } = lastEntry; + + const updatedEntry: ThreatMapEntries = { + ...lastEntry, + entries: [...innerEntries, getDefaultEmptyEntry()], + }; + + setUpdateEntries([...entries.slice(0, entries.length - 1), { ...updatedEntry }]); + }, [setUpdateEntries, entries]); + + const handleAddNewEntryItem = useCallback((): void => { + // There is a case where there are numerous list items, all with + // empty `entries` array. + const newItem = getNewItem(); + setUpdateEntries([...entries, { ...newItem }]); + }, [setUpdateEntries, entries]); + + const handleAddClick = useCallback((): void => { + handleAddNewEntryItemEntry(); + }, [handleAddNewEntryItemEntry]); + + // Bubble up changes to parent + useEffect(() => { + onChange({ entryItems: filterItems(entries), entriesToDelete }); + }, [onChange, entriesToDelete, entries]); + + // Defaults to never be sans entry, instead + // always falls back to an empty entry if user deletes all + useEffect(() => { + if ( + entries.length === 0 || + (entries.length === 1 && entries[0].entries != null && entries[0].entries.length === 0) + ) { + handleAddNewEntryItem(); + } + }, [entries, handleAddNewEntryItem]); + + useEffect(() => { + if (listItems.length > 0) { + setUpdateEntries(listItems); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + return ( + + {entries.map((entryListItem, index) => ( + + + {index !== 0 && + (andLogicIncluded ? ( + + + + + + + + + + + ) : ( + + + + ))} + + + + + + ))} + + + + {andLogicIncluded && ( + + + + )} + + + + + + + ); +}; + +ThreatMatchComponent.displayName = 'ThreatMatch'; diff --git a/x-pack/plugins/security_solution/public/common/components/threat_match/list_item.test.tsx b/x-pack/plugins/security_solution/public/common/components/threat_match/list_item.test.tsx new file mode 100644 index 0000000000000..90492bc46e2b0 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/threat_match/list_item.test.tsx @@ -0,0 +1,382 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React from 'react'; +import { ThemeProvider } from 'styled-components'; +import { mount } from 'enzyme'; +import euiLightVars from '@elastic/eui/dist/eui_theme_light.json'; + +import { useKibana } from '../../../common/lib/kibana'; +import { fields } from '../../../../../../../src/plugins/data/common/index_patterns/fields/fields.mocks'; + +import { ListItemComponent } from './list_item'; +import { ThreatMapEntries } from './types'; +import { IndexPattern } from 'src/plugins/data/public'; + +jest.mock('../../../common/lib/kibana'); + +const singlePayload = (): ThreatMapEntries => ({ + entries: [ + { + field: 'field.one', + type: 'mapping', + value: 'field.one', + }, + ], +}); + +const doublePayload = (): ThreatMapEntries => ({ + entries: [ + { + field: 'field.one', + type: 'mapping', + value: 'field.one', + }, + { + field: 'field.two', + type: 'mapping', + value: 'field.two', + }, + ], +}); + +describe('ListItemComponent', () => { + const getValueSuggestionsMock = jest.fn().mockResolvedValue(['field.one', 'field.two']); + + beforeAll(() => { + (useKibana as jest.Mock).mockReturnValue({ + services: { + data: { + autocomplete: { + getValueSuggestions: getValueSuggestionsMock, + }, + }, + }, + }); + }); + + afterEach(() => { + getValueSuggestionsMock.mockClear(); + }); + + describe('and badge logic', () => { + test('it renders "and" badge with extra top padding for the first item when "andLogicIncluded" is "true"', () => { + const wrapper = mount( + ({ eui: euiLightVars, darkMode: false })}> + + + ); + + expect( + wrapper.find('[data-test-subj="entryItemEntryFirstRowAndBadge"]').exists() + ).toBeTruthy(); + }); + + test('it renders "and" badge when more than one item entry exists and it is not the first item', () => { + const wrapper = mount( + ({ eui: euiLightVars, darkMode: false })}> + + + ); + + expect(wrapper.find('[data-test-subj="entryItemEntryAndBadge"]').exists()).toBeTruthy(); + }); + + test('it renders indented "and" badge when "andLogicIncluded" is "true" and only one entry exists', () => { + const wrapper = mount( + ({ eui: euiLightVars, darkMode: false })}> + + + ); + + expect( + wrapper.find('[data-test-subj="entryItemEntryInvisibleAndBadge"]').exists() + ).toBeTruthy(); + }); + + test('it renders no "and" badge when "andLogicIncluded" is "false"', () => { + const wrapper = mount( + ({ eui: euiLightVars, darkMode: false })}> + + + ); + + expect( + wrapper.find('[data-test-subj="entryItemEntryInvisibleAndBadge"]').exists() + ).toBeFalsy(); + expect(wrapper.find('[data-test-subj="entryItemEntryAndBadge"]').exists()).toBeFalsy(); + expect( + wrapper.find('[data-test-subj="entryItemEntryFirstRowAndBadge"]').exists() + ).toBeFalsy(); + }); + }); + + describe('delete button logic', () => { + test('it renders delete button disabled when it is only entry left', () => { + const item: ThreatMapEntries = { + entries: [{ ...singlePayload(), field: '', type: 'mapping', value: '' }], + }; + const wrapper = mount( + + ); + + expect( + wrapper.find('[data-test-subj="itemEntryDeleteButton"] button').props().disabled + ).toBeTruthy(); + }); + + test('it does not render delete button disabled when it is not the only entry left', () => { + const wrapper = mount( + + ); + + expect( + wrapper.find('[data-test-subj="itemEntryDeleteButton"] button').props().disabled + ).toBeFalsy(); + }); + + test('it does not render delete button disabled when "entryItemIndex" is not "0"', () => { + const wrapper = mount( + + ); + + expect( + wrapper.find('[data-test-subj="itemEntryDeleteButton"] button').props().disabled + ).toBeFalsy(); + }); + + test('it does not render delete button disabled when more than one entry exists', () => { + const wrapper = mount( + + ); + + expect( + wrapper.find('[data-test-subj="itemEntryDeleteButton"] button').at(0).props().disabled + ).toBeFalsy(); + }); + + test('it invokes "onChangeEntryItem" when delete button clicked', () => { + const mockOnDeleteEntryItem = jest.fn(); + const wrapper = mount( + + ); + + wrapper.find('[data-test-subj="itemEntryDeleteButton"] button').at(0).simulate('click'); + + const expected: ThreatMapEntries = { + entries: [ + { + field: 'field.two', + type: 'mapping', + value: 'field.two', + }, + ], + }; + + expect(mockOnDeleteEntryItem).toHaveBeenCalledWith(expected, 0); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/public/common/components/threat_match/list_item.tsx b/x-pack/plugins/security_solution/public/common/components/threat_match/list_item.tsx new file mode 100644 index 0000000000000..578986ccf17e4 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/threat_match/list_item.tsx @@ -0,0 +1,120 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { useMemo, useCallback } from 'react'; +import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import styled from 'styled-components'; + +import { IndexPattern } from '../../../../../../../src/plugins/data/common'; +import { getFormattedEntries, getUpdatedEntriesOnDelete } from './helpers'; +import { FormattedEntry, ThreatMapEntries, Entry } from './types'; +import { EntryItem } from './entry_item'; +import { EntryDeleteButtonComponent } from './entry_delete_button'; +import { AndBadgeComponent } from './and_badge'; + +const MyOverflowContainer = styled(EuiFlexItem)` + overflow: hidden; + width: 100%; +`; + +interface ListItemProps { + listItem: ThreatMapEntries; + listId: string; + listItemIndex: number; + indexPattern: IndexPattern; + threatIndexPatterns: IndexPattern; + andLogicIncluded: boolean; + isOnlyItem: boolean; + onDeleteEntryItem: (item: ThreatMapEntries, index: number) => void; + onChangeEntryItem: (item: ThreatMapEntries, index: number) => void; +} + +export const ListItemComponent = React.memo( + ({ + listItem, + listId, + listItemIndex, + indexPattern, + threatIndexPatterns, + isOnlyItem, + andLogicIncluded, + onDeleteEntryItem, + onChangeEntryItem, + }) => { + const handleEntryChange = useCallback( + (entry: Entry, entryIndex: number): void => { + const updatedEntries: Entry[] = [ + ...listItem.entries.slice(0, entryIndex), + { ...entry }, + ...listItem.entries.slice(entryIndex + 1), + ]; + const updatedEntryItem: ThreatMapEntries = { + ...listItem, + entries: updatedEntries, + }; + onChangeEntryItem(updatedEntryItem, listItemIndex); + }, + [onChangeEntryItem, listItem, listItemIndex] + ); + + const handleDeleteEntry = useCallback( + (entryIndex: number): void => { + const updatedEntryItem = getUpdatedEntriesOnDelete(listItem, entryIndex); + + onDeleteEntryItem(updatedEntryItem, listItemIndex); + }, + [listItem, onDeleteEntryItem, listItemIndex] + ); + + const entries = useMemo( + (): FormattedEntry[] => + indexPattern != null && listItem.entries.length > 0 + ? getFormattedEntries(indexPattern, listItem.entries) + : [], + [listItem.entries, indexPattern] + ); + return ( + + + {andLogicIncluded && ( + + )} + + + {entries.map((item, index) => ( + + + + + + + + + ))} + + + + + ); + } +); + +ListItemComponent.displayName = 'ListItem'; diff --git a/x-pack/plugins/security_solution/public/common/components/threat_match/logic_buttons.stories.tsx b/x-pack/plugins/security_solution/public/common/components/threat_match/logic_buttons.stories.tsx new file mode 100644 index 0000000000000..dc2fa79a7b8c1 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/threat_match/logic_buttons.stories.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; + * you may not use this file except in compliance with the Elastic License. + */ + +import { storiesOf, addDecorator } from '@storybook/react'; +import { action } from '@storybook/addon-actions'; +import React from 'react'; +import { ThemeProvider } from 'styled-components'; +import euiLightVars from '@elastic/eui/dist/eui_theme_light.json'; + +import { LogicButtons } from './logic_buttons'; + +addDecorator((storyFn) => ( + ({ eui: euiLightVars, darkMode: false })}>{storyFn()} +)); + +storiesOf('ThreatMatching|LogicButtons', module) + .add('and/or buttons', () => { + return ( + + ); + }) + .add('and disabled', () => { + return ( + + ); + }) + .add('or disabled', () => { + return ( + + ); + }); diff --git a/x-pack/plugins/security_solution/public/common/components/threat_match/logic_buttons.test.tsx b/x-pack/plugins/security_solution/public/common/components/threat_match/logic_buttons.test.tsx new file mode 100644 index 0000000000000..cd2fe3dc8f550 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/threat_match/logic_buttons.test.tsx @@ -0,0 +1,90 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { mount } from 'enzyme'; +import React from 'react'; + +import { LogicButtons } from './logic_buttons'; + +describe('LogicButtons', () => { + test('it renders "and" and "or" buttons', () => { + const wrapper = mount( + + ); + + expect(wrapper.find('[data-test-subj="andButton"] button')).toHaveLength(1); + expect(wrapper.find('[data-test-subj="orButton"] button')).toHaveLength(1); + }); + + test('it invokes "onOrClicked" when "or" button is clicked', () => { + const onOrClicked = jest.fn(); + + const wrapper = mount( + + ); + + wrapper.find('[data-test-subj="orButton"] button').simulate('click'); + + expect(onOrClicked).toHaveBeenCalledTimes(1); + }); + + test('it invokes "onAndClicked" when "and" button is clicked', () => { + const onAndClicked = jest.fn(); + + const wrapper = mount( + + ); + + wrapper.find('[data-test-subj="andButton"] button').simulate('click'); + + expect(onAndClicked).toHaveBeenCalledTimes(1); + }); + + test('it disables "and" button if "isAndDisabled" is true', () => { + const wrapper = mount( + + ); + + const andButton = wrapper.find('[data-test-subj="andButton"] button').at(0); + + expect(andButton.prop('disabled')).toBeTruthy(); + }); + + test('it disables "or" button if "isOrDisabled" is "true"', () => { + const wrapper = mount( + + ); + + const orButton = wrapper.find('[data-test-subj="orButton"] button').at(0); + + expect(orButton.prop('disabled')).toBeTruthy(); + }); +}); diff --git a/x-pack/plugins/security_solution/public/common/components/threat_match/logic_buttons.tsx b/x-pack/plugins/security_solution/public/common/components/threat_match/logic_buttons.tsx new file mode 100644 index 0000000000000..abfbfecdb1baa --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/threat_match/logic_buttons.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; + * you may not use this file except in compliance with the Elastic License. + */ +import React from 'react'; +import { EuiFlexGroup, EuiFlexItem, EuiButton } from '@elastic/eui'; +import styled from 'styled-components'; + +import * as i18n from './translations'; + +const MyEuiButton = styled(EuiButton)` + min-width: 95px; +`; + +interface LogicButtonsProps { + isOrDisabled: boolean; + isAndDisabled: boolean; + onAndClicked: () => void; + onOrClicked: () => void; +} + +export const LogicButtons: React.FC = ({ + isOrDisabled = false, + isAndDisabled = false, + onAndClicked, + onOrClicked, +}) => ( + + + + {i18n.AND} + + + + + {i18n.OR} + + + +); diff --git a/x-pack/plugins/security_solution/public/common/components/threat_match/reducer.test.ts b/x-pack/plugins/security_solution/public/common/components/threat_match/reducer.test.ts new file mode 100644 index 0000000000000..6b2a443ec45a5 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/threat_match/reducer.test.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; + * you may not use this file except in compliance with the Elastic License. + */ + +import { ThreatMapEntries } from './types'; +import { State, reducer } from './reducer'; +import { getDefaultEmptyEntry } from './helpers'; +import { ThreatMapEntry } from '../../../../common/detection_engine/schemas/types'; + +const initialState: State = { + andLogicIncluded: false, + entries: [], + entriesToDelete: [], +}; + +const getEntry = (): ThreatMapEntry => ({ + field: 'host.name', + type: 'mapping', + value: 'host.name', +}); + +describe('reducer', () => { + describe('#setEntries', () => { + test('should return "andLogicIncluded" ', () => { + const update = reducer()(initialState, { + type: 'setEntries', + entries: [], + }); + const expected: State = { + andLogicIncluded: false, + entries: [], + entriesToDelete: [], + }; + expect(update).toEqual(expected); + }); + + test('should set "andLogicIncluded" to true if any of the entries include entries with length greater than 1 ', () => { + const entries: ThreatMapEntries[] = [ + { + entries: [getEntry(), getEntry()], + }, + ]; + const { andLogicIncluded } = reducer()(initialState, { + type: 'setEntries', + entries, + }); + + expect(andLogicIncluded).toBeTruthy(); + }); + + test('should set "andLogicIncluded" to false if any of the entries include entries with length greater than 1 ', () => { + const entries: ThreatMapEntries[] = [ + { + entries: [getEntry()], + }, + ]; + const { andLogicIncluded } = reducer()(initialState, { + type: 'setEntries', + entries, + }); + + expect(andLogicIncluded).toBeFalsy(); + }); + }); + + describe('#setDefault', () => { + test('should restore initial state and add default empty entry to item" ', () => { + const entries: ThreatMapEntries[] = [ + { + entries: [getEntry()], + }, + ]; + + const update = reducer()( + { + andLogicIncluded: true, + entries, + entriesToDelete: [], + }, + { + type: 'setDefault', + initialState, + lastEntry: { + entries: [], + }, + } + ); + + expect(update).toEqual({ + ...initialState, + entries: [ + { + entries: [getDefaultEmptyEntry()], + }, + ], + }); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/public/common/components/threat_match/reducer.ts b/x-pack/plugins/security_solution/public/common/components/threat_match/reducer.ts new file mode 100644 index 0000000000000..3fd19d40afa53 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/threat_match/reducer.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; + * you may not use this file except in compliance with the Elastic License. + */ +import { ThreatMapEntries } from './types'; +import { getDefaultEmptyEntry } from './helpers'; + +export type ViewerModalName = 'addModal' | 'editModal' | null; + +export interface State { + andLogicIncluded: boolean; + entries: ThreatMapEntries[]; + entriesToDelete: ThreatMapEntries[]; +} + +export type Action = + | { + type: 'setEntries'; + entries: ThreatMapEntries[]; + } + | { + type: 'setDefault'; + initialState: State; + lastEntry: ThreatMapEntries; + }; + +export const reducer = () => (state: State, action: Action): State => { + switch (action.type) { + case 'setEntries': { + const isAndLogicIncluded = + action.entries.filter(({ entries }) => entries.length > 1).length > 0; + + const returnState = { + ...state, + andLogicIncluded: isAndLogicIncluded, + entries: action.entries, + }; + return returnState; + } + case 'setDefault': { + return { + ...state, + ...action.initialState, + entries: [{ ...action.lastEntry, entries: [getDefaultEmptyEntry()] }], + }; + } + default: + return state; + } +}; diff --git a/x-pack/plugins/security_solution/public/common/components/threat_match/translations.ts b/x-pack/plugins/security_solution/public/common/components/threat_match/translations.ts new file mode 100644 index 0000000000000..ca9f6a13856cf --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/threat_match/translations.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; + * you may not use this file except in compliance with the Elastic License. + */ + +import { i18n } from '@kbn/i18n'; + +export const FIELD = i18n.translate('xpack.securitySolution.threatMatch.fieldDescription', { + defaultMessage: 'Field', +}); + +export const THREAT_FIELD = i18n.translate( + 'xpack.securitySolution.threatMatch.threatFieldDescription', + { + defaultMessage: 'Threat index field', + } +); + +export const FIELD_PLACEHOLDER = i18n.translate( + 'xpack.securitySolution.threatMatch.fieldPlaceholderDescription', + { + defaultMessage: 'Search', + } +); + +export const MATCHES = i18n.translate('xpack.securitySolution.threatMatch.matchesLabel', { + defaultMessage: 'MATCHES', +}); + +export const AND = i18n.translate('xpack.securitySolution.threatMatch.andDescription', { + defaultMessage: 'AND', +}); + +export const OR = i18n.translate('xpack.securitySolution.threatMatch.orDescription', { + defaultMessage: 'OR', +}); diff --git a/x-pack/plugins/security_solution/public/common/components/threat_match/types.ts b/x-pack/plugins/security_solution/public/common/components/threat_match/types.ts new file mode 100644 index 0000000000000..0cbd885db2d54 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/threat_match/types.ts @@ -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; + * you may not use this file except in compliance with the Elastic License. + */ +import { ThreatMap, ThreatMapEntry } from '../../../../common/detection_engine/schemas/types'; +import { IFieldType } from '../../../../../../../src/plugins/data/common'; + +export interface FormattedEntry { + field: IFieldType | undefined; + type: 'mapping'; + value: IFieldType | undefined; + entryIndex: number; +} + +export interface EmptyEntry { + field: string | undefined; + type: 'mapping'; + value: string | undefined; +} + +export type Entry = ThreatMapEntry | EmptyEntry; + +export type ThreatMapEntries = Omit & { + entries: Entry[]; +}; diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/description_step/helpers.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/description_step/helpers.tsx index 4d46d4dc86846..9ef1dd2bcb204 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/description_step/helpers.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/description_step/helpers.tsx @@ -21,6 +21,8 @@ import { isEmpty } from 'lodash/fp'; import React from 'react'; import styled from 'styled-components'; +import { MATCHES, AND, OR } from '../../../../common/components/threat_match/translations'; +import { ThreatMapping } from '../../../../../common/detection_engine/schemas/types'; import { assertUnreachable } from '../../../../../common/utility_types'; import * as i18nSeverity from '../severity_mapping/translations'; import * as i18nRiskScore from '../risk_score_mapping/translations'; @@ -56,6 +58,7 @@ export const buildQueryBarDescription = ({ query, savedId, indexPatterns, + queryLabel, }: BuildQueryBarDescription): ListItems[] => { let items: ListItems[] = []; if (!isEmpty(filters)) { @@ -89,7 +92,7 @@ export const buildQueryBarDescription = ({ items = [ ...items, { - title: <>{i18n.QUERY_LABEL} , + title: <>{queryLabel ?? i18n.QUERY_LABEL} , description: <>{query} , }, ]; @@ -416,3 +419,40 @@ export const buildThresholdDescription = (label: string, threshold: Threshold): ), }, ]; + +export const buildThreatMappingDescription = ( + title: string, + threatMapping: ThreatMapping +): ListItems[] => { + const description = threatMapping.reduce( + (accumThreatMaps, threatMap, threatMapIndex, { length: threatMappingLength }) => { + const matches = threatMap.entries.reduce( + (accumItems, item, itemsIndex, { length: threatMapLength }) => { + if (threatMapLength === 1) { + return `${item.field} ${MATCHES} ${item.value}`; + } else if (itemsIndex === 0) { + return `(${item.field} ${MATCHES} ${item.value})`; + } else { + return `${accumItems} ${AND} (${item.field} ${MATCHES} ${item.value})`; + } + }, + '' + ); + + if (threatMappingLength === 1) { + return `${matches}`; + } else if (threatMapIndex === 0) { + return `(${matches})`; + } else { + return `${accumThreatMaps} ${OR} (${matches})`; + } + }, + '' + ); + return [ + { + title, + description, + }, + ]; +}; diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/description_step/index.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/description_step/index.tsx index 99e36669f78bb..83d087e60bc7d 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/description_step/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/description_step/index.tsx @@ -9,6 +9,7 @@ import { isEmpty, chunk, get, pick, isNumber } from 'lodash/fp'; import React, { memo, useState } from 'react'; import styled from 'styled-components'; +import { ThreatMapping } from '../../../../../common/detection_engine/schemas/types'; import { IIndexPattern, Filter, @@ -36,11 +37,13 @@ import { buildRiskScoreDescription, buildRuleTypeDescription, buildThresholdDescription, + buildThreatMappingDescription, } from './helpers'; import { buildMlJobDescription } from './ml_job_description'; import { buildActionsDescription } from './actions_description'; import { buildThrottleDescription } from './throttle_description'; import { Type } from '../../../../../common/detection_engine/schemas/common/schemas'; +import { THREAT_QUERY_LABEL } from './translations'; const DescriptionListContainer = styled(EuiDescriptionList)` &.euiDescriptionList--column .euiDescriptionList__title { @@ -156,6 +159,7 @@ export const addFilterStateIfNotThere = (filters: Filter[]): Filter[] => { }); }; +/* eslint complexity: ["error", 21]*/ export const getDescriptionItem = ( field: string, label: string, @@ -189,7 +193,7 @@ export const getDescriptionItem = ( } else if (field === 'falsePositives') { const values: string[] = get(field, data); return buildUnorderedListArrayDescription(label, field, values); - } else if (Array.isArray(get(field, data))) { + } else if (Array.isArray(get(field, data)) && field !== 'threatMapping') { const values: string[] = get(field, data); return buildStringArrayDescription(label, field, values); } else if (field === 'riskScore') { @@ -214,6 +218,22 @@ export const getDescriptionItem = ( return buildRuleTypeDescription(label, ruleType); } else if (field === 'kibanaSiemAppUrl') { return []; + } else if (field === 'threatQueryBar') { + const filters = addFilterStateIfNotThere(get('threatQueryBar.filters', data) ?? []); + const query = get('threatQueryBar.query.query', data); + const savedId = get('threatQueryBar.saved_id', data); + return buildQueryBarDescription({ + field, + filters, + filterManager, + query, + savedId, + indexPatterns, + queryLabel: THREAT_QUERY_LABEL, + }); + } else if (field === 'threatMapping') { + const threatMap: ThreatMapping = get(field, data); + return buildThreatMappingDescription(label, threatMap); } const description: string = get(field, data); diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/description_step/translations.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/description_step/translations.tsx index d714f04f519d4..d9186c2da7225 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/description_step/translations.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/description_step/translations.tsx @@ -20,6 +20,13 @@ export const QUERY_LABEL = i18n.translate( } ); +export const THREAT_QUERY_LABEL = i18n.translate( + 'xpack.securitySolution.detectionEngine.createRule.threatQueryLabel', + { + defaultMessage: 'Threat query', + } +); + export const SAVED_ID_LABEL = i18n.translate( 'xpack.securitySolution.detectionEngine.createRule.savedIdLabel', { diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/description_step/types.ts b/x-pack/plugins/security_solution/public/detections/components/rules/description_step/types.ts index bcda5ff67a9a6..719c38689b722 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/description_step/types.ts +++ b/x-pack/plugins/security_solution/public/detections/components/rules/description_step/types.ts @@ -24,6 +24,7 @@ export interface BuildQueryBarDescription { query: string; savedId: string; indexPatterns?: IIndexPattern; + queryLabel?: string; } export interface BuildThreatDescription { diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/select_rule_type/index.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/select_rule_type/index.tsx index 169e4f81d3498..9a1d11a2dfe42 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/select_rule_type/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/select_rule_type/index.tsx @@ -12,6 +12,7 @@ import { isThresholdRule, isEqlRule, isQueryRule, + isThreatMatchRule, } from '../../../../../common/detection_engine/utils'; import { FieldHook } from '../../../../shared_imports'; import { useKibana } from '../../../../common/lib/kibana'; @@ -45,6 +46,7 @@ export const SelectRuleType: React.FC = ({ const setMl = useCallback(() => setType('machine_learning'), [setType]); const setQuery = useCallback(() => setType('query'), [setType]); const setThreshold = useCallback(() => setType('threshold'), [setType]); + const setThreatMatch = useCallback(() => setType('threat_match'), [setType]); const mlCardDisabled = isReadOnly || !hasValidLicense || !isMlAdmin; const licensingUrl = useKibana().services.application.getUrlForApp('kibana', { path: '#/management/stack/license_management', @@ -86,6 +88,15 @@ export const SelectRuleType: React.FC = ({ [isReadOnly, ruleType, setThreshold] ); + const threatMatchSelectableConfig = useMemo( + () => ({ + isDisabled: isReadOnly, + onClick: setThreatMatch, + isSelected: isThreatMatchRule(ruleType), + }), + [isReadOnly, ruleType, setThreatMatch] + ); + return ( = ({ selectable={eqlSelectableConfig} /> + + } + isDisabled={ + threatMatchSelectableConfig.isDisabled && !threatMatchSelectableConfig.isSelected + } + selectable={threatMatchSelectableConfig} + /> + ); diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/select_rule_type/translations.ts b/x-pack/plugins/security_solution/public/detections/components/rules/select_rule_type/translations.ts index e7b231ca74958..7043aa2d2f956 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/select_rule_type/translations.ts +++ b/x-pack/plugins/security_solution/public/detections/components/rules/select_rule_type/translations.ts @@ -62,3 +62,17 @@ export const THRESHOLD_TYPE_DESCRIPTION = i18n.translate( defaultMessage: 'Aggregate query results to detect when number of matches exceeds threshold.', } ); + +export const THREAT_MATCH_TYPE_TITLE = i18n.translate( + 'xpack.securitySolution.detectionEngine.createRule.stepDefineRule.ruleTypeField.threatMatchTitle', + { + defaultMessage: 'Threat Match', + } +); + +export const THREAT_MATCH_TYPE_DESCRIPTION = i18n.translate( + 'xpack.securitySolution.detectionEngine.createRule.stepDefineRule.ruleTypeField.threatMatchDescription', + { + defaultMessage: 'Upload value lists to write rules around a list of known bad attributes', + } +); diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/step_define_rule/index.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/step_define_rule/index.tsx index dc31db76c3911..f728a508fef86 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/step_define_rule/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/step_define_rule/index.tsx @@ -11,6 +11,7 @@ import styled from 'styled-components'; // eslint-disable-next-line no-restricted-imports import isEqual from 'lodash/isEqual'; +import { IndexPattern } from 'src/plugins/data/public'; import { DEFAULT_INDEX_KEY } from '../../../../../common/constants'; import { DEFAULT_TIMELINE_TITLE } from '../../../../timelines/components/timeline/translations'; import { isMlRule } from '../../../../../common/machine_learning/helpers'; @@ -47,8 +48,13 @@ import { } from '../../../../shared_imports'; import { schema } from './schema'; import * as i18n from './translations'; -import { isEqlRule, isThresholdRule } from '../../../../../common/detection_engine/utils'; +import { + isEqlRule, + isThreatMatchRule, + isThresholdRule, +} from '../../../../../common/detection_engine/utils'; import { EqlQueryBar } from '../eql_query_bar'; +import { ThreatMatchInput } from '../threatmatch_input'; import { useFetchIndex } from '../../../../common/containers/source'; const CommonUseField = getUseField({ component: Field }); @@ -62,11 +68,18 @@ const stepDefineDefaultValue: DefineStepRule = { index: [], machineLearningJobId: '', ruleType: 'query', + threatIndex: [], queryBar: { query: { query: '', language: 'kuery' }, filters: [], saved_id: undefined, }, + threatQueryBar: { + query: { query: '*:*', language: 'kuery' }, + filters: [], + saved_id: undefined, + }, + threatMapping: [], threshold: { field: [], value: '200', @@ -121,14 +134,22 @@ const StepDefineRuleComponent: FC = ({ schema, }); const { getFields, getFormData, reset, submit } = form; - const [{ index: formIndex, ruleType: formRuleType }] = (useFormData({ - form, - watch: ['index', 'ruleType'], - }) as unknown) as [Partial]; + const [{ index: formIndex, ruleType: formRuleType, threatIndex: formThreatIndex }] = (useFormData( + { + form, + watch: ['index', 'ruleType', 'threatIndex'], + } + ) as unknown) as [Partial]; const index = formIndex || initialState.index; + const threatIndex = formThreatIndex || initialState.threatIndex; const ruleType = formRuleType || initialState.ruleType; const [indexPatternsLoading, { browserFields, indexPatterns }] = useFetchIndex(index); + const [ + threatIndexPatternsLoading, + { browserFields: threatBrowserFields, indexPatterns: threatIndexPatterns }, + ] = useFetchIndex(threatIndex); + // reset form when rule type changes useEffect(() => { reset({ resetValues: false }); @@ -146,7 +167,7 @@ const StepDefineRuleComponent: FC = ({ const getData = useCallback(async () => { const result = await submit(); - return result?.isValid + return result.isValid ? result : { isValid: false, @@ -184,6 +205,19 @@ const StepDefineRuleComponent: FC = ({ [browserFields] ); + const ThreatMatchInputChildren = useCallback( + ({ threatMapping }) => ( + + ), + [threatBrowserFields, threatIndexPatternsLoading, threatIndexPatterns, indexPatterns] + ); + return isReadOnlyView ? ( = ({ + + <> + + {ThreatMatchInputChildren} + + + = { index: { @@ -219,4 +231,126 @@ export const schema: FormSchema = { ], }, }, + threatIndex: { + type: FIELD_TYPES.COMBO_BOX, + label: i18n.translate( + 'xpack.securitySolution.detectionEngine.createRule.stepDefineRule.fieldThreatIndexPatternsLabel', + { + defaultMessage: 'Threat index patterns', + } + ), + helpText: {THREAT_MATCH_INDEX_HELPER_TEXT}, + validations: [ + { + validator: ( + ...args: Parameters + ): ReturnType> | undefined => { + const [{ formData }] = args; + const needsValidation = isThreatMatchRule(formData.ruleType); + if (!needsValidation) { + return; + } + return fieldValidators.emptyField( + i18n.translate( + 'xpack.securitySolution.detectionEngine.createRule.stepDefineRule.threatMatchoutputIndiceNameFieldRequiredError', + { + defaultMessage: 'A minimum of one index pattern is required.', + } + ) + )(...args); + }, + }, + ], + }, + threatMapping: { + label: i18n.translate( + 'xpack.securitySolution.detectionEngine.createRule.stepDefineRule.fieldThreatMappingLabel', + { + defaultMessage: 'Threat Mapping', + } + ), + validations: [ + { + validator: ( + ...args: Parameters + ): ReturnType> | undefined => { + const [{ path, formData }] = args; + const needsValidation = isThreatMatchRule(formData.ruleType); + if (!needsValidation) { + return; + } + if (singleEntryThreat(formData.threatMapping)) { + return { + code: 'ERR_FIELD_MISSING', + path, + message: THREAT_MATCH_REQUIRED, + }; + } else if (containsInvalidItems(formData.threatMapping)) { + return { + code: 'ERR_FIELD_MISSING', + path, + message: THREAT_MATCH_EMPTIES, + }; + } else { + return undefined; + } + }, + }, + ], + }, + threatQueryBar: { + label: i18n.translate( + 'xpack.securitySolution.detectionEngine.createRule.stepDefineRule.fieldThreatQueryBarLabel', + { + defaultMessage: 'Threat index query', + } + ), + validations: [ + { + validator: ( + ...args: Parameters + ): ReturnType> | undefined => { + const [{ value, path, formData }] = args; + const needsValidation = isThreatMatchRule(formData.ruleType); + if (!needsValidation) { + return; + } + + const { query, filters } = value as FieldValueQueryBar; + + return isEmpty(query.query as string) && isEmpty(filters) + ? { + code: 'ERR_FIELD_MISSING', + path, + message: CUSTOM_QUERY_REQUIRED, + } + : undefined; + }, + }, + { + validator: ( + ...args: Parameters + ): ReturnType> | undefined => { + const [{ value, path, formData }] = args; + const needsValidation = isThreatMatchRule(formData.ruleType); + if (!needsValidation) { + return; + } + const { query } = value as FieldValueQueryBar; + + if (!isEmpty(query.query as string) && query.language === 'kuery') { + try { + esKuery.fromKueryExpression(query.query); + } catch (err) { + return { + code: 'ERR_FIELD_FORMAT', + path, + message: INVALID_CUSTOM_QUERY, + }; + } + } + }, + }, + ], + }, }; diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/step_define_rule/translations.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/step_define_rule/translations.tsx index 860ed1831fdc6..8e0a3f9b8659e 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/step_define_rule/translations.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/step_define_rule/translations.tsx @@ -70,3 +70,24 @@ export const ENABLE_ML_JOB_WARNING = i18n.translate( 'This ML job is not currently running. Please set this job to run via "ML job settings" before activating this rule.', } ); + +export const THREAT_MATCH_INDEX_HELPER_TEXT = i18n.translate( + 'xpack.securitySolution.detectionEngine.createRule.stepDefineRule.threatMatchingIcesHelperDescription', + { + defaultMessage: 'Select threat indices', + } +); + +export const THREAT_MATCH_REQUIRED = i18n.translate( + 'xpack.securitySolution.detectionEngine.createRule.stepDefineRule.customThreatQueryFieldRequiredError', + { + defaultMessage: 'At least one threat match is required.', + } +); + +export const THREAT_MATCH_EMPTIES = i18n.translate( + 'xpack.securitySolution.detectionEngine.createRule.stepDefineRule.customThreatQueryFieldRequiredEmptyError', + { + defaultMessage: 'All matches require both a field and threat index field.', + } +); diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/threatmatch_input/index.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/threatmatch_input/index.tsx new file mode 100644 index 0000000000000..2a4609a2f5e9e --- /dev/null +++ b/x-pack/plugins/security_solution/public/detections/components/rules/threatmatch_input/index.tsx @@ -0,0 +1,114 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { useCallback } from 'react'; +import { EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiFormRow } from '@elastic/eui'; + +import { ThreatMapEntries } from '../../../../common/components/threat_match/types'; +import { ThreatMatchComponent } from '../../../../common/components/threat_match'; +import { BrowserField } from '../../../../common/containers/source'; +import { + FieldHook, + Field, + getUseField, + UseField, + getFieldValidityAndErrorMessage, +} from '../../../../shared_imports'; +import { schema } from '../step_define_rule/schema'; +import { QueryBarDefineRule } from '../query_bar'; +import { IndexPattern } from '../../../../../../../../src/plugins/data/public'; + +const CommonUseField = getUseField({ component: Field }); + +interface ThreatMatchInputProps { + threatMapping: FieldHook; + threatBrowserFields: Readonly>>; + threatIndexPatterns: IndexPattern; + indexPatterns: IndexPattern; + threatIndexPatternsLoading: boolean; +} + +const ThreatMatchInputComponent: React.FC = ({ + threatMapping, + indexPatterns, + threatIndexPatterns, + threatIndexPatternsLoading, + threatBrowserFields, +}: ThreatMatchInputProps) => { + const { setValue, value: threatItems } = threatMapping; + const { isInvalid, errorMessage } = getFieldValidityAndErrorMessage(threatMapping); + const handleBuilderOnChange = useCallback( + ({ entryItems }: { entryItems: ThreatMapEntries[] }): void => { + setValue(entryItems); + }, + [setValue] + ); + return ( + <> + + + + + + + + + + + + + + + + ); +}; + +export const ThreatMatchInput = React.memo(ThreatMatchInputComponent); diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/threatmatch_input/translations.ts b/x-pack/plugins/security_solution/public/detections/components/rules/threatmatch_input/translations.ts new file mode 100644 index 0000000000000..0aa268ae24ae1 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detections/components/rules/threatmatch_input/translations.ts @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { i18n } from '@kbn/i18n'; + +export const THREAT_MATCH_FIELD_PLACEHOLDER = i18n.translate( + 'xpack.securitySolution.detectionEngine.createRule.stepDefineRule.threatMatchField.threatMatchFieldPlaceholderText', + { + defaultMessage: 'All results', + } +); diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/types.ts b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/types.ts index 49579e893029b..e9c89130736c0 100644 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/types.ts +++ b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/types.ts @@ -18,7 +18,14 @@ import { threshold, type, } from '../../../../../common/detection_engine/schemas/common/schemas'; -import { listArray } from '../../../../../common/detection_engine/schemas/types'; +import { + listArray, + threat_query, + threat_index, + threat_mapping, + threat_language, + threat_filters, +} from '../../../../../common/detection_engine/schemas/types'; import { CreateRulesSchema, PatchRulesSchema, @@ -110,6 +117,11 @@ export const RuleSchema = t.intersection([ status: t.string, status_date: t.string, threshold, + threat_query, + threat_filters, + threat_index, + threat_mapping, + threat_language, timeline_id: t.string, timeline_title: t.string, timestamp_override, diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/__mocks__/mock.ts b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/__mocks__/mock.ts index 5a626ce0ff00a..5851177a4e4ab 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/__mocks__/mock.ts +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/__mocks__/mock.ts @@ -212,10 +212,13 @@ export const mockDefineStepRule = (): DefineStepRule => ({ machineLearningJobId: '', index: ['filebeat-'], queryBar: mockQueryBar, + threatQueryBar: mockQueryBar, + threatMapping: [], timeline: { id: '86aa74d0-2136-11ea-9864-ebc8cc1cb8c2', title: 'Titled timeline', }, + threatIndex: [], threshold: { field: [''], value: '100', diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/create/helpers.ts b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/create/helpers.ts index 65a5c6aca0050..160809a2ba3cd 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/create/helpers.ts +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/create/helpers.ts @@ -73,28 +73,77 @@ export interface RuleFields { index: unknown; ruleType: unknown; threshold?: unknown; + threatIndex?: unknown; + threatQueryBar?: unknown; + threatMapping?: unknown; + threatLanguage?: unknown; } -type QueryRuleFields = Omit; -type ThresholdRuleFields = Omit; -type MlRuleFields = Omit; + +type QueryRuleFields = Omit< + T, + | 'anomalyThreshold' + | 'machineLearningJobId' + | 'threshold' + | 'threatIndex' + | 'threatQueryBar' + | 'threatMapping' +>; +type ThresholdRuleFields = Omit< + T, + 'anomalyThreshold' | 'machineLearningJobId' | 'threatIndex' | 'threatQueryBar' | 'threatMapping' +>; +type MlRuleFields = Omit< + T, + 'queryBar' | 'index' | 'threshold' | 'threatIndex' | 'threatQueryBar' | 'threatMapping' +>; +type ThreatMatchRuleFields = Omit; const isMlFields = ( - fields: QueryRuleFields | MlRuleFields | ThresholdRuleFields + fields: QueryRuleFields | MlRuleFields | ThresholdRuleFields | ThreatMatchRuleFields ): fields is MlRuleFields => has('anomalyThreshold', fields); const isThresholdFields = ( - fields: QueryRuleFields | MlRuleFields | ThresholdRuleFields + fields: QueryRuleFields | MlRuleFields | ThresholdRuleFields | ThreatMatchRuleFields ): fields is ThresholdRuleFields => has('threshold', fields); -export const filterRuleFieldsForType = (fields: T, type: Type) => { +const isThreatMatchFields = ( + fields: QueryRuleFields | MlRuleFields | ThresholdRuleFields | ThreatMatchRuleFields +): fields is ThreatMatchRuleFields => has('threatIndex', fields); + +export const filterRuleFieldsForType = ( + fields: T, + type: Type +): QueryRuleFields | MlRuleFields | ThresholdRuleFields | ThreatMatchRuleFields => { switch (type) { case 'machine_learning': - const { index, queryBar, threshold, ...mlRuleFields } = fields; + const { + index, + queryBar, + threshold, + threatIndex, + threatQueryBar, + threatMapping, + ...mlRuleFields + } = fields; return mlRuleFields; case 'threshold': - const { anomalyThreshold, machineLearningJobId, ...thresholdRuleFields } = fields; + const { + anomalyThreshold, + machineLearningJobId, + threatIndex: _removedThreatIndex, + threatQueryBar: _removedThreatQueryBar, + threatMapping: _removedThreatMapping, + ...thresholdRuleFields + } = fields; return thresholdRuleFields; case 'threat_match': + const { + anomalyThreshold: _removedAnomalyThreshold, + machineLearningJobId: _removedMachineLearningJobId, + threshold: _removedThreshold, + ...threatMatchRuleFields + } = fields; + return threatMatchRuleFields; case 'query': case 'saved_query': case 'eql': @@ -102,6 +151,9 @@ export const filterRuleFieldsForType = (fields: T, type: T anomalyThreshold: _a, machineLearningJobId: _m, threshold: _t, + threatIndex: __removedThreatIndex, + threatQueryBar: __removedThreatQueryBar, + threatMapping: __removedThreatMapping, ...queryRuleFields } = fields; return queryRuleFields; @@ -140,6 +192,18 @@ export const formatDefineStepData = (defineStepData: DefineStepRule): DefineStep }, }), } + : isThreatMatchFields(ruleFields) + ? { + index: ruleFields.index, + filters: ruleFields.queryBar?.filters, + language: ruleFields.queryBar?.query?.language, + query: ruleFields.queryBar?.query?.query as string, + saved_id: ruleFields.queryBar?.saved_id, + threat_index: ruleFields.threatIndex, + threat_query: ruleFields.threatQueryBar?.query?.query as string, + threat_mapping: ruleFields.threatMapping, + threat_language: ruleFields.threatQueryBar?.query?.language, + } : { index: ruleFields.index, filters: ruleFields.queryBar?.filters, diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/create/index.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/create/index.tsx index 48247392dfe7f..542b7b1b84c3c 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/create/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/create/index.tsx @@ -183,10 +183,10 @@ const CreateRulePageComponent: React.FC = () => { if (nextStep != null) { goToStep(nextStep); } else { - const defineStep = await stepsData.current[RuleStep.defineRule]; - const aboutStep = await stepsData.current[RuleStep.aboutRule]; - const scheduleStep = await stepsData.current[RuleStep.scheduleRule]; - const actionsStep = await stepsData.current[RuleStep.ruleActions]; + const defineStep = stepsData.current[RuleStep.defineRule]; + const aboutStep = stepsData.current[RuleStep.aboutRule]; + const scheduleStep = stepsData.current[RuleStep.scheduleRule]; + const actionsStep = stepsData.current[RuleStep.ruleActions]; if ( stepIsValid(defineStep) && diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/helpers.test.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/helpers.test.tsx index 8545e5da512bb..0cd75506fa9f5 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/helpers.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/helpers.test.tsx @@ -82,6 +82,16 @@ describe('rule helpers', () => { field: ['host.name'], value: '50', }, + threatIndex: [], + threatMapping: [], + threatQueryBar: { + query: { + query: '', + language: '', + }, + filters: [], + saved_id: undefined, + }, timeline: { id: '86aa74d0-2136-11ea-9864-ebc8cc1cb8c2', title: 'Titled timeline', @@ -217,6 +227,16 @@ describe('rule helpers', () => { field: [], value: '100', }, + threatIndex: [], + threatMapping: [], + threatQueryBar: { + query: { + query: '', + language: '', + }, + filters: [], + saved_id: undefined, + }, timeline: { id: '86aa74d0-2136-11ea-9864-ebc8cc1cb8c2', title: 'Untitled timeline', @@ -249,6 +269,16 @@ describe('rule helpers', () => { field: [], value: '100', }, + threatIndex: [], + threatMapping: [], + threatQueryBar: { + query: { + query: '', + language: '', + }, + filters: [], + saved_id: undefined, + }, timeline: { id: '86aa74d0-2136-11ea-9864-ebc8cc1cb8c2', title: 'Untitled timeline', diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/helpers.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/helpers.tsx index 42fbe40d690ea..456bf8419a1f7 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/helpers.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/helpers.tsx @@ -79,6 +79,13 @@ export const getDefineStepsData = (rule: Rule): DefineStepRule => ({ anomalyThreshold: rule.anomaly_threshold ?? 50, machineLearningJobId: rule.machine_learning_job_id ?? '', index: rule.index ?? [], + threatIndex: rule.threat_index ?? [], + threatQueryBar: { + query: { query: rule.threat_query ?? '', language: rule.threat_language ?? '' }, + filters: (rule.threat_filters ?? []) as Filter[], + saved_id: undefined, + }, + threatMapping: rule.threat_mapping ?? [], queryBar: { query: { query: rule.query ?? '', language: rule.language ?? '' }, filters: (rule.filters ?? []) as Filter[], @@ -341,7 +348,6 @@ export const getActionMessageRuleParams = (ruleType: Type): string[] => { 'threat', 'type', 'version', - // 'lists', ]; const ruleParamsKeys = [ diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/types.ts b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/types.ts index e3d0ea123872a..f2afe32b1e12c 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/types.ts +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/types.ts @@ -22,7 +22,11 @@ import { Type, Severity, } from '../../../../../common/detection_engine/schemas/common/schemas'; -import { List } from '../../../../../common/detection_engine/schemas/types'; +import { + List, + ThreatIndex, + ThreatMapping, +} from '../../../../../common/detection_engine/schemas/types'; export interface EuiBasicTableSortTypes { field: string; @@ -124,6 +128,9 @@ export interface DefineStepRule { ruleType: Type; timeline: FieldValueTimeline; threshold: FieldValueThreshold; + threatIndex: ThreatIndex; + threatQueryBar: FieldValueQueryBar; + threatMapping: ThreatMapping; } export interface ScheduleStepRule { 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 9081831c45497..894ac2e0bb703 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 @@ -399,6 +399,7 @@ export const getResult = (): RuleAlertType => ({ timestampOverride: undefined, threatFilters: undefined, threatMapping: undefined, + threatLanguage: undefined, threatIndex: undefined, threatQuery: undefined, references: ['http://www.example.com', 'https://ww.example.com'], diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rules_bulk_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rules_bulk_route.ts index 067a4352e1080..09e161166dddf 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rules_bulk_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rules_bulk_route.ts @@ -96,6 +96,7 @@ export const createRulesBulkRoute = (router: IRouter, ml: SetupPlugins['ml']) => threat_index: threatIndex, threat_mapping: threatMapping, threat_query: threatQuery, + threat_language: threatLanguage, threshold, throttle, timestamp_override: timestampOverride, @@ -186,6 +187,7 @@ export const createRulesBulkRoute = (router: IRouter, ml: SetupPlugins['ml']) => threatMapping, threatQuery, threatIndex, + threatLanguage, threshold, timestampOverride, references, 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 54df87ca17787..9940a56988c77 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 @@ -84,6 +84,7 @@ export const createRulesRoute = (router: IRouter, ml: SetupPlugins['ml']): void threat_index: threatIndex, threat_query: threatQuery, threat_mapping: threatMapping, + threat_language: threatLanguage, throttle, timestamp_override: timestampOverride, to, @@ -175,6 +176,7 @@ export const createRulesRoute = (router: IRouter, ml: SetupPlugins['ml']): void threatIndex, threatQuery, threatMapping, + threatLanguage, timestampOverride, references, note, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/import_rules_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/import_rules_route.ts index 4dbca5df0041c..fb9d9c4ea72cf 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/import_rules_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/import_rules_route.ts @@ -163,6 +163,7 @@ export const importRulesRoute = (router: IRouter, config: ConfigType, ml: SetupP threat_index: threatIndex, threat_query: threatQuery, threat_mapping: threatMapping, + threat_language: threatLanguage, threshold, timestamp_override: timestampOverride, to, @@ -223,11 +224,12 @@ export const importRulesRoute = (router: IRouter, config: ConfigType, ml: SetupP to, type, threat, + threshold, threatFilters, threatIndex, threatQuery, - threshold, threatMapping, + threatLanguage, timestampOverride, references, note, @@ -272,6 +274,11 @@ export const importRulesRoute = (router: IRouter, config: ConfigType, ml: SetupP type, threat, threshold, + threatFilters, + threatIndex, + threatQuery, + threatMapping, + threatLanguage, references, note, version, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/patch_rules_bulk_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/patch_rules_bulk_route.ts index 39bbe9ee686a4..081e804cf7356 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/patch_rules_bulk_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/patch_rules_bulk_route.ts @@ -87,6 +87,11 @@ export const patchRulesBulkRoute = (router: IRouter, ml: SetupPlugins['ml']) => type, threat, threshold, + threat_filters: threatFilters, + threat_index: threatIndex, + threat_query: threatQuery, + threat_mapping: threatMapping, + threat_language: threatLanguage, timestamp_override: timestampOverride, throttle, references, @@ -147,6 +152,11 @@ export const patchRulesBulkRoute = (router: IRouter, ml: SetupPlugins['ml']) => type, threat, threshold, + threatFilters, + threatIndex, + threatQuery, + threatMapping, + threatLanguage, timestampOverride, references, note, 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 879bd8d5b8a1d..baa5468f862c3 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 @@ -78,6 +78,11 @@ export const patchRulesRoute = (router: IRouter, ml: SetupPlugins['ml']) => { type, threat, threshold, + threat_filters: threatFilters, + threat_index: threatIndex, + threat_query: threatQuery, + threat_mapping: threatMapping, + threat_language: threatLanguage, timestamp_override: timestampOverride, throttle, references, @@ -146,6 +151,11 @@ export const patchRulesRoute = (router: IRouter, ml: SetupPlugins['ml']) => { type, threat, threshold, + threatFilters, + threatIndex, + threatQuery, + threatMapping, + threatLanguage, timestampOverride, references, note, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_bulk_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_bulk_route.ts index 4df0773f86317..8828bbe6c9826 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_bulk_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_bulk_route.ts @@ -91,6 +91,11 @@ export const updateRulesBulkRoute = (router: IRouter, ml: SetupPlugins['ml']) => type, threat, threshold, + threat_filters: threatFilters, + threat_index: threatIndex, + threat_query: threatQuery, + threat_mapping: threatMapping, + threat_language: threatLanguage, throttle, timestamp_override: timestampOverride, references, @@ -158,6 +163,11 @@ export const updateRulesBulkRoute = (router: IRouter, ml: SetupPlugins['ml']) => type, threat, threshold, + threatFilters, + threatIndex, + threatQuery, + threatMapping, + threatLanguage, timestampOverride, references, note, 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 ef698db008d80..1fa3bb8c9bc82 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 @@ -81,6 +81,11 @@ export const updateRulesRoute = (router: IRouter, ml: SetupPlugins['ml']) => { type, threat, threshold, + threat_filters: threatFilters, + threat_index: threatIndex, + threat_query: threatQuery, + threat_mapping: threatMapping, + threat_language: threatLanguage, throttle, timestamp_override: timestampOverride, references, @@ -148,6 +153,11 @@ export const updateRulesRoute = (router: IRouter, ml: SetupPlugins['ml']) => { type, threat, threshold, + threatFilters, + threatIndex, + threatQuery, + threatMapping, + threatLanguage, timestampOverride, references, note, 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 2159245f2f735..13eb7495a898a 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 @@ -156,7 +156,7 @@ describe('utils', () => { ], }, ]; - threatRule.params.threatIndex = 'index-123'; + threatRule.params.threatIndex = ['index-123']; threatRule.params.threatFilters = threatFilters; threatRule.params.threatMapping = threatMapping; threatRule.params.threatQuery = '*:*'; @@ -164,7 +164,7 @@ describe('utils', () => { const rule = transformAlertToRule(threatRule); expect(rule).toEqual( expect.objectContaining({ - threat_index: 'index-123', + threat_index: ['index-123'], threat_filters: threatFilters, threat_mapping: threatMapping, threat_query: '*:*', 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 c75b32b614e07..fb4ba855f6536 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 @@ -150,6 +150,7 @@ export const transformAlertToRule = ( threat_index: alert.params.threatIndex, threat_query: alert.params.threatQuery, threat_mapping: alert.params.threatMapping, + threat_language: alert.params.threatLanguage, throttle: ruleActions?.ruleThrottle || 'no_actions', timestamp_override: alert.params.timestampOverride, note: alert.params.note, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/create_rules.mock.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/create_rules.mock.ts index a6034f3d7b7b3..271b1043ea568 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/create_rules.mock.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/create_rules.mock.ts @@ -42,6 +42,7 @@ export const getCreateRulesOptionsMock = (): CreateRulesOptions => ({ threat: [], threatFilters: undefined, threatMapping: undefined, + threatLanguage: undefined, threatQuery: undefined, threatIndex: undefined, threshold: undefined, @@ -92,6 +93,7 @@ export const getCreateMlRulesOptionsMock = (): CreateRulesOptions => ({ threatIndex: undefined, threatMapping: undefined, threatQuery: undefined, + threatLanguage: undefined, threshold: undefined, timestampOverride: undefined, to: 'now', diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/create_rules.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/create_rules.ts index 3a311d03e3c89..776882d0f8494 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/create_rules.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/create_rules.ts @@ -45,6 +45,7 @@ export const createRules = async ({ threat, threatFilters, threatIndex, + threatLanguage, threatQuery, threatMapping, threshold, @@ -96,6 +97,7 @@ export const createRules = async ({ threatIndex, threatQuery, threatMapping, + threatLanguage, timestampOverride, to, type, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/install_prepacked_rules.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/install_prepacked_rules.ts index 38adc03c00d50..0a43c652234d0 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/install_prepacked_rules.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/install_prepacked_rules.ts @@ -50,6 +50,7 @@ export const installPrepackagedRules = ( threat, threat_filters: threatFilters, threat_mapping: threatMapping, + threat_language: threatLanguage, threat_query: threatQuery, threat_index: threatIndex, threshold, @@ -101,6 +102,7 @@ export const installPrepackagedRules = ( threat, threatFilters, threatMapping, + threatLanguage, threatQuery, threatIndex, threshold, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/patch_rules.mock.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/patch_rules.mock.ts index 8672c85f98426..ef7cd35f28f1b 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/patch_rules.mock.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/patch_rules.mock.ts @@ -149,6 +149,11 @@ export const getPatchRulesOptionsMock = (): PatchRulesOptions => ({ tags: [], threat: [], threshold: undefined, + threatFilters: undefined, + threatIndex: undefined, + threatQuery: undefined, + threatMapping: undefined, + threatLanguage: undefined, timestampOverride: undefined, to: 'now', type: 'query', @@ -193,6 +198,11 @@ export const getPatchMlRulesOptionsMock = (): PatchRulesOptions => ({ tags: [], threat: [], threshold: undefined, + threatFilters: undefined, + threatIndex: undefined, + threatQuery: undefined, + threatMapping: undefined, + threatLanguage: undefined, timestampOverride: undefined, to: 'now', type: 'machine_learning', diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/patch_rules.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/patch_rules.ts index 852ff06bdc736..1982dcf9dd9b6 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/patch_rules.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/patch_rules.ts @@ -44,6 +44,11 @@ export const patchRules = async ({ tags, threat, threshold, + threatFilters, + threatIndex, + threatQuery, + threatMapping, + threatLanguage, timestampOverride, to, type, @@ -87,6 +92,11 @@ export const patchRules = async ({ tags, threat, threshold, + threatFilters, + threatIndex, + threatQuery, + threatMapping, + threatLanguage, timestampOverride, to, type, @@ -126,6 +136,11 @@ export const patchRules = async ({ severityMapping, threat, threshold, + threatFilters, + threatIndex, + threatQuery, + threatMapping, + threatLanguage, timestampOverride, to, type, 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 d688e1b338e21..8af622e6a128b 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 @@ -91,6 +91,7 @@ import { ThreatQueryOrUndefined, ThreatMappingOrUndefined, ThreatFiltersOrUndefined, + ThreatLanguageOrUndefined, } from '../../../../common/detection_engine/schemas/types/threat_mapping'; import { AlertsClient, PartialAlert } from '../../../../../alerts/server'; @@ -219,6 +220,7 @@ export interface CreateRulesOptions { threatIndex: ThreatIndexOrUndefined; threatQuery: ThreatQueryOrUndefined; threatMapping: ThreatMappingOrUndefined; + threatLanguage: ThreatLanguageOrUndefined; timestampOverride: TimestampOverrideOrUndefined; to: To; type: Type; @@ -264,6 +266,11 @@ export interface UpdateRulesOptions { tags: Tags; threat: Threat; threshold: ThresholdOrUndefined; + threatFilters: ThreatFiltersOrUndefined; + threatIndex: ThreatIndexOrUndefined; + threatQuery: ThreatQueryOrUndefined; + threatMapping: ThreatMappingOrUndefined; + threatLanguage: ThreatLanguageOrUndefined; timestampOverride: TimestampOverrideOrUndefined; to: To; type: Type; @@ -307,6 +314,11 @@ export interface PatchRulesOptions { tags: TagsOrUndefined; threat: ThreatOrUndefined; threshold: ThresholdOrUndefined; + threatFilters: ThreatFiltersOrUndefined; + threatIndex: ThreatIndexOrUndefined; + threatQuery: ThreatQueryOrUndefined; + threatMapping: ThreatMappingOrUndefined; + threatLanguage: ThreatLanguageOrUndefined; timestampOverride: TimestampOverrideOrUndefined; to: ToOrUndefined; type: TypeOrUndefined; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_prepacked_rules.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_prepacked_rules.ts index 01a481ed7b2d9..c685c4198c119 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_prepacked_rules.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_prepacked_rules.ts @@ -47,6 +47,11 @@ export const updatePrepackagedRules = async ( type, threat, threshold, + threat_filters: threatFilters, + threat_index: threatIndex, + threat_query: threatQuery, + threat_mapping: threatMapping, + threat_language: threatLanguage, timestamp_override: timestampOverride, references, version, @@ -97,6 +102,11 @@ export const updatePrepackagedRules = async ( type, threat, threshold, + threatFilters, + threatIndex, + threatQuery, + threatMapping, + threatLanguage, references, version, note, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_rules.mock.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_rules.mock.ts index 8cdc904a861c7..a33651580ef22 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_rules.mock.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_rules.mock.ts @@ -43,6 +43,11 @@ export const getUpdateRulesOptionsMock = (): UpdateRulesOptions => ({ tags: [], threat: [], threshold: undefined, + threatFilters: undefined, + threatIndex: undefined, + threatQuery: undefined, + threatMapping: undefined, + threatLanguage: undefined, timestampOverride: undefined, to: 'now', type: 'query', @@ -88,6 +93,11 @@ export const getUpdateMlRulesOptionsMock = (): UpdateRulesOptions => ({ tags: [], threat: [], threshold: undefined, + threatFilters: undefined, + threatIndex: undefined, + threatQuery: undefined, + threatMapping: undefined, + threatLanguage: undefined, timestampOverride: undefined, to: 'now', type: 'machine_learning', diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_rules.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_rules.ts index 08df785884b76..3da921ed47f26 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_rules.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_rules.ts @@ -45,6 +45,11 @@ export const updateRules = async ({ tags, threat, threshold, + threatFilters, + threatIndex, + threatQuery, + threatMapping, + threatLanguage, timestampOverride, to, type, @@ -89,6 +94,11 @@ export const updateRules = async ({ tags, threat, threshold, + threatFilters, + threatIndex, + threatQuery, + threatMapping, + threatLanguage, timestampOverride, to, type, @@ -134,6 +144,11 @@ export const updateRules = async ({ severityMapping, threat, threshold, + threatFilters, + threatIndex, + threatQuery, + threatMapping, + threatLanguage, timestampOverride, to, type, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/utils.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/utils.test.ts index 227f574bc4e4b..654383ff97c7a 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/utils.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/utils.test.ts @@ -55,6 +55,11 @@ describe('utils', () => { tags: undefined, threat: undefined, threshold: undefined, + threatFilters: undefined, + threatIndex: undefined, + threatQuery: undefined, + threatMapping: undefined, + threatLanguage: undefined, to: undefined, timestampOverride: undefined, type: undefined, @@ -98,6 +103,11 @@ describe('utils', () => { tags: undefined, threat: undefined, threshold: undefined, + threatFilters: undefined, + threatIndex: undefined, + threatQuery: undefined, + threatMapping: undefined, + threatLanguage: undefined, to: undefined, timestampOverride: undefined, type: undefined, @@ -141,6 +151,11 @@ describe('utils', () => { tags: undefined, threat: undefined, threshold: undefined, + threatFilters: undefined, + threatIndex: undefined, + threatQuery: undefined, + threatMapping: undefined, + threatLanguage: undefined, to: undefined, timestampOverride: undefined, type: undefined, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/utils.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/utils.ts index d9f953f2803a6..a9a100543b528 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/utils.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/utils.ts @@ -42,7 +42,14 @@ import { EventCategoryOverrideOrUndefined, } from '../../../../common/detection_engine/schemas/common/schemas'; import { PartialFilter } from '../types'; -import { ListArrayOrUndefined } from '../../../../common/detection_engine/schemas/types'; +import { + ListArrayOrUndefined, + ThreatFiltersOrUndefined, + ThreatIndexOrUndefined, + ThreatLanguageOrUndefined, + ThreatMappingOrUndefined, + ThreatQueryOrUndefined, +} from '../../../../common/detection_engine/schemas/types'; export const calculateInterval = ( interval: string | undefined, @@ -86,6 +93,11 @@ export interface UpdateProperties { tags: TagsOrUndefined; threat: ThreatOrUndefined; threshold: ThresholdOrUndefined; + threatFilters: ThreatFiltersOrUndefined; + threatIndex: ThreatIndexOrUndefined; + threatQuery: ThreatQueryOrUndefined; + threatMapping: ThreatMappingOrUndefined; + threatLanguage: ThreatLanguageOrUndefined; timestampOverride: TimestampOverrideOrUndefined; to: ToOrUndefined; type: TypeOrUndefined; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/rules/queries/query_with_threat_mapping.json b/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/rules/queries/query_with_threat_mapping.json index c914e568048a1..1e2f217751e96 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/rules/queries/query_with_threat_mapping.json +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/rules/queries/query_with_threat_mapping.json @@ -7,7 +7,7 @@ "type": "threat_match", "query": "*:*", "tags": ["tag_1", "tag_2"], - "threat_index": "mock-threat-list", + "threat_index": ["mock-threat-list"], "threat_query": "*:*", "threat_mapping": [ { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/__mocks__/es_results.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/__mocks__/es_results.ts index 501cd1fa6ecfb..cbf70f3119b31 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/__mocks__/es_results.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/__mocks__/es_results.ts @@ -60,6 +60,7 @@ export const sampleRuleAlertParams = ( threatQuery: undefined, threatMapping: undefined, threatIndex: undefined, + threatLanguage: undefined, timelineId: undefined, timelineTitle: undefined, timestampOverride: undefined, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/build_rule.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/build_rule.ts index 344f705c4af24..6a76c7842e451 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/build_rule.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/build_rule.ts @@ -168,6 +168,7 @@ export const buildRuleWithoutOverrides = ( threat_index: ruleParams.threatIndex, threat_query: ruleParams.threatQuery, threat_mapping: ruleParams.threatMapping, + threat_language: ruleParams.threatLanguage, }; return removeInternalTagsFromRule(rule); }; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/signal_params_schema.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/signal_params_schema.ts index 4006345b24385..cfe71f66395b0 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/signal_params_schema.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/signal_params_schema.ts @@ -50,9 +50,10 @@ const signalSchema = schema.object({ exceptions_list: schema.maybe(schema.arrayOf(schema.object({}, { unknowns: 'allow' }))), // For backwards compatibility with customers that had a data bug in 7.8. Once we use a migration script please remove this. exceptionsList: schema.maybe(schema.arrayOf(schema.object({}, { unknowns: 'allow' }))), threatFilters: schema.nullable(schema.arrayOf(schema.object({}, { unknowns: 'allow' }))), - threatIndex: schema.maybe(schema.string()), + threatIndex: schema.maybe(schema.arrayOf(schema.string())), threatQuery: schema.maybe(schema.string()), threatMapping: schema.maybe(schema.arrayOf(schema.object({}, { unknowns: 'allow' }))), + threatLanguage: schema.maybe(schema.string()), }); /** diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/signal_rule_alert_type.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/signal_rule_alert_type.ts index 95348808bb58f..9436dc9cf8a8e 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/signal_rule_alert_type.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/signal_rule_alert_type.ts @@ -112,6 +112,7 @@ export const signalRulesAlertType = ({ threatQuery, threatIndex, threatMapping, + threatLanguage, type, exceptionsList, } = params; @@ -389,6 +390,7 @@ export const signalRulesAlertType = ({ throttle, threatFilters: threatFilters ?? [], threatQuery, + threatLanguage, buildRuleMessage, threatIndex, }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threat_mapping/create_threat_signal.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threat_mapping/create_threat_signal.ts index 560e7ad7fe2cb..09ddfb342496d 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threat_mapping/create_threat_signal.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threat_mapping/create_threat_signal.ts @@ -45,6 +45,7 @@ export const createThreatSignal = async ({ throttle, threatFilters, threatQuery, + threatLanguage, buildRuleMessage, threatIndex, name, @@ -105,8 +106,9 @@ export const createThreatSignal = async ({ callCluster: services.callCluster, exceptionItems, query: threatQuery, + language: threatLanguage, threatFilters, - index: [threatIndex], + index: threatIndex, searchAfter, sortField: undefined, sortOrder: undefined, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threat_mapping/create_threat_signals.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threat_mapping/create_threat_signals.ts index f44c7a9684457..eeace508c9bfe 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threat_mapping/create_threat_signals.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threat_mapping/create_threat_signals.ts @@ -41,6 +41,7 @@ export const createThreatSignals = async ({ throttle, threatFilters, threatQuery, + threatLanguage, buildRuleMessage, threatIndex, name, @@ -59,7 +60,8 @@ export const createThreatSignals = async ({ exceptionItems, threatFilters, query: threatQuery, - index: [threatIndex], + language: threatLanguage, + index: threatIndex, searchAfter: undefined, sortField: undefined, sortOrder: undefined, @@ -99,6 +101,7 @@ export const createThreatSignals = async ({ threatQuery, buildRuleMessage, threatIndex, + threatLanguage, name, currentThreatList: threatList, currentResult: results, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threat_mapping/get_threat_list.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threat_mapping/get_threat_list.ts index 8b381ca0d96dc..3c3f5b544bb17 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threat_mapping/get_threat_list.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threat_mapping/get_threat_list.ts @@ -21,6 +21,7 @@ export const MAX_PER_PAGE = 9000; export const getThreatList = async ({ callCluster, query, + language, index, perPage, searchAfter, @@ -33,7 +34,13 @@ export const getThreatList = async ({ if (calculatedPerPage > 10000) { throw new TypeError('perPage cannot exceed the size of 10000'); } - const queryFilter = getQueryFilter(query, 'kuery', threatFilters, index, exceptionItems); + const queryFilter = getQueryFilter( + query, + language ?? 'kuery', + threatFilters, + index, + exceptionItems + ); const response: SearchResponse = await callCluster('search', { body: { query: queryFilter, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threat_mapping/types.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threat_mapping/types.ts index 7cd6e5196ea68..06c9c4c13c5f3 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threat_mapping/types.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threat_mapping/types.ts @@ -15,6 +15,8 @@ import { ThreatQuery, ThreatMapping, ThreatMappingEntries, + ThreatIndex, + ThreatLanguageOrUndefined, } from '../../../../../common/detection_engine/schemas/types/threat_mapping'; import { PartialFilter, RuleTypeParams } from '../../types'; import { AlertServices } from '../../../../../../alerts/server'; @@ -57,7 +59,8 @@ export interface CreateThreatSignalsOptions { threatFilters: PartialFilter[]; threatQuery: ThreatQuery; buildRuleMessage: BuildRuleMessage; - threatIndex: string; + threatIndex: ThreatIndex; + threatLanguage: ThreatLanguageOrUndefined; name: string; } @@ -93,7 +96,8 @@ export interface CreateThreatSignalOptions { threatFilters: PartialFilter[]; threatQuery: ThreatQuery; buildRuleMessage: BuildRuleMessage; - threatIndex: string; + threatIndex: ThreatIndex; + threatLanguage: ThreatLanguageOrUndefined; name: string; currentThreatList: SearchResponse; currentResult: SearchAfterAndBulkCreateReturnType; @@ -138,6 +142,7 @@ export interface BooleanFilter { export interface GetThreatListOptions { callCluster: ILegacyScopedClusterClient['callAsCurrentUser']; query: string; + language: ThreatLanguageOrUndefined; index: string[]; perPage?: number; searchAfter: string[] | undefined; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/types.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/types.ts index 728f5b1dd867f..cf4d989c1f4c8 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/types.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/types.ts @@ -43,6 +43,7 @@ import { ThreatIndexOrUndefined, ThreatQueryOrUndefined, ThreatMappingOrUndefined, + ThreatLanguageOrUndefined, } from '../../../common/detection_engine/schemas/types/threat_mapping'; import { LegacyCallAPIOptions } from '../../../../../../src/core/server'; @@ -85,6 +86,7 @@ export interface RuleTypeParams { threatIndex: ThreatIndexOrUndefined; threatQuery: ThreatQueryOrUndefined; threatMapping: ThreatMappingOrUndefined; + threatLanguage: ThreatLanguageOrUndefined; timestampOverride: TimestampOverrideOrUndefined; to: To; type: Type; From 0ee253e9e016b776e45387e3e30c0cec0721d372 Mon Sep 17 00:00:00 2001 From: Spencer Date: Thu, 1 Oct 2020 16:43:13 -0700 Subject: [PATCH 21/50] [optimizer] strip proptypes from plugin bundles in production (#79221) Co-authored-by: spalger --- packages/kbn-babel-preset/package.json | 1 + packages/kbn-babel-preset/webpack_preset.js | 13 +++++++++++++ packages/kbn-optimizer/src/worker/webpack.config.ts | 1 + yarn.lock | 5 +++++ 4 files changed, 20 insertions(+) diff --git a/packages/kbn-babel-preset/package.json b/packages/kbn-babel-preset/package.json index d6d1a78dd4a23..bc4e0ec338f94 100644 --- a/packages/kbn-babel-preset/package.json +++ b/packages/kbn-babel-preset/package.json @@ -15,6 +15,7 @@ "babel-plugin-add-module-exports": "^1.0.2", "babel-plugin-styled-components": "^1.10.7", "babel-plugin-transform-define": "^1.3.1", + "babel-plugin-transform-react-remove-prop-types": "^0.4.24", "react-is": "^16.8.0", "styled-components": "^5.1.0" } diff --git a/packages/kbn-babel-preset/webpack_preset.js b/packages/kbn-babel-preset/webpack_preset.js index a43d607edb17c..503b99d3c3e8a 100644 --- a/packages/kbn-babel-preset/webpack_preset.js +++ b/packages/kbn-babel-preset/webpack_preset.js @@ -40,5 +40,18 @@ module.exports = () => { }, ], ], + env: { + production: { + plugins: [ + [ + require.resolve('babel-plugin-transform-react-remove-prop-types'), + { + mode: 'remove', + removeImport: true, + }, + ], + ], + }, + }, }; }; diff --git a/packages/kbn-optimizer/src/worker/webpack.config.ts b/packages/kbn-optimizer/src/worker/webpack.config.ts index 2edf1c999888e..9678dd5de868b 100644 --- a/packages/kbn-optimizer/src/worker/webpack.config.ts +++ b/packages/kbn-optimizer/src/worker/webpack.config.ts @@ -200,6 +200,7 @@ export function getWebpackConfig(bundle: Bundle, bundleRefs: BundleRefs, worker: loader: 'babel-loader', options: { babelrc: false, + envName: worker.dist ? 'production' : 'development', presets: IS_CODE_COVERAGE ? [ISTANBUL_PRESET_PATH, BABEL_PRESET_PATH] : [BABEL_PRESET_PATH], diff --git a/yarn.lock b/yarn.lock index 77e3a399c4313..d795a174cfaa0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7612,6 +7612,11 @@ babel-plugin-transform-property-literals@^6.9.4: dependencies: esutils "^2.0.2" +babel-plugin-transform-react-remove-prop-types@^0.4.24: + version "0.4.24" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-remove-prop-types/-/babel-plugin-transform-react-remove-prop-types-0.4.24.tgz#f2edaf9b4c6a5fbe5c1d678bfb531078c1555f3a" + integrity sha512-eqj0hVcJUR57/Ug2zE1Yswsw4LhuqqHhD+8v120T1cl3kjg76QwtyBrdIk4WVwK+lAhBJVYCd/v+4nc4y+8JsA== + babel-plugin-transform-regexp-constructors@^0.4.3: version "0.4.3" resolved "https://registry.yarnpkg.com/babel-plugin-transform-regexp-constructors/-/babel-plugin-transform-regexp-constructors-0.4.3.tgz#58b7775b63afcf33328fae9a5f88fbd4fb0b4965" From e5d8d49164a8d993bdd314dd6c800f9186092148 Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Fri, 2 Oct 2020 00:46:00 +0100 Subject: [PATCH 22/50] chore(NA): assures a single version for the same dependency across the entire project (#78825) * chore(NA): script to check for multiple version of same dependency * chore(NA): remove multiple versions for the same dependency * chore(NA): hook single_version_dependencies script into the CI * chore(NA): remove grunt from the CI hook integration * chore(NA): update kbn pm dist * chore(NA): fix typechecking * chore(NA): update code to run under last extract-zip version * fix(NA): multiple versions of the same type dependency * move validation to bootstrap (#13) Co-authored-by: spalger * chore(NA): todo to remove logic to validate single version deps once we move into a single package.json * chore(NA): remove verify dependency versions jenkins task * chore(NA): update kbn pm dist file * chore(NA): remove last mention to verify_dependency_versions.sh fom tasks.groovy Co-authored-by: Spencer Co-authored-by: spalger Co-authored-by: Elastic Machine --- package.json | 10 +- packages/kbn-apm-config-loader/package.json | 2 +- packages/kbn-es/package.json | 2 +- packages/kbn-plugin-helpers/package.json | 2 +- packages/kbn-pm/dist/index.js | 4764 +++++++++-------- packages/kbn-pm/package.json | 6 +- .../kbn-pm/src/utils/validate_yarn_lock.ts | 62 + packages/kbn-release-notes/package.json | 2 +- packages/kbn-storybook/package.json | 4 +- packages/kbn-storybook/webpack.config.ts | 4 - packages/kbn-test/package.json | 2 +- packages/kbn-ui-framework/package.json | 6 +- tasks/config/run.js | 4 - tasks/jenkins.js | 1 - tasks/verify_dependency_versions.js | 53 - .../checks/verify_dependency_versions.sh | 5 - vars/tasks.groovy | 1 - x-pack/package.json | 12 +- x-pack/plugins/apm/e2e/package.json | 2 +- x-pack/plugins/apm/scripts/package.json | 2 +- .../server/browsers/extract/unzip.js | 16 +- .../public/common/mock/timeline_results.ts | 2 +- .../scripts/beat_docs/build.js | 38 +- yarn.lock | 363 +- 24 files changed, 2667 insertions(+), 2698 deletions(-) delete mode 100644 tasks/verify_dependency_versions.js delete mode 100755 test/scripts/checks/verify_dependency_versions.sh diff --git a/package.json b/package.json index 0eda8dd9f4114..ff98d7f85dcef 100644 --- a/package.json +++ b/package.json @@ -151,7 +151,7 @@ "angular-sanitize": "^1.8.0", "bluebird": "3.5.5", "boom": "^7.2.0", - "chalk": "^2.4.2", + "chalk": "^4.1.0", "check-disk-space": "^2.1.0", "chokidar": "^3.4.2", "color": "1.0.3", @@ -331,7 +331,7 @@ "@types/selenium-webdriver": "^4.0.9", "@types/semver": "^5.5.0", "@types/sinon": "^7.0.13", - "@types/strip-ansi": "^3.0.0", + "@types/strip-ansi": "^5.2.1", "@types/styled-components": "^5.1.0", "@types/supertest": "^2.0.5", "@types/supertest-as-promised": "^2.0.38", @@ -343,7 +343,7 @@ "@types/uuid": "^3.4.4", "@types/vinyl": "^2.0.4", "@types/vinyl-fs": "^2.4.11", - "@types/webpack": "^4.41.21", + "@types/webpack": "^4.41.3", "@types/webpack-env": "^1.15.2", "@types/zen-observable": "^0.8.0", "@typescript-eslint/eslint-plugin": "^3.10.0", @@ -470,10 +470,10 @@ "selenium-webdriver": "^4.0.0-alpha.7", "simple-git": "1.116.0", "sinon": "^7.4.2", - "strip-ansi": "^3.0.1", + "strip-ansi": "^6.0.0", "supertest": "^3.1.0", "supertest-as-promised": "^4.0.2", - "tape": "^4.13.0", + "tape": "^5.0.1", "topojson-client": "3.0.0", "tree-kill": "^1.2.2", "typescript": "4.0.2", diff --git a/packages/kbn-apm-config-loader/package.json b/packages/kbn-apm-config-loader/package.json index 1982ccdeda0ff..c570fdc0218b9 100644 --- a/packages/kbn-apm-config-loader/package.json +++ b/packages/kbn-apm-config-loader/package.json @@ -18,6 +18,6 @@ }, "devDependencies": { "typescript": "4.0.2", - "tsd": "^0.7.4" + "tsd": "^0.13.1" } } diff --git a/packages/kbn-es/package.json b/packages/kbn-es/package.json index 40d34c5d710bb..c3733094350be 100644 --- a/packages/kbn-es/package.json +++ b/packages/kbn-es/package.json @@ -9,7 +9,7 @@ "kbn:watch": "node scripts/build --watch" }, "dependencies": { - "@elastic/elasticsearch": "7.9.0-rc.1", + "@elastic/elasticsearch": "7.9.1", "@kbn/dev-utils": "1.0.0", "abort-controller": "^3.0.0", "chalk": "^4.1.0", diff --git a/packages/kbn-plugin-helpers/package.json b/packages/kbn-plugin-helpers/package.json index 65b44b6965048..a2c4e1e2134e7 100644 --- a/packages/kbn-plugin-helpers/package.json +++ b/packages/kbn-plugin-helpers/package.json @@ -18,7 +18,7 @@ "del": "^5.1.0", "execa": "^4.0.2", "gulp-zip": "^5.0.2", - "inquirer": "^1.2.2", + "inquirer": "^7.3.3", "load-json-file": "^6.2.0", "vinyl-fs": "^3.0.3" }, diff --git a/packages/kbn-pm/dist/index.js b/packages/kbn-pm/dist/index.js index 7dcfc1d778ea8..2882a72b3ac9d 100644 --- a/packages/kbn-pm/dist/index.js +++ b/packages/kbn-pm/dist/index.js @@ -94,7 +94,7 @@ __webpack_require__.r(__webpack_exports__); /* harmony import */ var _cli__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "run", function() { return _cli__WEBPACK_IMPORTED_MODULE_0__["run"]; }); -/* harmony import */ var _production__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(496); +/* harmony import */ var _production__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(500); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "buildProductionProjects", function() { return _production__WEBPACK_IMPORTED_MODULE_1__["buildProductionProjects"]; }); /* harmony import */ var _utils_projects__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(145); @@ -103,10 +103,10 @@ __webpack_require__.r(__webpack_exports__); /* harmony import */ var _utils_project__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(163); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "Project", function() { return _utils_project__WEBPACK_IMPORTED_MODULE_3__["Project"]; }); -/* harmony import */ var _utils_workspaces__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(275); +/* harmony import */ var _utils_workspaces__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(270); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "copyWorkspacePackages", function() { return _utils_workspaces__WEBPACK_IMPORTED_MODULE_4__["copyWorkspacePackages"]; }); -/* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(276); +/* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(271); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "getProjectPaths", function() { return _config__WEBPACK_IMPORTED_MODULE_5__["getProjectPaths"]; }); /* @@ -150,7 +150,7 @@ __webpack_require__.r(__webpack_exports__); /* harmony import */ var _kbn_dev_utils_tooling_log__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(5); /* harmony import */ var _kbn_dev_utils_tooling_log__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_kbn_dev_utils_tooling_log__WEBPACK_IMPORTED_MODULE_3__); /* harmony import */ var _commands__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(127); -/* harmony import */ var _run__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(489); +/* harmony import */ var _run__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(493); /* harmony import */ var _utils_log__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(143); /* * Licensed to Elasticsearch B.V. under one or more contributor @@ -8763,9 +8763,9 @@ exports.ToolingLogCollectingWriter = ToolingLogCollectingWriter; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "commands", function() { return commands; }); /* harmony import */ var _bootstrap__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(128); -/* harmony import */ var _clean__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(284); -/* harmony import */ var _run__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(388); -/* harmony import */ var _watch__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(389); +/* harmony import */ var _clean__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(279); +/* harmony import */ var _run__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(392); +/* harmony import */ var _watch__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(393); /* * Licensed to Elasticsearch B.V. under one or more contributor * license agreements. See the NOTICE file distributed with @@ -8806,10 +8806,10 @@ __webpack_require__.r(__webpack_exports__); /* harmony import */ var _utils_log__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(143); /* harmony import */ var _utils_parallelize__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(144); /* harmony import */ var _utils_projects__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(145); -/* harmony import */ var _utils_project_checksums__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(277); -/* harmony import */ var _utils_bootstrap_cache_file__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(282); -/* harmony import */ var _utils_yarn_lock__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(279); -/* harmony import */ var _utils_validate_yarn_lock__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(283); +/* harmony import */ var _utils_project_checksums__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(272); +/* harmony import */ var _utils_bootstrap_cache_file__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(277); +/* harmony import */ var _utils_yarn_lock__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(274); +/* harmony import */ var _utils_validate_yarn_lock__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(278); /* * Licensed to Elasticsearch B.V. under one or more contributor * license agreements. See the NOTICE file distributed with @@ -10831,7 +10831,7 @@ __webpack_require__.r(__webpack_exports__); /* harmony import */ var util__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(util__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var _errors__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(162); /* harmony import */ var _project__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(163); -/* harmony import */ var _workspaces__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(275); +/* harmony import */ var _workspaces__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(270); /* * Licensed to Elasticsearch B.V. under one or more contributor * license agreements. See the NOTICE file distributed with @@ -23648,11 +23648,11 @@ __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "spawnStreaming", function() { return spawnStreaming; }); /* harmony import */ var stream__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(137); /* harmony import */ var stream__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(stream__WEBPACK_IMPORTED_MODULE_0__); -/* harmony import */ var chalk__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(227); +/* harmony import */ var chalk__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(112); /* harmony import */ var chalk__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(chalk__WEBPACK_IMPORTED_MODULE_1__); -/* harmony import */ var execa__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(232); +/* harmony import */ var execa__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(227); /* harmony import */ var execa__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(execa__WEBPACK_IMPORTED_MODULE_2__); -/* harmony import */ var strong_log_transformer__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(267); +/* harmony import */ var strong_log_transformer__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(262); /* harmony import */ var strong_log_transformer__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(strong_log_transformer__WEBPACK_IMPORTED_MODULE_3__); /* harmony import */ var _log__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(143); function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } @@ -23743,602 +23743,18 @@ function spawnStreaming(command, args, opts, { "use strict"; -const ansiStyles = __webpack_require__(113); -const {stdout: stdoutColor, stderr: stderrColor} = __webpack_require__(228); -const { - stringReplaceAll, - stringEncaseCRLFWithFirstIndex -} = __webpack_require__(230); - -const {isArray} = Array; - -// `supportsColor.level` → `ansiStyles.color[name]` mapping -const levelMapping = [ - 'ansi', - 'ansi', - 'ansi256', - 'ansi16m' -]; - -const styles = Object.create(null); - -const applyOptions = (object, options = {}) => { - if (options.level && !(Number.isInteger(options.level) && options.level >= 0 && options.level <= 3)) { - throw new Error('The `level` option should be an integer from 0 to 3'); - } - - // Detect level if not set manually - const colorLevel = stdoutColor ? stdoutColor.level : 0; - object.level = options.level === undefined ? colorLevel : options.level; -}; - -class ChalkClass { - constructor(options) { - // eslint-disable-next-line no-constructor-return - return chalkFactory(options); - } -} - -const chalkFactory = options => { - const chalk = {}; - applyOptions(chalk, options); - - chalk.template = (...arguments_) => chalkTag(chalk.template, ...arguments_); - - Object.setPrototypeOf(chalk, Chalk.prototype); - Object.setPrototypeOf(chalk.template, chalk); - - chalk.template.constructor = () => { - throw new Error('`chalk.constructor()` is deprecated. Use `new chalk.Instance()` instead.'); - }; - - chalk.template.Instance = ChalkClass; - - return chalk.template; -}; - -function Chalk(options) { - return chalkFactory(options); -} - -for (const [styleName, style] of Object.entries(ansiStyles)) { - styles[styleName] = { - get() { - const builder = createBuilder(this, createStyler(style.open, style.close, this._styler), this._isEmpty); - Object.defineProperty(this, styleName, {value: builder}); - return builder; - } - }; -} - -styles.visible = { - get() { - const builder = createBuilder(this, this._styler, true); - Object.defineProperty(this, 'visible', {value: builder}); - return builder; - } -}; - -const usedModels = ['rgb', 'hex', 'keyword', 'hsl', 'hsv', 'hwb', 'ansi', 'ansi256']; - -for (const model of usedModels) { - styles[model] = { - get() { - const {level} = this; - return function (...arguments_) { - const styler = createStyler(ansiStyles.color[levelMapping[level]][model](...arguments_), ansiStyles.color.close, this._styler); - return createBuilder(this, styler, this._isEmpty); - }; - } - }; -} - -for (const model of usedModels) { - const bgModel = 'bg' + model[0].toUpperCase() + model.slice(1); - styles[bgModel] = { - get() { - const {level} = this; - return function (...arguments_) { - const styler = createStyler(ansiStyles.bgColor[levelMapping[level]][model](...arguments_), ansiStyles.bgColor.close, this._styler); - return createBuilder(this, styler, this._isEmpty); - }; - } - }; -} - -const proto = Object.defineProperties(() => {}, { - ...styles, - level: { - enumerable: true, - get() { - return this._generator.level; - }, - set(level) { - this._generator.level = level; - } - } -}); - -const createStyler = (open, close, parent) => { - let openAll; - let closeAll; - if (parent === undefined) { - openAll = open; - closeAll = close; - } else { - openAll = parent.openAll + open; - closeAll = close + parent.closeAll; - } - - return { - open, - close, - openAll, - closeAll, - parent - }; -}; - -const createBuilder = (self, _styler, _isEmpty) => { - const builder = (...arguments_) => { - if (isArray(arguments_[0]) && isArray(arguments_[0].raw)) { - // Called as a template literal, for example: chalk.red`2 + 3 = {bold ${2+3}}` - return applyStyle(builder, chalkTag(builder, ...arguments_)); - } - - // Single argument is hot path, implicit coercion is faster than anything - // eslint-disable-next-line no-implicit-coercion - return applyStyle(builder, (arguments_.length === 1) ? ('' + arguments_[0]) : arguments_.join(' ')); - }; - - // We alter the prototype because we must return a function, but there is - // no way to create a function with a different prototype - Object.setPrototypeOf(builder, proto); - - builder._generator = self; - builder._styler = _styler; - builder._isEmpty = _isEmpty; - - return builder; -}; - -const applyStyle = (self, string) => { - if (self.level <= 0 || !string) { - return self._isEmpty ? '' : string; - } - - let styler = self._styler; - - if (styler === undefined) { - return string; - } - - const {openAll, closeAll} = styler; - if (string.indexOf('\u001B') !== -1) { - while (styler !== undefined) { - // Replace any instances already present with a re-opening code - // otherwise only the part of the string until said closing code - // will be colored, and the rest will simply be 'plain'. - string = stringReplaceAll(string, styler.close, styler.open); - - styler = styler.parent; - } - } - - // We can move both next actions out of loop, because remaining actions in loop won't have - // any/visible effect on parts we add here. Close the styling before a linebreak and reopen - // after next line to fix a bleed issue on macOS: https://github.com/chalk/chalk/pull/92 - const lfIndex = string.indexOf('\n'); - if (lfIndex !== -1) { - string = stringEncaseCRLFWithFirstIndex(string, closeAll, openAll, lfIndex); - } - - return openAll + string + closeAll; -}; - -let template; -const chalkTag = (chalk, ...strings) => { - const [firstString] = strings; - - if (!isArray(firstString) || !isArray(firstString.raw)) { - // If chalk() was called by itself or with a string, - // return the string itself as a string. - return strings.join(' '); - } - - const arguments_ = strings.slice(1); - const parts = [firstString.raw[0]]; - - for (let i = 1; i < firstString.length; i++) { - parts.push( - String(arguments_[i - 1]).replace(/[{}\\]/g, '\\$&'), - String(firstString.raw[i]) - ); - } - - if (template === undefined) { - template = __webpack_require__(231); - } - - return template(chalk, parts.join('')); -}; - -Object.defineProperties(Chalk.prototype, styles); - -const chalk = Chalk(); // eslint-disable-line new-cap -chalk.supportsColor = stdoutColor; -chalk.stderr = Chalk({level: stderrColor ? stderrColor.level : 0}); // eslint-disable-line new-cap -chalk.stderr.supportsColor = stderrColor; - -module.exports = chalk; - - -/***/ }), -/* 228 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -const os = __webpack_require__(120); -const tty = __webpack_require__(121); -const hasFlag = __webpack_require__(229); - -const {env} = process; - -let forceColor; -if (hasFlag('no-color') || - hasFlag('no-colors') || - hasFlag('color=false') || - hasFlag('color=never')) { - forceColor = 0; -} else if (hasFlag('color') || - hasFlag('colors') || - hasFlag('color=true') || - hasFlag('color=always')) { - forceColor = 1; -} - -if ('FORCE_COLOR' in env) { - if (env.FORCE_COLOR === 'true') { - forceColor = 1; - } else if (env.FORCE_COLOR === 'false') { - forceColor = 0; - } else { - forceColor = env.FORCE_COLOR.length === 0 ? 1 : Math.min(parseInt(env.FORCE_COLOR, 10), 3); - } -} - -function translateLevel(level) { - if (level === 0) { - return false; - } - - return { - level, - hasBasic: true, - has256: level >= 2, - has16m: level >= 3 - }; -} - -function supportsColor(haveStream, streamIsTTY) { - if (forceColor === 0) { - return 0; - } - - if (hasFlag('color=16m') || - hasFlag('color=full') || - hasFlag('color=truecolor')) { - return 3; - } - - if (hasFlag('color=256')) { - return 2; - } - - if (haveStream && !streamIsTTY && forceColor === undefined) { - return 0; - } - - const min = forceColor || 0; - - if (env.TERM === 'dumb') { - return min; - } - - if (process.platform === 'win32') { - // Windows 10 build 10586 is the first Windows release that supports 256 colors. - // Windows 10 build 14931 is the first release that supports 16m/TrueColor. - const osRelease = os.release().split('.'); - if ( - Number(osRelease[0]) >= 10 && - Number(osRelease[2]) >= 10586 - ) { - return Number(osRelease[2]) >= 14931 ? 3 : 2; - } - - return 1; - } - - if ('CI' in env) { - if (['TRAVIS', 'CIRCLECI', 'APPVEYOR', 'GITLAB_CI'].some(sign => sign in env) || env.CI_NAME === 'codeship') { - return 1; - } - - return min; - } - - if ('TEAMCITY_VERSION' in env) { - return /^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env.TEAMCITY_VERSION) ? 1 : 0; - } - - if ('GITHUB_ACTIONS' in env) { - return 1; - } - - if (env.COLORTERM === 'truecolor') { - return 3; - } - - if ('TERM_PROGRAM' in env) { - const version = parseInt((env.TERM_PROGRAM_VERSION || '').split('.')[0], 10); - - switch (env.TERM_PROGRAM) { - case 'iTerm.app': - return version >= 3 ? 3 : 2; - case 'Apple_Terminal': - return 2; - // No default - } - } - - if (/-256(color)?$/i.test(env.TERM)) { - return 2; - } - - if (/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(env.TERM)) { - return 1; - } - - if ('COLORTERM' in env) { - return 1; - } - - return min; -} - -function getSupportLevel(stream) { - const level = supportsColor(stream, stream && stream.isTTY); - return translateLevel(level); -} - -module.exports = { - supportsColor: getSupportLevel, - stdout: translateLevel(supportsColor(true, tty.isatty(1))), - stderr: translateLevel(supportsColor(true, tty.isatty(2))) -}; - - -/***/ }), -/* 229 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -module.exports = (flag, argv = process.argv) => { - const prefix = flag.startsWith('-') ? '' : (flag.length === 1 ? '-' : '--'); - const position = argv.indexOf(prefix + flag); - const terminatorPosition = argv.indexOf('--'); - return position !== -1 && (terminatorPosition === -1 || position < terminatorPosition); -}; - - -/***/ }), -/* 230 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -const stringReplaceAll = (string, substring, replacer) => { - let index = string.indexOf(substring); - if (index === -1) { - return string; - } - - const substringLength = substring.length; - let endIndex = 0; - let returnValue = ''; - do { - returnValue += string.substr(endIndex, index - endIndex) + substring + replacer; - endIndex = index + substringLength; - index = string.indexOf(substring, endIndex); - } while (index !== -1); - - returnValue += string.substr(endIndex); - return returnValue; -}; - -const stringEncaseCRLFWithFirstIndex = (string, prefix, postfix, index) => { - let endIndex = 0; - let returnValue = ''; - do { - const gotCR = string[index - 1] === '\r'; - returnValue += string.substr(endIndex, (gotCR ? index - 1 : index) - endIndex) + prefix + (gotCR ? '\r\n' : '\n') + postfix; - endIndex = index + 1; - index = string.indexOf('\n', endIndex); - } while (index !== -1); - - returnValue += string.substr(endIndex); - return returnValue; -}; - -module.exports = { - stringReplaceAll, - stringEncaseCRLFWithFirstIndex -}; - - -/***/ }), -/* 231 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -const TEMPLATE_REGEX = /(?:\\(u(?:[a-f\d]{4}|\{[a-f\d]{1,6}\})|x[a-f\d]{2}|.))|(?:\{(~)?(\w+(?:\([^)]*\))?(?:\.\w+(?:\([^)]*\))?)*)(?:[ \t]|(?=\r?\n)))|(\})|((?:.|[\r\n\f])+?)/gi; -const STYLE_REGEX = /(?:^|\.)(\w+)(?:\(([^)]*)\))?/g; -const STRING_REGEX = /^(['"])((?:\\.|(?!\1)[^\\])*)\1$/; -const ESCAPE_REGEX = /\\(u(?:[a-f\d]{4}|{[a-f\d]{1,6}})|x[a-f\d]{2}|.)|([^\\])/gi; - -const ESCAPES = new Map([ - ['n', '\n'], - ['r', '\r'], - ['t', '\t'], - ['b', '\b'], - ['f', '\f'], - ['v', '\v'], - ['0', '\0'], - ['\\', '\\'], - ['e', '\u001B'], - ['a', '\u0007'] -]); - -function unescape(c) { - const u = c[0] === 'u'; - const bracket = c[1] === '{'; - - if ((u && !bracket && c.length === 5) || (c[0] === 'x' && c.length === 3)) { - return String.fromCharCode(parseInt(c.slice(1), 16)); - } - - if (u && bracket) { - return String.fromCodePoint(parseInt(c.slice(2, -1), 16)); - } - - return ESCAPES.get(c) || c; -} - -function parseArguments(name, arguments_) { - const results = []; - const chunks = arguments_.trim().split(/\s*,\s*/g); - let matches; - - for (const chunk of chunks) { - const number = Number(chunk); - if (!Number.isNaN(number)) { - results.push(number); - } else if ((matches = chunk.match(STRING_REGEX))) { - results.push(matches[2].replace(ESCAPE_REGEX, (m, escape, character) => escape ? unescape(escape) : character)); - } else { - throw new Error(`Invalid Chalk template style argument: ${chunk} (in style '${name}')`); - } - } - - return results; -} - -function parseStyle(style) { - STYLE_REGEX.lastIndex = 0; - - const results = []; - let matches; - - while ((matches = STYLE_REGEX.exec(style)) !== null) { - const name = matches[1]; - - if (matches[2]) { - const args = parseArguments(name, matches[2]); - results.push([name].concat(args)); - } else { - results.push([name]); - } - } - - return results; -} - -function buildStyle(chalk, styles) { - const enabled = {}; - - for (const layer of styles) { - for (const style of layer.styles) { - enabled[style[0]] = layer.inverse ? null : style.slice(1); - } - } - - let current = chalk; - for (const [styleName, styles] of Object.entries(enabled)) { - if (!Array.isArray(styles)) { - continue; - } - - if (!(styleName in current)) { - throw new Error(`Unknown Chalk style: ${styleName}`); - } - - current = styles.length > 0 ? current[styleName](...styles) : current[styleName]; - } - - return current; -} - -module.exports = (chalk, temporary) => { - const styles = []; - const chunks = []; - let chunk = []; - - // eslint-disable-next-line max-params - temporary.replace(TEMPLATE_REGEX, (m, escapeCharacter, inverse, style, close, character) => { - if (escapeCharacter) { - chunk.push(unescape(escapeCharacter)); - } else if (style) { - const string = chunk.join(''); - chunk = []; - chunks.push(styles.length === 0 ? string : buildStyle(chalk, styles)(string)); - styles.push({inverse, styles: parseStyle(style)}); - } else if (close) { - if (styles.length === 0) { - throw new Error('Found extraneous } in Chalk template literal'); - } - - chunks.push(buildStyle(chalk, styles)(chunk.join(''))); - chunk = []; - styles.pop(); - } else { - chunk.push(character); - } - }); - - chunks.push(chunk.join('')); - - if (styles.length > 0) { - const errMessage = `Chalk template literal is missing ${styles.length} closing bracket${styles.length === 1 ? '' : 's'} (\`}\`)`; - throw new Error(errMessage); - } - - return chunks.join(''); -}; - - -/***/ }), -/* 232 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - const path = __webpack_require__(4); -const childProcess = __webpack_require__(233); -const crossSpawn = __webpack_require__(234); -const stripFinalNewline = __webpack_require__(247); -const npmRunPath = __webpack_require__(248); -const onetime = __webpack_require__(249); -const makeError = __webpack_require__(251); -const normalizeStdio = __webpack_require__(256); -const {spawnedKill, spawnedCancel, setupTimeout, setExitHandler} = __webpack_require__(257); -const {handleInput, getSpawnedResult, makeAllStream, validateInputSync} = __webpack_require__(258); -const {mergePromise, getSpawnedPromise} = __webpack_require__(265); -const {joinCommand, parseCommand} = __webpack_require__(266); +const childProcess = __webpack_require__(228); +const crossSpawn = __webpack_require__(229); +const stripFinalNewline = __webpack_require__(242); +const npmRunPath = __webpack_require__(243); +const onetime = __webpack_require__(244); +const makeError = __webpack_require__(246); +const normalizeStdio = __webpack_require__(251); +const {spawnedKill, spawnedCancel, setupTimeout, setExitHandler} = __webpack_require__(252); +const {handleInput, getSpawnedResult, makeAllStream, validateInputSync} = __webpack_require__(253); +const {mergePromise, getSpawnedPromise} = __webpack_require__(260); +const {joinCommand, parseCommand} = __webpack_require__(261); const DEFAULT_MAX_BUFFER = 1000 * 1000 * 100; @@ -24585,21 +24001,21 @@ module.exports.node = (scriptPath, args, options = {}) => { /***/ }), -/* 233 */ +/* 228 */ /***/ (function(module, exports) { module.exports = require("child_process"); /***/ }), -/* 234 */ +/* 229 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const cp = __webpack_require__(233); -const parse = __webpack_require__(235); -const enoent = __webpack_require__(246); +const cp = __webpack_require__(228); +const parse = __webpack_require__(230); +const enoent = __webpack_require__(241); function spawn(command, args, options) { // Parse the arguments @@ -24637,16 +24053,16 @@ module.exports._enoent = enoent; /***/ }), -/* 235 */ +/* 230 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(4); -const resolveCommand = __webpack_require__(236); -const escape = __webpack_require__(242); -const readShebang = __webpack_require__(243); +const resolveCommand = __webpack_require__(231); +const escape = __webpack_require__(237); +const readShebang = __webpack_require__(238); const isWin = process.platform === 'win32'; const isExecutableRegExp = /\.(?:com|exe)$/i; @@ -24735,15 +24151,15 @@ module.exports = parse; /***/ }), -/* 236 */ +/* 231 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(4); -const which = __webpack_require__(237); -const pathKey = __webpack_require__(241)(); +const which = __webpack_require__(232); +const pathKey = __webpack_require__(236)(); function resolveCommandAttempt(parsed, withoutPathExt) { const cwd = process.cwd(); @@ -24793,7 +24209,7 @@ module.exports = resolveCommand; /***/ }), -/* 237 */ +/* 232 */ /***/ (function(module, exports, __webpack_require__) { const isWindows = process.platform === 'win32' || @@ -24802,7 +24218,7 @@ const isWindows = process.platform === 'win32' || const path = __webpack_require__(4) const COLON = isWindows ? ';' : ':' -const isexe = __webpack_require__(238) +const isexe = __webpack_require__(233) const getNotFoundError = (cmd) => Object.assign(new Error(`not found: ${cmd}`), { code: 'ENOENT' }) @@ -24924,15 +24340,15 @@ which.sync = whichSync /***/ }), -/* 238 */ +/* 233 */ /***/ (function(module, exports, __webpack_require__) { var fs = __webpack_require__(133) var core if (process.platform === 'win32' || global.TESTING_WINDOWS) { - core = __webpack_require__(239) + core = __webpack_require__(234) } else { - core = __webpack_require__(240) + core = __webpack_require__(235) } module.exports = isexe @@ -24987,7 +24403,7 @@ function sync (path, options) { /***/ }), -/* 239 */ +/* 234 */ /***/ (function(module, exports, __webpack_require__) { module.exports = isexe @@ -25035,7 +24451,7 @@ function sync (path, options) { /***/ }), -/* 240 */ +/* 235 */ /***/ (function(module, exports, __webpack_require__) { module.exports = isexe @@ -25082,7 +24498,7 @@ function checkMode (stat, options) { /***/ }), -/* 241 */ +/* 236 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -25105,7 +24521,7 @@ module.exports.default = pathKey; /***/ }), -/* 242 */ +/* 237 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -25157,14 +24573,14 @@ module.exports.argument = escapeArgument; /***/ }), -/* 243 */ +/* 238 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const fs = __webpack_require__(133); -const shebangCommand = __webpack_require__(244); +const shebangCommand = __webpack_require__(239); function readShebang(command) { // Read the first 150 bytes from the file @@ -25187,12 +24603,12 @@ module.exports = readShebang; /***/ }), -/* 244 */ +/* 239 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const shebangRegex = __webpack_require__(245); +const shebangRegex = __webpack_require__(240); module.exports = (string = '') => { const match = string.match(shebangRegex); @@ -25213,7 +24629,7 @@ module.exports = (string = '') => { /***/ }), -/* 245 */ +/* 240 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -25222,7 +24638,7 @@ module.exports = /^#!(.*)/; /***/ }), -/* 246 */ +/* 241 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -25288,7 +24704,7 @@ module.exports = { /***/ }), -/* 247 */ +/* 242 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -25311,13 +24727,13 @@ module.exports = input => { /***/ }), -/* 248 */ +/* 243 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(4); -const pathKey = __webpack_require__(241); +const pathKey = __webpack_require__(236); const npmRunPath = options => { options = { @@ -25365,12 +24781,12 @@ module.exports.env = options => { /***/ }), -/* 249 */ +/* 244 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const mimicFn = __webpack_require__(250); +const mimicFn = __webpack_require__(245); const calledFunctions = new WeakMap(); @@ -25422,7 +24838,7 @@ module.exports.callCount = fn => { /***/ }), -/* 250 */ +/* 245 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -25442,12 +24858,12 @@ module.exports.default = mimicFn; /***/ }), -/* 251 */ +/* 246 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const {signalsByName} = __webpack_require__(252); +const {signalsByName} = __webpack_require__(247); const getErrorPrefix = ({timedOut, timeout, errorCode, signal, signalDescription, exitCode, isCanceled}) => { if (timedOut) { @@ -25535,14 +24951,14 @@ module.exports = makeError; /***/ }), -/* 252 */ +/* 247 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports,"__esModule",{value:true});exports.signalsByNumber=exports.signalsByName=void 0;var _os=__webpack_require__(120); -var _signals=__webpack_require__(253); -var _realtime=__webpack_require__(255); +var _signals=__webpack_require__(248); +var _realtime=__webpack_require__(250); @@ -25612,14 +25028,14 @@ const signalsByNumber=getSignalsByNumber();exports.signalsByNumber=signalsByNumb //# sourceMappingURL=main.js.map /***/ }), -/* 253 */ +/* 248 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports,"__esModule",{value:true});exports.getSignals=void 0;var _os=__webpack_require__(120); -var _core=__webpack_require__(254); -var _realtime=__webpack_require__(255); +var _core=__webpack_require__(249); +var _realtime=__webpack_require__(250); @@ -25653,7 +25069,7 @@ return{name,number,description,supported,action,forced,standard}; //# sourceMappingURL=signals.js.map /***/ }), -/* 254 */ +/* 249 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -25932,7 +25348,7 @@ standard:"other"}];exports.SIGNALS=SIGNALS; //# sourceMappingURL=core.js.map /***/ }), -/* 255 */ +/* 250 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -25957,7 +25373,7 @@ const SIGRTMAX=64;exports.SIGRTMAX=SIGRTMAX; //# sourceMappingURL=realtime.js.map /***/ }), -/* 256 */ +/* 251 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -26016,7 +25432,7 @@ module.exports.node = opts => { /***/ }), -/* 257 */ +/* 252 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -26135,14 +25551,14 @@ module.exports = { /***/ }), -/* 258 */ +/* 253 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const isStream = __webpack_require__(259); -const getStream = __webpack_require__(260); -const mergeStream = __webpack_require__(264); +const isStream = __webpack_require__(254); +const getStream = __webpack_require__(255); +const mergeStream = __webpack_require__(259); // `input` option const handleInput = (spawned, input) => { @@ -26239,7 +25655,7 @@ module.exports = { /***/ }), -/* 259 */ +/* 254 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -26275,13 +25691,13 @@ module.exports = isStream; /***/ }), -/* 260 */ +/* 255 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const pump = __webpack_require__(261); -const bufferStream = __webpack_require__(263); +const pump = __webpack_require__(256); +const bufferStream = __webpack_require__(258); class MaxBufferError extends Error { constructor() { @@ -26340,11 +25756,11 @@ module.exports.MaxBufferError = MaxBufferError; /***/ }), -/* 261 */ +/* 256 */ /***/ (function(module, exports, __webpack_require__) { var once = __webpack_require__(161) -var eos = __webpack_require__(262) +var eos = __webpack_require__(257) var fs = __webpack_require__(133) // we only need fs to get the ReadStream and WriteStream prototypes var noop = function () {} @@ -26428,7 +25844,7 @@ module.exports = pump /***/ }), -/* 262 */ +/* 257 */ /***/ (function(module, exports, __webpack_require__) { var once = __webpack_require__(161); @@ -26528,7 +25944,7 @@ module.exports = eos; /***/ }), -/* 263 */ +/* 258 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -26587,7 +26003,7 @@ module.exports = options => { /***/ }), -/* 264 */ +/* 259 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -26635,7 +26051,7 @@ module.exports = function (/*streams...*/) { /***/ }), -/* 265 */ +/* 260 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -26688,7 +26104,7 @@ module.exports = { /***/ }), -/* 266 */ +/* 261 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -26733,7 +26149,7 @@ module.exports = { /***/ }), -/* 267 */ +/* 262 */ /***/ (function(module, exports, __webpack_require__) { // Copyright IBM Corp. 2014,2018. All Rights Reserved. @@ -26741,12 +26157,12 @@ module.exports = { // This file is licensed under the Apache License 2.0. // License text available at https://opensource.org/licenses/Apache-2.0 -module.exports = __webpack_require__(268); -module.exports.cli = __webpack_require__(272); +module.exports = __webpack_require__(263); +module.exports.cli = __webpack_require__(267); /***/ }), -/* 268 */ +/* 263 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -26761,9 +26177,9 @@ var stream = __webpack_require__(137); var util = __webpack_require__(111); var fs = __webpack_require__(133); -var through = __webpack_require__(269); -var duplexer = __webpack_require__(270); -var StringDecoder = __webpack_require__(271).StringDecoder; +var through = __webpack_require__(264); +var duplexer = __webpack_require__(265); +var StringDecoder = __webpack_require__(266).StringDecoder; module.exports = Logger; @@ -26952,7 +26368,7 @@ function lineMerger(host) { /***/ }), -/* 269 */ +/* 264 */ /***/ (function(module, exports, __webpack_require__) { var Stream = __webpack_require__(137) @@ -27066,7 +26482,7 @@ function through (write, end, opts) { /***/ }), -/* 270 */ +/* 265 */ /***/ (function(module, exports, __webpack_require__) { var Stream = __webpack_require__(137) @@ -27159,13 +26575,13 @@ function duplex(writer, reader) { /***/ }), -/* 271 */ +/* 266 */ /***/ (function(module, exports) { module.exports = require("string_decoder"); /***/ }), -/* 272 */ +/* 267 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -27176,11 +26592,11 @@ module.exports = require("string_decoder"); -var minimist = __webpack_require__(273); +var minimist = __webpack_require__(268); var path = __webpack_require__(4); -var Logger = __webpack_require__(268); -var pkg = __webpack_require__(274); +var Logger = __webpack_require__(263); +var pkg = __webpack_require__(269); module.exports = cli; @@ -27234,7 +26650,7 @@ function usage($0, p) { /***/ }), -/* 273 */ +/* 268 */ /***/ (function(module, exports) { module.exports = function (args, opts) { @@ -27485,13 +26901,13 @@ function isNumber (x) { /***/ }), -/* 274 */ +/* 269 */ /***/ (function(module) { module.exports = JSON.parse("{\"name\":\"strong-log-transformer\",\"version\":\"2.1.0\",\"description\":\"Stream transformer that prefixes lines with timestamps and other things.\",\"author\":\"Ryan Graham \",\"license\":\"Apache-2.0\",\"repository\":{\"type\":\"git\",\"url\":\"git://github.com/strongloop/strong-log-transformer\"},\"keywords\":[\"logging\",\"streams\"],\"bugs\":{\"url\":\"https://github.com/strongloop/strong-log-transformer/issues\"},\"homepage\":\"https://github.com/strongloop/strong-log-transformer\",\"directories\":{\"test\":\"test\"},\"bin\":{\"sl-log-transformer\":\"bin/sl-log-transformer.js\"},\"main\":\"index.js\",\"scripts\":{\"test\":\"tap --100 test/test-*\"},\"dependencies\":{\"duplexer\":\"^0.1.1\",\"minimist\":\"^1.2.0\",\"through\":\"^2.3.4\"},\"devDependencies\":{\"tap\":\"^12.0.1\"},\"engines\":{\"node\":\">=4\"}}"); /***/ }), -/* 275 */ +/* 270 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -27504,7 +26920,7 @@ __webpack_require__.r(__webpack_exports__); /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var util__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(111); /* harmony import */ var util__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(util__WEBPACK_IMPORTED_MODULE_2__); -/* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(276); +/* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(271); /* harmony import */ var _fs__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(130); /* harmony import */ var _package_json__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(164); /* harmony import */ var _projects__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(145); @@ -27599,7 +27015,7 @@ function packagesFromGlobPattern({ } /***/ }), -/* 276 */ +/* 271 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -27669,7 +27085,7 @@ function getProjectPaths({ } /***/ }), -/* 277 */ +/* 272 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -27677,13 +27093,13 @@ __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getAllChecksums", function() { return getAllChecksums; }); /* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(133); /* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(fs__WEBPACK_IMPORTED_MODULE_0__); -/* harmony import */ var crypto__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(278); +/* harmony import */ var crypto__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(273); /* harmony import */ var crypto__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(crypto__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var util__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(111); /* harmony import */ var util__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(util__WEBPACK_IMPORTED_MODULE_2__); -/* harmony import */ var execa__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(232); +/* harmony import */ var execa__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(227); /* harmony import */ var execa__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(execa__WEBPACK_IMPORTED_MODULE_3__); -/* harmony import */ var _yarn_lock__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(279); +/* harmony import */ var _yarn_lock__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(274); /* * Licensed to Elasticsearch B.V. under one or more contributor * license agreements. See the NOTICE file distributed with @@ -27882,20 +27298,20 @@ async function getAllChecksums(kbn, log, yarnLock) { } /***/ }), -/* 278 */ +/* 273 */ /***/ (function(module, exports) { module.exports = require("crypto"); /***/ }), -/* 279 */ +/* 274 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "readYarnLock", function() { return readYarnLock; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "resolveDepsForProject", function() { return resolveDepsForProject; }); -/* harmony import */ var _yarnpkg_lockfile__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(280); +/* harmony import */ var _yarnpkg_lockfile__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(275); /* harmony import */ var _yarnpkg_lockfile__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_yarnpkg_lockfile__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var _utils_fs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(130); /* @@ -28008,7 +27424,7 @@ function resolveDepsForProject({ } /***/ }), -/* 280 */ +/* 275 */ /***/ (function(module, exports, __webpack_require__) { module.exports = @@ -29567,7 +28983,7 @@ module.exports = invariant; /* 9 */ /***/ (function(module, exports) { -module.exports = __webpack_require__(278); +module.exports = __webpack_require__(273); /***/ }), /* 10 */, @@ -31891,7 +31307,7 @@ function onceStrict (fn) { /* 63 */ /***/ (function(module, exports) { -module.exports = __webpack_require__(281); +module.exports = __webpack_require__(276); /***/ }), /* 64 */, @@ -38286,13 +37702,13 @@ module.exports = process && support(supportLevel); /******/ ]); /***/ }), -/* 281 */ +/* 276 */ /***/ (function(module, exports) { module.exports = require("buffer"); /***/ }), -/* 282 */ +/* 277 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -38389,13 +37805,13 @@ class BootstrapCacheFile { } /***/ }), -/* 283 */ +/* 278 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "validateYarnLock", function() { return validateYarnLock; }); -/* harmony import */ var _yarnpkg_lockfile__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(280); +/* harmony import */ var _yarnpkg_lockfile__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(275); /* harmony import */ var _yarnpkg_lockfile__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_yarnpkg_lockfile__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var dedent__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(2); /* harmony import */ var dedent__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(dedent__WEBPACK_IMPORTED_MODULE_1__); @@ -38490,21 +37906,73 @@ async function validateYarnLock(kbn, yarnLock) { `); process.exit(1); + } // TODO: remove this once we move into a single package.json + // look through all the package.json files to find packages which have mismatched version ranges + + + const depRanges = new Map(); + + for (const project of kbn.getAllProjects().values()) { + for (const [dep, range] of Object.entries(project.allDependencies)) { + const existingDep = depRanges.get(dep); + + if (!existingDep) { + depRanges.set(dep, [{ + range, + projects: [project] + }]); + continue; + } + + const existingRange = existingDep.find(existing => existing.range === range); + + if (!existingRange) { + existingDep.push({ + range, + projects: [project] + }); + continue; + } + + existingRange.projects.push(project); + } + } + + const duplicateRanges = Array.from(depRanges.entries()).filter(([, ranges]) => ranges.length > 1).reduce((acc, [dep, ranges]) => [...acc, dep, ...ranges.map(({ + range, + projects + }) => ` ${range} => ${projects.map(p => p.name).join(', ')}`)], []).join('\n '); + + if (duplicateRanges) { + _log__WEBPACK_IMPORTED_MODULE_3__["log"].error(dedent__WEBPACK_IMPORTED_MODULE_1___default.a` + + [single_version_dependencies] Multiple version ranges for the same dependency + were found declared across different package.json files. Please consolidate + those to match across all package.json files. Different versions for the + same dependency is not supported. + + If you have questions about this please reach out to the operations team. + + The conflicting dependencies are: + + ${duplicateRanges} + `); + process.exit(1); } _log__WEBPACK_IMPORTED_MODULE_3__["log"].success('yarn.lock analysis completed without any issues'); } /***/ }), -/* 284 */ +/* 279 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CleanCommand", function() { return CleanCommand; }); -/* harmony import */ var del__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(285); +/* harmony import */ var del__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(280); /* harmony import */ var del__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(del__WEBPACK_IMPORTED_MODULE_0__); -/* harmony import */ var ora__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(372); +/* harmony import */ var ora__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(367); /* harmony import */ var ora__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(ora__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(4); /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_2__); @@ -38604,21 +38072,21 @@ const CleanCommand = { }; /***/ }), -/* 285 */ +/* 280 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const {promisify} = __webpack_require__(111); const path = __webpack_require__(4); -const globby = __webpack_require__(286); -const isGlob = __webpack_require__(364); -const slash = __webpack_require__(362); +const globby = __webpack_require__(281); +const isGlob = __webpack_require__(359); +const slash = __webpack_require__(357); const gracefulFs = __webpack_require__(132); -const isPathCwd = __webpack_require__(365); -const isPathInside = __webpack_require__(366); -const rimraf = __webpack_require__(367); -const pMap = __webpack_require__(368); +const isPathCwd = __webpack_require__(360); +const isPathInside = __webpack_require__(361); +const rimraf = __webpack_require__(362); +const pMap = __webpack_require__(363); const rimrafP = promisify(rimraf); @@ -38732,19 +38200,19 @@ module.exports.sync = (patterns, {force, dryRun, cwd = process.cwd(), ...options /***/ }), -/* 286 */ +/* 281 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const fs = __webpack_require__(133); -const arrayUnion = __webpack_require__(287); -const merge2 = __webpack_require__(288); +const arrayUnion = __webpack_require__(282); +const merge2 = __webpack_require__(283); const glob = __webpack_require__(146); -const fastGlob = __webpack_require__(289); -const dirGlob = __webpack_require__(358); -const gitignore = __webpack_require__(360); -const {FilterStream, UniqueStream} = __webpack_require__(363); +const fastGlob = __webpack_require__(284); +const dirGlob = __webpack_require__(353); +const gitignore = __webpack_require__(355); +const {FilterStream, UniqueStream} = __webpack_require__(358); const DEFAULT_FILTER = () => false; @@ -38917,7 +38385,7 @@ module.exports.gitignore = gitignore; /***/ }), -/* 287 */ +/* 282 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -38929,7 +38397,7 @@ module.exports = (...arguments_) => { /***/ }), -/* 288 */ +/* 283 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -39080,17 +38548,17 @@ function pauseStreams (streams, options) { /***/ }), -/* 289 */ +/* 284 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const taskManager = __webpack_require__(290); -const async_1 = __webpack_require__(319); -const stream_1 = __webpack_require__(354); -const sync_1 = __webpack_require__(355); -const settings_1 = __webpack_require__(357); -const utils = __webpack_require__(291); +const taskManager = __webpack_require__(285); +const async_1 = __webpack_require__(314); +const stream_1 = __webpack_require__(349); +const sync_1 = __webpack_require__(350); +const settings_1 = __webpack_require__(352); +const utils = __webpack_require__(286); async function FastGlob(source, options) { assertPatternsInput(source); const works = getWorks(source, async_1.default, options); @@ -39154,13 +38622,13 @@ module.exports = FastGlob; /***/ }), -/* 290 */ +/* 285 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const utils = __webpack_require__(291); +const utils = __webpack_require__(286); function generate(patterns, settings) { const positivePatterns = getPositivePatterns(patterns); const negativePatterns = getNegativePatternsAsPositive(patterns, settings.ignore); @@ -39225,30 +38693,30 @@ exports.convertPatternGroupToTask = convertPatternGroupToTask; /***/ }), -/* 291 */ +/* 286 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const array = __webpack_require__(292); +const array = __webpack_require__(287); exports.array = array; -const errno = __webpack_require__(293); +const errno = __webpack_require__(288); exports.errno = errno; -const fs = __webpack_require__(294); +const fs = __webpack_require__(289); exports.fs = fs; -const path = __webpack_require__(295); +const path = __webpack_require__(290); exports.path = path; -const pattern = __webpack_require__(296); +const pattern = __webpack_require__(291); exports.pattern = pattern; -const stream = __webpack_require__(317); +const stream = __webpack_require__(312); exports.stream = stream; -const string = __webpack_require__(318); +const string = __webpack_require__(313); exports.string = string; /***/ }), -/* 292 */ +/* 287 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -39276,7 +38744,7 @@ exports.splitWhen = splitWhen; /***/ }), -/* 293 */ +/* 288 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -39289,7 +38757,7 @@ exports.isEnoentCodeError = isEnoentCodeError; /***/ }), -/* 294 */ +/* 289 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -39314,7 +38782,7 @@ exports.createDirentFromStats = createDirentFromStats; /***/ }), -/* 295 */ +/* 290 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -39353,16 +38821,16 @@ exports.removeLeadingDotSegment = removeLeadingDotSegment; /***/ }), -/* 296 */ +/* 291 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const path = __webpack_require__(4); -const globParent = __webpack_require__(297); -const micromatch = __webpack_require__(300); -const picomatch = __webpack_require__(311); +const globParent = __webpack_require__(292); +const micromatch = __webpack_require__(295); +const picomatch = __webpack_require__(306); const GLOBSTAR = '**'; const ESCAPE_SYMBOL = '\\'; const COMMON_GLOB_SYMBOLS_RE = /[*?]|^!/; @@ -39472,13 +38940,13 @@ exports.matchAny = matchAny; /***/ }), -/* 297 */ +/* 292 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isGlob = __webpack_require__(298); +var isGlob = __webpack_require__(293); var pathPosixDirname = __webpack_require__(4).posix.dirname; var isWin32 = __webpack_require__(120).platform() === 'win32'; @@ -39520,7 +38988,7 @@ module.exports = function globParent(str, opts) { /***/ }), -/* 298 */ +/* 293 */ /***/ (function(module, exports, __webpack_require__) { /*! @@ -39530,7 +38998,7 @@ module.exports = function globParent(str, opts) { * Released under the MIT License. */ -var isExtglob = __webpack_require__(299); +var isExtglob = __webpack_require__(294); var chars = { '{': '}', '(': ')', '[': ']'}; var strictRegex = /\\(.)|(^!|\*|[\].+)]\?|\[[^\\\]]+\]|\{[^\\}]+\}|\(\?[:!=][^\\)]+\)|\([^|]+\|[^\\)]+\))/; var relaxedRegex = /\\(.)|(^!|[*?{}()[\]]|\(\?)/; @@ -39574,7 +39042,7 @@ module.exports = function isGlob(str, options) { /***/ }), -/* 299 */ +/* 294 */ /***/ (function(module, exports) { /*! @@ -39600,16 +39068,16 @@ module.exports = function isExtglob(str) { /***/ }), -/* 300 */ +/* 295 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const util = __webpack_require__(111); -const braces = __webpack_require__(301); -const picomatch = __webpack_require__(311); -const utils = __webpack_require__(314); +const braces = __webpack_require__(296); +const picomatch = __webpack_require__(306); +const utils = __webpack_require__(309); const isEmptyString = val => typeof val === 'string' && (val === '' || val === './'); /** @@ -40074,16 +39542,16 @@ module.exports = micromatch; /***/ }), -/* 301 */ +/* 296 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const stringify = __webpack_require__(302); -const compile = __webpack_require__(304); -const expand = __webpack_require__(308); -const parse = __webpack_require__(309); +const stringify = __webpack_require__(297); +const compile = __webpack_require__(299); +const expand = __webpack_require__(303); +const parse = __webpack_require__(304); /** * Expand the given pattern or create a regex-compatible string. @@ -40251,13 +39719,13 @@ module.exports = braces; /***/ }), -/* 302 */ +/* 297 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const utils = __webpack_require__(303); +const utils = __webpack_require__(298); module.exports = (ast, options = {}) => { let stringify = (node, parent = {}) => { @@ -40290,7 +39758,7 @@ module.exports = (ast, options = {}) => { /***/ }), -/* 303 */ +/* 298 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -40409,14 +39877,14 @@ exports.flatten = (...args) => { /***/ }), -/* 304 */ +/* 299 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const fill = __webpack_require__(305); -const utils = __webpack_require__(303); +const fill = __webpack_require__(300); +const utils = __webpack_require__(298); const compile = (ast, options = {}) => { let walk = (node, parent = {}) => { @@ -40473,7 +39941,7 @@ module.exports = compile; /***/ }), -/* 305 */ +/* 300 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -40487,7 +39955,7 @@ module.exports = compile; const util = __webpack_require__(111); -const toRegexRange = __webpack_require__(306); +const toRegexRange = __webpack_require__(301); const isObject = val => val !== null && typeof val === 'object' && !Array.isArray(val); @@ -40729,7 +40197,7 @@ module.exports = fill; /***/ }), -/* 306 */ +/* 301 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -40742,7 +40210,7 @@ module.exports = fill; -const isNumber = __webpack_require__(307); +const isNumber = __webpack_require__(302); const toRegexRange = (min, max, options) => { if (isNumber(min) === false) { @@ -41024,7 +40492,7 @@ module.exports = toRegexRange; /***/ }), -/* 307 */ +/* 302 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -41049,15 +40517,15 @@ module.exports = function(num) { /***/ }), -/* 308 */ +/* 303 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const fill = __webpack_require__(305); -const stringify = __webpack_require__(302); -const utils = __webpack_require__(303); +const fill = __webpack_require__(300); +const stringify = __webpack_require__(297); +const utils = __webpack_require__(298); const append = (queue = '', stash = '', enclose = false) => { let result = []; @@ -41169,13 +40637,13 @@ module.exports = expand; /***/ }), -/* 309 */ +/* 304 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const stringify = __webpack_require__(302); +const stringify = __webpack_require__(297); /** * Constants @@ -41197,7 +40665,7 @@ const { CHAR_SINGLE_QUOTE, /* ' */ CHAR_NO_BREAK_SPACE, CHAR_ZERO_WIDTH_NOBREAK_SPACE -} = __webpack_require__(310); +} = __webpack_require__(305); /** * parse @@ -41509,7 +40977,7 @@ module.exports = parse; /***/ }), -/* 310 */ +/* 305 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -41573,27 +41041,27 @@ module.exports = { /***/ }), -/* 311 */ +/* 306 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -module.exports = __webpack_require__(312); +module.exports = __webpack_require__(307); /***/ }), -/* 312 */ +/* 307 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(4); -const scan = __webpack_require__(313); -const parse = __webpack_require__(316); -const utils = __webpack_require__(314); -const constants = __webpack_require__(315); +const scan = __webpack_require__(308); +const parse = __webpack_require__(311); +const utils = __webpack_require__(309); +const constants = __webpack_require__(310); const isObject = val => val && typeof val === 'object' && !Array.isArray(val); /** @@ -41929,13 +41397,13 @@ module.exports = picomatch; /***/ }), -/* 313 */ +/* 308 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const utils = __webpack_require__(314); +const utils = __webpack_require__(309); const { CHAR_ASTERISK, /* * */ CHAR_AT, /* @ */ @@ -41952,7 +41420,7 @@ const { CHAR_RIGHT_CURLY_BRACE, /* } */ CHAR_RIGHT_PARENTHESES, /* ) */ CHAR_RIGHT_SQUARE_BRACKET /* ] */ -} = __webpack_require__(315); +} = __webpack_require__(310); const isPathSeparator = code => { return code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH; @@ -42319,7 +41787,7 @@ module.exports = scan; /***/ }), -/* 314 */ +/* 309 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -42332,7 +41800,7 @@ const { REGEX_REMOVE_BACKSLASH, REGEX_SPECIAL_CHARS, REGEX_SPECIAL_CHARS_GLOBAL -} = __webpack_require__(315); +} = __webpack_require__(310); exports.isObject = val => val !== null && typeof val === 'object' && !Array.isArray(val); exports.hasRegexChars = str => REGEX_SPECIAL_CHARS.test(str); @@ -42390,7 +41858,7 @@ exports.wrapOutput = (input, state = {}, options = {}) => { /***/ }), -/* 315 */ +/* 310 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -42576,14 +42044,14 @@ module.exports = { /***/ }), -/* 316 */ +/* 311 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const constants = __webpack_require__(315); -const utils = __webpack_require__(314); +const constants = __webpack_require__(310); +const utils = __webpack_require__(309); /** * Constants @@ -43661,13 +43129,13 @@ module.exports = parse; /***/ }), -/* 317 */ +/* 312 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const merge2 = __webpack_require__(288); +const merge2 = __webpack_require__(283); function merge(streams) { const mergedStream = merge2(streams); streams.forEach((stream) => { @@ -43684,7 +43152,7 @@ function propagateCloseEventToSources(streams) { /***/ }), -/* 318 */ +/* 313 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -43701,14 +43169,14 @@ exports.isEmpty = isEmpty; /***/ }), -/* 319 */ +/* 314 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const stream_1 = __webpack_require__(320); -const provider_1 = __webpack_require__(347); +const stream_1 = __webpack_require__(315); +const provider_1 = __webpack_require__(342); class ProviderAsync extends provider_1.default { constructor() { super(...arguments); @@ -43736,16 +43204,16 @@ exports.default = ProviderAsync; /***/ }), -/* 320 */ +/* 315 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const stream_1 = __webpack_require__(137); -const fsStat = __webpack_require__(321); -const fsWalk = __webpack_require__(326); -const reader_1 = __webpack_require__(346); +const fsStat = __webpack_require__(316); +const fsWalk = __webpack_require__(321); +const reader_1 = __webpack_require__(341); class ReaderStream extends reader_1.default { constructor() { super(...arguments); @@ -43798,15 +43266,15 @@ exports.default = ReaderStream; /***/ }), -/* 321 */ +/* 316 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const async = __webpack_require__(322); -const sync = __webpack_require__(323); -const settings_1 = __webpack_require__(324); +const async = __webpack_require__(317); +const sync = __webpack_require__(318); +const settings_1 = __webpack_require__(319); exports.Settings = settings_1.default; function stat(path, optionsOrSettingsOrCallback, callback) { if (typeof optionsOrSettingsOrCallback === 'function') { @@ -43829,7 +43297,7 @@ function getSettings(settingsOrOptions = {}) { /***/ }), -/* 322 */ +/* 317 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -43867,7 +43335,7 @@ function callSuccessCallback(callback, result) { /***/ }), -/* 323 */ +/* 318 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -43896,13 +43364,13 @@ exports.read = read; /***/ }), -/* 324 */ +/* 319 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const fs = __webpack_require__(325); +const fs = __webpack_require__(320); class Settings { constructor(_options = {}) { this._options = _options; @@ -43919,7 +43387,7 @@ exports.default = Settings; /***/ }), -/* 325 */ +/* 320 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -43942,16 +43410,16 @@ exports.createFileSystemAdapter = createFileSystemAdapter; /***/ }), -/* 326 */ +/* 321 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const async_1 = __webpack_require__(327); -const stream_1 = __webpack_require__(342); -const sync_1 = __webpack_require__(343); -const settings_1 = __webpack_require__(345); +const async_1 = __webpack_require__(322); +const stream_1 = __webpack_require__(337); +const sync_1 = __webpack_require__(338); +const settings_1 = __webpack_require__(340); exports.Settings = settings_1.default; function walk(directory, optionsOrSettingsOrCallback, callback) { if (typeof optionsOrSettingsOrCallback === 'function') { @@ -43981,13 +43449,13 @@ function getSettings(settingsOrOptions = {}) { /***/ }), -/* 327 */ +/* 322 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const async_1 = __webpack_require__(328); +const async_1 = __webpack_require__(323); class AsyncProvider { constructor(_root, _settings) { this._root = _root; @@ -44018,17 +43486,17 @@ function callSuccessCallback(callback, entries) { /***/ }), -/* 328 */ +/* 323 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const events_1 = __webpack_require__(155); -const fsScandir = __webpack_require__(329); -const fastq = __webpack_require__(338); -const common = __webpack_require__(340); -const reader_1 = __webpack_require__(341); +const fsScandir = __webpack_require__(324); +const fastq = __webpack_require__(333); +const common = __webpack_require__(335); +const reader_1 = __webpack_require__(336); class AsyncReader extends reader_1.default { constructor(_root, _settings) { super(_root, _settings); @@ -44118,15 +43586,15 @@ exports.default = AsyncReader; /***/ }), -/* 329 */ +/* 324 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const async = __webpack_require__(330); -const sync = __webpack_require__(335); -const settings_1 = __webpack_require__(336); +const async = __webpack_require__(325); +const sync = __webpack_require__(330); +const settings_1 = __webpack_require__(331); exports.Settings = settings_1.default; function scandir(path, optionsOrSettingsOrCallback, callback) { if (typeof optionsOrSettingsOrCallback === 'function') { @@ -44149,16 +43617,16 @@ function getSettings(settingsOrOptions = {}) { /***/ }), -/* 330 */ +/* 325 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const fsStat = __webpack_require__(321); -const rpl = __webpack_require__(331); -const constants_1 = __webpack_require__(332); -const utils = __webpack_require__(333); +const fsStat = __webpack_require__(316); +const rpl = __webpack_require__(326); +const constants_1 = __webpack_require__(327); +const utils = __webpack_require__(328); function read(directory, settings, callback) { if (!settings.stats && constants_1.IS_SUPPORT_READDIR_WITH_FILE_TYPES) { return readdirWithFileTypes(directory, settings, callback); @@ -44246,7 +43714,7 @@ function callSuccessCallback(callback, result) { /***/ }), -/* 331 */ +/* 326 */ /***/ (function(module, exports) { module.exports = runParallel @@ -44300,7 +43768,7 @@ function runParallel (tasks, cb) { /***/ }), -/* 332 */ +/* 327 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -44320,18 +43788,18 @@ exports.IS_SUPPORT_READDIR_WITH_FILE_TYPES = IS_MATCHED_BY_MAJOR || IS_MATCHED_B /***/ }), -/* 333 */ +/* 328 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const fs = __webpack_require__(334); +const fs = __webpack_require__(329); exports.fs = fs; /***/ }), -/* 334 */ +/* 329 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -44356,15 +43824,15 @@ exports.createDirentFromStats = createDirentFromStats; /***/ }), -/* 335 */ +/* 330 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const fsStat = __webpack_require__(321); -const constants_1 = __webpack_require__(332); -const utils = __webpack_require__(333); +const fsStat = __webpack_require__(316); +const constants_1 = __webpack_require__(327); +const utils = __webpack_require__(328); function read(directory, settings) { if (!settings.stats && constants_1.IS_SUPPORT_READDIR_WITH_FILE_TYPES) { return readdirWithFileTypes(directory, settings); @@ -44415,15 +43883,15 @@ exports.readdir = readdir; /***/ }), -/* 336 */ +/* 331 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const path = __webpack_require__(4); -const fsStat = __webpack_require__(321); -const fs = __webpack_require__(337); +const fsStat = __webpack_require__(316); +const fs = __webpack_require__(332); class Settings { constructor(_options = {}) { this._options = _options; @@ -44446,7 +43914,7 @@ exports.default = Settings; /***/ }), -/* 337 */ +/* 332 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -44471,13 +43939,13 @@ exports.createFileSystemAdapter = createFileSystemAdapter; /***/ }), -/* 338 */ +/* 333 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var reusify = __webpack_require__(339) +var reusify = __webpack_require__(334) function fastqueue (context, worker, concurrency) { if (typeof context === 'function') { @@ -44651,7 +44119,7 @@ module.exports = fastqueue /***/ }), -/* 339 */ +/* 334 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -44691,7 +44159,7 @@ module.exports = reusify /***/ }), -/* 340 */ +/* 335 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -44722,13 +44190,13 @@ exports.joinPathSegments = joinPathSegments; /***/ }), -/* 341 */ +/* 336 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const common = __webpack_require__(340); +const common = __webpack_require__(335); class Reader { constructor(_root, _settings) { this._root = _root; @@ -44740,14 +44208,14 @@ exports.default = Reader; /***/ }), -/* 342 */ +/* 337 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const stream_1 = __webpack_require__(137); -const async_1 = __webpack_require__(328); +const async_1 = __webpack_require__(323); class StreamProvider { constructor(_root, _settings) { this._root = _root; @@ -44777,13 +44245,13 @@ exports.default = StreamProvider; /***/ }), -/* 343 */ +/* 338 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const sync_1 = __webpack_require__(344); +const sync_1 = __webpack_require__(339); class SyncProvider { constructor(_root, _settings) { this._root = _root; @@ -44798,15 +44266,15 @@ exports.default = SyncProvider; /***/ }), -/* 344 */ +/* 339 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const fsScandir = __webpack_require__(329); -const common = __webpack_require__(340); -const reader_1 = __webpack_require__(341); +const fsScandir = __webpack_require__(324); +const common = __webpack_require__(335); +const reader_1 = __webpack_require__(336); class SyncReader extends reader_1.default { constructor() { super(...arguments); @@ -44864,14 +44332,14 @@ exports.default = SyncReader; /***/ }), -/* 345 */ +/* 340 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const path = __webpack_require__(4); -const fsScandir = __webpack_require__(329); +const fsScandir = __webpack_require__(324); class Settings { constructor(_options = {}) { this._options = _options; @@ -44897,15 +44365,15 @@ exports.default = Settings; /***/ }), -/* 346 */ +/* 341 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const path = __webpack_require__(4); -const fsStat = __webpack_require__(321); -const utils = __webpack_require__(291); +const fsStat = __webpack_require__(316); +const utils = __webpack_require__(286); class Reader { constructor(_settings) { this._settings = _settings; @@ -44937,17 +44405,17 @@ exports.default = Reader; /***/ }), -/* 347 */ +/* 342 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const path = __webpack_require__(4); -const deep_1 = __webpack_require__(348); -const entry_1 = __webpack_require__(351); -const error_1 = __webpack_require__(352); -const entry_2 = __webpack_require__(353); +const deep_1 = __webpack_require__(343); +const entry_1 = __webpack_require__(346); +const error_1 = __webpack_require__(347); +const entry_2 = __webpack_require__(348); class Provider { constructor(_settings) { this._settings = _settings; @@ -44992,14 +44460,14 @@ exports.default = Provider; /***/ }), -/* 348 */ +/* 343 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const utils = __webpack_require__(291); -const partial_1 = __webpack_require__(349); +const utils = __webpack_require__(286); +const partial_1 = __webpack_require__(344); class DeepFilter { constructor(_settings, _micromatchOptions) { this._settings = _settings; @@ -45053,13 +44521,13 @@ exports.default = DeepFilter; /***/ }), -/* 349 */ +/* 344 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const matcher_1 = __webpack_require__(350); +const matcher_1 = __webpack_require__(345); class PartialMatcher extends matcher_1.default { match(filepath) { const parts = filepath.split('/'); @@ -45098,13 +44566,13 @@ exports.default = PartialMatcher; /***/ }), -/* 350 */ +/* 345 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const utils = __webpack_require__(291); +const utils = __webpack_require__(286); class Matcher { constructor(_patterns, _settings, _micromatchOptions) { this._patterns = _patterns; @@ -45155,13 +44623,13 @@ exports.default = Matcher; /***/ }), -/* 351 */ +/* 346 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const utils = __webpack_require__(291); +const utils = __webpack_require__(286); class EntryFilter { constructor(_settings, _micromatchOptions) { this._settings = _settings; @@ -45217,13 +44685,13 @@ exports.default = EntryFilter; /***/ }), -/* 352 */ +/* 347 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const utils = __webpack_require__(291); +const utils = __webpack_require__(286); class ErrorFilter { constructor(_settings) { this._settings = _settings; @@ -45239,13 +44707,13 @@ exports.default = ErrorFilter; /***/ }), -/* 353 */ +/* 348 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const utils = __webpack_require__(291); +const utils = __webpack_require__(286); class EntryTransformer { constructor(_settings) { this._settings = _settings; @@ -45272,15 +44740,15 @@ exports.default = EntryTransformer; /***/ }), -/* 354 */ +/* 349 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const stream_1 = __webpack_require__(137); -const stream_2 = __webpack_require__(320); -const provider_1 = __webpack_require__(347); +const stream_2 = __webpack_require__(315); +const provider_1 = __webpack_require__(342); class ProviderStream extends provider_1.default { constructor() { super(...arguments); @@ -45310,14 +44778,14 @@ exports.default = ProviderStream; /***/ }), -/* 355 */ +/* 350 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const sync_1 = __webpack_require__(356); -const provider_1 = __webpack_require__(347); +const sync_1 = __webpack_require__(351); +const provider_1 = __webpack_require__(342); class ProviderSync extends provider_1.default { constructor() { super(...arguments); @@ -45340,15 +44808,15 @@ exports.default = ProviderSync; /***/ }), -/* 356 */ +/* 351 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const fsStat = __webpack_require__(321); -const fsWalk = __webpack_require__(326); -const reader_1 = __webpack_require__(346); +const fsStat = __webpack_require__(316); +const fsWalk = __webpack_require__(321); +const reader_1 = __webpack_require__(341); class ReaderSync extends reader_1.default { constructor() { super(...arguments); @@ -45390,7 +44858,7 @@ exports.default = ReaderSync; /***/ }), -/* 357 */ +/* 352 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -45449,13 +44917,13 @@ exports.default = Settings; /***/ }), -/* 358 */ +/* 353 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(4); -const pathType = __webpack_require__(359); +const pathType = __webpack_require__(354); const getExtensions = extensions => extensions.length > 1 ? `{${extensions.join(',')}}` : extensions[0]; @@ -45531,7 +44999,7 @@ module.exports.sync = (input, options) => { /***/ }), -/* 359 */ +/* 354 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -45581,7 +45049,7 @@ exports.isSymlinkSync = isTypeSync.bind(null, 'lstatSync', 'isSymbolicLink'); /***/ }), -/* 360 */ +/* 355 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -45589,9 +45057,9 @@ exports.isSymlinkSync = isTypeSync.bind(null, 'lstatSync', 'isSymbolicLink'); const {promisify} = __webpack_require__(111); const fs = __webpack_require__(133); const path = __webpack_require__(4); -const fastGlob = __webpack_require__(289); -const gitIgnore = __webpack_require__(361); -const slash = __webpack_require__(362); +const fastGlob = __webpack_require__(284); +const gitIgnore = __webpack_require__(356); +const slash = __webpack_require__(357); const DEFAULT_IGNORE = [ '**/node_modules/**', @@ -45705,7 +45173,7 @@ module.exports.sync = options => { /***/ }), -/* 361 */ +/* 356 */ /***/ (function(module, exports) { // A simple implementation of make-array @@ -46308,7 +45776,7 @@ if ( /***/ }), -/* 362 */ +/* 357 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -46326,7 +45794,7 @@ module.exports = path => { /***/ }), -/* 363 */ +/* 358 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -46379,7 +45847,7 @@ module.exports = { /***/ }), -/* 364 */ +/* 359 */ /***/ (function(module, exports, __webpack_require__) { /*! @@ -46389,7 +45857,7 @@ module.exports = { * Released under the MIT License. */ -var isExtglob = __webpack_require__(299); +var isExtglob = __webpack_require__(294); var chars = { '{': '}', '(': ')', '[': ']'}; var strictRegex = /\\(.)|(^!|\*|[\].+)]\?|\[[^\\\]]+\]|\{[^\\}]+\}|\(\?[:!=][^\\)]+\)|\([^|]+\|[^\\)]+\))/; var relaxedRegex = /\\(.)|(^!|[*?{}()[\]]|\(\?)/; @@ -46433,7 +45901,7 @@ module.exports = function isGlob(str, options) { /***/ }), -/* 365 */ +/* 360 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -46455,7 +45923,7 @@ module.exports = path_ => { /***/ }), -/* 366 */ +/* 361 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -46483,7 +45951,7 @@ module.exports = (childPath, parentPath) => { /***/ }), -/* 367 */ +/* 362 */ /***/ (function(module, exports, __webpack_require__) { const assert = __webpack_require__(139) @@ -46849,12 +46317,12 @@ rimraf.sync = rimrafSync /***/ }), -/* 368 */ +/* 363 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const AggregateError = __webpack_require__(369); +const AggregateError = __webpack_require__(364); module.exports = async ( iterable, @@ -46937,13 +46405,13 @@ module.exports = async ( /***/ }), -/* 369 */ +/* 364 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const indentString = __webpack_require__(370); -const cleanStack = __webpack_require__(371); +const indentString = __webpack_require__(365); +const cleanStack = __webpack_require__(366); const cleanInternalStack = stack => stack.replace(/\s+at .*aggregate-error\/index.js:\d+:\d+\)?/g, ''); @@ -46991,7 +46459,7 @@ module.exports = AggregateError; /***/ }), -/* 370 */ +/* 365 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -47033,7 +46501,7 @@ module.exports = (string, count = 1, options) => { /***/ }), -/* 371 */ +/* 366 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -47080,47 +46548,221 @@ module.exports = (stack, options) => { /***/ }), -/* 372 */ +/* 367 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const chalk = __webpack_require__(373); -const cliCursor = __webpack_require__(378); -const cliSpinners = __webpack_require__(382); -const logSymbols = __webpack_require__(384); +const readline = __webpack_require__(368); +const chalk = __webpack_require__(369); +const cliCursor = __webpack_require__(374); +const cliSpinners = __webpack_require__(376); +const logSymbols = __webpack_require__(378); +const stripAnsi = __webpack_require__(384); +const wcwidth = __webpack_require__(386); +const isInteractive = __webpack_require__(390); +const MuteStream = __webpack_require__(391); + +const TEXT = Symbol('text'); +const PREFIX_TEXT = Symbol('prefixText'); + +const ASCII_ETX_CODE = 0x03; // Ctrl+C emits this code + +class StdinDiscarder { + constructor() { + this.requests = 0; + + this.mutedStream = new MuteStream(); + this.mutedStream.pipe(process.stdout); + this.mutedStream.mute(); + + const self = this; + this.ourEmit = function (event, data, ...args) { + const {stdin} = process; + if (self.requests > 0 || stdin.emit === self.ourEmit) { + if (event === 'keypress') { // Fixes readline behavior + return; + } + + if (event === 'data' && data.includes(ASCII_ETX_CODE)) { + process.emit('SIGINT'); + } + + Reflect.apply(self.oldEmit, this, [event, data, ...args]); + } else { + Reflect.apply(process.stdin.emit, this, [event, data, ...args]); + } + }; + } + + start() { + this.requests++; + + if (this.requests === 1) { + this.realStart(); + } + } + + stop() { + if (this.requests <= 0) { + throw new Error('`stop` called more times than `start`'); + } + + this.requests--; + + if (this.requests === 0) { + this.realStop(); + } + } + + realStart() { + // No known way to make it work reliably on Windows + if (process.platform === 'win32') { + return; + } + + this.rl = readline.createInterface({ + input: process.stdin, + output: this.mutedStream + }); + + this.rl.on('SIGINT', () => { + if (process.listenerCount('SIGINT') === 0) { + process.emit('SIGINT'); + } else { + this.rl.close(); + process.kill(process.pid, 'SIGINT'); + } + }); + } + + realStop() { + if (process.platform === 'win32') { + return; + } + + this.rl.close(); + this.rl = undefined; + } +} + +let stdinDiscarder; class Ora { constructor(options) { + if (!stdinDiscarder) { + stdinDiscarder = new StdinDiscarder(); + } + if (typeof options === 'string') { options = { text: options }; } - this.options = Object.assign({ + this.options = { text: '', color: 'cyan', - stream: process.stderr - }, options); - - const sp = this.options.spinner; - this.spinner = typeof sp === 'object' ? sp : (process.platform === 'win32' ? cliSpinners.line : (cliSpinners[sp] || cliSpinners.dots)); // eslint-disable-line no-nested-ternary + stream: process.stderr, + discardStdin: true, + ...options + }; - if (this.spinner.frames === undefined) { - throw new Error('Spinner must define `frames`'); - } + this.spinner = this.options.spinner; - this.text = this.options.text; this.color = this.options.color; + this.hideCursor = this.options.hideCursor !== false; this.interval = this.options.interval || this.spinner.interval || 100; this.stream = this.options.stream; - this.id = null; + this.id = undefined; + this.isEnabled = typeof this.options.isEnabled === 'boolean' ? this.options.isEnabled : isInteractive({stream: this.stream}); + + // Set *after* `this.stream` + this.text = this.options.text; + this.prefixText = this.options.prefixText; + this.linesToClear = 0; + this.indent = this.options.indent; + this.discardStdin = this.options.discardStdin; + this.isDiscardingStdin = false; + } + + get indent() { + return this._indent; + } + + set indent(indent = 0) { + if (!(indent >= 0 && Number.isInteger(indent))) { + throw new Error('The `indent` option must be an integer from 0 and up'); + } + + this._indent = indent; + } + + _updateInterval(interval) { + if (interval !== undefined) { + this.interval = interval; + } + } + + get spinner() { + return this._spinner; + } + + set spinner(spinner) { this.frameIndex = 0; - this.enabled = typeof this.options.enabled === 'boolean' ? this.options.enabled : ((this.stream && this.stream.isTTY) && !process.env.CI); + + if (typeof spinner === 'object') { + if (spinner.frames === undefined) { + throw new Error('The given spinner must have a `frames` property'); + } + + this._spinner = spinner; + } else if (process.platform === 'win32') { + this._spinner = cliSpinners.line; + } else if (spinner === undefined) { + // Set default spinner + this._spinner = cliSpinners.dots; + } else if (cliSpinners[spinner]) { + this._spinner = cliSpinners[spinner]; + } else { + throw new Error(`There is no built-in spinner named '${spinner}'. See https://github.com/sindresorhus/cli-spinners/blob/master/spinners.json for a full list.`); + } + + this._updateInterval(this._spinner.interval); + } + + get text() { + return this[TEXT]; + } + + get prefixText() { + return this[PREFIX_TEXT]; + } + + get isSpinning() { + return this.id !== undefined; } + + updateLineCount() { + const columns = this.stream.columns || 80; + const fullPrefixText = (typeof this[PREFIX_TEXT] === 'string') ? this[PREFIX_TEXT] + '-' : ''; + this.lineCount = stripAnsi(fullPrefixText + '--' + this[TEXT]).split('\n').reduce((count, line) => { + return count + Math.max(1, Math.ceil(wcwidth(line) / columns)); + }, 0); + } + + set text(value) { + this[TEXT] = value; + this.updateLineCount(); + } + + set prefixText(value) { + this[PREFIX_TEXT] = value; + this.updateLineCount(); + } + frame() { - const frames = this.spinner.frames; + const {frames} = this.spinner; let frame = frames[this.frameIndex]; if (this.color) { @@ -47128,92 +46770,129 @@ class Ora { } this.frameIndex = ++this.frameIndex % frames.length; + const fullPrefixText = (typeof this.prefixText === 'string' && this.prefixText !== '') ? this.prefixText + ' ' : ''; + const fullText = typeof this.text === 'string' ? ' ' + this.text : ''; - return frame + ' ' + this.text; + return fullPrefixText + frame + fullText; } + clear() { - if (!this.enabled) { + if (!this.isEnabled || !this.stream.isTTY) { return this; } - this.stream.clearLine(); - this.stream.cursorTo(0); + for (let i = 0; i < this.linesToClear; i++) { + if (i > 0) { + this.stream.moveCursor(0, -1); + } + + this.stream.clearLine(); + this.stream.cursorTo(this.indent); + } + + this.linesToClear = 0; return this; } + render() { this.clear(); this.stream.write(this.frame()); + this.linesToClear = this.lineCount; return this; } + start(text) { if (text) { this.text = text; } - if (!this.enabled || this.id) { + if (!this.isEnabled) { + if (this.text) { + this.stream.write(`- ${this.text}\n`); + } + + return this; + } + + if (this.isSpinning) { return this; } - cliCursor.hide(this.stream); + if (this.hideCursor) { + cliCursor.hide(this.stream); + } + + if (this.discardStdin && process.stdin.isTTY) { + this.isDiscardingStdin = true; + stdinDiscarder.start(); + } + this.render(); this.id = setInterval(this.render.bind(this), this.interval); return this; } + stop() { - if (!this.enabled) { + if (!this.isEnabled) { return this; } clearInterval(this.id); - this.id = null; + this.id = undefined; this.frameIndex = 0; this.clear(); - cliCursor.show(this.stream); + if (this.hideCursor) { + cliCursor.show(this.stream); + } + + if (this.discardStdin && process.stdin.isTTY && this.isDiscardingStdin) { + stdinDiscarder.stop(); + this.isDiscardingStdin = false; + } return this; } + succeed(text) { return this.stopAndPersist({symbol: logSymbols.success, text}); } + fail(text) { return this.stopAndPersist({symbol: logSymbols.error, text}); } + warn(text) { return this.stopAndPersist({symbol: logSymbols.warning, text}); } - info(text) { - return this.stopAndPersist({symbol: logSymbols.info, text}); - } - stopAndPersist(options) { - if (!this.enabled) { - return this; - } - // Legacy argument - // TODO: Deprecate sometime in the future - if (typeof options === 'string') { - options = { - symbol: options - }; - } + info(text) { + return this.stopAndPersist({symbol: logSymbols.info, text}); + } - options = options || {}; + stopAndPersist(options = {}) { + const prefixText = options.prefixText || this.prefixText; + const fullPrefixText = (typeof prefixText === 'string' && prefixText !== '') ? prefixText + ' ' : ''; + const text = options.text || this.text; + const fullText = (typeof text === 'string') ? ' ' + text : ''; this.stop(); - this.stream.write(`${options.symbol || ' '} ${options.text || this.text}\n`); + this.stream.write(`${fullPrefixText}${options.symbol || ' '}${fullText}\n`); return this; } } -module.exports = function (opts) { - return new Ora(opts); +const oraFactory = function (options) { + return new Ora(options); }; +module.exports = oraFactory; + module.exports.promise = (action, options) => { + // eslint-disable-next-line promise/prefer-await-to-then if (typeof action.then !== 'function') { throw new TypeError('Parameter `action` must be a Promise'); } @@ -47221,451 +46900,298 @@ module.exports.promise = (action, options) => { const spinner = new Ora(options); spinner.start(); - action.then( - () => { + (async () => { + try { + await action; spinner.succeed(); - }, - () => { + } catch (_) { spinner.fail(); } - ); + })(); return spinner; }; /***/ }), -/* 373 */ -/***/ (function(module, exports, __webpack_require__) { +/* 368 */ +/***/ (function(module, exports) { -"use strict"; +module.exports = require("readline"); -const escapeStringRegexp = __webpack_require__(178); -const ansiStyles = __webpack_require__(374); -const stdoutColor = __webpack_require__(375).stdout; +/***/ }), +/* 369 */ +/***/ (function(module, exports, __webpack_require__) { -const template = __webpack_require__(377); +"use strict"; -const isSimpleWindowsTerm = process.platform === 'win32' && !(process.env.TERM || '').toLowerCase().startsWith('xterm'); +const ansiStyles = __webpack_require__(113); +const {stdout: stdoutColor, stderr: stderrColor} = __webpack_require__(370); +const { + stringReplaceAll, + stringEncaseCRLFWithFirstIndex +} = __webpack_require__(372); // `supportsColor.level` → `ansiStyles.color[name]` mapping -const levelMapping = ['ansi', 'ansi', 'ansi256', 'ansi16m']; - -// `color-convert` models to exclude from the Chalk API due to conflicts and such -const skipModels = new Set(['gray']); +const levelMapping = [ + 'ansi', + 'ansi', + 'ansi256', + 'ansi16m' +]; const styles = Object.create(null); -function applyOptions(obj, options) { - options = options || {}; +const applyOptions = (object, options = {}) => { + if (options.level > 3 || options.level < 0) { + throw new Error('The `level` option should be an integer from 0 to 3'); + } // Detect level if not set manually - const scLevel = stdoutColor ? stdoutColor.level : 0; - obj.level = options.level === undefined ? scLevel : options.level; - obj.enabled = 'enabled' in options ? options.enabled : obj.level > 0; + const colorLevel = stdoutColor ? stdoutColor.level : 0; + object.level = options.level === undefined ? colorLevel : options.level; +}; + +class ChalkClass { + constructor(options) { + return chalkFactory(options); + } } -function Chalk(options) { - // We check for this.template here since calling `chalk.constructor()` - // by itself will have a `this` of a previously constructed chalk object - if (!this || !(this instanceof Chalk) || this.template) { - const chalk = {}; - applyOptions(chalk, options); +const chalkFactory = options => { + const chalk = {}; + applyOptions(chalk, options); - chalk.template = function () { - const args = [].slice.call(arguments); - return chalkTag.apply(null, [chalk.template].concat(args)); - }; + chalk.template = (...arguments_) => chalkTag(chalk.template, ...arguments_); - Object.setPrototypeOf(chalk, Chalk.prototype); - Object.setPrototypeOf(chalk.template, chalk); + Object.setPrototypeOf(chalk, Chalk.prototype); + Object.setPrototypeOf(chalk.template, chalk); - chalk.template.constructor = Chalk; + chalk.template.constructor = () => { + throw new Error('`chalk.constructor()` is deprecated. Use `new chalk.Instance()` instead.'); + }; - return chalk.template; - } + chalk.template.Instance = ChalkClass; - applyOptions(this, options); -} + return chalk.template; +}; -// Use bright blue on Windows as the normal blue color is illegible -if (isSimpleWindowsTerm) { - ansiStyles.blue.open = '\u001B[94m'; +function Chalk(options) { + return chalkFactory(options); } -for (const key of Object.keys(ansiStyles)) { - ansiStyles[key].closeRe = new RegExp(escapeStringRegexp(ansiStyles[key].close), 'g'); - - styles[key] = { +for (const [styleName, style] of Object.entries(ansiStyles)) { + styles[styleName] = { get() { - const codes = ansiStyles[key]; - return build.call(this, this._styles ? this._styles.concat(codes) : [codes], this._empty, key); + const builder = createBuilder(this, createStyler(style.open, style.close, this._styler), this._isEmpty); + Object.defineProperty(this, styleName, {value: builder}); + return builder; } }; } styles.visible = { get() { - return build.call(this, this._styles || [], true, 'visible'); + const builder = createBuilder(this, this._styler, true); + Object.defineProperty(this, 'visible', {value: builder}); + return builder; } }; -ansiStyles.color.closeRe = new RegExp(escapeStringRegexp(ansiStyles.color.close), 'g'); -for (const model of Object.keys(ansiStyles.color.ansi)) { - if (skipModels.has(model)) { - continue; - } +const usedModels = ['rgb', 'hex', 'keyword', 'hsl', 'hsv', 'hwb', 'ansi', 'ansi256']; +for (const model of usedModels) { styles[model] = { get() { - const level = this.level; - return function () { - const open = ansiStyles.color[levelMapping[level]][model].apply(null, arguments); - const codes = { - open, - close: ansiStyles.color.close, - closeRe: ansiStyles.color.closeRe - }; - return build.call(this, this._styles ? this._styles.concat(codes) : [codes], this._empty, model); + const {level} = this; + return function (...arguments_) { + const styler = createStyler(ansiStyles.color[levelMapping[level]][model](...arguments_), ansiStyles.color.close, this._styler); + return createBuilder(this, styler, this._isEmpty); }; } }; } -ansiStyles.bgColor.closeRe = new RegExp(escapeStringRegexp(ansiStyles.bgColor.close), 'g'); -for (const model of Object.keys(ansiStyles.bgColor.ansi)) { - if (skipModels.has(model)) { - continue; - } - +for (const model of usedModels) { const bgModel = 'bg' + model[0].toUpperCase() + model.slice(1); styles[bgModel] = { get() { - const level = this.level; - return function () { - const open = ansiStyles.bgColor[levelMapping[level]][model].apply(null, arguments); - const codes = { - open, - close: ansiStyles.bgColor.close, - closeRe: ansiStyles.bgColor.closeRe - }; - return build.call(this, this._styles ? this._styles.concat(codes) : [codes], this._empty, model); + const {level} = this; + return function (...arguments_) { + const styler = createStyler(ansiStyles.bgColor[levelMapping[level]][model](...arguments_), ansiStyles.bgColor.close, this._styler); + return createBuilder(this, styler, this._isEmpty); }; } }; } -const proto = Object.defineProperties(() => {}, styles); - -function build(_styles, _empty, key) { - const builder = function () { - return applyStyle.apply(builder, arguments); - }; - - builder._styles = _styles; - builder._empty = _empty; - - const self = this; - - Object.defineProperty(builder, 'level', { +const proto = Object.defineProperties(() => {}, { + ...styles, + level: { enumerable: true, get() { - return self.level; + return this._generator.level; }, set(level) { - self.level = level; + this._generator.level = level; } - }); + } +}); - Object.defineProperty(builder, 'enabled', { - enumerable: true, - get() { - return self.enabled; - }, - set(enabled) { - self.enabled = enabled; - } - }); +const createStyler = (open, close, parent) => { + let openAll; + let closeAll; + if (parent === undefined) { + openAll = open; + closeAll = close; + } else { + openAll = parent.openAll + open; + closeAll = close + parent.closeAll; + } - // See below for fix regarding invisible grey/dim combination on Windows - builder.hasGrey = this.hasGrey || key === 'gray' || key === 'grey'; + return { + open, + close, + openAll, + closeAll, + parent + }; +}; + +const createBuilder = (self, _styler, _isEmpty) => { + const builder = (...arguments_) => { + // Single argument is hot path, implicit coercion is faster than anything + // eslint-disable-next-line no-implicit-coercion + return applyStyle(builder, (arguments_.length === 1) ? ('' + arguments_[0]) : arguments_.join(' ')); + }; // `__proto__` is used because we must return a function, but there is // no way to create a function with a different prototype builder.__proto__ = proto; // eslint-disable-line no-proto - return builder; -} + builder._generator = self; + builder._styler = _styler; + builder._isEmpty = _isEmpty; -function applyStyle() { - // Support varags, but simply cast to string in case there's only one arg - const args = arguments; - const argsLen = args.length; - let str = String(arguments[0]); + return builder; +}; - if (argsLen === 0) { - return ''; +const applyStyle = (self, string) => { + if (self.level <= 0 || !string) { + return self._isEmpty ? '' : string; } - if (argsLen > 1) { - // Don't slice `arguments`, it prevents V8 optimizations - for (let a = 1; a < argsLen; a++) { - str += ' ' + args[a]; - } - } + let styler = self._styler; - if (!this.enabled || this.level <= 0 || !str) { - return this._empty ? '' : str; + if (styler === undefined) { + return string; } - // Turns out that on Windows dimmed gray text becomes invisible in cmd.exe, - // see https://github.com/chalk/chalk/issues/58 - // If we're on Windows and we're dealing with a gray color, temporarily make 'dim' a noop. - const originalDim = ansiStyles.dim.open; - if (isSimpleWindowsTerm && this.hasGrey) { - ansiStyles.dim.open = ''; - } + const {openAll, closeAll} = styler; + if (string.indexOf('\u001B') !== -1) { + while (styler !== undefined) { + // Replace any instances already present with a re-opening code + // otherwise only the part of the string until said closing code + // will be colored, and the rest will simply be 'plain'. + string = stringReplaceAll(string, styler.close, styler.open); - for (const code of this._styles.slice().reverse()) { - // Replace any instances already present with a re-opening code - // otherwise only the part of the string until said closing code - // will be colored, and the rest will simply be 'plain'. - str = code.open + str.replace(code.closeRe, code.open) + code.close; + styler = styler.parent; + } + } - // Close the styling before a linebreak and reopen - // after next line to fix a bleed issue on macOS - // https://github.com/chalk/chalk/pull/92 - str = str.replace(/\r?\n/g, `${code.close}$&${code.open}`); + // We can move both next actions out of loop, because remaining actions in loop won't have + // any/visible effect on parts we add here. Close the styling before a linebreak and reopen + // after next line to fix a bleed issue on macOS: https://github.com/chalk/chalk/pull/92 + const lfIndex = string.indexOf('\n'); + if (lfIndex !== -1) { + string = stringEncaseCRLFWithFirstIndex(string, closeAll, openAll, lfIndex); } - // Reset the original `dim` if we changed it to work around the Windows dimmed gray issue - ansiStyles.dim.open = originalDim; + return openAll + string + closeAll; +}; - return str; -} +let template; +const chalkTag = (chalk, ...strings) => { + const [firstString] = strings; -function chalkTag(chalk, strings) { - if (!Array.isArray(strings)) { + if (!Array.isArray(firstString)) { // If chalk() was called by itself or with a string, // return the string itself as a string. - return [].slice.call(arguments, 1).join(' '); + return strings.join(' '); } - const args = [].slice.call(arguments, 2); - const parts = [strings.raw[0]]; + const arguments_ = strings.slice(1); + const parts = [firstString.raw[0]]; - for (let i = 1; i < strings.length; i++) { - parts.push(String(args[i - 1]).replace(/[{}\\]/g, '\\$&')); - parts.push(String(strings.raw[i])); + for (let i = 1; i < firstString.length; i++) { + parts.push( + String(arguments_[i - 1]).replace(/[{}\\]/g, '\\$&'), + String(firstString.raw[i]) + ); + } + + if (template === undefined) { + template = __webpack_require__(373); } return template(chalk, parts.join('')); -} +}; Object.defineProperties(Chalk.prototype, styles); -module.exports = Chalk(); // eslint-disable-line new-cap -module.exports.supportsColor = stdoutColor; -module.exports.default = module.exports; // For TypeScript - - -/***/ }), -/* 374 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/* WEBPACK VAR INJECTION */(function(module) { -const colorConvert = __webpack_require__(180); - -const wrapAnsi16 = (fn, offset) => function () { - const code = fn.apply(colorConvert, arguments); - return `\u001B[${code + offset}m`; -}; - -const wrapAnsi256 = (fn, offset) => function () { - const code = fn.apply(colorConvert, arguments); - return `\u001B[${38 + offset};5;${code}m`; -}; +const chalk = Chalk(); // eslint-disable-line new-cap +chalk.supportsColor = stdoutColor; +chalk.stderr = Chalk({level: stderrColor ? stderrColor.level : 0}); // eslint-disable-line new-cap +chalk.stderr.supportsColor = stderrColor; -const wrapAnsi16m = (fn, offset) => function () { - const rgb = fn.apply(colorConvert, arguments); - return `\u001B[${38 + offset};2;${rgb[0]};${rgb[1]};${rgb[2]}m`; +// For TypeScript +chalk.Level = { + None: 0, + Basic: 1, + Ansi256: 2, + TrueColor: 3, + 0: 'None', + 1: 'Basic', + 2: 'Ansi256', + 3: 'TrueColor' }; -function assembleStyles() { - const codes = new Map(); - const styles = { - modifier: { - reset: [0, 0], - // 21 isn't widely supported and 22 does the same thing - bold: [1, 22], - dim: [2, 22], - italic: [3, 23], - underline: [4, 24], - inverse: [7, 27], - hidden: [8, 28], - strikethrough: [9, 29] - }, - color: { - black: [30, 39], - red: [31, 39], - green: [32, 39], - yellow: [33, 39], - blue: [34, 39], - magenta: [35, 39], - cyan: [36, 39], - white: [37, 39], - gray: [90, 39], - - // Bright color - redBright: [91, 39], - greenBright: [92, 39], - yellowBright: [93, 39], - blueBright: [94, 39], - magentaBright: [95, 39], - cyanBright: [96, 39], - whiteBright: [97, 39] - }, - bgColor: { - bgBlack: [40, 49], - bgRed: [41, 49], - bgGreen: [42, 49], - bgYellow: [43, 49], - bgBlue: [44, 49], - bgMagenta: [45, 49], - bgCyan: [46, 49], - bgWhite: [47, 49], - - // Bright color - bgBlackBright: [100, 49], - bgRedBright: [101, 49], - bgGreenBright: [102, 49], - bgYellowBright: [103, 49], - bgBlueBright: [104, 49], - bgMagentaBright: [105, 49], - bgCyanBright: [106, 49], - bgWhiteBright: [107, 49] - } - }; - - // Fix humans - styles.color.grey = styles.color.gray; - - for (const groupName of Object.keys(styles)) { - const group = styles[groupName]; - - for (const styleName of Object.keys(group)) { - const style = group[styleName]; - - styles[styleName] = { - open: `\u001B[${style[0]}m`, - close: `\u001B[${style[1]}m` - }; - - group[styleName] = styles[styleName]; - - codes.set(style[0], style[1]); - } - - Object.defineProperty(styles, groupName, { - value: group, - enumerable: false - }); - - Object.defineProperty(styles, 'codes', { - value: codes, - enumerable: false - }); - } - - const ansi2ansi = n => n; - const rgb2rgb = (r, g, b) => [r, g, b]; - - styles.color.close = '\u001B[39m'; - styles.bgColor.close = '\u001B[49m'; - - styles.color.ansi = { - ansi: wrapAnsi16(ansi2ansi, 0) - }; - styles.color.ansi256 = { - ansi256: wrapAnsi256(ansi2ansi, 0) - }; - styles.color.ansi16m = { - rgb: wrapAnsi16m(rgb2rgb, 0) - }; - - styles.bgColor.ansi = { - ansi: wrapAnsi16(ansi2ansi, 10) - }; - styles.bgColor.ansi256 = { - ansi256: wrapAnsi256(ansi2ansi, 10) - }; - styles.bgColor.ansi16m = { - rgb: wrapAnsi16m(rgb2rgb, 10) - }; - - for (let key of Object.keys(colorConvert)) { - if (typeof colorConvert[key] !== 'object') { - continue; - } - - const suite = colorConvert[key]; - - if (key === 'ansi16') { - key = 'ansi'; - } - - if ('ansi16' in suite) { - styles.color.ansi[key] = wrapAnsi16(suite.ansi16, 0); - styles.bgColor.ansi[key] = wrapAnsi16(suite.ansi16, 10); - } - - if ('ansi256' in suite) { - styles.color.ansi256[key] = wrapAnsi256(suite.ansi256, 0); - styles.bgColor.ansi256[key] = wrapAnsi256(suite.ansi256, 10); - } - - if ('rgb' in suite) { - styles.color.ansi16m[key] = wrapAnsi16m(suite.rgb, 0); - styles.bgColor.ansi16m[key] = wrapAnsi16m(suite.rgb, 10); - } - } - - return styles; -} - -// Make the export immutable -Object.defineProperty(module, 'exports', { - enumerable: true, - get: assembleStyles -}); +module.exports = chalk; -/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(114)(module))) /***/ }), -/* 375 */ +/* 370 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const os = __webpack_require__(120); -const hasFlag = __webpack_require__(376); +const tty = __webpack_require__(121); +const hasFlag = __webpack_require__(371); -const env = process.env; +const {env} = process; let forceColor; if (hasFlag('no-color') || hasFlag('no-colors') || - hasFlag('color=false')) { - forceColor = false; + hasFlag('color=false') || + hasFlag('color=never')) { + forceColor = 0; } else if (hasFlag('color') || hasFlag('colors') || hasFlag('color=true') || hasFlag('color=always')) { - forceColor = true; + forceColor = 1; } + if ('FORCE_COLOR' in env) { - forceColor = env.FORCE_COLOR.length === 0 || parseInt(env.FORCE_COLOR, 10) !== 0; + if (env.FORCE_COLOR === 'true') { + forceColor = 1; + } else if (env.FORCE_COLOR === 'false') { + forceColor = 0; + } else { + forceColor = env.FORCE_COLOR.length === 0 ? 1 : Math.min(parseInt(env.FORCE_COLOR, 10), 3); + } } function translateLevel(level) { @@ -47681,8 +47207,8 @@ function translateLevel(level) { }; } -function supportsColor(stream) { - if (forceColor === false) { +function supportsColor(haveStream, streamIsTTY) { + if (forceColor === 0) { return 0; } @@ -47696,22 +47222,21 @@ function supportsColor(stream) { return 2; } - if (stream && !stream.isTTY && forceColor !== true) { + if (haveStream && !streamIsTTY && forceColor === undefined) { return 0; } - const min = forceColor ? 1 : 0; + const min = forceColor || 0; + + if (env.TERM === 'dumb') { + return min; + } if (process.platform === 'win32') { - // Node.js 7.5.0 is the first version of Node.js to include a patch to - // libuv that enables 256 color output on Windows. Anything earlier and it - // won't work. However, here we target Node.js 8 at minimum as it is an LTS - // release, and Node.js 7 is not. Windows 10 build 10586 is the first Windows - // release that supports 256 colors. Windows 10 build 14931 is the first release - // that supports 16m/TrueColor. + // Windows 10 build 10586 is the first Windows release that supports 256 colors. + // Windows 10 build 14931 is the first release that supports 16m/TrueColor. const osRelease = os.release().split('.'); if ( - Number(process.versions.node.split('.')[0]) >= 8 && Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586 ) { @@ -47733,6 +47258,10 @@ function supportsColor(stream) { return /^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env.TEAMCITY_VERSION) ? 1 : 0; } + if ('GITHUB_ACTIONS' in env) { + return 1; + } + if (env.COLORTERM === 'truecolor') { return 3; } @@ -47761,50 +47290,92 @@ function supportsColor(stream) { return 1; } - if (env.TERM === 'dumb') { - return min; - } - return min; } function getSupportLevel(stream) { - const level = supportsColor(stream); + const level = supportsColor(stream, stream && stream.isTTY); return translateLevel(level); } module.exports = { supportsColor: getSupportLevel, - stdout: getSupportLevel(process.stdout), - stderr: getSupportLevel(process.stderr) + stdout: translateLevel(supportsColor(true, tty.isatty(1))), + stderr: translateLevel(supportsColor(true, tty.isatty(2))) }; /***/ }), -/* 376 */ +/* 371 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -module.exports = (flag, argv) => { - argv = argv || process.argv; + +module.exports = (flag, argv = process.argv) => { const prefix = flag.startsWith('-') ? '' : (flag.length === 1 ? '-' : '--'); - const pos = argv.indexOf(prefix + flag); - const terminatorPos = argv.indexOf('--'); - return pos !== -1 && (terminatorPos === -1 ? true : pos < terminatorPos); + const position = argv.indexOf(prefix + flag); + const terminatorPosition = argv.indexOf('--'); + return position !== -1 && (terminatorPosition === -1 || position < terminatorPosition); }; /***/ }), -/* 377 */ +/* 372 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const TEMPLATE_REGEX = /(?:\\(u[a-f\d]{4}|x[a-f\d]{2}|.))|(?:\{(~)?(\w+(?:\([^)]*\))?(?:\.\w+(?:\([^)]*\))?)*)(?:[ \t]|(?=\r?\n)))|(\})|((?:.|[\r\n\f])+?)/gi; + +const stringReplaceAll = (string, substring, replacer) => { + let index = string.indexOf(substring); + if (index === -1) { + return string; + } + + const substringLength = substring.length; + let endIndex = 0; + let returnValue = ''; + do { + returnValue += string.substr(endIndex, index - endIndex) + substring + replacer; + endIndex = index + substringLength; + index = string.indexOf(substring, endIndex); + } while (index !== -1); + + returnValue += string.substr(endIndex); + return returnValue; +}; + +const stringEncaseCRLFWithFirstIndex = (string, prefix, postfix, index) => { + let endIndex = 0; + let returnValue = ''; + do { + const gotCR = string[index - 1] === '\r'; + returnValue += string.substr(endIndex, (gotCR ? index - 1 : index) - endIndex) + prefix + (gotCR ? '\r\n' : '\n') + postfix; + endIndex = index + 1; + index = string.indexOf('\n', endIndex); + } while (index !== -1); + + returnValue += string.substr(endIndex); + return returnValue; +}; + +module.exports = { + stringReplaceAll, + stringEncaseCRLFWithFirstIndex +}; + + +/***/ }), +/* 373 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +const TEMPLATE_REGEX = /(?:\\(u(?:[a-f\d]{4}|\{[a-f\d]{1,6}\})|x[a-f\d]{2}|.))|(?:\{(~)?(\w+(?:\([^)]*\))?(?:\.\w+(?:\([^)]*\))?)*)(?:[ \t]|(?=\r?\n)))|(\})|((?:.|[\r\n\f])+?)/gi; const STYLE_REGEX = /(?:^|\.)(\w+)(?:\(([^)]*)\))?/g; const STRING_REGEX = /^(['"])((?:\\.|(?!\1)[^\\])*)\1$/; -const ESCAPE_REGEX = /\\(u[a-f\d]{4}|x[a-f\d]{2}|.)|([^\\])/gi; +const ESCAPE_REGEX = /\\(u(?:[a-f\d]{4}|\{[a-f\d]{1,6}\})|x[a-f\d]{2}|.)|([^\\])/gi; const ESCAPES = new Map([ ['n', '\n'], @@ -47820,23 +47391,31 @@ const ESCAPES = new Map([ ]); function unescape(c) { - if ((c[0] === 'u' && c.length === 5) || (c[0] === 'x' && c.length === 3)) { + const u = c[0] === 'u'; + const bracket = c[1] === '{'; + + if ((u && !bracket && c.length === 5) || (c[0] === 'x' && c.length === 3)) { return String.fromCharCode(parseInt(c.slice(1), 16)); } + if (u && bracket) { + return String.fromCodePoint(parseInt(c.slice(2, -1), 16)); + } + return ESCAPES.get(c) || c; } -function parseArguments(name, args) { +function parseArguments(name, arguments_) { const results = []; - const chunks = args.trim().split(/\s*,\s*/g); + const chunks = arguments_.trim().split(/\s*,\s*/g); let matches; for (const chunk of chunks) { - if (!isNaN(chunk)) { - results.push(Number(chunk)); + const number = Number(chunk); + if (!Number.isNaN(number)) { + results.push(number); } else if ((matches = chunk.match(STRING_REGEX))) { - results.push(matches[2].replace(ESCAPE_REGEX, (m, escape, chr) => escape ? unescape(escape) : chr)); + results.push(matches[2].replace(ESCAPE_REGEX, (m, escape, character) => escape ? unescape(escape) : character)); } else { throw new Error(`Invalid Chalk template style argument: ${chunk} (in style '${name}')`); } @@ -47875,36 +47454,34 @@ function buildStyle(chalk, styles) { } let current = chalk; - for (const styleName of Object.keys(enabled)) { - if (Array.isArray(enabled[styleName])) { - if (!(styleName in current)) { - throw new Error(`Unknown Chalk style: ${styleName}`); - } + for (const [styleName, styles] of Object.entries(enabled)) { + if (!Array.isArray(styles)) { + continue; + } - if (enabled[styleName].length > 0) { - current = current[styleName].apply(current, enabled[styleName]); - } else { - current = current[styleName]; - } + if (!(styleName in current)) { + throw new Error(`Unknown Chalk style: ${styleName}`); } + + current = styles.length > 0 ? current[styleName](...styles) : current[styleName]; } return current; } -module.exports = (chalk, tmp) => { +module.exports = (chalk, temporary) => { const styles = []; const chunks = []; let chunk = []; // eslint-disable-next-line max-params - tmp.replace(TEMPLATE_REGEX, (m, escapeChar, inverse, style, close, chr) => { - if (escapeChar) { - chunk.push(unescape(escapeChar)); + temporary.replace(TEMPLATE_REGEX, (m, escapeCharacter, inverse, style, close, character) => { + if (escapeCharacter) { + chunk.push(unescape(escapeCharacter)); } else if (style) { - const str = chunk.join(''); + const string = chunk.join(''); chunk = []; - chunks.push(styles.length === 0 ? str : buildStyle(chalk, styles)(str)); + chunks.push(styles.length === 0 ? string : buildStyle(chalk, styles)(string)); styles.push({inverse, styles: parseStyle(style)}); } else if (close) { if (styles.length === 0) { @@ -47915,7 +47492,7 @@ module.exports = (chalk, tmp) => { chunk = []; styles.pop(); } else { - chunk.push(chr); + chunk.push(character); } }); @@ -47931,151 +47508,100 @@ module.exports = (chalk, tmp) => { /***/ }), -/* 378 */ +/* 374 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const restoreCursor = __webpack_require__(379); - -let hidden = false; +const restoreCursor = __webpack_require__(375); -exports.show = stream => { - const s = stream || process.stderr; +let isHidden = false; - if (!s.isTTY) { +exports.show = (writableStream = process.stderr) => { + if (!writableStream.isTTY) { return; } - hidden = false; - s.write('\u001b[?25h'); + isHidden = false; + writableStream.write('\u001B[?25h'); }; -exports.hide = stream => { - const s = stream || process.stderr; - - if (!s.isTTY) { +exports.hide = (writableStream = process.stderr) => { + if (!writableStream.isTTY) { return; } restoreCursor(); - hidden = true; - s.write('\u001b[?25l'); + isHidden = true; + writableStream.write('\u001B[?25l'); }; -exports.toggle = (force, stream) => { +exports.toggle = (force, writableStream) => { if (force !== undefined) { - hidden = force; + isHidden = force; } - if (hidden) { - exports.show(stream); + if (isHidden) { + exports.show(writableStream); } else { - exports.hide(stream); + exports.hide(writableStream); } }; /***/ }), -/* 379 */ +/* 375 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const onetime = __webpack_require__(380); +const onetime = __webpack_require__(244); const signalExit = __webpack_require__(217); module.exports = onetime(() => { signalExit(() => { - process.stderr.write('\u001b[?25h'); + process.stderr.write('\u001B[?25h'); }, {alwaysLast: true}); }); /***/ }), -/* 380 */ +/* 376 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const mimicFn = __webpack_require__(381); - -module.exports = (fn, opts) => { - // TODO: Remove this in v3 - if (opts === true) { - throw new TypeError('The second argument is now an options object'); - } - - if (typeof fn !== 'function') { - throw new TypeError('Expected a function'); - } - - opts = opts || {}; - - let ret; - let called = false; - const fnName = fn.displayName || fn.name || ''; - - const onetime = function () { - if (called) { - if (opts.throw === true) { - throw new Error(`Function \`${fnName}\` can only be called once`); - } - - return ret; - } - - called = true; - ret = fn.apply(this, arguments); - fn = null; - return ret; - }; +const spinners = Object.assign({}, __webpack_require__(377)); - mimicFn(onetime, fn); +const spinnersList = Object.keys(spinners); - return onetime; -}; - - -/***/ }), -/* 381 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -module.exports = (to, from) => { - // TODO: use `Reflect.ownKeys()` when targeting Node.js 6 - for (const prop of Object.getOwnPropertyNames(from).concat(Object.getOwnPropertySymbols(from))) { - Object.defineProperty(to, prop, Object.getOwnPropertyDescriptor(from, prop)); +Object.defineProperty(spinners, 'random', { + get() { + const randomIndex = Math.floor(Math.random() * spinnersList.length); + const spinnerName = spinnersList[randomIndex]; + return spinners[spinnerName]; } +}); - return to; -}; - - -/***/ }), -/* 382 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -module.exports = __webpack_require__(383); +module.exports = spinners; +// TODO: Remove this for the next major release +module.exports.default = spinners; /***/ }), -/* 383 */ +/* 377 */ /***/ (function(module) { -module.exports = JSON.parse("{\"dots\":{\"interval\":80,\"frames\":[\"⠋\",\"⠙\",\"⠹\",\"⠸\",\"⠼\",\"⠴\",\"⠦\",\"⠧\",\"⠇\",\"⠏\"]},\"dots2\":{\"interval\":80,\"frames\":[\"⣾\",\"⣽\",\"⣻\",\"⢿\",\"⡿\",\"⣟\",\"⣯\",\"⣷\"]},\"dots3\":{\"interval\":80,\"frames\":[\"⠋\",\"⠙\",\"⠚\",\"⠞\",\"⠖\",\"⠦\",\"⠴\",\"⠲\",\"⠳\",\"⠓\"]},\"dots4\":{\"interval\":80,\"frames\":[\"⠄\",\"⠆\",\"⠇\",\"⠋\",\"⠙\",\"⠸\",\"⠰\",\"⠠\",\"⠰\",\"⠸\",\"⠙\",\"⠋\",\"⠇\",\"⠆\"]},\"dots5\":{\"interval\":80,\"frames\":[\"⠋\",\"⠙\",\"⠚\",\"⠒\",\"⠂\",\"⠂\",\"⠒\",\"⠲\",\"⠴\",\"⠦\",\"⠖\",\"⠒\",\"⠐\",\"⠐\",\"⠒\",\"⠓\",\"⠋\"]},\"dots6\":{\"interval\":80,\"frames\":[\"⠁\",\"⠉\",\"⠙\",\"⠚\",\"⠒\",\"⠂\",\"⠂\",\"⠒\",\"⠲\",\"⠴\",\"⠤\",\"⠄\",\"⠄\",\"⠤\",\"⠴\",\"⠲\",\"⠒\",\"⠂\",\"⠂\",\"⠒\",\"⠚\",\"⠙\",\"⠉\",\"⠁\"]},\"dots7\":{\"interval\":80,\"frames\":[\"⠈\",\"⠉\",\"⠋\",\"⠓\",\"⠒\",\"⠐\",\"⠐\",\"⠒\",\"⠖\",\"⠦\",\"⠤\",\"⠠\",\"⠠\",\"⠤\",\"⠦\",\"⠖\",\"⠒\",\"⠐\",\"⠐\",\"⠒\",\"⠓\",\"⠋\",\"⠉\",\"⠈\"]},\"dots8\":{\"interval\":80,\"frames\":[\"⠁\",\"⠁\",\"⠉\",\"⠙\",\"⠚\",\"⠒\",\"⠂\",\"⠂\",\"⠒\",\"⠲\",\"⠴\",\"⠤\",\"⠄\",\"⠄\",\"⠤\",\"⠠\",\"⠠\",\"⠤\",\"⠦\",\"⠖\",\"⠒\",\"⠐\",\"⠐\",\"⠒\",\"⠓\",\"⠋\",\"⠉\",\"⠈\",\"⠈\"]},\"dots9\":{\"interval\":80,\"frames\":[\"⢹\",\"⢺\",\"⢼\",\"⣸\",\"⣇\",\"⡧\",\"⡗\",\"⡏\"]},\"dots10\":{\"interval\":80,\"frames\":[\"⢄\",\"⢂\",\"⢁\",\"⡁\",\"⡈\",\"⡐\",\"⡠\"]},\"dots11\":{\"interval\":100,\"frames\":[\"⠁\",\"⠂\",\"⠄\",\"⡀\",\"⢀\",\"⠠\",\"⠐\",\"⠈\"]},\"dots12\":{\"interval\":80,\"frames\":[\"⢀⠀\",\"⡀⠀\",\"⠄⠀\",\"⢂⠀\",\"⡂⠀\",\"⠅⠀\",\"⢃⠀\",\"⡃⠀\",\"⠍⠀\",\"⢋⠀\",\"⡋⠀\",\"⠍⠁\",\"⢋⠁\",\"⡋⠁\",\"⠍⠉\",\"⠋⠉\",\"⠋⠉\",\"⠉⠙\",\"⠉⠙\",\"⠉⠩\",\"⠈⢙\",\"⠈⡙\",\"⢈⠩\",\"⡀⢙\",\"⠄⡙\",\"⢂⠩\",\"⡂⢘\",\"⠅⡘\",\"⢃⠨\",\"⡃⢐\",\"⠍⡐\",\"⢋⠠\",\"⡋⢀\",\"⠍⡁\",\"⢋⠁\",\"⡋⠁\",\"⠍⠉\",\"⠋⠉\",\"⠋⠉\",\"⠉⠙\",\"⠉⠙\",\"⠉⠩\",\"⠈⢙\",\"⠈⡙\",\"⠈⠩\",\"⠀⢙\",\"⠀⡙\",\"⠀⠩\",\"⠀⢘\",\"⠀⡘\",\"⠀⠨\",\"⠀⢐\",\"⠀⡐\",\"⠀⠠\",\"⠀⢀\",\"⠀⡀\"]},\"line\":{\"interval\":130,\"frames\":[\"-\",\"\\\\\",\"|\",\"/\"]},\"line2\":{\"interval\":100,\"frames\":[\"⠂\",\"-\",\"–\",\"—\",\"–\",\"-\"]},\"pipe\":{\"interval\":100,\"frames\":[\"┤\",\"┘\",\"┴\",\"└\",\"├\",\"┌\",\"┬\",\"┐\"]},\"simpleDots\":{\"interval\":400,\"frames\":[\". \",\".. \",\"...\",\" \"]},\"simpleDotsScrolling\":{\"interval\":200,\"frames\":[\". \",\".. \",\"...\",\" ..\",\" .\",\" \"]},\"star\":{\"interval\":70,\"frames\":[\"✶\",\"✸\",\"✹\",\"✺\",\"✹\",\"✷\"]},\"star2\":{\"interval\":80,\"frames\":[\"+\",\"x\",\"*\"]},\"flip\":{\"interval\":70,\"frames\":[\"_\",\"_\",\"_\",\"-\",\"`\",\"`\",\"'\",\"´\",\"-\",\"_\",\"_\",\"_\"]},\"hamburger\":{\"interval\":100,\"frames\":[\"☱\",\"☲\",\"☴\"]},\"growVertical\":{\"interval\":120,\"frames\":[\"▁\",\"▃\",\"▄\",\"▅\",\"▆\",\"▇\",\"▆\",\"▅\",\"▄\",\"▃\"]},\"growHorizontal\":{\"interval\":120,\"frames\":[\"▏\",\"▎\",\"▍\",\"▌\",\"▋\",\"▊\",\"▉\",\"▊\",\"▋\",\"▌\",\"▍\",\"▎\"]},\"balloon\":{\"interval\":140,\"frames\":[\" \",\".\",\"o\",\"O\",\"@\",\"*\",\" \"]},\"balloon2\":{\"interval\":120,\"frames\":[\".\",\"o\",\"O\",\"°\",\"O\",\"o\",\".\"]},\"noise\":{\"interval\":100,\"frames\":[\"▓\",\"▒\",\"░\"]},\"bounce\":{\"interval\":120,\"frames\":[\"⠁\",\"⠂\",\"⠄\",\"⠂\"]},\"boxBounce\":{\"interval\":120,\"frames\":[\"▖\",\"▘\",\"▝\",\"▗\"]},\"boxBounce2\":{\"interval\":100,\"frames\":[\"▌\",\"▀\",\"▐\",\"▄\"]},\"triangle\":{\"interval\":50,\"frames\":[\"◢\",\"◣\",\"◤\",\"◥\"]},\"arc\":{\"interval\":100,\"frames\":[\"◜\",\"◠\",\"◝\",\"◞\",\"◡\",\"◟\"]},\"circle\":{\"interval\":120,\"frames\":[\"◡\",\"⊙\",\"◠\"]},\"squareCorners\":{\"interval\":180,\"frames\":[\"◰\",\"◳\",\"◲\",\"◱\"]},\"circleQuarters\":{\"interval\":120,\"frames\":[\"◴\",\"◷\",\"◶\",\"◵\"]},\"circleHalves\":{\"interval\":50,\"frames\":[\"◐\",\"◓\",\"◑\",\"◒\"]},\"squish\":{\"interval\":100,\"frames\":[\"╫\",\"╪\"]},\"toggle\":{\"interval\":250,\"frames\":[\"⊶\",\"⊷\"]},\"toggle2\":{\"interval\":80,\"frames\":[\"▫\",\"▪\"]},\"toggle3\":{\"interval\":120,\"frames\":[\"□\",\"■\"]},\"toggle4\":{\"interval\":100,\"frames\":[\"■\",\"□\",\"▪\",\"▫\"]},\"toggle5\":{\"interval\":100,\"frames\":[\"▮\",\"▯\"]},\"toggle6\":{\"interval\":300,\"frames\":[\"ဝ\",\"၀\"]},\"toggle7\":{\"interval\":80,\"frames\":[\"⦾\",\"⦿\"]},\"toggle8\":{\"interval\":100,\"frames\":[\"◍\",\"◌\"]},\"toggle9\":{\"interval\":100,\"frames\":[\"◉\",\"◎\"]},\"toggle10\":{\"interval\":100,\"frames\":[\"㊂\",\"㊀\",\"㊁\"]},\"toggle11\":{\"interval\":50,\"frames\":[\"⧇\",\"⧆\"]},\"toggle12\":{\"interval\":120,\"frames\":[\"☗\",\"☖\"]},\"toggle13\":{\"interval\":80,\"frames\":[\"=\",\"*\",\"-\"]},\"arrow\":{\"interval\":100,\"frames\":[\"←\",\"↖\",\"↑\",\"↗\",\"→\",\"↘\",\"↓\",\"↙\"]},\"arrow2\":{\"interval\":80,\"frames\":[\"⬆️ \",\"↗️ \",\"➡️ \",\"↘️ \",\"⬇️ \",\"↙️ \",\"⬅️ \",\"↖️ \"]},\"arrow3\":{\"interval\":120,\"frames\":[\"▹▹▹▹▹\",\"▸▹▹▹▹\",\"▹▸▹▹▹\",\"▹▹▸▹▹\",\"▹▹▹▸▹\",\"▹▹▹▹▸\"]},\"bouncingBar\":{\"interval\":80,\"frames\":[\"[ ]\",\"[= ]\",\"[== ]\",\"[=== ]\",\"[ ===]\",\"[ ==]\",\"[ =]\",\"[ ]\",\"[ =]\",\"[ ==]\",\"[ ===]\",\"[====]\",\"[=== ]\",\"[== ]\",\"[= ]\"]},\"bouncingBall\":{\"interval\":80,\"frames\":[\"( ● )\",\"( ● )\",\"( ● )\",\"( ● )\",\"( ●)\",\"( ● )\",\"( ● )\",\"( ● )\",\"( ● )\",\"(● )\"]},\"smiley\":{\"interval\":200,\"frames\":[\"😄 \",\"😝 \"]},\"monkey\":{\"interval\":300,\"frames\":[\"🙈 \",\"🙈 \",\"🙉 \",\"🙊 \"]},\"hearts\":{\"interval\":100,\"frames\":[\"💛 \",\"💙 \",\"💜 \",\"💚 \",\"❤️ \"]},\"clock\":{\"interval\":100,\"frames\":[\"🕐 \",\"🕑 \",\"🕒 \",\"🕓 \",\"🕔 \",\"🕕 \",\"🕖 \",\"🕗 \",\"🕘 \",\"🕙 \",\"🕚 \"]},\"earth\":{\"interval\":180,\"frames\":[\"🌍 \",\"🌎 \",\"🌏 \"]},\"moon\":{\"interval\":80,\"frames\":[\"🌑 \",\"🌒 \",\"🌓 \",\"🌔 \",\"🌕 \",\"🌖 \",\"🌗 \",\"🌘 \"]},\"runner\":{\"interval\":140,\"frames\":[\"🚶 \",\"🏃 \"]},\"pong\":{\"interval\":80,\"frames\":[\"▐⠂ ▌\",\"▐⠈ ▌\",\"▐ ⠂ ▌\",\"▐ ⠠ ▌\",\"▐ ⡀ ▌\",\"▐ ⠠ ▌\",\"▐ ⠂ ▌\",\"▐ ⠈ ▌\",\"▐ ⠂ ▌\",\"▐ ⠠ ▌\",\"▐ ⡀ ▌\",\"▐ ⠠ ▌\",\"▐ ⠂ ▌\",\"▐ ⠈ ▌\",\"▐ ⠂▌\",\"▐ ⠠▌\",\"▐ ⡀▌\",\"▐ ⠠ ▌\",\"▐ ⠂ ▌\",\"▐ ⠈ ▌\",\"▐ ⠂ ▌\",\"▐ ⠠ ▌\",\"▐ ⡀ ▌\",\"▐ ⠠ ▌\",\"▐ ⠂ ▌\",\"▐ ⠈ ▌\",\"▐ ⠂ ▌\",\"▐ ⠠ ▌\",\"▐ ⡀ ▌\",\"▐⠠ ▌\"]},\"shark\":{\"interval\":120,\"frames\":[\"▐|\\\\____________▌\",\"▐_|\\\\___________▌\",\"▐__|\\\\__________▌\",\"▐___|\\\\_________▌\",\"▐____|\\\\________▌\",\"▐_____|\\\\_______▌\",\"▐______|\\\\______▌\",\"▐_______|\\\\_____▌\",\"▐________|\\\\____▌\",\"▐_________|\\\\___▌\",\"▐__________|\\\\__▌\",\"▐___________|\\\\_▌\",\"▐____________|\\\\▌\",\"▐____________/|▌\",\"▐___________/|_▌\",\"▐__________/|__▌\",\"▐_________/|___▌\",\"▐________/|____▌\",\"▐_______/|_____▌\",\"▐______/|______▌\",\"▐_____/|_______▌\",\"▐____/|________▌\",\"▐___/|_________▌\",\"▐__/|__________▌\",\"▐_/|___________▌\",\"▐/|____________▌\"]},\"dqpb\":{\"interval\":100,\"frames\":[\"d\",\"q\",\"p\",\"b\"]},\"weather\":{\"interval\":100,\"frames\":[\"☀️ \",\"☀️ \",\"☀️ \",\"🌤 \",\"⛅️ \",\"🌥 \",\"☁️ \",\"🌧 \",\"🌨 \",\"🌧 \",\"🌨 \",\"🌧 \",\"🌨 \",\"⛈ \",\"🌨 \",\"🌧 \",\"🌨 \",\"☁️ \",\"🌥 \",\"⛅️ \",\"🌤 \",\"☀️ \",\"☀️ \"]},\"christmas\":{\"interval\":400,\"frames\":[\"🌲\",\"🎄\"]}}"); +module.exports = JSON.parse("{\"dots\":{\"interval\":80,\"frames\":[\"⠋\",\"⠙\",\"⠹\",\"⠸\",\"⠼\",\"⠴\",\"⠦\",\"⠧\",\"⠇\",\"⠏\"]},\"dots2\":{\"interval\":80,\"frames\":[\"⣾\",\"⣽\",\"⣻\",\"⢿\",\"⡿\",\"⣟\",\"⣯\",\"⣷\"]},\"dots3\":{\"interval\":80,\"frames\":[\"⠋\",\"⠙\",\"⠚\",\"⠞\",\"⠖\",\"⠦\",\"⠴\",\"⠲\",\"⠳\",\"⠓\"]},\"dots4\":{\"interval\":80,\"frames\":[\"⠄\",\"⠆\",\"⠇\",\"⠋\",\"⠙\",\"⠸\",\"⠰\",\"⠠\",\"⠰\",\"⠸\",\"⠙\",\"⠋\",\"⠇\",\"⠆\"]},\"dots5\":{\"interval\":80,\"frames\":[\"⠋\",\"⠙\",\"⠚\",\"⠒\",\"⠂\",\"⠂\",\"⠒\",\"⠲\",\"⠴\",\"⠦\",\"⠖\",\"⠒\",\"⠐\",\"⠐\",\"⠒\",\"⠓\",\"⠋\"]},\"dots6\":{\"interval\":80,\"frames\":[\"⠁\",\"⠉\",\"⠙\",\"⠚\",\"⠒\",\"⠂\",\"⠂\",\"⠒\",\"⠲\",\"⠴\",\"⠤\",\"⠄\",\"⠄\",\"⠤\",\"⠴\",\"⠲\",\"⠒\",\"⠂\",\"⠂\",\"⠒\",\"⠚\",\"⠙\",\"⠉\",\"⠁\"]},\"dots7\":{\"interval\":80,\"frames\":[\"⠈\",\"⠉\",\"⠋\",\"⠓\",\"⠒\",\"⠐\",\"⠐\",\"⠒\",\"⠖\",\"⠦\",\"⠤\",\"⠠\",\"⠠\",\"⠤\",\"⠦\",\"⠖\",\"⠒\",\"⠐\",\"⠐\",\"⠒\",\"⠓\",\"⠋\",\"⠉\",\"⠈\"]},\"dots8\":{\"interval\":80,\"frames\":[\"⠁\",\"⠁\",\"⠉\",\"⠙\",\"⠚\",\"⠒\",\"⠂\",\"⠂\",\"⠒\",\"⠲\",\"⠴\",\"⠤\",\"⠄\",\"⠄\",\"⠤\",\"⠠\",\"⠠\",\"⠤\",\"⠦\",\"⠖\",\"⠒\",\"⠐\",\"⠐\",\"⠒\",\"⠓\",\"⠋\",\"⠉\",\"⠈\",\"⠈\"]},\"dots9\":{\"interval\":80,\"frames\":[\"⢹\",\"⢺\",\"⢼\",\"⣸\",\"⣇\",\"⡧\",\"⡗\",\"⡏\"]},\"dots10\":{\"interval\":80,\"frames\":[\"⢄\",\"⢂\",\"⢁\",\"⡁\",\"⡈\",\"⡐\",\"⡠\"]},\"dots11\":{\"interval\":100,\"frames\":[\"⠁\",\"⠂\",\"⠄\",\"⡀\",\"⢀\",\"⠠\",\"⠐\",\"⠈\"]},\"dots12\":{\"interval\":80,\"frames\":[\"⢀⠀\",\"⡀⠀\",\"⠄⠀\",\"⢂⠀\",\"⡂⠀\",\"⠅⠀\",\"⢃⠀\",\"⡃⠀\",\"⠍⠀\",\"⢋⠀\",\"⡋⠀\",\"⠍⠁\",\"⢋⠁\",\"⡋⠁\",\"⠍⠉\",\"⠋⠉\",\"⠋⠉\",\"⠉⠙\",\"⠉⠙\",\"⠉⠩\",\"⠈⢙\",\"⠈⡙\",\"⢈⠩\",\"⡀⢙\",\"⠄⡙\",\"⢂⠩\",\"⡂⢘\",\"⠅⡘\",\"⢃⠨\",\"⡃⢐\",\"⠍⡐\",\"⢋⠠\",\"⡋⢀\",\"⠍⡁\",\"⢋⠁\",\"⡋⠁\",\"⠍⠉\",\"⠋⠉\",\"⠋⠉\",\"⠉⠙\",\"⠉⠙\",\"⠉⠩\",\"⠈⢙\",\"⠈⡙\",\"⠈⠩\",\"⠀⢙\",\"⠀⡙\",\"⠀⠩\",\"⠀⢘\",\"⠀⡘\",\"⠀⠨\",\"⠀⢐\",\"⠀⡐\",\"⠀⠠\",\"⠀⢀\",\"⠀⡀\"]},\"dots8Bit\":{\"interval\":80,\"frames\":[\"⠀\",\"⠁\",\"⠂\",\"⠃\",\"⠄\",\"⠅\",\"⠆\",\"⠇\",\"⡀\",\"⡁\",\"⡂\",\"⡃\",\"⡄\",\"⡅\",\"⡆\",\"⡇\",\"⠈\",\"⠉\",\"⠊\",\"⠋\",\"⠌\",\"⠍\",\"⠎\",\"⠏\",\"⡈\",\"⡉\",\"⡊\",\"⡋\",\"⡌\",\"⡍\",\"⡎\",\"⡏\",\"⠐\",\"⠑\",\"⠒\",\"⠓\",\"⠔\",\"⠕\",\"⠖\",\"⠗\",\"⡐\",\"⡑\",\"⡒\",\"⡓\",\"⡔\",\"⡕\",\"⡖\",\"⡗\",\"⠘\",\"⠙\",\"⠚\",\"⠛\",\"⠜\",\"⠝\",\"⠞\",\"⠟\",\"⡘\",\"⡙\",\"⡚\",\"⡛\",\"⡜\",\"⡝\",\"⡞\",\"⡟\",\"⠠\",\"⠡\",\"⠢\",\"⠣\",\"⠤\",\"⠥\",\"⠦\",\"⠧\",\"⡠\",\"⡡\",\"⡢\",\"⡣\",\"⡤\",\"⡥\",\"⡦\",\"⡧\",\"⠨\",\"⠩\",\"⠪\",\"⠫\",\"⠬\",\"⠭\",\"⠮\",\"⠯\",\"⡨\",\"⡩\",\"⡪\",\"⡫\",\"⡬\",\"⡭\",\"⡮\",\"⡯\",\"⠰\",\"⠱\",\"⠲\",\"⠳\",\"⠴\",\"⠵\",\"⠶\",\"⠷\",\"⡰\",\"⡱\",\"⡲\",\"⡳\",\"⡴\",\"⡵\",\"⡶\",\"⡷\",\"⠸\",\"⠹\",\"⠺\",\"⠻\",\"⠼\",\"⠽\",\"⠾\",\"⠿\",\"⡸\",\"⡹\",\"⡺\",\"⡻\",\"⡼\",\"⡽\",\"⡾\",\"⡿\",\"⢀\",\"⢁\",\"⢂\",\"⢃\",\"⢄\",\"⢅\",\"⢆\",\"⢇\",\"⣀\",\"⣁\",\"⣂\",\"⣃\",\"⣄\",\"⣅\",\"⣆\",\"⣇\",\"⢈\",\"⢉\",\"⢊\",\"⢋\",\"⢌\",\"⢍\",\"⢎\",\"⢏\",\"⣈\",\"⣉\",\"⣊\",\"⣋\",\"⣌\",\"⣍\",\"⣎\",\"⣏\",\"⢐\",\"⢑\",\"⢒\",\"⢓\",\"⢔\",\"⢕\",\"⢖\",\"⢗\",\"⣐\",\"⣑\",\"⣒\",\"⣓\",\"⣔\",\"⣕\",\"⣖\",\"⣗\",\"⢘\",\"⢙\",\"⢚\",\"⢛\",\"⢜\",\"⢝\",\"⢞\",\"⢟\",\"⣘\",\"⣙\",\"⣚\",\"⣛\",\"⣜\",\"⣝\",\"⣞\",\"⣟\",\"⢠\",\"⢡\",\"⢢\",\"⢣\",\"⢤\",\"⢥\",\"⢦\",\"⢧\",\"⣠\",\"⣡\",\"⣢\",\"⣣\",\"⣤\",\"⣥\",\"⣦\",\"⣧\",\"⢨\",\"⢩\",\"⢪\",\"⢫\",\"⢬\",\"⢭\",\"⢮\",\"⢯\",\"⣨\",\"⣩\",\"⣪\",\"⣫\",\"⣬\",\"⣭\",\"⣮\",\"⣯\",\"⢰\",\"⢱\",\"⢲\",\"⢳\",\"⢴\",\"⢵\",\"⢶\",\"⢷\",\"⣰\",\"⣱\",\"⣲\",\"⣳\",\"⣴\",\"⣵\",\"⣶\",\"⣷\",\"⢸\",\"⢹\",\"⢺\",\"⢻\",\"⢼\",\"⢽\",\"⢾\",\"⢿\",\"⣸\",\"⣹\",\"⣺\",\"⣻\",\"⣼\",\"⣽\",\"⣾\",\"⣿\"]},\"line\":{\"interval\":130,\"frames\":[\"-\",\"\\\\\",\"|\",\"/\"]},\"line2\":{\"interval\":100,\"frames\":[\"⠂\",\"-\",\"–\",\"—\",\"–\",\"-\"]},\"pipe\":{\"interval\":100,\"frames\":[\"┤\",\"┘\",\"┴\",\"└\",\"├\",\"┌\",\"┬\",\"┐\"]},\"simpleDots\":{\"interval\":400,\"frames\":[\". \",\".. \",\"...\",\" \"]},\"simpleDotsScrolling\":{\"interval\":200,\"frames\":[\". \",\".. \",\"...\",\" ..\",\" .\",\" \"]},\"star\":{\"interval\":70,\"frames\":[\"✶\",\"✸\",\"✹\",\"✺\",\"✹\",\"✷\"]},\"star2\":{\"interval\":80,\"frames\":[\"+\",\"x\",\"*\"]},\"flip\":{\"interval\":70,\"frames\":[\"_\",\"_\",\"_\",\"-\",\"`\",\"`\",\"'\",\"´\",\"-\",\"_\",\"_\",\"_\"]},\"hamburger\":{\"interval\":100,\"frames\":[\"☱\",\"☲\",\"☴\"]},\"growVertical\":{\"interval\":120,\"frames\":[\"▁\",\"▃\",\"▄\",\"▅\",\"▆\",\"▇\",\"▆\",\"▅\",\"▄\",\"▃\"]},\"growHorizontal\":{\"interval\":120,\"frames\":[\"▏\",\"▎\",\"▍\",\"▌\",\"▋\",\"▊\",\"▉\",\"▊\",\"▋\",\"▌\",\"▍\",\"▎\"]},\"balloon\":{\"interval\":140,\"frames\":[\" \",\".\",\"o\",\"O\",\"@\",\"*\",\" \"]},\"balloon2\":{\"interval\":120,\"frames\":[\".\",\"o\",\"O\",\"°\",\"O\",\"o\",\".\"]},\"noise\":{\"interval\":100,\"frames\":[\"▓\",\"▒\",\"░\"]},\"bounce\":{\"interval\":120,\"frames\":[\"⠁\",\"⠂\",\"⠄\",\"⠂\"]},\"boxBounce\":{\"interval\":120,\"frames\":[\"▖\",\"▘\",\"▝\",\"▗\"]},\"boxBounce2\":{\"interval\":100,\"frames\":[\"▌\",\"▀\",\"▐\",\"▄\"]},\"triangle\":{\"interval\":50,\"frames\":[\"◢\",\"◣\",\"◤\",\"◥\"]},\"arc\":{\"interval\":100,\"frames\":[\"◜\",\"◠\",\"◝\",\"◞\",\"◡\",\"◟\"]},\"circle\":{\"interval\":120,\"frames\":[\"◡\",\"⊙\",\"◠\"]},\"squareCorners\":{\"interval\":180,\"frames\":[\"◰\",\"◳\",\"◲\",\"◱\"]},\"circleQuarters\":{\"interval\":120,\"frames\":[\"◴\",\"◷\",\"◶\",\"◵\"]},\"circleHalves\":{\"interval\":50,\"frames\":[\"◐\",\"◓\",\"◑\",\"◒\"]},\"squish\":{\"interval\":100,\"frames\":[\"╫\",\"╪\"]},\"toggle\":{\"interval\":250,\"frames\":[\"⊶\",\"⊷\"]},\"toggle2\":{\"interval\":80,\"frames\":[\"▫\",\"▪\"]},\"toggle3\":{\"interval\":120,\"frames\":[\"□\",\"■\"]},\"toggle4\":{\"interval\":100,\"frames\":[\"■\",\"□\",\"▪\",\"▫\"]},\"toggle5\":{\"interval\":100,\"frames\":[\"▮\",\"▯\"]},\"toggle6\":{\"interval\":300,\"frames\":[\"ဝ\",\"၀\"]},\"toggle7\":{\"interval\":80,\"frames\":[\"⦾\",\"⦿\"]},\"toggle8\":{\"interval\":100,\"frames\":[\"◍\",\"◌\"]},\"toggle9\":{\"interval\":100,\"frames\":[\"◉\",\"◎\"]},\"toggle10\":{\"interval\":100,\"frames\":[\"㊂\",\"㊀\",\"㊁\"]},\"toggle11\":{\"interval\":50,\"frames\":[\"⧇\",\"⧆\"]},\"toggle12\":{\"interval\":120,\"frames\":[\"☗\",\"☖\"]},\"toggle13\":{\"interval\":80,\"frames\":[\"=\",\"*\",\"-\"]},\"arrow\":{\"interval\":100,\"frames\":[\"←\",\"↖\",\"↑\",\"↗\",\"→\",\"↘\",\"↓\",\"↙\"]},\"arrow2\":{\"interval\":80,\"frames\":[\"⬆️ \",\"↗️ \",\"➡️ \",\"↘️ \",\"⬇️ \",\"↙️ \",\"⬅️ \",\"↖️ \"]},\"arrow3\":{\"interval\":120,\"frames\":[\"▹▹▹▹▹\",\"▸▹▹▹▹\",\"▹▸▹▹▹\",\"▹▹▸▹▹\",\"▹▹▹▸▹\",\"▹▹▹▹▸\"]},\"bouncingBar\":{\"interval\":80,\"frames\":[\"[ ]\",\"[= ]\",\"[== ]\",\"[=== ]\",\"[ ===]\",\"[ ==]\",\"[ =]\",\"[ ]\",\"[ =]\",\"[ ==]\",\"[ ===]\",\"[====]\",\"[=== ]\",\"[== ]\",\"[= ]\"]},\"bouncingBall\":{\"interval\":80,\"frames\":[\"( ● )\",\"( ● )\",\"( ● )\",\"( ● )\",\"( ●)\",\"( ● )\",\"( ● )\",\"( ● )\",\"( ● )\",\"(● )\"]},\"smiley\":{\"interval\":200,\"frames\":[\"😄 \",\"😝 \"]},\"monkey\":{\"interval\":300,\"frames\":[\"🙈 \",\"🙈 \",\"🙉 \",\"🙊 \"]},\"hearts\":{\"interval\":100,\"frames\":[\"💛 \",\"💙 \",\"💜 \",\"💚 \",\"❤️ \"]},\"clock\":{\"interval\":100,\"frames\":[\"🕛 \",\"🕐 \",\"🕑 \",\"🕒 \",\"🕓 \",\"🕔 \",\"🕕 \",\"🕖 \",\"🕗 \",\"🕘 \",\"🕙 \",\"🕚 \"]},\"earth\":{\"interval\":180,\"frames\":[\"🌍 \",\"🌎 \",\"🌏 \"]},\"material\":{\"interval\":17,\"frames\":[\"█▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁\",\"██▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁\",\"███▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁\",\"████▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁\",\"██████▁▁▁▁▁▁▁▁▁▁▁▁▁▁\",\"██████▁▁▁▁▁▁▁▁▁▁▁▁▁▁\",\"███████▁▁▁▁▁▁▁▁▁▁▁▁▁\",\"████████▁▁▁▁▁▁▁▁▁▁▁▁\",\"█████████▁▁▁▁▁▁▁▁▁▁▁\",\"█████████▁▁▁▁▁▁▁▁▁▁▁\",\"██████████▁▁▁▁▁▁▁▁▁▁\",\"███████████▁▁▁▁▁▁▁▁▁\",\"█████████████▁▁▁▁▁▁▁\",\"██████████████▁▁▁▁▁▁\",\"██████████████▁▁▁▁▁▁\",\"▁██████████████▁▁▁▁▁\",\"▁██████████████▁▁▁▁▁\",\"▁██████████████▁▁▁▁▁\",\"▁▁██████████████▁▁▁▁\",\"▁▁▁██████████████▁▁▁\",\"▁▁▁▁█████████████▁▁▁\",\"▁▁▁▁██████████████▁▁\",\"▁▁▁▁██████████████▁▁\",\"▁▁▁▁▁██████████████▁\",\"▁▁▁▁▁██████████████▁\",\"▁▁▁▁▁██████████████▁\",\"▁▁▁▁▁▁██████████████\",\"▁▁▁▁▁▁██████████████\",\"▁▁▁▁▁▁▁█████████████\",\"▁▁▁▁▁▁▁█████████████\",\"▁▁▁▁▁▁▁▁████████████\",\"▁▁▁▁▁▁▁▁████████████\",\"▁▁▁▁▁▁▁▁▁███████████\",\"▁▁▁▁▁▁▁▁▁███████████\",\"▁▁▁▁▁▁▁▁▁▁██████████\",\"▁▁▁▁▁▁▁▁▁▁██████████\",\"▁▁▁▁▁▁▁▁▁▁▁▁████████\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁███████\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁██████\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█████\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█████\",\"█▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁████\",\"██▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁███\",\"██▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁███\",\"███▁▁▁▁▁▁▁▁▁▁▁▁▁▁███\",\"████▁▁▁▁▁▁▁▁▁▁▁▁▁▁██\",\"█████▁▁▁▁▁▁▁▁▁▁▁▁▁▁█\",\"█████▁▁▁▁▁▁▁▁▁▁▁▁▁▁█\",\"██████▁▁▁▁▁▁▁▁▁▁▁▁▁█\",\"████████▁▁▁▁▁▁▁▁▁▁▁▁\",\"█████████▁▁▁▁▁▁▁▁▁▁▁\",\"█████████▁▁▁▁▁▁▁▁▁▁▁\",\"█████████▁▁▁▁▁▁▁▁▁▁▁\",\"█████████▁▁▁▁▁▁▁▁▁▁▁\",\"███████████▁▁▁▁▁▁▁▁▁\",\"████████████▁▁▁▁▁▁▁▁\",\"████████████▁▁▁▁▁▁▁▁\",\"██████████████▁▁▁▁▁▁\",\"██████████████▁▁▁▁▁▁\",\"▁██████████████▁▁▁▁▁\",\"▁██████████████▁▁▁▁▁\",\"▁▁▁█████████████▁▁▁▁\",\"▁▁▁▁▁████████████▁▁▁\",\"▁▁▁▁▁████████████▁▁▁\",\"▁▁▁▁▁▁███████████▁▁▁\",\"▁▁▁▁▁▁▁▁█████████▁▁▁\",\"▁▁▁▁▁▁▁▁█████████▁▁▁\",\"▁▁▁▁▁▁▁▁▁█████████▁▁\",\"▁▁▁▁▁▁▁▁▁█████████▁▁\",\"▁▁▁▁▁▁▁▁▁▁█████████▁\",\"▁▁▁▁▁▁▁▁▁▁▁████████▁\",\"▁▁▁▁▁▁▁▁▁▁▁████████▁\",\"▁▁▁▁▁▁▁▁▁▁▁▁███████▁\",\"▁▁▁▁▁▁▁▁▁▁▁▁███████▁\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁███████\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁███████\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█████\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁████\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁████\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁████\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁███\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁███\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁██\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁██\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁██\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁\"]},\"moon\":{\"interval\":80,\"frames\":[\"🌑 \",\"🌒 \",\"🌓 \",\"🌔 \",\"🌕 \",\"🌖 \",\"🌗 \",\"🌘 \"]},\"runner\":{\"interval\":140,\"frames\":[\"🚶 \",\"🏃 \"]},\"pong\":{\"interval\":80,\"frames\":[\"▐⠂ ▌\",\"▐⠈ ▌\",\"▐ ⠂ ▌\",\"▐ ⠠ ▌\",\"▐ ⡀ ▌\",\"▐ ⠠ ▌\",\"▐ ⠂ ▌\",\"▐ ⠈ ▌\",\"▐ ⠂ ▌\",\"▐ ⠠ ▌\",\"▐ ⡀ ▌\",\"▐ ⠠ ▌\",\"▐ ⠂ ▌\",\"▐ ⠈ ▌\",\"▐ ⠂▌\",\"▐ ⠠▌\",\"▐ ⡀▌\",\"▐ ⠠ ▌\",\"▐ ⠂ ▌\",\"▐ ⠈ ▌\",\"▐ ⠂ ▌\",\"▐ ⠠ ▌\",\"▐ ⡀ ▌\",\"▐ ⠠ ▌\",\"▐ ⠂ ▌\",\"▐ ⠈ ▌\",\"▐ ⠂ ▌\",\"▐ ⠠ ▌\",\"▐ ⡀ ▌\",\"▐⠠ ▌\"]},\"shark\":{\"interval\":120,\"frames\":[\"▐|\\\\____________▌\",\"▐_|\\\\___________▌\",\"▐__|\\\\__________▌\",\"▐___|\\\\_________▌\",\"▐____|\\\\________▌\",\"▐_____|\\\\_______▌\",\"▐______|\\\\______▌\",\"▐_______|\\\\_____▌\",\"▐________|\\\\____▌\",\"▐_________|\\\\___▌\",\"▐__________|\\\\__▌\",\"▐___________|\\\\_▌\",\"▐____________|\\\\▌\",\"▐____________/|▌\",\"▐___________/|_▌\",\"▐__________/|__▌\",\"▐_________/|___▌\",\"▐________/|____▌\",\"▐_______/|_____▌\",\"▐______/|______▌\",\"▐_____/|_______▌\",\"▐____/|________▌\",\"▐___/|_________▌\",\"▐__/|__________▌\",\"▐_/|___________▌\",\"▐/|____________▌\"]},\"dqpb\":{\"interval\":100,\"frames\":[\"d\",\"q\",\"p\",\"b\"]},\"weather\":{\"interval\":100,\"frames\":[\"☀️ \",\"☀️ \",\"☀️ \",\"🌤 \",\"⛅️ \",\"🌥 \",\"☁️ \",\"🌧 \",\"🌨 \",\"🌧 \",\"🌨 \",\"🌧 \",\"🌨 \",\"⛈ \",\"🌨 \",\"🌧 \",\"🌨 \",\"☁️ \",\"🌥 \",\"⛅️ \",\"🌤 \",\"☀️ \",\"☀️ \"]},\"christmas\":{\"interval\":400,\"frames\":[\"🌲\",\"🎄\"]},\"grenade\":{\"interval\":80,\"frames\":[\"، \",\"′ \",\" ´ \",\" ‾ \",\" ⸌\",\" ⸊\",\" |\",\" ⁎\",\" ⁕\",\" ෴ \",\" ⁓\",\" \",\" \",\" \"]},\"point\":{\"interval\":125,\"frames\":[\"∙∙∙\",\"●∙∙\",\"∙●∙\",\"∙∙●\",\"∙∙∙\"]},\"layer\":{\"interval\":150,\"frames\":[\"-\",\"=\",\"≡\"]},\"betaWave\":{\"interval\":80,\"frames\":[\"ρββββββ\",\"βρβββββ\",\"ββρββββ\",\"βββρβββ\",\"ββββρββ\",\"βββββρβ\",\"ββββββρ\"]}}"); /***/ }), -/* 384 */ +/* 378 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const chalk = __webpack_require__(385); +const chalk = __webpack_require__(379); const isSupported = process.platform !== 'win32' || process.env.CI || process.env.TERM === 'xterm-256color'; @@ -48097,16 +47623,16 @@ module.exports = isSupported ? main : fallbacks; /***/ }), -/* 385 */ +/* 379 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const escapeStringRegexp = __webpack_require__(178); -const ansiStyles = __webpack_require__(386); -const stdoutColor = __webpack_require__(184).stdout; +const ansiStyles = __webpack_require__(380); +const stdoutColor = __webpack_require__(381).stdout; -const template = __webpack_require__(387); +const template = __webpack_require__(383); const isSimpleWindowsTerm = process.platform === 'win32' && !(process.env.TERM || '').toLowerCase().startsWith('xterm'); @@ -48332,7 +47858,7 @@ module.exports.default = module.exports; // For TypeScript /***/ }), -/* 386 */ +/* 380 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -48505,7 +48031,160 @@ Object.defineProperty(module, 'exports', { /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(114)(module))) /***/ }), -/* 387 */ +/* 381 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +const os = __webpack_require__(120); +const hasFlag = __webpack_require__(382); + +const env = process.env; + +let forceColor; +if (hasFlag('no-color') || + hasFlag('no-colors') || + hasFlag('color=false')) { + forceColor = false; +} else if (hasFlag('color') || + hasFlag('colors') || + hasFlag('color=true') || + hasFlag('color=always')) { + forceColor = true; +} +if ('FORCE_COLOR' in env) { + forceColor = env.FORCE_COLOR.length === 0 || parseInt(env.FORCE_COLOR, 10) !== 0; +} + +function translateLevel(level) { + if (level === 0) { + return false; + } + + return { + level, + hasBasic: true, + has256: level >= 2, + has16m: level >= 3 + }; +} + +function supportsColor(stream) { + if (forceColor === false) { + return 0; + } + + if (hasFlag('color=16m') || + hasFlag('color=full') || + hasFlag('color=truecolor')) { + return 3; + } + + if (hasFlag('color=256')) { + return 2; + } + + if (stream && !stream.isTTY && forceColor !== true) { + return 0; + } + + const min = forceColor ? 1 : 0; + + if (process.platform === 'win32') { + // Node.js 7.5.0 is the first version of Node.js to include a patch to + // libuv that enables 256 color output on Windows. Anything earlier and it + // won't work. However, here we target Node.js 8 at minimum as it is an LTS + // release, and Node.js 7 is not. Windows 10 build 10586 is the first Windows + // release that supports 256 colors. Windows 10 build 14931 is the first release + // that supports 16m/TrueColor. + const osRelease = os.release().split('.'); + if ( + Number(process.versions.node.split('.')[0]) >= 8 && + Number(osRelease[0]) >= 10 && + Number(osRelease[2]) >= 10586 + ) { + return Number(osRelease[2]) >= 14931 ? 3 : 2; + } + + return 1; + } + + if ('CI' in env) { + if (['TRAVIS', 'CIRCLECI', 'APPVEYOR', 'GITLAB_CI'].some(sign => sign in env) || env.CI_NAME === 'codeship') { + return 1; + } + + return min; + } + + if ('TEAMCITY_VERSION' in env) { + return /^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env.TEAMCITY_VERSION) ? 1 : 0; + } + + if (env.COLORTERM === 'truecolor') { + return 3; + } + + if ('TERM_PROGRAM' in env) { + const version = parseInt((env.TERM_PROGRAM_VERSION || '').split('.')[0], 10); + + switch (env.TERM_PROGRAM) { + case 'iTerm.app': + return version >= 3 ? 3 : 2; + case 'Apple_Terminal': + return 2; + // No default + } + } + + if (/-256(color)?$/i.test(env.TERM)) { + return 2; + } + + if (/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(env.TERM)) { + return 1; + } + + if ('COLORTERM' in env) { + return 1; + } + + if (env.TERM === 'dumb') { + return min; + } + + return min; +} + +function getSupportLevel(stream) { + const level = supportsColor(stream); + return translateLevel(level); +} + +module.exports = { + supportsColor: getSupportLevel, + stdout: getSupportLevel(process.stdout), + stderr: getSupportLevel(process.stderr) +}; + + +/***/ }), +/* 382 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +module.exports = (flag, argv) => { + argv = argv || process.argv; + const prefix = flag.startsWith('-') ? '' : (flag.length === 1 ? '-' : '--'); + const pos = argv.indexOf(prefix + flag); + const terminatorPos = argv.indexOf('--'); + return pos !== -1 && (terminatorPos === -1 ? true : pos < terminatorPos); +}; + + +/***/ }), +/* 383 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -48639,8 +48318,555 @@ module.exports = (chalk, tmp) => { }; +/***/ }), +/* 384 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +const ansiRegex = __webpack_require__(385); + +module.exports = string => typeof string === 'string' ? string.replace(ansiRegex(), '') : string; + + +/***/ }), +/* 385 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +module.exports = ({onlyFirst = false} = {}) => { + const pattern = [ + '[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)', + '(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))' + ].join('|'); + + return new RegExp(pattern, onlyFirst ? undefined : 'g'); +}; + + +/***/ }), +/* 386 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var defaults = __webpack_require__(387) +var combining = __webpack_require__(389) + +var DEFAULTS = { + nul: 0, + control: 0 +} + +module.exports = function wcwidth(str) { + return wcswidth(str, DEFAULTS) +} + +module.exports.config = function(opts) { + opts = defaults(opts || {}, DEFAULTS) + return function wcwidth(str) { + return wcswidth(str, opts) + } +} + +/* + * The following functions define the column width of an ISO 10646 + * character as follows: + * - The null character (U+0000) has a column width of 0. + * - Other C0/C1 control characters and DEL will lead to a return value + * of -1. + * - Non-spacing and enclosing combining characters (general category + * code Mn or Me in the + * Unicode database) have a column width of 0. + * - SOFT HYPHEN (U+00AD) has a column width of 1. + * - Other format characters (general category code Cf in the Unicode + * database) and ZERO WIDTH + * SPACE (U+200B) have a column width of 0. + * - Hangul Jamo medial vowels and final consonants (U+1160-U+11FF) + * have a column width of 0. + * - Spacing characters in the East Asian Wide (W) or East Asian + * Full-width (F) category as + * defined in Unicode Technical Report #11 have a column width of 2. + * - All remaining characters (including all printable ISO 8859-1 and + * WGL4 characters, Unicode control characters, etc.) have a column + * width of 1. + * This implementation assumes that characters are encoded in ISO 10646. +*/ + +function wcswidth(str, opts) { + if (typeof str !== 'string') return wcwidth(str, opts) + + var s = 0 + for (var i = 0; i < str.length; i++) { + var n = wcwidth(str.charCodeAt(i), opts) + if (n < 0) return -1 + s += n + } + + return s +} + +function wcwidth(ucs, opts) { + // test for 8-bit control characters + if (ucs === 0) return opts.nul + if (ucs < 32 || (ucs >= 0x7f && ucs < 0xa0)) return opts.control + + // binary search in table of non-spacing characters + if (bisearch(ucs)) return 0 + + // if we arrive here, ucs is not a combining or C0/C1 control character + return 1 + + (ucs >= 0x1100 && + (ucs <= 0x115f || // Hangul Jamo init. consonants + ucs == 0x2329 || ucs == 0x232a || + (ucs >= 0x2e80 && ucs <= 0xa4cf && + ucs != 0x303f) || // CJK ... Yi + (ucs >= 0xac00 && ucs <= 0xd7a3) || // Hangul Syllables + (ucs >= 0xf900 && ucs <= 0xfaff) || // CJK Compatibility Ideographs + (ucs >= 0xfe10 && ucs <= 0xfe19) || // Vertical forms + (ucs >= 0xfe30 && ucs <= 0xfe6f) || // CJK Compatibility Forms + (ucs >= 0xff00 && ucs <= 0xff60) || // Fullwidth Forms + (ucs >= 0xffe0 && ucs <= 0xffe6) || + (ucs >= 0x20000 && ucs <= 0x2fffd) || + (ucs >= 0x30000 && ucs <= 0x3fffd))); +} + +function bisearch(ucs) { + var min = 0 + var max = combining.length - 1 + var mid + + if (ucs < combining[0][0] || ucs > combining[max][1]) return false + + while (max >= min) { + mid = Math.floor((min + max) / 2) + if (ucs > combining[mid][1]) min = mid + 1 + else if (ucs < combining[mid][0]) max = mid - 1 + else return true + } + + return false +} + + +/***/ }), +/* 387 */ +/***/ (function(module, exports, __webpack_require__) { + +var clone = __webpack_require__(388); + +module.exports = function(options, defaults) { + options = options || {}; + + Object.keys(defaults).forEach(function(key) { + if (typeof options[key] === 'undefined') { + options[key] = clone(defaults[key]); + } + }); + + return options; +}; + /***/ }), /* 388 */ +/***/ (function(module, exports, __webpack_require__) { + +var clone = (function() { +'use strict'; + +/** + * Clones (copies) an Object using deep copying. + * + * This function supports circular references by default, but if you are certain + * there are no circular references in your object, you can save some CPU time + * by calling clone(obj, false). + * + * Caution: if `circular` is false and `parent` contains circular references, + * your program may enter an infinite loop and crash. + * + * @param `parent` - the object to be cloned + * @param `circular` - set to true if the object to be cloned may contain + * circular references. (optional - true by default) + * @param `depth` - set to a number if the object is only to be cloned to + * a particular depth. (optional - defaults to Infinity) + * @param `prototype` - sets the prototype to be used when cloning an object. + * (optional - defaults to parent prototype). +*/ +function clone(parent, circular, depth, prototype) { + var filter; + if (typeof circular === 'object') { + depth = circular.depth; + prototype = circular.prototype; + filter = circular.filter; + circular = circular.circular + } + // maintain two arrays for circular references, where corresponding parents + // and children have the same index + var allParents = []; + var allChildren = []; + + var useBuffer = typeof Buffer != 'undefined'; + + if (typeof circular == 'undefined') + circular = true; + + if (typeof depth == 'undefined') + depth = Infinity; + + // recurse this function so we don't reset allParents and allChildren + function _clone(parent, depth) { + // cloning null always returns null + if (parent === null) + return null; + + if (depth == 0) + return parent; + + var child; + var proto; + if (typeof parent != 'object') { + return parent; + } + + if (clone.__isArray(parent)) { + child = []; + } else if (clone.__isRegExp(parent)) { + child = new RegExp(parent.source, __getRegExpFlags(parent)); + if (parent.lastIndex) child.lastIndex = parent.lastIndex; + } else if (clone.__isDate(parent)) { + child = new Date(parent.getTime()); + } else if (useBuffer && Buffer.isBuffer(parent)) { + if (Buffer.allocUnsafe) { + // Node.js >= 4.5.0 + child = Buffer.allocUnsafe(parent.length); + } else { + // Older Node.js versions + child = new Buffer(parent.length); + } + parent.copy(child); + return child; + } else { + if (typeof prototype == 'undefined') { + proto = Object.getPrototypeOf(parent); + child = Object.create(proto); + } + else { + child = Object.create(prototype); + proto = prototype; + } + } + + if (circular) { + var index = allParents.indexOf(parent); + + if (index != -1) { + return allChildren[index]; + } + allParents.push(parent); + allChildren.push(child); + } + + for (var i in parent) { + var attrs; + if (proto) { + attrs = Object.getOwnPropertyDescriptor(proto, i); + } + + if (attrs && attrs.set == null) { + continue; + } + child[i] = _clone(parent[i], depth - 1); + } + + return child; + } + + return _clone(parent, depth); +} + +/** + * Simple flat clone using prototype, accepts only objects, usefull for property + * override on FLAT configuration object (no nested props). + * + * USE WITH CAUTION! This may not behave as you wish if you do not know how this + * works. + */ +clone.clonePrototype = function clonePrototype(parent) { + if (parent === null) + return null; + + var c = function () {}; + c.prototype = parent; + return new c(); +}; + +// private utility functions + +function __objToStr(o) { + return Object.prototype.toString.call(o); +}; +clone.__objToStr = __objToStr; + +function __isDate(o) { + return typeof o === 'object' && __objToStr(o) === '[object Date]'; +}; +clone.__isDate = __isDate; + +function __isArray(o) { + return typeof o === 'object' && __objToStr(o) === '[object Array]'; +}; +clone.__isArray = __isArray; + +function __isRegExp(o) { + return typeof o === 'object' && __objToStr(o) === '[object RegExp]'; +}; +clone.__isRegExp = __isRegExp; + +function __getRegExpFlags(re) { + var flags = ''; + if (re.global) flags += 'g'; + if (re.ignoreCase) flags += 'i'; + if (re.multiline) flags += 'm'; + return flags; +}; +clone.__getRegExpFlags = __getRegExpFlags; + +return clone; +})(); + +if ( true && module.exports) { + module.exports = clone; +} + + +/***/ }), +/* 389 */ +/***/ (function(module, exports) { + +module.exports = [ + [ 0x0300, 0x036F ], [ 0x0483, 0x0486 ], [ 0x0488, 0x0489 ], + [ 0x0591, 0x05BD ], [ 0x05BF, 0x05BF ], [ 0x05C1, 0x05C2 ], + [ 0x05C4, 0x05C5 ], [ 0x05C7, 0x05C7 ], [ 0x0600, 0x0603 ], + [ 0x0610, 0x0615 ], [ 0x064B, 0x065E ], [ 0x0670, 0x0670 ], + [ 0x06D6, 0x06E4 ], [ 0x06E7, 0x06E8 ], [ 0x06EA, 0x06ED ], + [ 0x070F, 0x070F ], [ 0x0711, 0x0711 ], [ 0x0730, 0x074A ], + [ 0x07A6, 0x07B0 ], [ 0x07EB, 0x07F3 ], [ 0x0901, 0x0902 ], + [ 0x093C, 0x093C ], [ 0x0941, 0x0948 ], [ 0x094D, 0x094D ], + [ 0x0951, 0x0954 ], [ 0x0962, 0x0963 ], [ 0x0981, 0x0981 ], + [ 0x09BC, 0x09BC ], [ 0x09C1, 0x09C4 ], [ 0x09CD, 0x09CD ], + [ 0x09E2, 0x09E3 ], [ 0x0A01, 0x0A02 ], [ 0x0A3C, 0x0A3C ], + [ 0x0A41, 0x0A42 ], [ 0x0A47, 0x0A48 ], [ 0x0A4B, 0x0A4D ], + [ 0x0A70, 0x0A71 ], [ 0x0A81, 0x0A82 ], [ 0x0ABC, 0x0ABC ], + [ 0x0AC1, 0x0AC5 ], [ 0x0AC7, 0x0AC8 ], [ 0x0ACD, 0x0ACD ], + [ 0x0AE2, 0x0AE3 ], [ 0x0B01, 0x0B01 ], [ 0x0B3C, 0x0B3C ], + [ 0x0B3F, 0x0B3F ], [ 0x0B41, 0x0B43 ], [ 0x0B4D, 0x0B4D ], + [ 0x0B56, 0x0B56 ], [ 0x0B82, 0x0B82 ], [ 0x0BC0, 0x0BC0 ], + [ 0x0BCD, 0x0BCD ], [ 0x0C3E, 0x0C40 ], [ 0x0C46, 0x0C48 ], + [ 0x0C4A, 0x0C4D ], [ 0x0C55, 0x0C56 ], [ 0x0CBC, 0x0CBC ], + [ 0x0CBF, 0x0CBF ], [ 0x0CC6, 0x0CC6 ], [ 0x0CCC, 0x0CCD ], + [ 0x0CE2, 0x0CE3 ], [ 0x0D41, 0x0D43 ], [ 0x0D4D, 0x0D4D ], + [ 0x0DCA, 0x0DCA ], [ 0x0DD2, 0x0DD4 ], [ 0x0DD6, 0x0DD6 ], + [ 0x0E31, 0x0E31 ], [ 0x0E34, 0x0E3A ], [ 0x0E47, 0x0E4E ], + [ 0x0EB1, 0x0EB1 ], [ 0x0EB4, 0x0EB9 ], [ 0x0EBB, 0x0EBC ], + [ 0x0EC8, 0x0ECD ], [ 0x0F18, 0x0F19 ], [ 0x0F35, 0x0F35 ], + [ 0x0F37, 0x0F37 ], [ 0x0F39, 0x0F39 ], [ 0x0F71, 0x0F7E ], + [ 0x0F80, 0x0F84 ], [ 0x0F86, 0x0F87 ], [ 0x0F90, 0x0F97 ], + [ 0x0F99, 0x0FBC ], [ 0x0FC6, 0x0FC6 ], [ 0x102D, 0x1030 ], + [ 0x1032, 0x1032 ], [ 0x1036, 0x1037 ], [ 0x1039, 0x1039 ], + [ 0x1058, 0x1059 ], [ 0x1160, 0x11FF ], [ 0x135F, 0x135F ], + [ 0x1712, 0x1714 ], [ 0x1732, 0x1734 ], [ 0x1752, 0x1753 ], + [ 0x1772, 0x1773 ], [ 0x17B4, 0x17B5 ], [ 0x17B7, 0x17BD ], + [ 0x17C6, 0x17C6 ], [ 0x17C9, 0x17D3 ], [ 0x17DD, 0x17DD ], + [ 0x180B, 0x180D ], [ 0x18A9, 0x18A9 ], [ 0x1920, 0x1922 ], + [ 0x1927, 0x1928 ], [ 0x1932, 0x1932 ], [ 0x1939, 0x193B ], + [ 0x1A17, 0x1A18 ], [ 0x1B00, 0x1B03 ], [ 0x1B34, 0x1B34 ], + [ 0x1B36, 0x1B3A ], [ 0x1B3C, 0x1B3C ], [ 0x1B42, 0x1B42 ], + [ 0x1B6B, 0x1B73 ], [ 0x1DC0, 0x1DCA ], [ 0x1DFE, 0x1DFF ], + [ 0x200B, 0x200F ], [ 0x202A, 0x202E ], [ 0x2060, 0x2063 ], + [ 0x206A, 0x206F ], [ 0x20D0, 0x20EF ], [ 0x302A, 0x302F ], + [ 0x3099, 0x309A ], [ 0xA806, 0xA806 ], [ 0xA80B, 0xA80B ], + [ 0xA825, 0xA826 ], [ 0xFB1E, 0xFB1E ], [ 0xFE00, 0xFE0F ], + [ 0xFE20, 0xFE23 ], [ 0xFEFF, 0xFEFF ], [ 0xFFF9, 0xFFFB ], + [ 0x10A01, 0x10A03 ], [ 0x10A05, 0x10A06 ], [ 0x10A0C, 0x10A0F ], + [ 0x10A38, 0x10A3A ], [ 0x10A3F, 0x10A3F ], [ 0x1D167, 0x1D169 ], + [ 0x1D173, 0x1D182 ], [ 0x1D185, 0x1D18B ], [ 0x1D1AA, 0x1D1AD ], + [ 0x1D242, 0x1D244 ], [ 0xE0001, 0xE0001 ], [ 0xE0020, 0xE007F ], + [ 0xE0100, 0xE01EF ] +] + + +/***/ }), +/* 390 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +module.exports = ({stream = process.stdout} = {}) => { + return Boolean( + stream && stream.isTTY && + process.env.TERM !== 'dumb' && + !('CI' in process.env) + ); +}; + + +/***/ }), +/* 391 */ +/***/ (function(module, exports, __webpack_require__) { + +var Stream = __webpack_require__(137) + +module.exports = MuteStream + +// var out = new MuteStream(process.stdout) +// argument auto-pipes +function MuteStream (opts) { + Stream.apply(this) + opts = opts || {} + this.writable = this.readable = true + this.muted = false + this.on('pipe', this._onpipe) + this.replace = opts.replace + + // For readline-type situations + // This much at the start of a line being redrawn after a ctrl char + // is seen (such as backspace) won't be redrawn as the replacement + this._prompt = opts.prompt || null + this._hadControl = false +} + +MuteStream.prototype = Object.create(Stream.prototype) + +Object.defineProperty(MuteStream.prototype, 'constructor', { + value: MuteStream, + enumerable: false +}) + +MuteStream.prototype.mute = function () { + this.muted = true +} + +MuteStream.prototype.unmute = function () { + this.muted = false +} + +Object.defineProperty(MuteStream.prototype, '_onpipe', { + value: onPipe, + enumerable: false, + writable: true, + configurable: true +}) + +function onPipe (src) { + this._src = src +} + +Object.defineProperty(MuteStream.prototype, 'isTTY', { + get: getIsTTY, + set: setIsTTY, + enumerable: true, + configurable: true +}) + +function getIsTTY () { + return( (this._dest) ? this._dest.isTTY + : (this._src) ? this._src.isTTY + : false + ) +} + +// basically just get replace the getter/setter with a regular value +function setIsTTY (isTTY) { + Object.defineProperty(this, 'isTTY', { + value: isTTY, + enumerable: true, + writable: true, + configurable: true + }) +} + +Object.defineProperty(MuteStream.prototype, 'rows', { + get: function () { + return( this._dest ? this._dest.rows + : this._src ? this._src.rows + : undefined ) + }, enumerable: true, configurable: true }) + +Object.defineProperty(MuteStream.prototype, 'columns', { + get: function () { + return( this._dest ? this._dest.columns + : this._src ? this._src.columns + : undefined ) + }, enumerable: true, configurable: true }) + + +MuteStream.prototype.pipe = function (dest, options) { + this._dest = dest + return Stream.prototype.pipe.call(this, dest, options) +} + +MuteStream.prototype.pause = function () { + if (this._src) return this._src.pause() +} + +MuteStream.prototype.resume = function () { + if (this._src) return this._src.resume() +} + +MuteStream.prototype.write = function (c) { + if (this.muted) { + if (!this.replace) return true + if (c.match(/^\u001b/)) { + if(c.indexOf(this._prompt) === 0) { + c = c.substr(this._prompt.length); + c = c.replace(/./g, this.replace); + c = this._prompt + c; + } + this._hadControl = true + return this.emit('data', c) + } else { + if (this._prompt && this._hadControl && + c.indexOf(this._prompt) === 0) { + this._hadControl = false + this.emit('data', this._prompt) + c = c.substr(this._prompt.length) + } + c = c.toString().replace(/./g, this.replace) + } + } + this.emit('data', c) +} + +MuteStream.prototype.end = function (c) { + if (this.muted) { + if (c && this.replace) { + c = c.toString().replace(/./g, this.replace) + } else { + c = null + } + } + if (c) this.emit('data', c) + this.emit('end') +} + +function proxy (fn) { return function () { + var d = this._dest + var s = this._src + if (d && d[fn]) d[fn].apply(d, arguments) + if (s && s[fn]) s[fn].apply(s, arguments) +}} + +MuteStream.prototype.destroy = proxy('destroy') +MuteStream.prototype.destroySoon = proxy('destroySoon') +MuteStream.prototype.close = proxy('close') + + +/***/ }), +/* 392 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -48701,7 +48927,7 @@ const RunCommand = { }; /***/ }), -/* 389 */ +/* 393 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -48711,7 +48937,7 @@ __webpack_require__.r(__webpack_exports__); /* harmony import */ var _utils_log__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(143); /* harmony import */ var _utils_parallelize__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(144); /* harmony import */ var _utils_projects__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(145); -/* harmony import */ var _utils_watch__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(390); +/* harmony import */ var _utils_watch__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(394); /* * Licensed to Elasticsearch B.V. under one or more contributor * license agreements. See the NOTICE file distributed with @@ -48796,14 +49022,14 @@ const WatchCommand = { }; /***/ }), -/* 390 */ +/* 394 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "waitUntilWatchIsReady", function() { return waitUntilWatchIsReady; }); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(8); -/* harmony import */ var rxjs_operators__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(391); +/* harmony import */ var rxjs_operators__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(395); /* * Licensed to Elasticsearch B.V. under one or more contributor * license agreements. See the NOTICE file distributed with @@ -48870,141 +49096,141 @@ function waitUntilWatchIsReady(stream, opts = {}) { } /***/ }), -/* 391 */ +/* 395 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); -/* harmony import */ var _internal_operators_audit__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(392); +/* harmony import */ var _internal_operators_audit__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(396); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "audit", function() { return _internal_operators_audit__WEBPACK_IMPORTED_MODULE_0__["audit"]; }); -/* harmony import */ var _internal_operators_auditTime__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(393); +/* harmony import */ var _internal_operators_auditTime__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(397); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "auditTime", function() { return _internal_operators_auditTime__WEBPACK_IMPORTED_MODULE_1__["auditTime"]; }); -/* harmony import */ var _internal_operators_buffer__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(394); +/* harmony import */ var _internal_operators_buffer__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(398); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "buffer", function() { return _internal_operators_buffer__WEBPACK_IMPORTED_MODULE_2__["buffer"]; }); -/* harmony import */ var _internal_operators_bufferCount__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(395); +/* harmony import */ var _internal_operators_bufferCount__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(399); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "bufferCount", function() { return _internal_operators_bufferCount__WEBPACK_IMPORTED_MODULE_3__["bufferCount"]; }); -/* harmony import */ var _internal_operators_bufferTime__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(396); +/* harmony import */ var _internal_operators_bufferTime__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(400); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "bufferTime", function() { return _internal_operators_bufferTime__WEBPACK_IMPORTED_MODULE_4__["bufferTime"]; }); -/* harmony import */ var _internal_operators_bufferToggle__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(397); +/* harmony import */ var _internal_operators_bufferToggle__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(401); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "bufferToggle", function() { return _internal_operators_bufferToggle__WEBPACK_IMPORTED_MODULE_5__["bufferToggle"]; }); -/* harmony import */ var _internal_operators_bufferWhen__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(398); +/* harmony import */ var _internal_operators_bufferWhen__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(402); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "bufferWhen", function() { return _internal_operators_bufferWhen__WEBPACK_IMPORTED_MODULE_6__["bufferWhen"]; }); -/* harmony import */ var _internal_operators_catchError__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(399); +/* harmony import */ var _internal_operators_catchError__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(403); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "catchError", function() { return _internal_operators_catchError__WEBPACK_IMPORTED_MODULE_7__["catchError"]; }); -/* harmony import */ var _internal_operators_combineAll__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(400); +/* harmony import */ var _internal_operators_combineAll__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(404); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "combineAll", function() { return _internal_operators_combineAll__WEBPACK_IMPORTED_MODULE_8__["combineAll"]; }); -/* harmony import */ var _internal_operators_combineLatest__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(401); +/* harmony import */ var _internal_operators_combineLatest__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(405); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "combineLatest", function() { return _internal_operators_combineLatest__WEBPACK_IMPORTED_MODULE_9__["combineLatest"]; }); -/* harmony import */ var _internal_operators_concat__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(402); +/* harmony import */ var _internal_operators_concat__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(406); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "concat", function() { return _internal_operators_concat__WEBPACK_IMPORTED_MODULE_10__["concat"]; }); /* harmony import */ var _internal_operators_concatAll__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(80); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "concatAll", function() { return _internal_operators_concatAll__WEBPACK_IMPORTED_MODULE_11__["concatAll"]; }); -/* harmony import */ var _internal_operators_concatMap__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(403); +/* harmony import */ var _internal_operators_concatMap__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(407); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "concatMap", function() { return _internal_operators_concatMap__WEBPACK_IMPORTED_MODULE_12__["concatMap"]; }); -/* harmony import */ var _internal_operators_concatMapTo__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(404); +/* harmony import */ var _internal_operators_concatMapTo__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(408); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "concatMapTo", function() { return _internal_operators_concatMapTo__WEBPACK_IMPORTED_MODULE_13__["concatMapTo"]; }); -/* harmony import */ var _internal_operators_count__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(405); +/* harmony import */ var _internal_operators_count__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(409); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "count", function() { return _internal_operators_count__WEBPACK_IMPORTED_MODULE_14__["count"]; }); -/* harmony import */ var _internal_operators_debounce__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(406); +/* harmony import */ var _internal_operators_debounce__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(410); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "debounce", function() { return _internal_operators_debounce__WEBPACK_IMPORTED_MODULE_15__["debounce"]; }); -/* harmony import */ var _internal_operators_debounceTime__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(407); +/* harmony import */ var _internal_operators_debounceTime__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(411); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "debounceTime", function() { return _internal_operators_debounceTime__WEBPACK_IMPORTED_MODULE_16__["debounceTime"]; }); -/* harmony import */ var _internal_operators_defaultIfEmpty__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(408); +/* harmony import */ var _internal_operators_defaultIfEmpty__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(412); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "defaultIfEmpty", function() { return _internal_operators_defaultIfEmpty__WEBPACK_IMPORTED_MODULE_17__["defaultIfEmpty"]; }); -/* harmony import */ var _internal_operators_delay__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(409); +/* harmony import */ var _internal_operators_delay__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(413); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "delay", function() { return _internal_operators_delay__WEBPACK_IMPORTED_MODULE_18__["delay"]; }); -/* harmony import */ var _internal_operators_delayWhen__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(411); +/* harmony import */ var _internal_operators_delayWhen__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(415); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "delayWhen", function() { return _internal_operators_delayWhen__WEBPACK_IMPORTED_MODULE_19__["delayWhen"]; }); -/* harmony import */ var _internal_operators_dematerialize__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(412); +/* harmony import */ var _internal_operators_dematerialize__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(416); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "dematerialize", function() { return _internal_operators_dematerialize__WEBPACK_IMPORTED_MODULE_20__["dematerialize"]; }); -/* harmony import */ var _internal_operators_distinct__WEBPACK_IMPORTED_MODULE_21__ = __webpack_require__(413); +/* harmony import */ var _internal_operators_distinct__WEBPACK_IMPORTED_MODULE_21__ = __webpack_require__(417); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "distinct", function() { return _internal_operators_distinct__WEBPACK_IMPORTED_MODULE_21__["distinct"]; }); -/* harmony import */ var _internal_operators_distinctUntilChanged__WEBPACK_IMPORTED_MODULE_22__ = __webpack_require__(414); +/* harmony import */ var _internal_operators_distinctUntilChanged__WEBPACK_IMPORTED_MODULE_22__ = __webpack_require__(418); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "distinctUntilChanged", function() { return _internal_operators_distinctUntilChanged__WEBPACK_IMPORTED_MODULE_22__["distinctUntilChanged"]; }); -/* harmony import */ var _internal_operators_distinctUntilKeyChanged__WEBPACK_IMPORTED_MODULE_23__ = __webpack_require__(415); +/* harmony import */ var _internal_operators_distinctUntilKeyChanged__WEBPACK_IMPORTED_MODULE_23__ = __webpack_require__(419); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "distinctUntilKeyChanged", function() { return _internal_operators_distinctUntilKeyChanged__WEBPACK_IMPORTED_MODULE_23__["distinctUntilKeyChanged"]; }); -/* harmony import */ var _internal_operators_elementAt__WEBPACK_IMPORTED_MODULE_24__ = __webpack_require__(416); +/* harmony import */ var _internal_operators_elementAt__WEBPACK_IMPORTED_MODULE_24__ = __webpack_require__(420); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "elementAt", function() { return _internal_operators_elementAt__WEBPACK_IMPORTED_MODULE_24__["elementAt"]; }); -/* harmony import */ var _internal_operators_endWith__WEBPACK_IMPORTED_MODULE_25__ = __webpack_require__(419); +/* harmony import */ var _internal_operators_endWith__WEBPACK_IMPORTED_MODULE_25__ = __webpack_require__(423); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "endWith", function() { return _internal_operators_endWith__WEBPACK_IMPORTED_MODULE_25__["endWith"]; }); -/* harmony import */ var _internal_operators_every__WEBPACK_IMPORTED_MODULE_26__ = __webpack_require__(420); +/* harmony import */ var _internal_operators_every__WEBPACK_IMPORTED_MODULE_26__ = __webpack_require__(424); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "every", function() { return _internal_operators_every__WEBPACK_IMPORTED_MODULE_26__["every"]; }); -/* harmony import */ var _internal_operators_exhaust__WEBPACK_IMPORTED_MODULE_27__ = __webpack_require__(421); +/* harmony import */ var _internal_operators_exhaust__WEBPACK_IMPORTED_MODULE_27__ = __webpack_require__(425); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "exhaust", function() { return _internal_operators_exhaust__WEBPACK_IMPORTED_MODULE_27__["exhaust"]; }); -/* harmony import */ var _internal_operators_exhaustMap__WEBPACK_IMPORTED_MODULE_28__ = __webpack_require__(422); +/* harmony import */ var _internal_operators_exhaustMap__WEBPACK_IMPORTED_MODULE_28__ = __webpack_require__(426); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "exhaustMap", function() { return _internal_operators_exhaustMap__WEBPACK_IMPORTED_MODULE_28__["exhaustMap"]; }); -/* harmony import */ var _internal_operators_expand__WEBPACK_IMPORTED_MODULE_29__ = __webpack_require__(423); +/* harmony import */ var _internal_operators_expand__WEBPACK_IMPORTED_MODULE_29__ = __webpack_require__(427); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "expand", function() { return _internal_operators_expand__WEBPACK_IMPORTED_MODULE_29__["expand"]; }); /* harmony import */ var _internal_operators_filter__WEBPACK_IMPORTED_MODULE_30__ = __webpack_require__(104); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "filter", function() { return _internal_operators_filter__WEBPACK_IMPORTED_MODULE_30__["filter"]; }); -/* harmony import */ var _internal_operators_finalize__WEBPACK_IMPORTED_MODULE_31__ = __webpack_require__(424); +/* harmony import */ var _internal_operators_finalize__WEBPACK_IMPORTED_MODULE_31__ = __webpack_require__(428); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "finalize", function() { return _internal_operators_finalize__WEBPACK_IMPORTED_MODULE_31__["finalize"]; }); -/* harmony import */ var _internal_operators_find__WEBPACK_IMPORTED_MODULE_32__ = __webpack_require__(425); +/* harmony import */ var _internal_operators_find__WEBPACK_IMPORTED_MODULE_32__ = __webpack_require__(429); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "find", function() { return _internal_operators_find__WEBPACK_IMPORTED_MODULE_32__["find"]; }); -/* harmony import */ var _internal_operators_findIndex__WEBPACK_IMPORTED_MODULE_33__ = __webpack_require__(426); +/* harmony import */ var _internal_operators_findIndex__WEBPACK_IMPORTED_MODULE_33__ = __webpack_require__(430); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "findIndex", function() { return _internal_operators_findIndex__WEBPACK_IMPORTED_MODULE_33__["findIndex"]; }); -/* harmony import */ var _internal_operators_first__WEBPACK_IMPORTED_MODULE_34__ = __webpack_require__(427); +/* harmony import */ var _internal_operators_first__WEBPACK_IMPORTED_MODULE_34__ = __webpack_require__(431); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "first", function() { return _internal_operators_first__WEBPACK_IMPORTED_MODULE_34__["first"]; }); /* harmony import */ var _internal_operators_groupBy__WEBPACK_IMPORTED_MODULE_35__ = __webpack_require__(31); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "groupBy", function() { return _internal_operators_groupBy__WEBPACK_IMPORTED_MODULE_35__["groupBy"]; }); -/* harmony import */ var _internal_operators_ignoreElements__WEBPACK_IMPORTED_MODULE_36__ = __webpack_require__(428); +/* harmony import */ var _internal_operators_ignoreElements__WEBPACK_IMPORTED_MODULE_36__ = __webpack_require__(432); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "ignoreElements", function() { return _internal_operators_ignoreElements__WEBPACK_IMPORTED_MODULE_36__["ignoreElements"]; }); -/* harmony import */ var _internal_operators_isEmpty__WEBPACK_IMPORTED_MODULE_37__ = __webpack_require__(429); +/* harmony import */ var _internal_operators_isEmpty__WEBPACK_IMPORTED_MODULE_37__ = __webpack_require__(433); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "isEmpty", function() { return _internal_operators_isEmpty__WEBPACK_IMPORTED_MODULE_37__["isEmpty"]; }); -/* harmony import */ var _internal_operators_last__WEBPACK_IMPORTED_MODULE_38__ = __webpack_require__(430); +/* harmony import */ var _internal_operators_last__WEBPACK_IMPORTED_MODULE_38__ = __webpack_require__(434); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "last", function() { return _internal_operators_last__WEBPACK_IMPORTED_MODULE_38__["last"]; }); /* harmony import */ var _internal_operators_map__WEBPACK_IMPORTED_MODULE_39__ = __webpack_require__(66); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "map", function() { return _internal_operators_map__WEBPACK_IMPORTED_MODULE_39__["map"]; }); -/* harmony import */ var _internal_operators_mapTo__WEBPACK_IMPORTED_MODULE_40__ = __webpack_require__(432); +/* harmony import */ var _internal_operators_mapTo__WEBPACK_IMPORTED_MODULE_40__ = __webpack_require__(436); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "mapTo", function() { return _internal_operators_mapTo__WEBPACK_IMPORTED_MODULE_40__["mapTo"]; }); -/* harmony import */ var _internal_operators_materialize__WEBPACK_IMPORTED_MODULE_41__ = __webpack_require__(433); +/* harmony import */ var _internal_operators_materialize__WEBPACK_IMPORTED_MODULE_41__ = __webpack_require__(437); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "materialize", function() { return _internal_operators_materialize__WEBPACK_IMPORTED_MODULE_41__["materialize"]; }); -/* harmony import */ var _internal_operators_max__WEBPACK_IMPORTED_MODULE_42__ = __webpack_require__(434); +/* harmony import */ var _internal_operators_max__WEBPACK_IMPORTED_MODULE_42__ = __webpack_require__(438); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "max", function() { return _internal_operators_max__WEBPACK_IMPORTED_MODULE_42__["max"]; }); -/* harmony import */ var _internal_operators_merge__WEBPACK_IMPORTED_MODULE_43__ = __webpack_require__(437); +/* harmony import */ var _internal_operators_merge__WEBPACK_IMPORTED_MODULE_43__ = __webpack_require__(441); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "merge", function() { return _internal_operators_merge__WEBPACK_IMPORTED_MODULE_43__["merge"]; }); /* harmony import */ var _internal_operators_mergeAll__WEBPACK_IMPORTED_MODULE_44__ = __webpack_require__(81); @@ -49015,175 +49241,175 @@ __webpack_require__.r(__webpack_exports__); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "flatMap", function() { return _internal_operators_mergeMap__WEBPACK_IMPORTED_MODULE_45__["mergeMap"]; }); -/* harmony import */ var _internal_operators_mergeMapTo__WEBPACK_IMPORTED_MODULE_46__ = __webpack_require__(438); +/* harmony import */ var _internal_operators_mergeMapTo__WEBPACK_IMPORTED_MODULE_46__ = __webpack_require__(442); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "mergeMapTo", function() { return _internal_operators_mergeMapTo__WEBPACK_IMPORTED_MODULE_46__["mergeMapTo"]; }); -/* harmony import */ var _internal_operators_mergeScan__WEBPACK_IMPORTED_MODULE_47__ = __webpack_require__(439); +/* harmony import */ var _internal_operators_mergeScan__WEBPACK_IMPORTED_MODULE_47__ = __webpack_require__(443); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "mergeScan", function() { return _internal_operators_mergeScan__WEBPACK_IMPORTED_MODULE_47__["mergeScan"]; }); -/* harmony import */ var _internal_operators_min__WEBPACK_IMPORTED_MODULE_48__ = __webpack_require__(440); +/* harmony import */ var _internal_operators_min__WEBPACK_IMPORTED_MODULE_48__ = __webpack_require__(444); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "min", function() { return _internal_operators_min__WEBPACK_IMPORTED_MODULE_48__["min"]; }); -/* harmony import */ var _internal_operators_multicast__WEBPACK_IMPORTED_MODULE_49__ = __webpack_require__(441); +/* harmony import */ var _internal_operators_multicast__WEBPACK_IMPORTED_MODULE_49__ = __webpack_require__(445); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "multicast", function() { return _internal_operators_multicast__WEBPACK_IMPORTED_MODULE_49__["multicast"]; }); /* harmony import */ var _internal_operators_observeOn__WEBPACK_IMPORTED_MODULE_50__ = __webpack_require__(41); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "observeOn", function() { return _internal_operators_observeOn__WEBPACK_IMPORTED_MODULE_50__["observeOn"]; }); -/* harmony import */ var _internal_operators_onErrorResumeNext__WEBPACK_IMPORTED_MODULE_51__ = __webpack_require__(442); +/* harmony import */ var _internal_operators_onErrorResumeNext__WEBPACK_IMPORTED_MODULE_51__ = __webpack_require__(446); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "onErrorResumeNext", function() { return _internal_operators_onErrorResumeNext__WEBPACK_IMPORTED_MODULE_51__["onErrorResumeNext"]; }); -/* harmony import */ var _internal_operators_pairwise__WEBPACK_IMPORTED_MODULE_52__ = __webpack_require__(443); +/* harmony import */ var _internal_operators_pairwise__WEBPACK_IMPORTED_MODULE_52__ = __webpack_require__(447); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "pairwise", function() { return _internal_operators_pairwise__WEBPACK_IMPORTED_MODULE_52__["pairwise"]; }); -/* harmony import */ var _internal_operators_partition__WEBPACK_IMPORTED_MODULE_53__ = __webpack_require__(444); +/* harmony import */ var _internal_operators_partition__WEBPACK_IMPORTED_MODULE_53__ = __webpack_require__(448); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "partition", function() { return _internal_operators_partition__WEBPACK_IMPORTED_MODULE_53__["partition"]; }); -/* harmony import */ var _internal_operators_pluck__WEBPACK_IMPORTED_MODULE_54__ = __webpack_require__(445); +/* harmony import */ var _internal_operators_pluck__WEBPACK_IMPORTED_MODULE_54__ = __webpack_require__(449); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "pluck", function() { return _internal_operators_pluck__WEBPACK_IMPORTED_MODULE_54__["pluck"]; }); -/* harmony import */ var _internal_operators_publish__WEBPACK_IMPORTED_MODULE_55__ = __webpack_require__(446); +/* harmony import */ var _internal_operators_publish__WEBPACK_IMPORTED_MODULE_55__ = __webpack_require__(450); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "publish", function() { return _internal_operators_publish__WEBPACK_IMPORTED_MODULE_55__["publish"]; }); -/* harmony import */ var _internal_operators_publishBehavior__WEBPACK_IMPORTED_MODULE_56__ = __webpack_require__(447); +/* harmony import */ var _internal_operators_publishBehavior__WEBPACK_IMPORTED_MODULE_56__ = __webpack_require__(451); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "publishBehavior", function() { return _internal_operators_publishBehavior__WEBPACK_IMPORTED_MODULE_56__["publishBehavior"]; }); -/* harmony import */ var _internal_operators_publishLast__WEBPACK_IMPORTED_MODULE_57__ = __webpack_require__(448); +/* harmony import */ var _internal_operators_publishLast__WEBPACK_IMPORTED_MODULE_57__ = __webpack_require__(452); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "publishLast", function() { return _internal_operators_publishLast__WEBPACK_IMPORTED_MODULE_57__["publishLast"]; }); -/* harmony import */ var _internal_operators_publishReplay__WEBPACK_IMPORTED_MODULE_58__ = __webpack_require__(449); +/* harmony import */ var _internal_operators_publishReplay__WEBPACK_IMPORTED_MODULE_58__ = __webpack_require__(453); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "publishReplay", function() { return _internal_operators_publishReplay__WEBPACK_IMPORTED_MODULE_58__["publishReplay"]; }); -/* harmony import */ var _internal_operators_race__WEBPACK_IMPORTED_MODULE_59__ = __webpack_require__(450); +/* harmony import */ var _internal_operators_race__WEBPACK_IMPORTED_MODULE_59__ = __webpack_require__(454); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "race", function() { return _internal_operators_race__WEBPACK_IMPORTED_MODULE_59__["race"]; }); -/* harmony import */ var _internal_operators_reduce__WEBPACK_IMPORTED_MODULE_60__ = __webpack_require__(435); +/* harmony import */ var _internal_operators_reduce__WEBPACK_IMPORTED_MODULE_60__ = __webpack_require__(439); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "reduce", function() { return _internal_operators_reduce__WEBPACK_IMPORTED_MODULE_60__["reduce"]; }); -/* harmony import */ var _internal_operators_repeat__WEBPACK_IMPORTED_MODULE_61__ = __webpack_require__(451); +/* harmony import */ var _internal_operators_repeat__WEBPACK_IMPORTED_MODULE_61__ = __webpack_require__(455); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "repeat", function() { return _internal_operators_repeat__WEBPACK_IMPORTED_MODULE_61__["repeat"]; }); -/* harmony import */ var _internal_operators_repeatWhen__WEBPACK_IMPORTED_MODULE_62__ = __webpack_require__(452); +/* harmony import */ var _internal_operators_repeatWhen__WEBPACK_IMPORTED_MODULE_62__ = __webpack_require__(456); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "repeatWhen", function() { return _internal_operators_repeatWhen__WEBPACK_IMPORTED_MODULE_62__["repeatWhen"]; }); -/* harmony import */ var _internal_operators_retry__WEBPACK_IMPORTED_MODULE_63__ = __webpack_require__(453); +/* harmony import */ var _internal_operators_retry__WEBPACK_IMPORTED_MODULE_63__ = __webpack_require__(457); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "retry", function() { return _internal_operators_retry__WEBPACK_IMPORTED_MODULE_63__["retry"]; }); -/* harmony import */ var _internal_operators_retryWhen__WEBPACK_IMPORTED_MODULE_64__ = __webpack_require__(454); +/* harmony import */ var _internal_operators_retryWhen__WEBPACK_IMPORTED_MODULE_64__ = __webpack_require__(458); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "retryWhen", function() { return _internal_operators_retryWhen__WEBPACK_IMPORTED_MODULE_64__["retryWhen"]; }); /* harmony import */ var _internal_operators_refCount__WEBPACK_IMPORTED_MODULE_65__ = __webpack_require__(30); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "refCount", function() { return _internal_operators_refCount__WEBPACK_IMPORTED_MODULE_65__["refCount"]; }); -/* harmony import */ var _internal_operators_sample__WEBPACK_IMPORTED_MODULE_66__ = __webpack_require__(455); +/* harmony import */ var _internal_operators_sample__WEBPACK_IMPORTED_MODULE_66__ = __webpack_require__(459); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "sample", function() { return _internal_operators_sample__WEBPACK_IMPORTED_MODULE_66__["sample"]; }); -/* harmony import */ var _internal_operators_sampleTime__WEBPACK_IMPORTED_MODULE_67__ = __webpack_require__(456); +/* harmony import */ var _internal_operators_sampleTime__WEBPACK_IMPORTED_MODULE_67__ = __webpack_require__(460); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "sampleTime", function() { return _internal_operators_sampleTime__WEBPACK_IMPORTED_MODULE_67__["sampleTime"]; }); -/* harmony import */ var _internal_operators_scan__WEBPACK_IMPORTED_MODULE_68__ = __webpack_require__(436); +/* harmony import */ var _internal_operators_scan__WEBPACK_IMPORTED_MODULE_68__ = __webpack_require__(440); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "scan", function() { return _internal_operators_scan__WEBPACK_IMPORTED_MODULE_68__["scan"]; }); -/* harmony import */ var _internal_operators_sequenceEqual__WEBPACK_IMPORTED_MODULE_69__ = __webpack_require__(457); +/* harmony import */ var _internal_operators_sequenceEqual__WEBPACK_IMPORTED_MODULE_69__ = __webpack_require__(461); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "sequenceEqual", function() { return _internal_operators_sequenceEqual__WEBPACK_IMPORTED_MODULE_69__["sequenceEqual"]; }); -/* harmony import */ var _internal_operators_share__WEBPACK_IMPORTED_MODULE_70__ = __webpack_require__(458); +/* harmony import */ var _internal_operators_share__WEBPACK_IMPORTED_MODULE_70__ = __webpack_require__(462); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "share", function() { return _internal_operators_share__WEBPACK_IMPORTED_MODULE_70__["share"]; }); -/* harmony import */ var _internal_operators_shareReplay__WEBPACK_IMPORTED_MODULE_71__ = __webpack_require__(459); +/* harmony import */ var _internal_operators_shareReplay__WEBPACK_IMPORTED_MODULE_71__ = __webpack_require__(463); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "shareReplay", function() { return _internal_operators_shareReplay__WEBPACK_IMPORTED_MODULE_71__["shareReplay"]; }); -/* harmony import */ var _internal_operators_single__WEBPACK_IMPORTED_MODULE_72__ = __webpack_require__(460); +/* harmony import */ var _internal_operators_single__WEBPACK_IMPORTED_MODULE_72__ = __webpack_require__(464); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "single", function() { return _internal_operators_single__WEBPACK_IMPORTED_MODULE_72__["single"]; }); -/* harmony import */ var _internal_operators_skip__WEBPACK_IMPORTED_MODULE_73__ = __webpack_require__(461); +/* harmony import */ var _internal_operators_skip__WEBPACK_IMPORTED_MODULE_73__ = __webpack_require__(465); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "skip", function() { return _internal_operators_skip__WEBPACK_IMPORTED_MODULE_73__["skip"]; }); -/* harmony import */ var _internal_operators_skipLast__WEBPACK_IMPORTED_MODULE_74__ = __webpack_require__(462); +/* harmony import */ var _internal_operators_skipLast__WEBPACK_IMPORTED_MODULE_74__ = __webpack_require__(466); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "skipLast", function() { return _internal_operators_skipLast__WEBPACK_IMPORTED_MODULE_74__["skipLast"]; }); -/* harmony import */ var _internal_operators_skipUntil__WEBPACK_IMPORTED_MODULE_75__ = __webpack_require__(463); +/* harmony import */ var _internal_operators_skipUntil__WEBPACK_IMPORTED_MODULE_75__ = __webpack_require__(467); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "skipUntil", function() { return _internal_operators_skipUntil__WEBPACK_IMPORTED_MODULE_75__["skipUntil"]; }); -/* harmony import */ var _internal_operators_skipWhile__WEBPACK_IMPORTED_MODULE_76__ = __webpack_require__(464); +/* harmony import */ var _internal_operators_skipWhile__WEBPACK_IMPORTED_MODULE_76__ = __webpack_require__(468); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "skipWhile", function() { return _internal_operators_skipWhile__WEBPACK_IMPORTED_MODULE_76__["skipWhile"]; }); -/* harmony import */ var _internal_operators_startWith__WEBPACK_IMPORTED_MODULE_77__ = __webpack_require__(465); +/* harmony import */ var _internal_operators_startWith__WEBPACK_IMPORTED_MODULE_77__ = __webpack_require__(469); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "startWith", function() { return _internal_operators_startWith__WEBPACK_IMPORTED_MODULE_77__["startWith"]; }); -/* harmony import */ var _internal_operators_subscribeOn__WEBPACK_IMPORTED_MODULE_78__ = __webpack_require__(466); +/* harmony import */ var _internal_operators_subscribeOn__WEBPACK_IMPORTED_MODULE_78__ = __webpack_require__(470); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "subscribeOn", function() { return _internal_operators_subscribeOn__WEBPACK_IMPORTED_MODULE_78__["subscribeOn"]; }); -/* harmony import */ var _internal_operators_switchAll__WEBPACK_IMPORTED_MODULE_79__ = __webpack_require__(468); +/* harmony import */ var _internal_operators_switchAll__WEBPACK_IMPORTED_MODULE_79__ = __webpack_require__(472); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "switchAll", function() { return _internal_operators_switchAll__WEBPACK_IMPORTED_MODULE_79__["switchAll"]; }); -/* harmony import */ var _internal_operators_switchMap__WEBPACK_IMPORTED_MODULE_80__ = __webpack_require__(469); +/* harmony import */ var _internal_operators_switchMap__WEBPACK_IMPORTED_MODULE_80__ = __webpack_require__(473); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "switchMap", function() { return _internal_operators_switchMap__WEBPACK_IMPORTED_MODULE_80__["switchMap"]; }); -/* harmony import */ var _internal_operators_switchMapTo__WEBPACK_IMPORTED_MODULE_81__ = __webpack_require__(470); +/* harmony import */ var _internal_operators_switchMapTo__WEBPACK_IMPORTED_MODULE_81__ = __webpack_require__(474); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "switchMapTo", function() { return _internal_operators_switchMapTo__WEBPACK_IMPORTED_MODULE_81__["switchMapTo"]; }); -/* harmony import */ var _internal_operators_take__WEBPACK_IMPORTED_MODULE_82__ = __webpack_require__(418); +/* harmony import */ var _internal_operators_take__WEBPACK_IMPORTED_MODULE_82__ = __webpack_require__(422); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "take", function() { return _internal_operators_take__WEBPACK_IMPORTED_MODULE_82__["take"]; }); -/* harmony import */ var _internal_operators_takeLast__WEBPACK_IMPORTED_MODULE_83__ = __webpack_require__(431); +/* harmony import */ var _internal_operators_takeLast__WEBPACK_IMPORTED_MODULE_83__ = __webpack_require__(435); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "takeLast", function() { return _internal_operators_takeLast__WEBPACK_IMPORTED_MODULE_83__["takeLast"]; }); -/* harmony import */ var _internal_operators_takeUntil__WEBPACK_IMPORTED_MODULE_84__ = __webpack_require__(471); +/* harmony import */ var _internal_operators_takeUntil__WEBPACK_IMPORTED_MODULE_84__ = __webpack_require__(475); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "takeUntil", function() { return _internal_operators_takeUntil__WEBPACK_IMPORTED_MODULE_84__["takeUntil"]; }); -/* harmony import */ var _internal_operators_takeWhile__WEBPACK_IMPORTED_MODULE_85__ = __webpack_require__(472); +/* harmony import */ var _internal_operators_takeWhile__WEBPACK_IMPORTED_MODULE_85__ = __webpack_require__(476); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "takeWhile", function() { return _internal_operators_takeWhile__WEBPACK_IMPORTED_MODULE_85__["takeWhile"]; }); -/* harmony import */ var _internal_operators_tap__WEBPACK_IMPORTED_MODULE_86__ = __webpack_require__(473); +/* harmony import */ var _internal_operators_tap__WEBPACK_IMPORTED_MODULE_86__ = __webpack_require__(477); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "tap", function() { return _internal_operators_tap__WEBPACK_IMPORTED_MODULE_86__["tap"]; }); -/* harmony import */ var _internal_operators_throttle__WEBPACK_IMPORTED_MODULE_87__ = __webpack_require__(474); +/* harmony import */ var _internal_operators_throttle__WEBPACK_IMPORTED_MODULE_87__ = __webpack_require__(478); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "throttle", function() { return _internal_operators_throttle__WEBPACK_IMPORTED_MODULE_87__["throttle"]; }); -/* harmony import */ var _internal_operators_throttleTime__WEBPACK_IMPORTED_MODULE_88__ = __webpack_require__(475); +/* harmony import */ var _internal_operators_throttleTime__WEBPACK_IMPORTED_MODULE_88__ = __webpack_require__(479); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "throttleTime", function() { return _internal_operators_throttleTime__WEBPACK_IMPORTED_MODULE_88__["throttleTime"]; }); -/* harmony import */ var _internal_operators_throwIfEmpty__WEBPACK_IMPORTED_MODULE_89__ = __webpack_require__(417); +/* harmony import */ var _internal_operators_throwIfEmpty__WEBPACK_IMPORTED_MODULE_89__ = __webpack_require__(421); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "throwIfEmpty", function() { return _internal_operators_throwIfEmpty__WEBPACK_IMPORTED_MODULE_89__["throwIfEmpty"]; }); -/* harmony import */ var _internal_operators_timeInterval__WEBPACK_IMPORTED_MODULE_90__ = __webpack_require__(476); +/* harmony import */ var _internal_operators_timeInterval__WEBPACK_IMPORTED_MODULE_90__ = __webpack_require__(480); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "timeInterval", function() { return _internal_operators_timeInterval__WEBPACK_IMPORTED_MODULE_90__["timeInterval"]; }); -/* harmony import */ var _internal_operators_timeout__WEBPACK_IMPORTED_MODULE_91__ = __webpack_require__(477); +/* harmony import */ var _internal_operators_timeout__WEBPACK_IMPORTED_MODULE_91__ = __webpack_require__(481); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "timeout", function() { return _internal_operators_timeout__WEBPACK_IMPORTED_MODULE_91__["timeout"]; }); -/* harmony import */ var _internal_operators_timeoutWith__WEBPACK_IMPORTED_MODULE_92__ = __webpack_require__(478); +/* harmony import */ var _internal_operators_timeoutWith__WEBPACK_IMPORTED_MODULE_92__ = __webpack_require__(482); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "timeoutWith", function() { return _internal_operators_timeoutWith__WEBPACK_IMPORTED_MODULE_92__["timeoutWith"]; }); -/* harmony import */ var _internal_operators_timestamp__WEBPACK_IMPORTED_MODULE_93__ = __webpack_require__(479); +/* harmony import */ var _internal_operators_timestamp__WEBPACK_IMPORTED_MODULE_93__ = __webpack_require__(483); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "timestamp", function() { return _internal_operators_timestamp__WEBPACK_IMPORTED_MODULE_93__["timestamp"]; }); -/* harmony import */ var _internal_operators_toArray__WEBPACK_IMPORTED_MODULE_94__ = __webpack_require__(480); +/* harmony import */ var _internal_operators_toArray__WEBPACK_IMPORTED_MODULE_94__ = __webpack_require__(484); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "toArray", function() { return _internal_operators_toArray__WEBPACK_IMPORTED_MODULE_94__["toArray"]; }); -/* harmony import */ var _internal_operators_window__WEBPACK_IMPORTED_MODULE_95__ = __webpack_require__(481); +/* harmony import */ var _internal_operators_window__WEBPACK_IMPORTED_MODULE_95__ = __webpack_require__(485); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "window", function() { return _internal_operators_window__WEBPACK_IMPORTED_MODULE_95__["window"]; }); -/* harmony import */ var _internal_operators_windowCount__WEBPACK_IMPORTED_MODULE_96__ = __webpack_require__(482); +/* harmony import */ var _internal_operators_windowCount__WEBPACK_IMPORTED_MODULE_96__ = __webpack_require__(486); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "windowCount", function() { return _internal_operators_windowCount__WEBPACK_IMPORTED_MODULE_96__["windowCount"]; }); -/* harmony import */ var _internal_operators_windowTime__WEBPACK_IMPORTED_MODULE_97__ = __webpack_require__(483); +/* harmony import */ var _internal_operators_windowTime__WEBPACK_IMPORTED_MODULE_97__ = __webpack_require__(487); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "windowTime", function() { return _internal_operators_windowTime__WEBPACK_IMPORTED_MODULE_97__["windowTime"]; }); -/* harmony import */ var _internal_operators_windowToggle__WEBPACK_IMPORTED_MODULE_98__ = __webpack_require__(484); +/* harmony import */ var _internal_operators_windowToggle__WEBPACK_IMPORTED_MODULE_98__ = __webpack_require__(488); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "windowToggle", function() { return _internal_operators_windowToggle__WEBPACK_IMPORTED_MODULE_98__["windowToggle"]; }); -/* harmony import */ var _internal_operators_windowWhen__WEBPACK_IMPORTED_MODULE_99__ = __webpack_require__(485); +/* harmony import */ var _internal_operators_windowWhen__WEBPACK_IMPORTED_MODULE_99__ = __webpack_require__(489); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "windowWhen", function() { return _internal_operators_windowWhen__WEBPACK_IMPORTED_MODULE_99__["windowWhen"]; }); -/* harmony import */ var _internal_operators_withLatestFrom__WEBPACK_IMPORTED_MODULE_100__ = __webpack_require__(486); +/* harmony import */ var _internal_operators_withLatestFrom__WEBPACK_IMPORTED_MODULE_100__ = __webpack_require__(490); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "withLatestFrom", function() { return _internal_operators_withLatestFrom__WEBPACK_IMPORTED_MODULE_100__["withLatestFrom"]; }); -/* harmony import */ var _internal_operators_zip__WEBPACK_IMPORTED_MODULE_101__ = __webpack_require__(487); +/* harmony import */ var _internal_operators_zip__WEBPACK_IMPORTED_MODULE_101__ = __webpack_require__(491); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "zip", function() { return _internal_operators_zip__WEBPACK_IMPORTED_MODULE_101__["zip"]; }); -/* harmony import */ var _internal_operators_zipAll__WEBPACK_IMPORTED_MODULE_102__ = __webpack_require__(488); +/* harmony import */ var _internal_operators_zipAll__WEBPACK_IMPORTED_MODULE_102__ = __webpack_require__(492); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "zipAll", function() { return _internal_operators_zipAll__WEBPACK_IMPORTED_MODULE_102__["zipAll"]; }); /** PURE_IMPORTS_START PURE_IMPORTS_END */ @@ -49295,7 +49521,7 @@ __webpack_require__.r(__webpack_exports__); /***/ }), -/* 392 */ +/* 396 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -49376,14 +49602,14 @@ var AuditSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 393 */ +/* 397 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "auditTime", function() { return auditTime; }); /* harmony import */ var _scheduler_async__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(55); -/* harmony import */ var _audit__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(392); +/* harmony import */ var _audit__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(396); /* harmony import */ var _observable_timer__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(107); /** PURE_IMPORTS_START _scheduler_async,_audit,_observable_timer PURE_IMPORTS_END */ @@ -49399,7 +49625,7 @@ function auditTime(duration, scheduler) { /***/ }), -/* 394 */ +/* 398 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -49448,7 +49674,7 @@ var BufferSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 395 */ +/* 399 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -49549,7 +49775,7 @@ var BufferSkipCountSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 396 */ +/* 400 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -49710,7 +49936,7 @@ function dispatchBufferClose(arg) { /***/ }), -/* 397 */ +/* 401 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -49830,7 +50056,7 @@ var BufferToggleSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 398 */ +/* 402 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -49925,7 +50151,7 @@ var BufferWhenSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 399 */ +/* 403 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -49989,7 +50215,7 @@ var CatchSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 400 */ +/* 404 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -50005,7 +50231,7 @@ function combineAll(project) { /***/ }), -/* 401 */ +/* 405 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -50037,7 +50263,7 @@ function combineLatest() { /***/ }), -/* 402 */ +/* 406 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -50057,7 +50283,7 @@ function concat() { /***/ }), -/* 403 */ +/* 407 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -50073,13 +50299,13 @@ function concatMap(project, resultSelector) { /***/ }), -/* 404 */ +/* 408 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "concatMapTo", function() { return concatMapTo; }); -/* harmony import */ var _concatMap__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(403); +/* harmony import */ var _concatMap__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(407); /** PURE_IMPORTS_START _concatMap PURE_IMPORTS_END */ function concatMapTo(innerObservable, resultSelector) { @@ -50089,7 +50315,7 @@ function concatMapTo(innerObservable, resultSelector) { /***/ }), -/* 405 */ +/* 409 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -50154,7 +50380,7 @@ var CountSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 406 */ +/* 410 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -50242,7 +50468,7 @@ var DebounceSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 407 */ +/* 411 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -50318,7 +50544,7 @@ function dispatchNext(subscriber) { /***/ }), -/* 408 */ +/* 412 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -50368,7 +50594,7 @@ var DefaultIfEmptySubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 409 */ +/* 413 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -50376,7 +50602,7 @@ __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "delay", function() { return delay; }); /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); /* harmony import */ var _scheduler_async__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(55); -/* harmony import */ var _util_isDate__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(410); +/* harmony import */ var _util_isDate__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(414); /* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(11); /* harmony import */ var _Notification__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(42); /** PURE_IMPORTS_START tslib,_scheduler_async,_util_isDate,_Subscriber,_Notification PURE_IMPORTS_END */ @@ -50475,7 +50701,7 @@ var DelayMessage = /*@__PURE__*/ (function () { /***/ }), -/* 410 */ +/* 414 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -50489,7 +50715,7 @@ function isDate(value) { /***/ }), -/* 411 */ +/* 415 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -50635,7 +50861,7 @@ var SubscriptionDelaySubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 412 */ +/* 416 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -50673,7 +50899,7 @@ var DeMaterializeSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 413 */ +/* 417 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -50751,7 +50977,7 @@ var DistinctSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 414 */ +/* 418 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -50822,13 +51048,13 @@ var DistinctUntilChangedSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 415 */ +/* 419 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "distinctUntilKeyChanged", function() { return distinctUntilKeyChanged; }); -/* harmony import */ var _distinctUntilChanged__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(414); +/* harmony import */ var _distinctUntilChanged__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(418); /** PURE_IMPORTS_START _distinctUntilChanged PURE_IMPORTS_END */ function distinctUntilKeyChanged(key, compare) { @@ -50838,7 +51064,7 @@ function distinctUntilKeyChanged(key, compare) { /***/ }), -/* 416 */ +/* 420 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -50846,9 +51072,9 @@ __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "elementAt", function() { return elementAt; }); /* harmony import */ var _util_ArgumentOutOfRangeError__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(62); /* harmony import */ var _filter__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(104); -/* harmony import */ var _throwIfEmpty__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(417); -/* harmony import */ var _defaultIfEmpty__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(408); -/* harmony import */ var _take__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(418); +/* harmony import */ var _throwIfEmpty__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(421); +/* harmony import */ var _defaultIfEmpty__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(412); +/* harmony import */ var _take__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(422); /** PURE_IMPORTS_START _util_ArgumentOutOfRangeError,_filter,_throwIfEmpty,_defaultIfEmpty,_take PURE_IMPORTS_END */ @@ -50870,7 +51096,7 @@ function elementAt(index, defaultValue) { /***/ }), -/* 417 */ +/* 421 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -50936,7 +51162,7 @@ function defaultErrorFactory() { /***/ }), -/* 418 */ +/* 422 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -50998,7 +51224,7 @@ var TakeSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 419 */ +/* 423 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -51020,7 +51246,7 @@ function endWith() { /***/ }), -/* 420 */ +/* 424 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -51082,7 +51308,7 @@ var EverySubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 421 */ +/* 425 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -51139,7 +51365,7 @@ var SwitchFirstSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 422 */ +/* 426 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -51239,7 +51465,7 @@ var ExhaustMapSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 423 */ +/* 427 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -51358,7 +51584,7 @@ var ExpandSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 424 */ +/* 428 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -51396,7 +51622,7 @@ var FinallySubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 425 */ +/* 429 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -51468,13 +51694,13 @@ var FindValueSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 426 */ +/* 430 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "findIndex", function() { return findIndex; }); -/* harmony import */ var _operators_find__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(425); +/* harmony import */ var _operators_find__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(429); /** PURE_IMPORTS_START _operators_find PURE_IMPORTS_END */ function findIndex(predicate, thisArg) { @@ -51484,7 +51710,7 @@ function findIndex(predicate, thisArg) { /***/ }), -/* 427 */ +/* 431 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -51492,9 +51718,9 @@ __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "first", function() { return first; }); /* harmony import */ var _util_EmptyError__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(63); /* harmony import */ var _filter__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(104); -/* harmony import */ var _take__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(418); -/* harmony import */ var _defaultIfEmpty__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(408); -/* harmony import */ var _throwIfEmpty__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(417); +/* harmony import */ var _take__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(422); +/* harmony import */ var _defaultIfEmpty__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(412); +/* harmony import */ var _throwIfEmpty__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(421); /* harmony import */ var _util_identity__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(25); /** PURE_IMPORTS_START _util_EmptyError,_filter,_take,_defaultIfEmpty,_throwIfEmpty,_util_identity PURE_IMPORTS_END */ @@ -51511,7 +51737,7 @@ function first(predicate, defaultValue) { /***/ }), -/* 428 */ +/* 432 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -51548,7 +51774,7 @@ var IgnoreElementsSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 429 */ +/* 433 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -51592,7 +51818,7 @@ var IsEmptySubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 430 */ +/* 434 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -51600,9 +51826,9 @@ __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "last", function() { return last; }); /* harmony import */ var _util_EmptyError__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(63); /* harmony import */ var _filter__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(104); -/* harmony import */ var _takeLast__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(431); -/* harmony import */ var _throwIfEmpty__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(417); -/* harmony import */ var _defaultIfEmpty__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(408); +/* harmony import */ var _takeLast__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(435); +/* harmony import */ var _throwIfEmpty__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(421); +/* harmony import */ var _defaultIfEmpty__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(412); /* harmony import */ var _util_identity__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(25); /** PURE_IMPORTS_START _util_EmptyError,_filter,_takeLast,_throwIfEmpty,_defaultIfEmpty,_util_identity PURE_IMPORTS_END */ @@ -51619,7 +51845,7 @@ function last(predicate, defaultValue) { /***/ }), -/* 431 */ +/* 435 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -51696,7 +51922,7 @@ var TakeLastSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 432 */ +/* 436 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -51735,7 +51961,7 @@ var MapToSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 433 */ +/* 437 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -51785,13 +52011,13 @@ var MaterializeSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 434 */ +/* 438 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "max", function() { return max; }); -/* harmony import */ var _reduce__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(435); +/* harmony import */ var _reduce__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(439); /** PURE_IMPORTS_START _reduce PURE_IMPORTS_END */ function max(comparer) { @@ -51804,15 +52030,15 @@ function max(comparer) { /***/ }), -/* 435 */ +/* 439 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "reduce", function() { return reduce; }); -/* harmony import */ var _scan__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(436); -/* harmony import */ var _takeLast__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(431); -/* harmony import */ var _defaultIfEmpty__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(408); +/* harmony import */ var _scan__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(440); +/* harmony import */ var _takeLast__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(435); +/* harmony import */ var _defaultIfEmpty__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(412); /* harmony import */ var _util_pipe__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(24); /** PURE_IMPORTS_START _scan,_takeLast,_defaultIfEmpty,_util_pipe PURE_IMPORTS_END */ @@ -51833,7 +52059,7 @@ function reduce(accumulator, seed) { /***/ }), -/* 436 */ +/* 440 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -51915,7 +52141,7 @@ var ScanSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 437 */ +/* 441 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -51935,7 +52161,7 @@ function merge() { /***/ }), -/* 438 */ +/* 442 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -51960,7 +52186,7 @@ function mergeMapTo(innerObservable, resultSelector, concurrent) { /***/ }), -/* 439 */ +/* 443 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -52075,13 +52301,13 @@ var MergeScanSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 440 */ +/* 444 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "min", function() { return min; }); -/* harmony import */ var _reduce__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(435); +/* harmony import */ var _reduce__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(439); /** PURE_IMPORTS_START _reduce PURE_IMPORTS_END */ function min(comparer) { @@ -52094,7 +52320,7 @@ function min(comparer) { /***/ }), -/* 441 */ +/* 445 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -52143,7 +52369,7 @@ var MulticastOperator = /*@__PURE__*/ (function () { /***/ }), -/* 442 */ +/* 446 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -52237,7 +52463,7 @@ var OnErrorResumeNextSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 443 */ +/* 447 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -52285,7 +52511,7 @@ var PairwiseSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 444 */ +/* 448 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -52308,7 +52534,7 @@ function partition(predicate, thisArg) { /***/ }), -/* 445 */ +/* 449 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -52348,14 +52574,14 @@ function plucker(props, length) { /***/ }), -/* 446 */ +/* 450 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "publish", function() { return publish; }); /* harmony import */ var _Subject__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(27); -/* harmony import */ var _multicast__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(441); +/* harmony import */ var _multicast__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(445); /** PURE_IMPORTS_START _Subject,_multicast PURE_IMPORTS_END */ @@ -52368,14 +52594,14 @@ function publish(selector) { /***/ }), -/* 447 */ +/* 451 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "publishBehavior", function() { return publishBehavior; }); /* harmony import */ var _BehaviorSubject__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(32); -/* harmony import */ var _multicast__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(441); +/* harmony import */ var _multicast__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(445); /** PURE_IMPORTS_START _BehaviorSubject,_multicast PURE_IMPORTS_END */ @@ -52386,14 +52612,14 @@ function publishBehavior(value) { /***/ }), -/* 448 */ +/* 452 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "publishLast", function() { return publishLast; }); /* harmony import */ var _AsyncSubject__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(50); -/* harmony import */ var _multicast__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(441); +/* harmony import */ var _multicast__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(445); /** PURE_IMPORTS_START _AsyncSubject,_multicast PURE_IMPORTS_END */ @@ -52404,14 +52630,14 @@ function publishLast() { /***/ }), -/* 449 */ +/* 453 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "publishReplay", function() { return publishReplay; }); /* harmony import */ var _ReplaySubject__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(33); -/* harmony import */ var _multicast__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(441); +/* harmony import */ var _multicast__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(445); /** PURE_IMPORTS_START _ReplaySubject,_multicast PURE_IMPORTS_END */ @@ -52427,7 +52653,7 @@ function publishReplay(bufferSize, windowTime, selectorOrScheduler, scheduler) { /***/ }), -/* 450 */ +/* 454 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -52454,7 +52680,7 @@ function race() { /***/ }), -/* 451 */ +/* 455 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -52519,7 +52745,7 @@ var RepeatSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 452 */ +/* 456 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -52615,7 +52841,7 @@ var RepeatWhenSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 453 */ +/* 457 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -52668,7 +52894,7 @@ var RetrySubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 454 */ +/* 458 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -52756,7 +52982,7 @@ var RetryWhenSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 455 */ +/* 459 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -52813,7 +53039,7 @@ var SampleSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 456 */ +/* 460 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -52873,7 +53099,7 @@ function dispatchNotification(state) { /***/ }), -/* 457 */ +/* 461 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -52996,13 +53222,13 @@ var SequenceEqualCompareToSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 458 */ +/* 462 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "share", function() { return share; }); -/* harmony import */ var _multicast__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(441); +/* harmony import */ var _multicast__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(445); /* harmony import */ var _refCount__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(30); /* harmony import */ var _Subject__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(27); /** PURE_IMPORTS_START _multicast,_refCount,_Subject PURE_IMPORTS_END */ @@ -53019,7 +53245,7 @@ function share() { /***/ }), -/* 459 */ +/* 463 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -53084,7 +53310,7 @@ function shareReplayOperator(_a) { /***/ }), -/* 460 */ +/* 464 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -53164,7 +53390,7 @@ var SingleSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 461 */ +/* 465 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -53206,7 +53432,7 @@ var SkipSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 462 */ +/* 466 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -53268,7 +53494,7 @@ var SkipLastSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 463 */ +/* 467 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -53329,7 +53555,7 @@ var SkipUntilSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 464 */ +/* 468 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -53385,7 +53611,7 @@ var SkipWhileSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 465 */ +/* 469 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -53414,13 +53640,13 @@ function startWith() { /***/ }), -/* 466 */ +/* 470 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "subscribeOn", function() { return subscribeOn; }); -/* harmony import */ var _observable_SubscribeOnObservable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(467); +/* harmony import */ var _observable_SubscribeOnObservable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(471); /** PURE_IMPORTS_START _observable_SubscribeOnObservable PURE_IMPORTS_END */ function subscribeOn(scheduler, delay) { @@ -53445,7 +53671,7 @@ var SubscribeOnOperator = /*@__PURE__*/ (function () { /***/ }), -/* 467 */ +/* 471 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -53509,13 +53735,13 @@ var SubscribeOnObservable = /*@__PURE__*/ (function (_super) { /***/ }), -/* 468 */ +/* 472 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "switchAll", function() { return switchAll; }); -/* harmony import */ var _switchMap__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(469); +/* harmony import */ var _switchMap__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(473); /* harmony import */ var _util_identity__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(25); /** PURE_IMPORTS_START _switchMap,_util_identity PURE_IMPORTS_END */ @@ -53527,7 +53753,7 @@ function switchAll() { /***/ }), -/* 469 */ +/* 473 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -53621,13 +53847,13 @@ var SwitchMapSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 470 */ +/* 474 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "switchMapTo", function() { return switchMapTo; }); -/* harmony import */ var _switchMap__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(469); +/* harmony import */ var _switchMap__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(473); /** PURE_IMPORTS_START _switchMap PURE_IMPORTS_END */ function switchMapTo(innerObservable, resultSelector) { @@ -53637,7 +53863,7 @@ function switchMapTo(innerObservable, resultSelector) { /***/ }), -/* 471 */ +/* 475 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -53687,7 +53913,7 @@ var TakeUntilSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 472 */ +/* 476 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -53755,7 +53981,7 @@ var TakeWhileSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 473 */ +/* 477 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -53843,7 +54069,7 @@ var TapSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 474 */ +/* 478 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -53947,7 +54173,7 @@ var ThrottleSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 475 */ +/* 479 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -53956,7 +54182,7 @@ __webpack_require__.r(__webpack_exports__); /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); /* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(11); /* harmony import */ var _scheduler_async__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(55); -/* harmony import */ var _throttle__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(474); +/* harmony import */ var _throttle__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(478); /** PURE_IMPORTS_START tslib,_Subscriber,_scheduler_async,_throttle PURE_IMPORTS_END */ @@ -54045,7 +54271,7 @@ function dispatchNext(arg) { /***/ }), -/* 476 */ +/* 480 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -54053,7 +54279,7 @@ __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "timeInterval", function() { return timeInterval; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TimeInterval", function() { return TimeInterval; }); /* harmony import */ var _scheduler_async__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(55); -/* harmony import */ var _scan__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(436); +/* harmony import */ var _scan__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(440); /* harmony import */ var _observable_defer__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(90); /* harmony import */ var _map__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(66); /** PURE_IMPORTS_START _scheduler_async,_scan,_observable_defer,_map PURE_IMPORTS_END */ @@ -54089,7 +54315,7 @@ var TimeInterval = /*@__PURE__*/ (function () { /***/ }), -/* 477 */ +/* 481 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -54097,7 +54323,7 @@ __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "timeout", function() { return timeout; }); /* harmony import */ var _scheduler_async__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(55); /* harmony import */ var _util_TimeoutError__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(64); -/* harmony import */ var _timeoutWith__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(478); +/* harmony import */ var _timeoutWith__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(482); /* harmony import */ var _observable_throwError__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(49); /** PURE_IMPORTS_START _scheduler_async,_util_TimeoutError,_timeoutWith,_observable_throwError PURE_IMPORTS_END */ @@ -54114,7 +54340,7 @@ function timeout(due, scheduler) { /***/ }), -/* 478 */ +/* 482 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -54122,7 +54348,7 @@ __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "timeoutWith", function() { return timeoutWith; }); /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); /* harmony import */ var _scheduler_async__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(55); -/* harmony import */ var _util_isDate__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(410); +/* harmony import */ var _util_isDate__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(414); /* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(69); /* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(70); /** PURE_IMPORTS_START tslib,_scheduler_async,_util_isDate,_OuterSubscriber,_util_subscribeToResult PURE_IMPORTS_END */ @@ -54196,7 +54422,7 @@ var TimeoutWithSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 479 */ +/* 483 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -54226,13 +54452,13 @@ var Timestamp = /*@__PURE__*/ (function () { /***/ }), -/* 480 */ +/* 484 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "toArray", function() { return toArray; }); -/* harmony import */ var _reduce__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(435); +/* harmony import */ var _reduce__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(439); /** PURE_IMPORTS_START _reduce PURE_IMPORTS_END */ function toArrayReducer(arr, item, index) { @@ -54249,7 +54475,7 @@ function toArray() { /***/ }), -/* 481 */ +/* 485 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -54329,7 +54555,7 @@ var WindowSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 482 */ +/* 486 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -54419,7 +54645,7 @@ var WindowCountSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 483 */ +/* 487 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -54589,7 +54815,7 @@ function dispatchWindowClose(state) { /***/ }), -/* 484 */ +/* 488 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -54732,7 +54958,7 @@ var WindowToggleSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 485 */ +/* 489 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -54829,7 +55055,7 @@ var WindowSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 486 */ +/* 490 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -54924,7 +55150,7 @@ var WithLatestFromSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 487 */ +/* 491 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -54946,7 +55172,7 @@ function zip() { /***/ }), -/* 488 */ +/* 492 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -54962,7 +55188,7 @@ function zipAll(project) { /***/ }), -/* 489 */ +/* 493 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -54971,8 +55197,8 @@ __webpack_require__.r(__webpack_exports__); /* harmony import */ var _utils_errors__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); /* harmony import */ var _utils_log__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(143); /* harmony import */ var _utils_projects__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(145); -/* harmony import */ var _utils_projects_tree__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(490); -/* harmony import */ var _utils_kibana__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(491); +/* harmony import */ var _utils_projects_tree__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(494); +/* harmony import */ var _utils_kibana__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(495); function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } @@ -55054,13 +55280,13 @@ function toArray(value) { } /***/ }), -/* 490 */ +/* 494 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "renderProjectsTree", function() { return renderProjectsTree; }); -/* harmony import */ var chalk__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(227); +/* harmony import */ var chalk__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(112); /* harmony import */ var chalk__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(chalk__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(4); /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_1__); @@ -55207,7 +55433,7 @@ function addProjectToTree(tree, pathParts, project) { } /***/ }), -/* 491 */ +/* 495 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -55215,13 +55441,13 @@ __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Kibana", function() { return Kibana; }); /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(4); /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_0__); -/* harmony import */ var multimatch__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(492); +/* harmony import */ var multimatch__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(496); /* harmony import */ var multimatch__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(multimatch__WEBPACK_IMPORTED_MODULE_1__); -/* harmony import */ var is_path_inside__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(366); +/* harmony import */ var is_path_inside__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(361); /* harmony import */ var is_path_inside__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(is_path_inside__WEBPACK_IMPORTED_MODULE_2__); -/* harmony import */ var _yarn_lock__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(279); +/* harmony import */ var _yarn_lock__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(274); /* harmony import */ var _projects__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(145); -/* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(276); +/* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(271); function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } @@ -55383,15 +55609,15 @@ class Kibana { } /***/ }), -/* 492 */ +/* 496 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const minimatch = __webpack_require__(149); -const arrayUnion = __webpack_require__(493); -const arrayDiffer = __webpack_require__(494); -const arrify = __webpack_require__(495); +const arrayUnion = __webpack_require__(497); +const arrayDiffer = __webpack_require__(498); +const arrify = __webpack_require__(499); module.exports = (list, patterns, options = {}) => { list = arrify(list); @@ -55415,7 +55641,7 @@ module.exports = (list, patterns, options = {}) => { /***/ }), -/* 493 */ +/* 497 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -55427,7 +55653,7 @@ module.exports = (...arguments_) => { /***/ }), -/* 494 */ +/* 498 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -55442,7 +55668,7 @@ module.exports = arrayDiffer; /***/ }), -/* 495 */ +/* 499 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -55472,12 +55698,12 @@ module.exports = arrify; /***/ }), -/* 496 */ +/* 500 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); -/* harmony import */ var _build_production_projects__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(497); +/* harmony import */ var _build_production_projects__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(501); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "buildProductionProjects", function() { return _build_production_projects__WEBPACK_IMPORTED_MODULE_0__["buildProductionProjects"]; }); /* @@ -55501,19 +55727,19 @@ __webpack_require__.r(__webpack_exports__); /***/ }), -/* 497 */ +/* 501 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "buildProductionProjects", function() { return buildProductionProjects; }); -/* harmony import */ var cpy__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(498); +/* harmony import */ var cpy__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(502); /* harmony import */ var cpy__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(cpy__WEBPACK_IMPORTED_MODULE_0__); -/* harmony import */ var del__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(285); +/* harmony import */ var del__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(280); /* harmony import */ var del__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(del__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(4); /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_2__); -/* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(276); +/* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(271); /* harmony import */ var _utils_fs__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(130); /* harmony import */ var _utils_log__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(143); /* harmony import */ var _utils_package_json__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(164); @@ -55649,7 +55875,7 @@ async function copyToBuild(project, kibanaRoot, buildRoot) { } /***/ }), -/* 498 */ +/* 502 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -55657,13 +55883,13 @@ async function copyToBuild(project, kibanaRoot, buildRoot) { const EventEmitter = __webpack_require__(155); const path = __webpack_require__(4); const os = __webpack_require__(120); -const pAll = __webpack_require__(499); -const arrify = __webpack_require__(501); -const globby = __webpack_require__(502); -const isGlob = __webpack_require__(700); -const cpFile = __webpack_require__(701); -const junk = __webpack_require__(713); -const CpyError = __webpack_require__(714); +const pAll = __webpack_require__(503); +const arrify = __webpack_require__(505); +const globby = __webpack_require__(506); +const isGlob = __webpack_require__(704); +const cpFile = __webpack_require__(705); +const junk = __webpack_require__(717); +const CpyError = __webpack_require__(718); const defaultOptions = { ignoreJunk: true @@ -55782,12 +56008,12 @@ module.exports = (source, destination, { /***/ }), -/* 499 */ +/* 503 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const pMap = __webpack_require__(500); +const pMap = __webpack_require__(504); module.exports = (iterable, options) => pMap(iterable, element => element(), options); // TODO: Remove this for the next major release @@ -55795,7 +56021,7 @@ module.exports.default = module.exports; /***/ }), -/* 500 */ +/* 504 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -55874,7 +56100,7 @@ module.exports.default = pMap; /***/ }), -/* 501 */ +/* 505 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -55904,17 +56130,17 @@ module.exports = arrify; /***/ }), -/* 502 */ +/* 506 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const fs = __webpack_require__(133); -const arrayUnion = __webpack_require__(503); +const arrayUnion = __webpack_require__(507); const glob = __webpack_require__(146); -const fastGlob = __webpack_require__(505); -const dirGlob = __webpack_require__(693); -const gitignore = __webpack_require__(696); +const fastGlob = __webpack_require__(509); +const dirGlob = __webpack_require__(697); +const gitignore = __webpack_require__(700); const DEFAULT_FILTER = () => false; @@ -56059,12 +56285,12 @@ module.exports.gitignore = gitignore; /***/ }), -/* 503 */ +/* 507 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var arrayUniq = __webpack_require__(504); +var arrayUniq = __webpack_require__(508); module.exports = function () { return arrayUniq([].concat.apply([], arguments)); @@ -56072,7 +56298,7 @@ module.exports = function () { /***/ }), -/* 504 */ +/* 508 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -56141,10 +56367,10 @@ if ('Set' in global) { /***/ }), -/* 505 */ +/* 509 */ /***/ (function(module, exports, __webpack_require__) { -const pkg = __webpack_require__(506); +const pkg = __webpack_require__(510); module.exports = pkg.async; module.exports.default = pkg.async; @@ -56157,19 +56383,19 @@ module.exports.generateTasks = pkg.generateTasks; /***/ }), -/* 506 */ +/* 510 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -var optionsManager = __webpack_require__(507); -var taskManager = __webpack_require__(508); -var reader_async_1 = __webpack_require__(664); -var reader_stream_1 = __webpack_require__(688); -var reader_sync_1 = __webpack_require__(689); -var arrayUtils = __webpack_require__(691); -var streamUtils = __webpack_require__(692); +var optionsManager = __webpack_require__(511); +var taskManager = __webpack_require__(512); +var reader_async_1 = __webpack_require__(668); +var reader_stream_1 = __webpack_require__(692); +var reader_sync_1 = __webpack_require__(693); +var arrayUtils = __webpack_require__(695); +var streamUtils = __webpack_require__(696); /** * Synchronous API. */ @@ -56235,7 +56461,7 @@ function isString(source) { /***/ }), -/* 507 */ +/* 511 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -56273,13 +56499,13 @@ exports.prepare = prepare; /***/ }), -/* 508 */ +/* 512 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -var patternUtils = __webpack_require__(509); +var patternUtils = __webpack_require__(513); /** * Generate tasks based on parent directory of each pattern. */ @@ -56370,16 +56596,16 @@ exports.convertPatternGroupToTask = convertPatternGroupToTask; /***/ }), -/* 509 */ +/* 513 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var path = __webpack_require__(4); -var globParent = __webpack_require__(510); -var isGlob = __webpack_require__(513); -var micromatch = __webpack_require__(514); +var globParent = __webpack_require__(514); +var isGlob = __webpack_require__(517); +var micromatch = __webpack_require__(518); var GLOBSTAR = '**'; /** * Return true for static pattern. @@ -56525,15 +56751,15 @@ exports.matchAny = matchAny; /***/ }), -/* 510 */ +/* 514 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var path = __webpack_require__(4); -var isglob = __webpack_require__(511); -var pathDirname = __webpack_require__(512); +var isglob = __webpack_require__(515); +var pathDirname = __webpack_require__(516); var isWin32 = __webpack_require__(120).platform() === 'win32'; module.exports = function globParent(str) { @@ -56556,7 +56782,7 @@ module.exports = function globParent(str) { /***/ }), -/* 511 */ +/* 515 */ /***/ (function(module, exports, __webpack_require__) { /*! @@ -56566,7 +56792,7 @@ module.exports = function globParent(str) { * Licensed under the MIT License. */ -var isExtglob = __webpack_require__(299); +var isExtglob = __webpack_require__(294); module.exports = function isGlob(str) { if (typeof str !== 'string' || str === '') { @@ -56587,7 +56813,7 @@ module.exports = function isGlob(str) { /***/ }), -/* 512 */ +/* 516 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -56737,7 +56963,7 @@ module.exports.win32 = win32; /***/ }), -/* 513 */ +/* 517 */ /***/ (function(module, exports, __webpack_require__) { /*! @@ -56747,7 +56973,7 @@ module.exports.win32 = win32; * Released under the MIT License. */ -var isExtglob = __webpack_require__(299); +var isExtglob = __webpack_require__(294); var chars = { '{': '}', '(': ')', '[': ']'}; module.exports = function isGlob(str, options) { @@ -56789,7 +57015,7 @@ module.exports = function isGlob(str, options) { /***/ }), -/* 514 */ +/* 518 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -56800,18 +57026,18 @@ module.exports = function isGlob(str, options) { */ var util = __webpack_require__(111); -var braces = __webpack_require__(515); -var toRegex = __webpack_require__(617); -var extend = __webpack_require__(625); +var braces = __webpack_require__(519); +var toRegex = __webpack_require__(621); +var extend = __webpack_require__(629); /** * Local dependencies */ -var compilers = __webpack_require__(628); -var parsers = __webpack_require__(660); -var cache = __webpack_require__(661); -var utils = __webpack_require__(662); +var compilers = __webpack_require__(632); +var parsers = __webpack_require__(664); +var cache = __webpack_require__(665); +var utils = __webpack_require__(666); var MAX_LENGTH = 1024 * 64; /** @@ -57673,7 +57899,7 @@ module.exports = micromatch; /***/ }), -/* 515 */ +/* 519 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -57683,18 +57909,18 @@ module.exports = micromatch; * Module dependencies */ -var toRegex = __webpack_require__(516); -var unique = __webpack_require__(528); -var extend = __webpack_require__(525); +var toRegex = __webpack_require__(520); +var unique = __webpack_require__(532); +var extend = __webpack_require__(529); /** * Local dependencies */ -var compilers = __webpack_require__(529); -var parsers = __webpack_require__(544); -var Braces = __webpack_require__(554); -var utils = __webpack_require__(530); +var compilers = __webpack_require__(533); +var parsers = __webpack_require__(548); +var Braces = __webpack_require__(558); +var utils = __webpack_require__(534); var MAX_LENGTH = 1024 * 64; var cache = {}; @@ -57998,15 +58224,15 @@ module.exports = braces; /***/ }), -/* 516 */ +/* 520 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var define = __webpack_require__(517); -var extend = __webpack_require__(525); -var not = __webpack_require__(527); +var define = __webpack_require__(521); +var extend = __webpack_require__(529); +var not = __webpack_require__(531); var MAX_LENGTH = 1024 * 64; /** @@ -58153,7 +58379,7 @@ module.exports.makeRe = makeRe; /***/ }), -/* 517 */ +/* 521 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -58166,7 +58392,7 @@ module.exports.makeRe = makeRe; -var isDescriptor = __webpack_require__(518); +var isDescriptor = __webpack_require__(522); module.exports = function defineProperty(obj, prop, val) { if (typeof obj !== 'object' && typeof obj !== 'function') { @@ -58191,7 +58417,7 @@ module.exports = function defineProperty(obj, prop, val) { /***/ }), -/* 518 */ +/* 522 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -58204,9 +58430,9 @@ module.exports = function defineProperty(obj, prop, val) { -var typeOf = __webpack_require__(519); -var isAccessor = __webpack_require__(520); -var isData = __webpack_require__(523); +var typeOf = __webpack_require__(523); +var isAccessor = __webpack_require__(524); +var isData = __webpack_require__(527); module.exports = function isDescriptor(obj, key) { if (typeOf(obj) !== 'object') { @@ -58220,7 +58446,7 @@ module.exports = function isDescriptor(obj, key) { /***/ }), -/* 519 */ +/* 523 */ /***/ (function(module, exports) { var toString = Object.prototype.toString; @@ -58373,7 +58599,7 @@ function isBuffer(val) { /***/ }), -/* 520 */ +/* 524 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -58386,7 +58612,7 @@ function isBuffer(val) { -var typeOf = __webpack_require__(521); +var typeOf = __webpack_require__(525); // accessor descriptor properties var accessor = { @@ -58449,10 +58675,10 @@ module.exports = isAccessorDescriptor; /***/ }), -/* 521 */ +/* 525 */ /***/ (function(module, exports, __webpack_require__) { -var isBuffer = __webpack_require__(522); +var isBuffer = __webpack_require__(526); var toString = Object.prototype.toString; /** @@ -58571,7 +58797,7 @@ module.exports = function kindOf(val) { /***/ }), -/* 522 */ +/* 526 */ /***/ (function(module, exports) { /*! @@ -58598,7 +58824,7 @@ function isSlowBuffer (obj) { /***/ }), -/* 523 */ +/* 527 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -58611,7 +58837,7 @@ function isSlowBuffer (obj) { -var typeOf = __webpack_require__(524); +var typeOf = __webpack_require__(528); // data descriptor properties var data = { @@ -58660,10 +58886,10 @@ module.exports = isDataDescriptor; /***/ }), -/* 524 */ +/* 528 */ /***/ (function(module, exports, __webpack_require__) { -var isBuffer = __webpack_require__(522); +var isBuffer = __webpack_require__(526); var toString = Object.prototype.toString; /** @@ -58782,13 +59008,13 @@ module.exports = function kindOf(val) { /***/ }), -/* 525 */ +/* 529 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isObject = __webpack_require__(526); +var isObject = __webpack_require__(530); module.exports = function extend(o/*, objects*/) { if (!isObject(o)) { o = {}; } @@ -58822,7 +59048,7 @@ function hasOwn(obj, key) { /***/ }), -/* 526 */ +/* 530 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -58842,13 +59068,13 @@ module.exports = function isExtendable(val) { /***/ }), -/* 527 */ +/* 531 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var extend = __webpack_require__(525); +var extend = __webpack_require__(529); /** * The main export is a function that takes a `pattern` string and an `options` object. @@ -58915,7 +59141,7 @@ module.exports = toRegex; /***/ }), -/* 528 */ +/* 532 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -58965,13 +59191,13 @@ module.exports.immutable = function uniqueImmutable(arr) { /***/ }), -/* 529 */ +/* 533 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var utils = __webpack_require__(530); +var utils = __webpack_require__(534); module.exports = function(braces, options) { braces.compiler @@ -59254,25 +59480,25 @@ function hasQueue(node) { /***/ }), -/* 530 */ +/* 534 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var splitString = __webpack_require__(531); +var splitString = __webpack_require__(535); var utils = module.exports; /** * Module dependencies */ -utils.extend = __webpack_require__(525); -utils.flatten = __webpack_require__(537); -utils.isObject = __webpack_require__(535); -utils.fillRange = __webpack_require__(538); -utils.repeat = __webpack_require__(543); -utils.unique = __webpack_require__(528); +utils.extend = __webpack_require__(529); +utils.flatten = __webpack_require__(541); +utils.isObject = __webpack_require__(539); +utils.fillRange = __webpack_require__(542); +utils.repeat = __webpack_require__(547); +utils.unique = __webpack_require__(532); utils.define = function(obj, key, val) { Object.defineProperty(obj, key, { @@ -59604,7 +59830,7 @@ utils.escapeRegex = function(str) { /***/ }), -/* 531 */ +/* 535 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -59617,7 +59843,7 @@ utils.escapeRegex = function(str) { -var extend = __webpack_require__(532); +var extend = __webpack_require__(536); module.exports = function(str, options, fn) { if (typeof str !== 'string') { @@ -59782,14 +60008,14 @@ function keepEscaping(opts, str, idx) { /***/ }), -/* 532 */ +/* 536 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isExtendable = __webpack_require__(533); -var assignSymbols = __webpack_require__(536); +var isExtendable = __webpack_require__(537); +var assignSymbols = __webpack_require__(540); module.exports = Object.assign || function(obj/*, objects*/) { if (obj === null || typeof obj === 'undefined') { @@ -59849,7 +60075,7 @@ function isEnum(obj, key) { /***/ }), -/* 533 */ +/* 537 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -59862,7 +60088,7 @@ function isEnum(obj, key) { -var isPlainObject = __webpack_require__(534); +var isPlainObject = __webpack_require__(538); module.exports = function isExtendable(val) { return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); @@ -59870,7 +60096,7 @@ module.exports = function isExtendable(val) { /***/ }), -/* 534 */ +/* 538 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -59883,7 +60109,7 @@ module.exports = function isExtendable(val) { -var isObject = __webpack_require__(535); +var isObject = __webpack_require__(539); function isObjectObject(o) { return isObject(o) === true @@ -59914,7 +60140,7 @@ module.exports = function isPlainObject(o) { /***/ }), -/* 535 */ +/* 539 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -59933,7 +60159,7 @@ module.exports = function isObject(val) { /***/ }), -/* 536 */ +/* 540 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -59980,7 +60206,7 @@ module.exports = function(receiver, objects) { /***/ }), -/* 537 */ +/* 541 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -60009,7 +60235,7 @@ function flat(arr, res) { /***/ }), -/* 538 */ +/* 542 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -60023,10 +60249,10 @@ function flat(arr, res) { var util = __webpack_require__(111); -var isNumber = __webpack_require__(539); -var extend = __webpack_require__(525); -var repeat = __webpack_require__(541); -var toRegex = __webpack_require__(542); +var isNumber = __webpack_require__(543); +var extend = __webpack_require__(529); +var repeat = __webpack_require__(545); +var toRegex = __webpack_require__(546); /** * Return a range of numbers or letters. @@ -60224,7 +60450,7 @@ module.exports = fillRange; /***/ }), -/* 539 */ +/* 543 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -60237,7 +60463,7 @@ module.exports = fillRange; -var typeOf = __webpack_require__(540); +var typeOf = __webpack_require__(544); module.exports = function isNumber(num) { var type = typeOf(num); @@ -60253,10 +60479,10 @@ module.exports = function isNumber(num) { /***/ }), -/* 540 */ +/* 544 */ /***/ (function(module, exports, __webpack_require__) { -var isBuffer = __webpack_require__(522); +var isBuffer = __webpack_require__(526); var toString = Object.prototype.toString; /** @@ -60375,7 +60601,7 @@ module.exports = function kindOf(val) { /***/ }), -/* 541 */ +/* 545 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -60452,7 +60678,7 @@ function repeat(str, num) { /***/ }), -/* 542 */ +/* 546 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -60465,8 +60691,8 @@ function repeat(str, num) { -var repeat = __webpack_require__(541); -var isNumber = __webpack_require__(539); +var repeat = __webpack_require__(545); +var isNumber = __webpack_require__(543); var cache = {}; function toRegexRange(min, max, options) { @@ -60753,7 +60979,7 @@ module.exports = toRegexRange; /***/ }), -/* 543 */ +/* 547 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -60778,14 +61004,14 @@ module.exports = function repeat(ele, num) { /***/ }), -/* 544 */ +/* 548 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var Node = __webpack_require__(545); -var utils = __webpack_require__(530); +var Node = __webpack_require__(549); +var utils = __webpack_require__(534); /** * Braces parsers @@ -61145,15 +61371,15 @@ function concatNodes(pos, node, parent, options) { /***/ }), -/* 545 */ +/* 549 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isObject = __webpack_require__(535); -var define = __webpack_require__(546); -var utils = __webpack_require__(553); +var isObject = __webpack_require__(539); +var define = __webpack_require__(550); +var utils = __webpack_require__(557); var ownNames; /** @@ -61644,7 +61870,7 @@ exports = module.exports = Node; /***/ }), -/* 546 */ +/* 550 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -61657,7 +61883,7 @@ exports = module.exports = Node; -var isDescriptor = __webpack_require__(547); +var isDescriptor = __webpack_require__(551); module.exports = function defineProperty(obj, prop, val) { if (typeof obj !== 'object' && typeof obj !== 'function') { @@ -61682,7 +61908,7 @@ module.exports = function defineProperty(obj, prop, val) { /***/ }), -/* 547 */ +/* 551 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -61695,9 +61921,9 @@ module.exports = function defineProperty(obj, prop, val) { -var typeOf = __webpack_require__(548); -var isAccessor = __webpack_require__(549); -var isData = __webpack_require__(551); +var typeOf = __webpack_require__(552); +var isAccessor = __webpack_require__(553); +var isData = __webpack_require__(555); module.exports = function isDescriptor(obj, key) { if (typeOf(obj) !== 'object') { @@ -61711,7 +61937,7 @@ module.exports = function isDescriptor(obj, key) { /***/ }), -/* 548 */ +/* 552 */ /***/ (function(module, exports) { var toString = Object.prototype.toString; @@ -61846,7 +62072,7 @@ function isBuffer(val) { /***/ }), -/* 549 */ +/* 553 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -61859,7 +62085,7 @@ function isBuffer(val) { -var typeOf = __webpack_require__(550); +var typeOf = __webpack_require__(554); // accessor descriptor properties var accessor = { @@ -61922,7 +62148,7 @@ module.exports = isAccessorDescriptor; /***/ }), -/* 550 */ +/* 554 */ /***/ (function(module, exports) { var toString = Object.prototype.toString; @@ -62057,7 +62283,7 @@ function isBuffer(val) { /***/ }), -/* 551 */ +/* 555 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -62070,7 +62296,7 @@ function isBuffer(val) { -var typeOf = __webpack_require__(552); +var typeOf = __webpack_require__(556); module.exports = function isDataDescriptor(obj, prop) { // data descriptor properties @@ -62113,7 +62339,7 @@ module.exports = function isDataDescriptor(obj, prop) { /***/ }), -/* 552 */ +/* 556 */ /***/ (function(module, exports) { var toString = Object.prototype.toString; @@ -62248,13 +62474,13 @@ function isBuffer(val) { /***/ }), -/* 553 */ +/* 557 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var typeOf = __webpack_require__(540); +var typeOf = __webpack_require__(544); var utils = module.exports; /** @@ -63274,17 +63500,17 @@ function assert(val, message) { /***/ }), -/* 554 */ +/* 558 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var extend = __webpack_require__(525); -var Snapdragon = __webpack_require__(555); -var compilers = __webpack_require__(529); -var parsers = __webpack_require__(544); -var utils = __webpack_require__(530); +var extend = __webpack_require__(529); +var Snapdragon = __webpack_require__(559); +var compilers = __webpack_require__(533); +var parsers = __webpack_require__(548); +var utils = __webpack_require__(534); /** * Customize Snapdragon parser and renderer @@ -63385,17 +63611,17 @@ module.exports = Braces; /***/ }), -/* 555 */ +/* 559 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var Base = __webpack_require__(556); -var define = __webpack_require__(517); -var Compiler = __webpack_require__(585); -var Parser = __webpack_require__(614); -var utils = __webpack_require__(594); +var Base = __webpack_require__(560); +var define = __webpack_require__(521); +var Compiler = __webpack_require__(589); +var Parser = __webpack_require__(618); +var utils = __webpack_require__(598); var regexCache = {}; var cache = {}; @@ -63566,20 +63792,20 @@ module.exports.Parser = Parser; /***/ }), -/* 556 */ +/* 560 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var util = __webpack_require__(111); -var define = __webpack_require__(557); -var CacheBase = __webpack_require__(558); -var Emitter = __webpack_require__(559); -var isObject = __webpack_require__(535); -var merge = __webpack_require__(576); -var pascal = __webpack_require__(579); -var cu = __webpack_require__(580); +var define = __webpack_require__(561); +var CacheBase = __webpack_require__(562); +var Emitter = __webpack_require__(563); +var isObject = __webpack_require__(539); +var merge = __webpack_require__(580); +var pascal = __webpack_require__(583); +var cu = __webpack_require__(584); /** * Optionally define a custom `cache` namespace to use. @@ -64008,7 +64234,7 @@ module.exports.namespace = namespace; /***/ }), -/* 557 */ +/* 561 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -64021,7 +64247,7 @@ module.exports.namespace = namespace; -var isDescriptor = __webpack_require__(547); +var isDescriptor = __webpack_require__(551); module.exports = function defineProperty(obj, prop, val) { if (typeof obj !== 'object' && typeof obj !== 'function') { @@ -64046,21 +64272,21 @@ module.exports = function defineProperty(obj, prop, val) { /***/ }), -/* 558 */ +/* 562 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isObject = __webpack_require__(535); -var Emitter = __webpack_require__(559); -var visit = __webpack_require__(560); -var toPath = __webpack_require__(563); -var union = __webpack_require__(564); -var del = __webpack_require__(568); -var get = __webpack_require__(566); -var has = __webpack_require__(573); -var set = __webpack_require__(567); +var isObject = __webpack_require__(539); +var Emitter = __webpack_require__(563); +var visit = __webpack_require__(564); +var toPath = __webpack_require__(567); +var union = __webpack_require__(568); +var del = __webpack_require__(572); +var get = __webpack_require__(570); +var has = __webpack_require__(577); +var set = __webpack_require__(571); /** * Create a `Cache` constructor that when instantiated will @@ -64314,7 +64540,7 @@ module.exports.namespace = namespace; /***/ }), -/* 559 */ +/* 563 */ /***/ (function(module, exports, __webpack_require__) { @@ -64483,7 +64709,7 @@ Emitter.prototype.hasListeners = function(event){ /***/ }), -/* 560 */ +/* 564 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -64496,8 +64722,8 @@ Emitter.prototype.hasListeners = function(event){ -var visit = __webpack_require__(561); -var mapVisit = __webpack_require__(562); +var visit = __webpack_require__(565); +var mapVisit = __webpack_require__(566); module.exports = function(collection, method, val) { var result; @@ -64520,7 +64746,7 @@ module.exports = function(collection, method, val) { /***/ }), -/* 561 */ +/* 565 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -64533,7 +64759,7 @@ module.exports = function(collection, method, val) { -var isObject = __webpack_require__(535); +var isObject = __webpack_require__(539); module.exports = function visit(thisArg, method, target, val) { if (!isObject(thisArg) && typeof thisArg !== 'function') { @@ -64560,14 +64786,14 @@ module.exports = function visit(thisArg, method, target, val) { /***/ }), -/* 562 */ +/* 566 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var util = __webpack_require__(111); -var visit = __webpack_require__(561); +var visit = __webpack_require__(565); /** * Map `visit` over an array of objects. @@ -64604,7 +64830,7 @@ function isObject(val) { /***/ }), -/* 563 */ +/* 567 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -64617,7 +64843,7 @@ function isObject(val) { -var typeOf = __webpack_require__(540); +var typeOf = __webpack_require__(544); module.exports = function toPath(args) { if (typeOf(args) !== 'arguments') { @@ -64644,16 +64870,16 @@ function filter(arr) { /***/ }), -/* 564 */ +/* 568 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isObject = __webpack_require__(526); -var union = __webpack_require__(565); -var get = __webpack_require__(566); -var set = __webpack_require__(567); +var isObject = __webpack_require__(530); +var union = __webpack_require__(569); +var get = __webpack_require__(570); +var set = __webpack_require__(571); module.exports = function unionValue(obj, prop, value) { if (!isObject(obj)) { @@ -64681,7 +64907,7 @@ function arrayify(val) { /***/ }), -/* 565 */ +/* 569 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -64717,7 +64943,7 @@ module.exports = function union(init) { /***/ }), -/* 566 */ +/* 570 */ /***/ (function(module, exports) { /*! @@ -64773,7 +64999,7 @@ function toString(val) { /***/ }), -/* 567 */ +/* 571 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -64786,10 +65012,10 @@ function toString(val) { -var split = __webpack_require__(531); -var extend = __webpack_require__(525); -var isPlainObject = __webpack_require__(534); -var isObject = __webpack_require__(526); +var split = __webpack_require__(535); +var extend = __webpack_require__(529); +var isPlainObject = __webpack_require__(538); +var isObject = __webpack_require__(530); module.exports = function(obj, prop, val) { if (!isObject(obj)) { @@ -64835,7 +65061,7 @@ function isValidKey(key) { /***/ }), -/* 568 */ +/* 572 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -64848,8 +65074,8 @@ function isValidKey(key) { -var isObject = __webpack_require__(535); -var has = __webpack_require__(569); +var isObject = __webpack_require__(539); +var has = __webpack_require__(573); module.exports = function unset(obj, prop) { if (!isObject(obj)) { @@ -64874,7 +65100,7 @@ module.exports = function unset(obj, prop) { /***/ }), -/* 569 */ +/* 573 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -64887,9 +65113,9 @@ module.exports = function unset(obj, prop) { -var isObject = __webpack_require__(570); -var hasValues = __webpack_require__(572); -var get = __webpack_require__(566); +var isObject = __webpack_require__(574); +var hasValues = __webpack_require__(576); +var get = __webpack_require__(570); module.exports = function(obj, prop, noZero) { if (isObject(obj)) { @@ -64900,7 +65126,7 @@ module.exports = function(obj, prop, noZero) { /***/ }), -/* 570 */ +/* 574 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -64913,7 +65139,7 @@ module.exports = function(obj, prop, noZero) { -var isArray = __webpack_require__(571); +var isArray = __webpack_require__(575); module.exports = function isObject(val) { return val != null && typeof val === 'object' && isArray(val) === false; @@ -64921,7 +65147,7 @@ module.exports = function isObject(val) { /***/ }), -/* 571 */ +/* 575 */ /***/ (function(module, exports) { var toString = {}.toString; @@ -64932,7 +65158,7 @@ module.exports = Array.isArray || function (arr) { /***/ }), -/* 572 */ +/* 576 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -64975,7 +65201,7 @@ module.exports = function hasValue(o, noZero) { /***/ }), -/* 573 */ +/* 577 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -64988,9 +65214,9 @@ module.exports = function hasValue(o, noZero) { -var isObject = __webpack_require__(535); -var hasValues = __webpack_require__(574); -var get = __webpack_require__(566); +var isObject = __webpack_require__(539); +var hasValues = __webpack_require__(578); +var get = __webpack_require__(570); module.exports = function(val, prop) { return hasValues(isObject(val) && prop ? get(val, prop) : val); @@ -64998,7 +65224,7 @@ module.exports = function(val, prop) { /***/ }), -/* 574 */ +/* 578 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -65011,8 +65237,8 @@ module.exports = function(val, prop) { -var typeOf = __webpack_require__(575); -var isNumber = __webpack_require__(539); +var typeOf = __webpack_require__(579); +var isNumber = __webpack_require__(543); module.exports = function hasValue(val) { // is-number checks for NaN and other edge cases @@ -65065,10 +65291,10 @@ module.exports = function hasValue(val) { /***/ }), -/* 575 */ +/* 579 */ /***/ (function(module, exports, __webpack_require__) { -var isBuffer = __webpack_require__(522); +var isBuffer = __webpack_require__(526); var toString = Object.prototype.toString; /** @@ -65190,14 +65416,14 @@ module.exports = function kindOf(val) { /***/ }), -/* 576 */ +/* 580 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isExtendable = __webpack_require__(577); -var forIn = __webpack_require__(578); +var isExtendable = __webpack_require__(581); +var forIn = __webpack_require__(582); function mixinDeep(target, objects) { var len = arguments.length, i = 0; @@ -65261,7 +65487,7 @@ module.exports = mixinDeep; /***/ }), -/* 577 */ +/* 581 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -65274,7 +65500,7 @@ module.exports = mixinDeep; -var isPlainObject = __webpack_require__(534); +var isPlainObject = __webpack_require__(538); module.exports = function isExtendable(val) { return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); @@ -65282,7 +65508,7 @@ module.exports = function isExtendable(val) { /***/ }), -/* 578 */ +/* 582 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -65305,7 +65531,7 @@ module.exports = function forIn(obj, fn, thisArg) { /***/ }), -/* 579 */ +/* 583 */ /***/ (function(module, exports) { /*! @@ -65332,14 +65558,14 @@ module.exports = pascalcase; /***/ }), -/* 580 */ +/* 584 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var util = __webpack_require__(111); -var utils = __webpack_require__(581); +var utils = __webpack_require__(585); /** * Expose class utils @@ -65704,7 +65930,7 @@ cu.bubble = function(Parent, events) { /***/ }), -/* 581 */ +/* 585 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -65718,10 +65944,10 @@ var utils = {}; * Lazily required module dependencies */ -utils.union = __webpack_require__(565); -utils.define = __webpack_require__(517); -utils.isObj = __webpack_require__(535); -utils.staticExtend = __webpack_require__(582); +utils.union = __webpack_require__(569); +utils.define = __webpack_require__(521); +utils.isObj = __webpack_require__(539); +utils.staticExtend = __webpack_require__(586); /** @@ -65732,7 +65958,7 @@ module.exports = utils; /***/ }), -/* 582 */ +/* 586 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -65745,8 +65971,8 @@ module.exports = utils; -var copy = __webpack_require__(583); -var define = __webpack_require__(517); +var copy = __webpack_require__(587); +var define = __webpack_require__(521); var util = __webpack_require__(111); /** @@ -65829,15 +66055,15 @@ module.exports = extend; /***/ }), -/* 583 */ +/* 587 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var typeOf = __webpack_require__(540); -var copyDescriptor = __webpack_require__(584); -var define = __webpack_require__(517); +var typeOf = __webpack_require__(544); +var copyDescriptor = __webpack_require__(588); +var define = __webpack_require__(521); /** * Copy static properties, prototype properties, and descriptors from one object to another. @@ -66010,7 +66236,7 @@ module.exports.has = has; /***/ }), -/* 584 */ +/* 588 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -66098,16 +66324,16 @@ function isObject(val) { /***/ }), -/* 585 */ +/* 589 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var use = __webpack_require__(586); -var define = __webpack_require__(517); -var debug = __webpack_require__(588)('snapdragon:compiler'); -var utils = __webpack_require__(594); +var use = __webpack_require__(590); +var define = __webpack_require__(521); +var debug = __webpack_require__(592)('snapdragon:compiler'); +var utils = __webpack_require__(598); /** * Create a new `Compiler` with the given `options`. @@ -66261,7 +66487,7 @@ Compiler.prototype = { // source map support if (opts.sourcemap) { - var sourcemaps = __webpack_require__(613); + var sourcemaps = __webpack_require__(617); sourcemaps(this); this.mapVisit(this.ast.nodes); this.applySourceMaps(); @@ -66282,7 +66508,7 @@ module.exports = Compiler; /***/ }), -/* 586 */ +/* 590 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -66295,7 +66521,7 @@ module.exports = Compiler; -var utils = __webpack_require__(587); +var utils = __webpack_require__(591); module.exports = function base(app, opts) { if (!utils.isObject(app) && typeof app !== 'function') { @@ -66410,7 +66636,7 @@ module.exports = function base(app, opts) { /***/ }), -/* 587 */ +/* 591 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -66424,8 +66650,8 @@ var utils = {}; * Lazily required module dependencies */ -utils.define = __webpack_require__(517); -utils.isObject = __webpack_require__(535); +utils.define = __webpack_require__(521); +utils.isObject = __webpack_require__(539); utils.isString = function(val) { @@ -66440,7 +66666,7 @@ module.exports = utils; /***/ }), -/* 588 */ +/* 592 */ /***/ (function(module, exports, __webpack_require__) { /** @@ -66449,14 +66675,14 @@ module.exports = utils; */ if (typeof process !== 'undefined' && process.type === 'renderer') { - module.exports = __webpack_require__(589); + module.exports = __webpack_require__(593); } else { - module.exports = __webpack_require__(592); + module.exports = __webpack_require__(596); } /***/ }), -/* 589 */ +/* 593 */ /***/ (function(module, exports, __webpack_require__) { /** @@ -66465,7 +66691,7 @@ if (typeof process !== 'undefined' && process.type === 'renderer') { * Expose `debug()` as the module. */ -exports = module.exports = __webpack_require__(590); +exports = module.exports = __webpack_require__(594); exports.log = log; exports.formatArgs = formatArgs; exports.save = save; @@ -66647,7 +66873,7 @@ function localstorage() { /***/ }), -/* 590 */ +/* 594 */ /***/ (function(module, exports, __webpack_require__) { @@ -66663,7 +66889,7 @@ exports.coerce = coerce; exports.disable = disable; exports.enable = enable; exports.enabled = enabled; -exports.humanize = __webpack_require__(591); +exports.humanize = __webpack_require__(595); /** * The currently active debug mode names, and names to skip. @@ -66855,7 +67081,7 @@ function coerce(val) { /***/ }), -/* 591 */ +/* 595 */ /***/ (function(module, exports) { /** @@ -67013,7 +67239,7 @@ function plural(ms, n, name) { /***/ }), -/* 592 */ +/* 596 */ /***/ (function(module, exports, __webpack_require__) { /** @@ -67029,7 +67255,7 @@ var util = __webpack_require__(111); * Expose `debug()` as the module. */ -exports = module.exports = __webpack_require__(590); +exports = module.exports = __webpack_require__(594); exports.init = init; exports.log = log; exports.formatArgs = formatArgs; @@ -67208,7 +67434,7 @@ function createWritableStdioStream (fd) { case 'PIPE': case 'TCP': - var net = __webpack_require__(593); + var net = __webpack_require__(597); stream = new net.Socket({ fd: fd, readable: false, @@ -67267,13 +67493,13 @@ exports.enable(load()); /***/ }), -/* 593 */ +/* 597 */ /***/ (function(module, exports) { module.exports = require("net"); /***/ }), -/* 594 */ +/* 598 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -67283,9 +67509,9 @@ module.exports = require("net"); * Module dependencies */ -exports.extend = __webpack_require__(525); -exports.SourceMap = __webpack_require__(595); -exports.sourceMapResolve = __webpack_require__(606); +exports.extend = __webpack_require__(529); +exports.SourceMap = __webpack_require__(599); +exports.sourceMapResolve = __webpack_require__(610); /** * Convert backslash in the given string to forward slashes @@ -67328,7 +67554,7 @@ exports.last = function(arr, n) { /***/ }), -/* 595 */ +/* 599 */ /***/ (function(module, exports, __webpack_require__) { /* @@ -67336,13 +67562,13 @@ exports.last = function(arr, n) { * Licensed under the New BSD license. See LICENSE.txt or: * http://opensource.org/licenses/BSD-3-Clause */ -exports.SourceMapGenerator = __webpack_require__(596).SourceMapGenerator; -exports.SourceMapConsumer = __webpack_require__(602).SourceMapConsumer; -exports.SourceNode = __webpack_require__(605).SourceNode; +exports.SourceMapGenerator = __webpack_require__(600).SourceMapGenerator; +exports.SourceMapConsumer = __webpack_require__(606).SourceMapConsumer; +exports.SourceNode = __webpack_require__(609).SourceNode; /***/ }), -/* 596 */ +/* 600 */ /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -67352,10 +67578,10 @@ exports.SourceNode = __webpack_require__(605).SourceNode; * http://opensource.org/licenses/BSD-3-Clause */ -var base64VLQ = __webpack_require__(597); -var util = __webpack_require__(599); -var ArraySet = __webpack_require__(600).ArraySet; -var MappingList = __webpack_require__(601).MappingList; +var base64VLQ = __webpack_require__(601); +var util = __webpack_require__(603); +var ArraySet = __webpack_require__(604).ArraySet; +var MappingList = __webpack_require__(605).MappingList; /** * An instance of the SourceMapGenerator represents a source map which is @@ -67764,7 +67990,7 @@ exports.SourceMapGenerator = SourceMapGenerator; /***/ }), -/* 597 */ +/* 601 */ /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -67804,7 +68030,7 @@ exports.SourceMapGenerator = SourceMapGenerator; * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -var base64 = __webpack_require__(598); +var base64 = __webpack_require__(602); // A single base 64 digit can contain 6 bits of data. For the base 64 variable // length quantities we use in the source map spec, the first bit is the sign, @@ -67910,7 +68136,7 @@ exports.decode = function base64VLQ_decode(aStr, aIndex, aOutParam) { /***/ }), -/* 598 */ +/* 602 */ /***/ (function(module, exports) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -67983,7 +68209,7 @@ exports.decode = function (charCode) { /***/ }), -/* 599 */ +/* 603 */ /***/ (function(module, exports) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -68406,7 +68632,7 @@ exports.compareByGeneratedPositionsInflated = compareByGeneratedPositionsInflate /***/ }), -/* 600 */ +/* 604 */ /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -68416,7 +68642,7 @@ exports.compareByGeneratedPositionsInflated = compareByGeneratedPositionsInflate * http://opensource.org/licenses/BSD-3-Clause */ -var util = __webpack_require__(599); +var util = __webpack_require__(603); var has = Object.prototype.hasOwnProperty; var hasNativeMap = typeof Map !== "undefined"; @@ -68533,7 +68759,7 @@ exports.ArraySet = ArraySet; /***/ }), -/* 601 */ +/* 605 */ /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -68543,7 +68769,7 @@ exports.ArraySet = ArraySet; * http://opensource.org/licenses/BSD-3-Clause */ -var util = __webpack_require__(599); +var util = __webpack_require__(603); /** * Determine whether mappingB is after mappingA with respect to generated @@ -68618,7 +68844,7 @@ exports.MappingList = MappingList; /***/ }), -/* 602 */ +/* 606 */ /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -68628,11 +68854,11 @@ exports.MappingList = MappingList; * http://opensource.org/licenses/BSD-3-Clause */ -var util = __webpack_require__(599); -var binarySearch = __webpack_require__(603); -var ArraySet = __webpack_require__(600).ArraySet; -var base64VLQ = __webpack_require__(597); -var quickSort = __webpack_require__(604).quickSort; +var util = __webpack_require__(603); +var binarySearch = __webpack_require__(607); +var ArraySet = __webpack_require__(604).ArraySet; +var base64VLQ = __webpack_require__(601); +var quickSort = __webpack_require__(608).quickSort; function SourceMapConsumer(aSourceMap) { var sourceMap = aSourceMap; @@ -69706,7 +69932,7 @@ exports.IndexedSourceMapConsumer = IndexedSourceMapConsumer; /***/ }), -/* 603 */ +/* 607 */ /***/ (function(module, exports) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -69823,7 +70049,7 @@ exports.search = function search(aNeedle, aHaystack, aCompare, aBias) { /***/ }), -/* 604 */ +/* 608 */ /***/ (function(module, exports) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -69943,7 +70169,7 @@ exports.quickSort = function (ary, comparator) { /***/ }), -/* 605 */ +/* 609 */ /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -69953,8 +70179,8 @@ exports.quickSort = function (ary, comparator) { * http://opensource.org/licenses/BSD-3-Clause */ -var SourceMapGenerator = __webpack_require__(596).SourceMapGenerator; -var util = __webpack_require__(599); +var SourceMapGenerator = __webpack_require__(600).SourceMapGenerator; +var util = __webpack_require__(603); // Matches a Windows-style `\r\n` newline or a `\n` newline used by all other // operating systems these days (capturing the result). @@ -70362,17 +70588,17 @@ exports.SourceNode = SourceNode; /***/ }), -/* 606 */ +/* 610 */ /***/ (function(module, exports, __webpack_require__) { // Copyright 2014, 2015, 2016, 2017 Simon Lydell // X11 (“MIT”) Licensed. (See LICENSE.) -var sourceMappingURL = __webpack_require__(607) -var resolveUrl = __webpack_require__(608) -var decodeUriComponent = __webpack_require__(609) -var urix = __webpack_require__(611) -var atob = __webpack_require__(612) +var sourceMappingURL = __webpack_require__(611) +var resolveUrl = __webpack_require__(612) +var decodeUriComponent = __webpack_require__(613) +var urix = __webpack_require__(615) +var atob = __webpack_require__(616) @@ -70670,7 +70896,7 @@ module.exports = { /***/ }), -/* 607 */ +/* 611 */ /***/ (function(module, exports, __webpack_require__) { var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_RESULT__;// Copyright 2014 Simon Lydell @@ -70733,7 +70959,7 @@ void (function(root, factory) { /***/ }), -/* 608 */ +/* 612 */ /***/ (function(module, exports, __webpack_require__) { // Copyright 2014 Simon Lydell @@ -70751,13 +70977,13 @@ module.exports = resolveUrl /***/ }), -/* 609 */ +/* 613 */ /***/ (function(module, exports, __webpack_require__) { // Copyright 2017 Simon Lydell // X11 (“MIT”) Licensed. (See LICENSE.) -var decodeUriComponent = __webpack_require__(610) +var decodeUriComponent = __webpack_require__(614) function customDecodeUriComponent(string) { // `decodeUriComponent` turns `+` into ` `, but that's not wanted. @@ -70768,7 +70994,7 @@ module.exports = customDecodeUriComponent /***/ }), -/* 610 */ +/* 614 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -70869,7 +71095,7 @@ module.exports = function (encodedURI) { /***/ }), -/* 611 */ +/* 615 */ /***/ (function(module, exports, __webpack_require__) { // Copyright 2014 Simon Lydell @@ -70892,7 +71118,7 @@ module.exports = urix /***/ }), -/* 612 */ +/* 616 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -70906,7 +71132,7 @@ module.exports = atob.atob = atob; /***/ }), -/* 613 */ +/* 617 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -70914,8 +71140,8 @@ module.exports = atob.atob = atob; var fs = __webpack_require__(133); var path = __webpack_require__(4); -var define = __webpack_require__(517); -var utils = __webpack_require__(594); +var define = __webpack_require__(521); +var utils = __webpack_require__(598); /** * Expose `mixin()`. @@ -71058,19 +71284,19 @@ exports.comment = function(node) { /***/ }), -/* 614 */ +/* 618 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var use = __webpack_require__(586); +var use = __webpack_require__(590); var util = __webpack_require__(111); -var Cache = __webpack_require__(615); -var define = __webpack_require__(517); -var debug = __webpack_require__(588)('snapdragon:parser'); -var Position = __webpack_require__(616); -var utils = __webpack_require__(594); +var Cache = __webpack_require__(619); +var define = __webpack_require__(521); +var debug = __webpack_require__(592)('snapdragon:parser'); +var Position = __webpack_require__(620); +var utils = __webpack_require__(598); /** * Create a new `Parser` with the given `input` and `options`. @@ -71598,7 +71824,7 @@ module.exports = Parser; /***/ }), -/* 615 */ +/* 619 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -71705,13 +71931,13 @@ MapCache.prototype.del = function mapDelete(key) { /***/ }), -/* 616 */ +/* 620 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var define = __webpack_require__(517); +var define = __webpack_require__(521); /** * Store position for a node @@ -71726,16 +71952,16 @@ module.exports = function Position(start, parser) { /***/ }), -/* 617 */ +/* 621 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var safe = __webpack_require__(618); -var define = __webpack_require__(624); -var extend = __webpack_require__(625); -var not = __webpack_require__(627); +var safe = __webpack_require__(622); +var define = __webpack_require__(628); +var extend = __webpack_require__(629); +var not = __webpack_require__(631); var MAX_LENGTH = 1024 * 64; /** @@ -71888,10 +72114,10 @@ module.exports.makeRe = makeRe; /***/ }), -/* 618 */ +/* 622 */ /***/ (function(module, exports, __webpack_require__) { -var parse = __webpack_require__(619); +var parse = __webpack_require__(623); var types = parse.types; module.exports = function (re, opts) { @@ -71937,13 +72163,13 @@ function isRegExp (x) { /***/ }), -/* 619 */ +/* 623 */ /***/ (function(module, exports, __webpack_require__) { -var util = __webpack_require__(620); -var types = __webpack_require__(621); -var sets = __webpack_require__(622); -var positions = __webpack_require__(623); +var util = __webpack_require__(624); +var types = __webpack_require__(625); +var sets = __webpack_require__(626); +var positions = __webpack_require__(627); module.exports = function(regexpStr) { @@ -72225,11 +72451,11 @@ module.exports.types = types; /***/ }), -/* 620 */ +/* 624 */ /***/ (function(module, exports, __webpack_require__) { -var types = __webpack_require__(621); -var sets = __webpack_require__(622); +var types = __webpack_require__(625); +var sets = __webpack_require__(626); // All of these are private and only used by randexp. @@ -72342,7 +72568,7 @@ exports.error = function(regexp, msg) { /***/ }), -/* 621 */ +/* 625 */ /***/ (function(module, exports) { module.exports = { @@ -72358,10 +72584,10 @@ module.exports = { /***/ }), -/* 622 */ +/* 626 */ /***/ (function(module, exports, __webpack_require__) { -var types = __webpack_require__(621); +var types = __webpack_require__(625); var INTS = function() { return [{ type: types.RANGE , from: 48, to: 57 }]; @@ -72446,10 +72672,10 @@ exports.anyChar = function() { /***/ }), -/* 623 */ +/* 627 */ /***/ (function(module, exports, __webpack_require__) { -var types = __webpack_require__(621); +var types = __webpack_require__(625); exports.wordBoundary = function() { return { type: types.POSITION, value: 'b' }; @@ -72469,7 +72695,7 @@ exports.end = function() { /***/ }), -/* 624 */ +/* 628 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -72482,8 +72708,8 @@ exports.end = function() { -var isobject = __webpack_require__(535); -var isDescriptor = __webpack_require__(547); +var isobject = __webpack_require__(539); +var isDescriptor = __webpack_require__(551); var define = (typeof Reflect !== 'undefined' && Reflect.defineProperty) ? Reflect.defineProperty : Object.defineProperty; @@ -72514,14 +72740,14 @@ module.exports = function defineProperty(obj, key, val) { /***/ }), -/* 625 */ +/* 629 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isExtendable = __webpack_require__(626); -var assignSymbols = __webpack_require__(536); +var isExtendable = __webpack_require__(630); +var assignSymbols = __webpack_require__(540); module.exports = Object.assign || function(obj/*, objects*/) { if (obj === null || typeof obj === 'undefined') { @@ -72581,7 +72807,7 @@ function isEnum(obj, key) { /***/ }), -/* 626 */ +/* 630 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -72594,7 +72820,7 @@ function isEnum(obj, key) { -var isPlainObject = __webpack_require__(534); +var isPlainObject = __webpack_require__(538); module.exports = function isExtendable(val) { return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); @@ -72602,14 +72828,14 @@ module.exports = function isExtendable(val) { /***/ }), -/* 627 */ +/* 631 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var extend = __webpack_require__(625); -var safe = __webpack_require__(618); +var extend = __webpack_require__(629); +var safe = __webpack_require__(622); /** * The main export is a function that takes a `pattern` string and an `options` object. @@ -72681,14 +72907,14 @@ module.exports = toRegex; /***/ }), -/* 628 */ +/* 632 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var nanomatch = __webpack_require__(629); -var extglob = __webpack_require__(644); +var nanomatch = __webpack_require__(633); +var extglob = __webpack_require__(648); module.exports = function(snapdragon) { var compilers = snapdragon.compiler.compilers; @@ -72765,7 +72991,7 @@ function escapeExtglobs(compiler) { /***/ }), -/* 629 */ +/* 633 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -72776,17 +73002,17 @@ function escapeExtglobs(compiler) { */ var util = __webpack_require__(111); -var toRegex = __webpack_require__(516); -var extend = __webpack_require__(630); +var toRegex = __webpack_require__(520); +var extend = __webpack_require__(634); /** * Local dependencies */ -var compilers = __webpack_require__(632); -var parsers = __webpack_require__(633); -var cache = __webpack_require__(636); -var utils = __webpack_require__(638); +var compilers = __webpack_require__(636); +var parsers = __webpack_require__(637); +var cache = __webpack_require__(640); +var utils = __webpack_require__(642); var MAX_LENGTH = 1024 * 64; /** @@ -73610,14 +73836,14 @@ module.exports = nanomatch; /***/ }), -/* 630 */ +/* 634 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isExtendable = __webpack_require__(631); -var assignSymbols = __webpack_require__(536); +var isExtendable = __webpack_require__(635); +var assignSymbols = __webpack_require__(540); module.exports = Object.assign || function(obj/*, objects*/) { if (obj === null || typeof obj === 'undefined') { @@ -73677,7 +73903,7 @@ function isEnum(obj, key) { /***/ }), -/* 631 */ +/* 635 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -73690,7 +73916,7 @@ function isEnum(obj, key) { -var isPlainObject = __webpack_require__(534); +var isPlainObject = __webpack_require__(538); module.exports = function isExtendable(val) { return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); @@ -73698,7 +73924,7 @@ module.exports = function isExtendable(val) { /***/ }), -/* 632 */ +/* 636 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -74044,15 +74270,15 @@ module.exports = function(nanomatch, options) { /***/ }), -/* 633 */ +/* 637 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var regexNot = __webpack_require__(527); -var toRegex = __webpack_require__(516); -var isOdd = __webpack_require__(634); +var regexNot = __webpack_require__(531); +var toRegex = __webpack_require__(520); +var isOdd = __webpack_require__(638); /** * Characters to use in negation regex (we want to "not" match @@ -74438,7 +74664,7 @@ module.exports.not = NOT_REGEX; /***/ }), -/* 634 */ +/* 638 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -74451,7 +74677,7 @@ module.exports.not = NOT_REGEX; -var isNumber = __webpack_require__(635); +var isNumber = __webpack_require__(639); module.exports = function isOdd(i) { if (!isNumber(i)) { @@ -74465,7 +74691,7 @@ module.exports = function isOdd(i) { /***/ }), -/* 635 */ +/* 639 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -74493,14 +74719,14 @@ module.exports = function isNumber(num) { /***/ }), -/* 636 */ +/* 640 */ /***/ (function(module, exports, __webpack_require__) { -module.exports = new (__webpack_require__(637))(); +module.exports = new (__webpack_require__(641))(); /***/ }), -/* 637 */ +/* 641 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -74513,7 +74739,7 @@ module.exports = new (__webpack_require__(637))(); -var MapCache = __webpack_require__(615); +var MapCache = __webpack_require__(619); /** * Create a new `FragmentCache` with an optional object to use for `caches`. @@ -74635,7 +74861,7 @@ exports = module.exports = FragmentCache; /***/ }), -/* 638 */ +/* 642 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -74648,14 +74874,14 @@ var path = __webpack_require__(4); * Module dependencies */ -var isWindows = __webpack_require__(639)(); -var Snapdragon = __webpack_require__(555); -utils.define = __webpack_require__(640); -utils.diff = __webpack_require__(641); -utils.extend = __webpack_require__(630); -utils.pick = __webpack_require__(642); -utils.typeOf = __webpack_require__(643); -utils.unique = __webpack_require__(528); +var isWindows = __webpack_require__(643)(); +var Snapdragon = __webpack_require__(559); +utils.define = __webpack_require__(644); +utils.diff = __webpack_require__(645); +utils.extend = __webpack_require__(634); +utils.pick = __webpack_require__(646); +utils.typeOf = __webpack_require__(647); +utils.unique = __webpack_require__(532); /** * Returns true if the given value is effectively an empty string @@ -75021,7 +75247,7 @@ utils.unixify = function(options) { /***/ }), -/* 639 */ +/* 643 */ /***/ (function(module, exports, __webpack_require__) { var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/*! @@ -75049,7 +75275,7 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_ /***/ }), -/* 640 */ +/* 644 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -75062,8 +75288,8 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_ -var isobject = __webpack_require__(535); -var isDescriptor = __webpack_require__(547); +var isobject = __webpack_require__(539); +var isDescriptor = __webpack_require__(551); var define = (typeof Reflect !== 'undefined' && Reflect.defineProperty) ? Reflect.defineProperty : Object.defineProperty; @@ -75094,7 +75320,7 @@ module.exports = function defineProperty(obj, key, val) { /***/ }), -/* 641 */ +/* 645 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -75148,7 +75374,7 @@ function diffArray(one, two) { /***/ }), -/* 642 */ +/* 646 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -75161,7 +75387,7 @@ function diffArray(one, two) { -var isObject = __webpack_require__(535); +var isObject = __webpack_require__(539); module.exports = function pick(obj, keys) { if (!isObject(obj) && typeof obj !== 'function') { @@ -75190,7 +75416,7 @@ module.exports = function pick(obj, keys) { /***/ }), -/* 643 */ +/* 647 */ /***/ (function(module, exports) { var toString = Object.prototype.toString; @@ -75325,7 +75551,7 @@ function isBuffer(val) { /***/ }), -/* 644 */ +/* 648 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -75335,18 +75561,18 @@ function isBuffer(val) { * Module dependencies */ -var extend = __webpack_require__(525); -var unique = __webpack_require__(528); -var toRegex = __webpack_require__(516); +var extend = __webpack_require__(529); +var unique = __webpack_require__(532); +var toRegex = __webpack_require__(520); /** * Local dependencies */ -var compilers = __webpack_require__(645); -var parsers = __webpack_require__(656); -var Extglob = __webpack_require__(659); -var utils = __webpack_require__(658); +var compilers = __webpack_require__(649); +var parsers = __webpack_require__(660); +var Extglob = __webpack_require__(663); +var utils = __webpack_require__(662); var MAX_LENGTH = 1024 * 64; /** @@ -75663,13 +75889,13 @@ module.exports = extglob; /***/ }), -/* 645 */ +/* 649 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var brackets = __webpack_require__(646); +var brackets = __webpack_require__(650); /** * Extglob compilers @@ -75839,7 +76065,7 @@ module.exports = function(extglob) { /***/ }), -/* 646 */ +/* 650 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -75849,17 +76075,17 @@ module.exports = function(extglob) { * Local dependencies */ -var compilers = __webpack_require__(647); -var parsers = __webpack_require__(649); +var compilers = __webpack_require__(651); +var parsers = __webpack_require__(653); /** * Module dependencies */ -var debug = __webpack_require__(651)('expand-brackets'); -var extend = __webpack_require__(525); -var Snapdragon = __webpack_require__(555); -var toRegex = __webpack_require__(516); +var debug = __webpack_require__(655)('expand-brackets'); +var extend = __webpack_require__(529); +var Snapdragon = __webpack_require__(559); +var toRegex = __webpack_require__(520); /** * Parses the given POSIX character class `pattern` and returns a @@ -76057,13 +76283,13 @@ module.exports = brackets; /***/ }), -/* 647 */ +/* 651 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var posix = __webpack_require__(648); +var posix = __webpack_require__(652); module.exports = function(brackets) { brackets.compiler @@ -76151,7 +76377,7 @@ module.exports = function(brackets) { /***/ }), -/* 648 */ +/* 652 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -76180,14 +76406,14 @@ module.exports = { /***/ }), -/* 649 */ +/* 653 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var utils = __webpack_require__(650); -var define = __webpack_require__(517); +var utils = __webpack_require__(654); +var define = __webpack_require__(521); /** * Text regex @@ -76406,14 +76632,14 @@ module.exports.TEXT_REGEX = TEXT_REGEX; /***/ }), -/* 650 */ +/* 654 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var toRegex = __webpack_require__(516); -var regexNot = __webpack_require__(527); +var toRegex = __webpack_require__(520); +var regexNot = __webpack_require__(531); var cached; /** @@ -76447,7 +76673,7 @@ exports.createRegex = function(pattern, include) { /***/ }), -/* 651 */ +/* 655 */ /***/ (function(module, exports, __webpack_require__) { /** @@ -76456,14 +76682,14 @@ exports.createRegex = function(pattern, include) { */ if (typeof process !== 'undefined' && process.type === 'renderer') { - module.exports = __webpack_require__(652); + module.exports = __webpack_require__(656); } else { - module.exports = __webpack_require__(655); + module.exports = __webpack_require__(659); } /***/ }), -/* 652 */ +/* 656 */ /***/ (function(module, exports, __webpack_require__) { /** @@ -76472,7 +76698,7 @@ if (typeof process !== 'undefined' && process.type === 'renderer') { * Expose `debug()` as the module. */ -exports = module.exports = __webpack_require__(653); +exports = module.exports = __webpack_require__(657); exports.log = log; exports.formatArgs = formatArgs; exports.save = save; @@ -76654,7 +76880,7 @@ function localstorage() { /***/ }), -/* 653 */ +/* 657 */ /***/ (function(module, exports, __webpack_require__) { @@ -76670,7 +76896,7 @@ exports.coerce = coerce; exports.disable = disable; exports.enable = enable; exports.enabled = enabled; -exports.humanize = __webpack_require__(654); +exports.humanize = __webpack_require__(658); /** * The currently active debug mode names, and names to skip. @@ -76862,7 +77088,7 @@ function coerce(val) { /***/ }), -/* 654 */ +/* 658 */ /***/ (function(module, exports) { /** @@ -77020,7 +77246,7 @@ function plural(ms, n, name) { /***/ }), -/* 655 */ +/* 659 */ /***/ (function(module, exports, __webpack_require__) { /** @@ -77036,7 +77262,7 @@ var util = __webpack_require__(111); * Expose `debug()` as the module. */ -exports = module.exports = __webpack_require__(653); +exports = module.exports = __webpack_require__(657); exports.init = init; exports.log = log; exports.formatArgs = formatArgs; @@ -77215,7 +77441,7 @@ function createWritableStdioStream (fd) { case 'PIPE': case 'TCP': - var net = __webpack_require__(593); + var net = __webpack_require__(597); stream = new net.Socket({ fd: fd, readable: false, @@ -77274,15 +77500,15 @@ exports.enable(load()); /***/ }), -/* 656 */ +/* 660 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var brackets = __webpack_require__(646); -var define = __webpack_require__(657); -var utils = __webpack_require__(658); +var brackets = __webpack_require__(650); +var define = __webpack_require__(661); +var utils = __webpack_require__(662); /** * Characters to use in text regex (we want to "not" match @@ -77437,7 +77663,7 @@ module.exports = parsers; /***/ }), -/* 657 */ +/* 661 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -77450,7 +77676,7 @@ module.exports = parsers; -var isDescriptor = __webpack_require__(547); +var isDescriptor = __webpack_require__(551); module.exports = function defineProperty(obj, prop, val) { if (typeof obj !== 'object' && typeof obj !== 'function') { @@ -77475,14 +77701,14 @@ module.exports = function defineProperty(obj, prop, val) { /***/ }), -/* 658 */ +/* 662 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var regex = __webpack_require__(527); -var Cache = __webpack_require__(637); +var regex = __webpack_require__(531); +var Cache = __webpack_require__(641); /** * Utils @@ -77551,7 +77777,7 @@ utils.createRegex = function(str) { /***/ }), -/* 659 */ +/* 663 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -77561,16 +77787,16 @@ utils.createRegex = function(str) { * Module dependencies */ -var Snapdragon = __webpack_require__(555); -var define = __webpack_require__(657); -var extend = __webpack_require__(525); +var Snapdragon = __webpack_require__(559); +var define = __webpack_require__(661); +var extend = __webpack_require__(529); /** * Local dependencies */ -var compilers = __webpack_require__(645); -var parsers = __webpack_require__(656); +var compilers = __webpack_require__(649); +var parsers = __webpack_require__(660); /** * Customize Snapdragon parser and renderer @@ -77636,16 +77862,16 @@ module.exports = Extglob; /***/ }), -/* 660 */ +/* 664 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var extglob = __webpack_require__(644); -var nanomatch = __webpack_require__(629); -var regexNot = __webpack_require__(527); -var toRegex = __webpack_require__(617); +var extglob = __webpack_require__(648); +var nanomatch = __webpack_require__(633); +var regexNot = __webpack_require__(531); +var toRegex = __webpack_require__(621); var not; /** @@ -77726,14 +77952,14 @@ function textRegex(pattern) { /***/ }), -/* 661 */ +/* 665 */ /***/ (function(module, exports, __webpack_require__) { -module.exports = new (__webpack_require__(637))(); +module.exports = new (__webpack_require__(641))(); /***/ }), -/* 662 */ +/* 666 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -77746,13 +77972,13 @@ var path = __webpack_require__(4); * Module dependencies */ -var Snapdragon = __webpack_require__(555); -utils.define = __webpack_require__(624); -utils.diff = __webpack_require__(641); -utils.extend = __webpack_require__(625); -utils.pick = __webpack_require__(642); -utils.typeOf = __webpack_require__(663); -utils.unique = __webpack_require__(528); +var Snapdragon = __webpack_require__(559); +utils.define = __webpack_require__(628); +utils.diff = __webpack_require__(645); +utils.extend = __webpack_require__(629); +utils.pick = __webpack_require__(646); +utils.typeOf = __webpack_require__(667); +utils.unique = __webpack_require__(532); /** * Returns true if the platform is windows, or `path.sep` is `\\`. @@ -78049,7 +78275,7 @@ utils.unixify = function(options) { /***/ }), -/* 663 */ +/* 667 */ /***/ (function(module, exports) { var toString = Object.prototype.toString; @@ -78184,7 +78410,7 @@ function isBuffer(val) { /***/ }), -/* 664 */ +/* 668 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -78203,9 +78429,9 @@ var __extends = (this && this.__extends) || (function () { }; })(); Object.defineProperty(exports, "__esModule", { value: true }); -var readdir = __webpack_require__(665); -var reader_1 = __webpack_require__(678); -var fs_stream_1 = __webpack_require__(682); +var readdir = __webpack_require__(669); +var reader_1 = __webpack_require__(682); +var fs_stream_1 = __webpack_require__(686); var ReaderAsync = /** @class */ (function (_super) { __extends(ReaderAsync, _super); function ReaderAsync() { @@ -78266,15 +78492,15 @@ exports.default = ReaderAsync; /***/ }), -/* 665 */ +/* 669 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const readdirSync = __webpack_require__(666); -const readdirAsync = __webpack_require__(674); -const readdirStream = __webpack_require__(677); +const readdirSync = __webpack_require__(670); +const readdirAsync = __webpack_require__(678); +const readdirStream = __webpack_require__(681); module.exports = exports = readdirAsyncPath; exports.readdir = exports.readdirAsync = exports.async = readdirAsyncPath; @@ -78358,7 +78584,7 @@ function readdirStreamStat (dir, options) { /***/ }), -/* 666 */ +/* 670 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -78366,11 +78592,11 @@ function readdirStreamStat (dir, options) { module.exports = readdirSync; -const DirectoryReader = __webpack_require__(667); +const DirectoryReader = __webpack_require__(671); let syncFacade = { - fs: __webpack_require__(672), - forEach: __webpack_require__(673), + fs: __webpack_require__(676), + forEach: __webpack_require__(677), sync: true }; @@ -78399,7 +78625,7 @@ function readdirSync (dir, options, internalOptions) { /***/ }), -/* 667 */ +/* 671 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -78408,9 +78634,9 @@ function readdirSync (dir, options, internalOptions) { const Readable = __webpack_require__(137).Readable; const EventEmitter = __webpack_require__(155).EventEmitter; const path = __webpack_require__(4); -const normalizeOptions = __webpack_require__(668); -const stat = __webpack_require__(670); -const call = __webpack_require__(671); +const normalizeOptions = __webpack_require__(672); +const stat = __webpack_require__(674); +const call = __webpack_require__(675); /** * Asynchronously reads the contents of a directory and streams the results @@ -78786,14 +79012,14 @@ module.exports = DirectoryReader; /***/ }), -/* 668 */ +/* 672 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(4); -const globToRegExp = __webpack_require__(669); +const globToRegExp = __webpack_require__(673); module.exports = normalizeOptions; @@ -78970,7 +79196,7 @@ function normalizeOptions (options, internalOptions) { /***/ }), -/* 669 */ +/* 673 */ /***/ (function(module, exports) { module.exports = function (glob, opts) { @@ -79107,13 +79333,13 @@ module.exports = function (glob, opts) { /***/ }), -/* 670 */ +/* 674 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const call = __webpack_require__(671); +const call = __webpack_require__(675); module.exports = stat; @@ -79188,7 +79414,7 @@ function symlinkStat (fs, path, lstats, callback) { /***/ }), -/* 671 */ +/* 675 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -79249,14 +79475,14 @@ function callOnce (fn) { /***/ }), -/* 672 */ +/* 676 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const fs = __webpack_require__(133); -const call = __webpack_require__(671); +const call = __webpack_require__(675); /** * A facade around {@link fs.readdirSync} that allows it to be called @@ -79320,7 +79546,7 @@ exports.lstat = function (path, callback) { /***/ }), -/* 673 */ +/* 677 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -79349,7 +79575,7 @@ function syncForEach (array, iterator, done) { /***/ }), -/* 674 */ +/* 678 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -79357,12 +79583,12 @@ function syncForEach (array, iterator, done) { module.exports = readdirAsync; -const maybe = __webpack_require__(675); -const DirectoryReader = __webpack_require__(667); +const maybe = __webpack_require__(679); +const DirectoryReader = __webpack_require__(671); let asyncFacade = { fs: __webpack_require__(133), - forEach: __webpack_require__(676), + forEach: __webpack_require__(680), async: true }; @@ -79404,7 +79630,7 @@ function readdirAsync (dir, options, callback, internalOptions) { /***/ }), -/* 675 */ +/* 679 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -79431,7 +79657,7 @@ module.exports = function maybe (cb, promise) { /***/ }), -/* 676 */ +/* 680 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -79467,7 +79693,7 @@ function asyncForEach (array, iterator, done) { /***/ }), -/* 677 */ +/* 681 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -79475,11 +79701,11 @@ function asyncForEach (array, iterator, done) { module.exports = readdirStream; -const DirectoryReader = __webpack_require__(667); +const DirectoryReader = __webpack_require__(671); let streamFacade = { fs: __webpack_require__(133), - forEach: __webpack_require__(676), + forEach: __webpack_require__(680), async: true }; @@ -79499,16 +79725,16 @@ function readdirStream (dir, options, internalOptions) { /***/ }), -/* 678 */ +/* 682 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var path = __webpack_require__(4); -var deep_1 = __webpack_require__(679); -var entry_1 = __webpack_require__(681); -var pathUtil = __webpack_require__(680); +var deep_1 = __webpack_require__(683); +var entry_1 = __webpack_require__(685); +var pathUtil = __webpack_require__(684); var Reader = /** @class */ (function () { function Reader(options) { this.options = options; @@ -79574,14 +79800,14 @@ exports.default = Reader; /***/ }), -/* 679 */ +/* 683 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -var pathUtils = __webpack_require__(680); -var patternUtils = __webpack_require__(509); +var pathUtils = __webpack_require__(684); +var patternUtils = __webpack_require__(513); var DeepFilter = /** @class */ (function () { function DeepFilter(options, micromatchOptions) { this.options = options; @@ -79664,7 +79890,7 @@ exports.default = DeepFilter; /***/ }), -/* 680 */ +/* 684 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -79695,14 +79921,14 @@ exports.makeAbsolute = makeAbsolute; /***/ }), -/* 681 */ +/* 685 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -var pathUtils = __webpack_require__(680); -var patternUtils = __webpack_require__(509); +var pathUtils = __webpack_require__(684); +var patternUtils = __webpack_require__(513); var EntryFilter = /** @class */ (function () { function EntryFilter(options, micromatchOptions) { this.options = options; @@ -79787,7 +80013,7 @@ exports.default = EntryFilter; /***/ }), -/* 682 */ +/* 686 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -79807,8 +80033,8 @@ var __extends = (this && this.__extends) || (function () { })(); Object.defineProperty(exports, "__esModule", { value: true }); var stream = __webpack_require__(137); -var fsStat = __webpack_require__(683); -var fs_1 = __webpack_require__(687); +var fsStat = __webpack_require__(687); +var fs_1 = __webpack_require__(691); var FileSystemStream = /** @class */ (function (_super) { __extends(FileSystemStream, _super); function FileSystemStream() { @@ -79858,14 +80084,14 @@ exports.default = FileSystemStream; /***/ }), -/* 683 */ +/* 687 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const optionsManager = __webpack_require__(684); -const statProvider = __webpack_require__(686); +const optionsManager = __webpack_require__(688); +const statProvider = __webpack_require__(690); /** * Asynchronous API. */ @@ -79896,13 +80122,13 @@ exports.statSync = statSync; /***/ }), -/* 684 */ +/* 688 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const fsAdapter = __webpack_require__(685); +const fsAdapter = __webpack_require__(689); function prepare(opts) { const options = Object.assign({ fs: fsAdapter.getFileSystemAdapter(opts ? opts.fs : undefined), @@ -79915,7 +80141,7 @@ exports.prepare = prepare; /***/ }), -/* 685 */ +/* 689 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -79938,7 +80164,7 @@ exports.getFileSystemAdapter = getFileSystemAdapter; /***/ }), -/* 686 */ +/* 690 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -79990,7 +80216,7 @@ exports.isFollowedSymlink = isFollowedSymlink; /***/ }), -/* 687 */ +/* 691 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -80021,7 +80247,7 @@ exports.default = FileSystem; /***/ }), -/* 688 */ +/* 692 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -80041,9 +80267,9 @@ var __extends = (this && this.__extends) || (function () { })(); Object.defineProperty(exports, "__esModule", { value: true }); var stream = __webpack_require__(137); -var readdir = __webpack_require__(665); -var reader_1 = __webpack_require__(678); -var fs_stream_1 = __webpack_require__(682); +var readdir = __webpack_require__(669); +var reader_1 = __webpack_require__(682); +var fs_stream_1 = __webpack_require__(686); var TransformStream = /** @class */ (function (_super) { __extends(TransformStream, _super); function TransformStream(reader) { @@ -80111,7 +80337,7 @@ exports.default = ReaderStream; /***/ }), -/* 689 */ +/* 693 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -80130,9 +80356,9 @@ var __extends = (this && this.__extends) || (function () { }; })(); Object.defineProperty(exports, "__esModule", { value: true }); -var readdir = __webpack_require__(665); -var reader_1 = __webpack_require__(678); -var fs_sync_1 = __webpack_require__(690); +var readdir = __webpack_require__(669); +var reader_1 = __webpack_require__(682); +var fs_sync_1 = __webpack_require__(694); var ReaderSync = /** @class */ (function (_super) { __extends(ReaderSync, _super); function ReaderSync() { @@ -80192,7 +80418,7 @@ exports.default = ReaderSync; /***/ }), -/* 690 */ +/* 694 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -80211,8 +80437,8 @@ var __extends = (this && this.__extends) || (function () { }; })(); Object.defineProperty(exports, "__esModule", { value: true }); -var fsStat = __webpack_require__(683); -var fs_1 = __webpack_require__(687); +var fsStat = __webpack_require__(687); +var fs_1 = __webpack_require__(691); var FileSystemSync = /** @class */ (function (_super) { __extends(FileSystemSync, _super); function FileSystemSync() { @@ -80258,7 +80484,7 @@ exports.default = FileSystemSync; /***/ }), -/* 691 */ +/* 695 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -80274,13 +80500,13 @@ exports.flatten = flatten; /***/ }), -/* 692 */ +/* 696 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -var merge2 = __webpack_require__(288); +var merge2 = __webpack_require__(283); /** * Merge multiple streams and propagate their errors into one stream in parallel. */ @@ -80295,13 +80521,13 @@ exports.merge = merge; /***/ }), -/* 693 */ +/* 697 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(4); -const pathType = __webpack_require__(694); +const pathType = __webpack_require__(698); const getExtensions = extensions => extensions.length > 1 ? `{${extensions.join(',')}}` : extensions[0]; @@ -80367,13 +80593,13 @@ module.exports.sync = (input, opts) => { /***/ }), -/* 694 */ +/* 698 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const fs = __webpack_require__(133); -const pify = __webpack_require__(695); +const pify = __webpack_require__(699); function type(fn, fn2, fp) { if (typeof fp !== 'string') { @@ -80416,7 +80642,7 @@ exports.symlinkSync = typeSync.bind(null, 'lstatSync', 'isSymbolicLink'); /***/ }), -/* 695 */ +/* 699 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -80507,17 +80733,17 @@ module.exports = (obj, opts) => { /***/ }), -/* 696 */ +/* 700 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const fs = __webpack_require__(133); const path = __webpack_require__(4); -const fastGlob = __webpack_require__(505); -const gitIgnore = __webpack_require__(697); -const pify = __webpack_require__(698); -const slash = __webpack_require__(699); +const fastGlob = __webpack_require__(509); +const gitIgnore = __webpack_require__(701); +const pify = __webpack_require__(702); +const slash = __webpack_require__(703); const DEFAULT_IGNORE = [ '**/node_modules/**', @@ -80615,7 +80841,7 @@ module.exports.sync = options => { /***/ }), -/* 697 */ +/* 701 */ /***/ (function(module, exports) { // A simple implementation of make-array @@ -81084,7 +81310,7 @@ module.exports = options => new IgnoreBase(options) /***/ }), -/* 698 */ +/* 702 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -81159,7 +81385,7 @@ module.exports = (input, options) => { /***/ }), -/* 699 */ +/* 703 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -81177,7 +81403,7 @@ module.exports = input => { /***/ }), -/* 700 */ +/* 704 */ /***/ (function(module, exports, __webpack_require__) { /*! @@ -81187,7 +81413,7 @@ module.exports = input => { * Released under the MIT License. */ -var isExtglob = __webpack_require__(299); +var isExtglob = __webpack_require__(294); var chars = { '{': '}', '(': ')', '[': ']'}; var strictRegex = /\\(.)|(^!|\*|[\].+)]\?|\[[^\\\]]+\]|\{[^\\}]+\}|\(\?[:!=][^\\)]+\)|\([^|]+\|[^\\)]+\))/; var relaxedRegex = /\\(.)|(^!|[*?{}()[\]]|\(\?)/; @@ -81231,17 +81457,17 @@ module.exports = function isGlob(str, options) { /***/ }), -/* 701 */ +/* 705 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(4); const {constants: fsConstants} = __webpack_require__(133); -const pEvent = __webpack_require__(702); -const CpFileError = __webpack_require__(705); -const fs = __webpack_require__(709); -const ProgressEmitter = __webpack_require__(712); +const pEvent = __webpack_require__(706); +const CpFileError = __webpack_require__(709); +const fs = __webpack_require__(713); +const ProgressEmitter = __webpack_require__(716); const cpFileAsync = async (source, destination, options, progressEmitter) => { let readError; @@ -81355,12 +81581,12 @@ module.exports.sync = (source, destination, options) => { /***/ }), -/* 702 */ +/* 706 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const pTimeout = __webpack_require__(703); +const pTimeout = __webpack_require__(707); const symbolAsyncIterator = Symbol.asyncIterator || '@@asyncIterator'; @@ -81651,12 +81877,12 @@ module.exports.iterator = (emitter, event, options) => { /***/ }), -/* 703 */ +/* 707 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const pFinally = __webpack_require__(704); +const pFinally = __webpack_require__(708); class TimeoutError extends Error { constructor(message) { @@ -81702,7 +81928,7 @@ module.exports.TimeoutError = TimeoutError; /***/ }), -/* 704 */ +/* 708 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -81724,12 +81950,12 @@ module.exports = (promise, onFinally) => { /***/ }), -/* 705 */ +/* 709 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const NestedError = __webpack_require__(706); +const NestedError = __webpack_require__(710); class CpFileError extends NestedError { constructor(message, nested) { @@ -81743,10 +81969,10 @@ module.exports = CpFileError; /***/ }), -/* 706 */ +/* 710 */ /***/ (function(module, exports, __webpack_require__) { -var inherits = __webpack_require__(707); +var inherits = __webpack_require__(711); var NestedError = function (message, nested) { this.nested = nested; @@ -81797,7 +82023,7 @@ module.exports = NestedError; /***/ }), -/* 707 */ +/* 711 */ /***/ (function(module, exports, __webpack_require__) { try { @@ -81805,12 +82031,12 @@ try { if (typeof util.inherits !== 'function') throw ''; module.exports = util.inherits; } catch (e) { - module.exports = __webpack_require__(708); + module.exports = __webpack_require__(712); } /***/ }), -/* 708 */ +/* 712 */ /***/ (function(module, exports) { if (typeof Object.create === 'function') { @@ -81839,16 +82065,16 @@ if (typeof Object.create === 'function') { /***/ }), -/* 709 */ +/* 713 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const {promisify} = __webpack_require__(111); const fs = __webpack_require__(132); -const makeDir = __webpack_require__(710); -const pEvent = __webpack_require__(702); -const CpFileError = __webpack_require__(705); +const makeDir = __webpack_require__(714); +const pEvent = __webpack_require__(706); +const CpFileError = __webpack_require__(709); const stat = promisify(fs.stat); const lstat = promisify(fs.lstat); @@ -81945,7 +82171,7 @@ exports.copyFileSync = (source, destination, flags) => { /***/ }), -/* 710 */ +/* 714 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -81953,7 +82179,7 @@ exports.copyFileSync = (source, destination, flags) => { const fs = __webpack_require__(133); const path = __webpack_require__(4); const {promisify} = __webpack_require__(111); -const semver = __webpack_require__(711); +const semver = __webpack_require__(715); const useNativeRecursiveOption = semver.satisfies(process.version, '>=10.12.0'); @@ -82108,7 +82334,7 @@ module.exports.sync = (input, options) => { /***/ }), -/* 711 */ +/* 715 */ /***/ (function(module, exports) { exports = module.exports = SemVer @@ -83710,7 +83936,7 @@ function coerce (version, options) { /***/ }), -/* 712 */ +/* 716 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -83751,7 +83977,7 @@ module.exports = ProgressEmitter; /***/ }), -/* 713 */ +/* 717 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -83797,12 +84023,12 @@ exports.default = module.exports; /***/ }), -/* 714 */ +/* 718 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const NestedError = __webpack_require__(715); +const NestedError = __webpack_require__(719); class CpyError extends NestedError { constructor(message, nested) { @@ -83816,7 +84042,7 @@ module.exports = CpyError; /***/ }), -/* 715 */ +/* 719 */ /***/ (function(module, exports, __webpack_require__) { var inherits = __webpack_require__(111).inherits; diff --git a/packages/kbn-pm/package.json b/packages/kbn-pm/package.json index c2f9236d9e798..f4e9ee8249900 100644 --- a/packages/kbn-pm/package.json +++ b/packages/kbn-pm/package.json @@ -28,7 +28,7 @@ "@types/node": ">=10.17.17 <10.20.0", "@types/ora": "^1.3.5", "@types/read-pkg": "^4.0.0", - "@types/strip-ansi": "^3.0.0", + "@types/strip-ansi": "^5.2.1", "@types/strong-log-transformer": "^1.0.0", "@types/tempy": "^0.2.0", "@types/write-pkg": "^3.1.0", @@ -50,13 +50,13 @@ "log-symbols": "^2.2.0", "multimatch": "^4.0.0", "ncp": "^2.0.0", - "ora": "^1.4.0", + "ora": "^4.0.4", "prettier": "^2.1.1", "read-pkg": "^5.2.0", "rxjs": "^6.5.5", "spawn-sync": "^1.0.15", "string-replace-loader": "^2.2.0", - "strip-ansi": "^4.0.0", + "strip-ansi": "^6.0.0", "strong-log-transformer": "^2.1.0", "tempy": "^0.3.0", "typescript": "4.0.2", diff --git a/packages/kbn-pm/src/utils/validate_yarn_lock.ts b/packages/kbn-pm/src/utils/validate_yarn_lock.ts index e110dc4d921cf..ec853a3a958fb 100644 --- a/packages/kbn-pm/src/utils/validate_yarn_lock.ts +++ b/packages/kbn-pm/src/utils/validate_yarn_lock.ts @@ -25,6 +25,7 @@ import { writeFile } from './fs'; import { Kibana } from './kibana'; import { YarnLock } from './yarn_lock'; import { log } from './log'; +import { Project } from './project'; export async function validateYarnLock(kbn: Kibana, yarnLock: YarnLock) { // look through all of the packages in the yarn.lock file to see if @@ -95,5 +96,66 @@ export async function validateYarnLock(kbn: Kibana, yarnLock: YarnLock) { process.exit(1); } + // TODO: remove this once we move into a single package.json + // look through all the package.json files to find packages which have mismatched version ranges + const depRanges = new Map>(); + for (const project of kbn.getAllProjects().values()) { + for (const [dep, range] of Object.entries(project.allDependencies)) { + const existingDep = depRanges.get(dep); + if (!existingDep) { + depRanges.set(dep, [ + { + range, + projects: [project], + }, + ]); + continue; + } + + const existingRange = existingDep.find((existing) => existing.range === range); + if (!existingRange) { + existingDep.push({ + range, + projects: [project], + }); + continue; + } + + existingRange.projects.push(project); + } + } + + const duplicateRanges = Array.from(depRanges.entries()) + .filter(([, ranges]) => ranges.length > 1) + .reduce( + (acc: string[], [dep, ranges]) => [ + ...acc, + dep, + ...ranges.map( + ({ range, projects }) => ` ${range} => ${projects.map((p) => p.name).join(', ')}` + ), + ], + [] + ) + .join('\n '); + + if (duplicateRanges) { + log.error(dedent` + + [single_version_dependencies] Multiple version ranges for the same dependency + were found declared across different package.json files. Please consolidate + those to match across all package.json files. Different versions for the + same dependency is not supported. + + If you have questions about this please reach out to the operations team. + + The conflicting dependencies are: + + ${duplicateRanges} + `); + + process.exit(1); + } + log.success('yarn.lock analysis completed without any issues'); } diff --git a/packages/kbn-release-notes/package.json b/packages/kbn-release-notes/package.json index f8971fa02aa87..268530c22399a 100644 --- a/packages/kbn-release-notes/package.json +++ b/packages/kbn-release-notes/package.json @@ -13,7 +13,7 @@ "axios": "^0.19.2", "cheerio": "0.22.0", "dedent": "^0.7.0", - "graphql": "^14.0.0", + "graphql": "^0.13.2", "graphql-tag": "^2.10.3", "terminal-link": "^2.1.1" }, diff --git a/packages/kbn-storybook/package.json b/packages/kbn-storybook/package.json index 05fdb8489a1c3..58359159e950d 100644 --- a/packages/kbn-storybook/package.json +++ b/packages/kbn-storybook/package.json @@ -13,8 +13,8 @@ "@storybook/core": "^6.0.16", "@storybook/react": "^6.0.16", "@storybook/theming": "^6.0.16", - "@types/loader-utils": "^2.0.1", - "@types/webpack": "^4.41.5", + "@types/loader-utils": "^1.1.3", + "@types/webpack": "^4.41.3", "@types/webpack-env": "^1.15.2", "@types/webpack-merge": "^4.1.5", "@kbn/utils": "1.0.0", diff --git a/packages/kbn-storybook/webpack.config.ts b/packages/kbn-storybook/webpack.config.ts index 98fca597ffd78..84f8cfaefd669 100644 --- a/packages/kbn-storybook/webpack.config.ts +++ b/packages/kbn-storybook/webpack.config.ts @@ -100,9 +100,5 @@ export default function ({ config: storybookConfig }: { config: Configuration }) if (htmlWebpackPlugin) { htmlWebpackPlugin.options.template = require.resolve('../lib/templates/index.ejs'); } - - // @ts-expect-error There's a long error here about the types of the - // incompatibility of Configuration, but it looks like it just may be Webpack - // type definition related. return webpackMerge(storybookConfig, config); } diff --git a/packages/kbn-test/package.json b/packages/kbn-test/package.json index c616c836d5ff4..4e86ec4bd72e0 100644 --- a/packages/kbn-test/package.json +++ b/packages/kbn-test/package.json @@ -32,7 +32,7 @@ "lodash": "^4.17.20", "parse-link-header": "^1.0.1", "rxjs": "^6.5.5", - "strip-ansi": "^5.2.0", + "strip-ansi": "^6.0.0", "tar-fs": "^2.1.0", "xml2js": "^0.4.22", "zlib": "^1.0.5" diff --git a/packages/kbn-ui-framework/package.json b/packages/kbn-ui-framework/package.json index be18b7cfc0d01..676985fa24740 100644 --- a/packages/kbn-ui-framework/package.json +++ b/packages/kbn-ui-framework/package.json @@ -58,10 +58,10 @@ "postcss-loader": "^3.0.0", "raw-loader": "^3.1.0", "react-dom": "^16.12.0", - "react-redux": "^5.1.2", - "react-router": "^3.2.0", + "react-redux": "^7.2.0", + "react-router": "^5.2.0", "react-router-redux": "^4.0.8", - "redux": "3.7.2", + "redux": "^4.0.5", "redux-thunk": "^2.3.0", "regenerator-runtime": "^0.13.3", "sass-loader": "^8.0.2", diff --git a/tasks/config/run.js b/tasks/config/run.js index 148be6ea8afaa..eddcb0bdd59d0 100644 --- a/tasks/config/run.js +++ b/tasks/config/run.js @@ -240,10 +240,6 @@ module.exports = function () { args: ['scripts/check_licenses', '--dev'], }), - verifyDependencyVersions: gruntTaskWithGithubChecks( - 'Verify dependency versions', - 'verifyDependencyVersions' - ), test_jest: gruntTaskWithGithubChecks('Jest tests', 'test:jest'), test_jest_integration: gruntTaskWithGithubChecks( 'Jest integration tests', diff --git a/tasks/jenkins.js b/tasks/jenkins.js index 90efadf41c435..4e3358ce81bbd 100644 --- a/tasks/jenkins.js +++ b/tasks/jenkins.js @@ -31,7 +31,6 @@ module.exports = function (grunt) { 'run:checkFileCasing', 'run:checkLockfileSymlinks', 'run:licenses', - 'run:verifyDependencyVersions', 'run:verifyNotice', 'run:mocha', 'run:test_jest', diff --git a/tasks/verify_dependency_versions.js b/tasks/verify_dependency_versions.js deleted file mode 100644 index 14ecbb9ba8603..0000000000000 --- a/tasks/verify_dependency_versions.js +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { size } from 'lodash'; -import kibana from '../package.json'; -import xpack from '../x-pack/package.json'; - -function getMismatches(depType) { - return Object.keys(kibana[depType]) - .map((key) => { - const xpackValue = xpack[depType][key]; - const kibanaValue = kibana[depType][key]; - if (xpackValue && kibanaValue && xpackValue !== kibanaValue && !key.includes('@kbn/')) { - return { - key, - xpack: xpackValue, - kibana: kibanaValue, - }; - } - }) - .filter((key) => !!key); -} - -export default function verifyDependencyVersions(grunt) { - grunt.registerTask('verifyDependencyVersions', 'Checks dependency versions', () => { - const devDependenciesMismatches = getMismatches('devDependencies'); - if (size(devDependenciesMismatches) > 0) { - grunt.log.error( - 'The following devDependencies do not match:', - JSON.stringify(devDependenciesMismatches, null, 4) - ); - return false; - } else { - grunt.log.writeln('devDependencies match!'); - } - }); -} diff --git a/test/scripts/checks/verify_dependency_versions.sh b/test/scripts/checks/verify_dependency_versions.sh deleted file mode 100755 index b73a71e7ff7fd..0000000000000 --- a/test/scripts/checks/verify_dependency_versions.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env bash - -source src/dev/ci_setup/setup_env.sh - -yarn run grunt run:verifyDependencyVersions diff --git a/vars/tasks.groovy b/vars/tasks.groovy index edd2c0aa47401..09ff1b0a7d95b 100644 --- a/vars/tasks.groovy +++ b/vars/tasks.groovy @@ -12,7 +12,6 @@ def check() { kibanaPipeline.scriptTask('Check File Casing', 'test/scripts/checks/file_casing.sh'), kibanaPipeline.scriptTask('Check Lockfile Symlinks', 'test/scripts/checks/lock_file_symlinks.sh'), kibanaPipeline.scriptTask('Check Licenses', 'test/scripts/checks/licenses.sh'), - kibanaPipeline.scriptTask('Verify Dependency Versions', 'test/scripts/checks/verify_dependency_versions.sh'), kibanaPipeline.scriptTask('Verify NOTICE', 'test/scripts/checks/verify_notice.sh'), kibanaPipeline.scriptTask('Test Projects', 'test/scripts/checks/test_projects.sh'), kibanaPipeline.scriptTask('Test Hardening', 'test/scripts/checks/test_hardening.sh'), diff --git a/x-pack/package.json b/x-pack/package.json index f9b193bb4da06..5742200b55d9f 100644 --- a/x-pack/package.json +++ b/x-pack/package.json @@ -29,7 +29,7 @@ "**/@types/node": ">=10.17.17 <10.20.0" }, "devDependencies": { - "@cypress/webpack-preprocessor": "^4.1.0", + "@cypress/webpack-preprocessor": "^5.4.1", "@elastic/apm-rum-react": "^1.2.5", "@elastic/maki": "6.3.0", "@kbn/dev-utils": "1.0.0", @@ -159,7 +159,7 @@ "copy-to-clipboard": "^3.0.8", "copy-webpack-plugin": "^6.0.2", "cronstrue": "^1.51.0", - "cypress": "5.0.0", + "cypress": "^5.0.0", "cypress-multi-reporters": "^1.2.3", "cypress-promise": "^1.1.0", "d3": "3.5.17", @@ -257,7 +257,7 @@ "tinycolor2": "1.4.1", "topojson-client": "3.0.0", "tree-kill": "^1.2.2", - "ts-loader": "^6.0.4", + "ts-loader": "^7.0.5", "typescript": "4.0.2", "typescript-fsa": "^3.0.0", "typescript-fsa-reducers": "^1.2.1", @@ -309,7 +309,7 @@ "dedent": "^0.7.0", "del": "^5.1.0", "elasticsearch": "^16.7.0", - "extract-zip": "^1.7.0", + "extract-zip": "^2.0.1", "file-type": "^10.9.0", "font-awesome": "4.7.0", "fp-ts": "^2.3.1", @@ -321,7 +321,7 @@ "glob": "^7.1.2", "graphql": "^0.13.2", "graphql-fields": "^1.0.2", - "graphql-tag": "^2.9.2", + "graphql-tag": "^2.10.3", "graphql-tools": "^3.0.2", "h2o2": "^8.1.2", "handlebars": "4.7.6", @@ -372,7 +372,7 @@ "redux-observable": "^1.2.0", "redux-thunk": "^2.3.0", "request": "^2.88.0", - "rison-node": "0.3.1", + "rison-node": "1.0.2", "rxjs": "^6.5.5", "semver": "^5.7.0", "set-value": "^3.0.2", diff --git a/x-pack/plugins/apm/e2e/package.json b/x-pack/plugins/apm/e2e/package.json index 649198b7eae11..041f9ea7f21c0 100644 --- a/x-pack/plugins/apm/e2e/package.json +++ b/x-pack/plugins/apm/e2e/package.json @@ -14,7 +14,7 @@ "@types/node": ">=10.17.17 <10.20.0", "axios": "^0.19.2", "cypress-cucumber-preprocessor": "^2.5.2", - "cypress": "^4.9.0", + "cypress": "^5.0.0", "ora": "^4.0.4", "p-limit": "^3.0.1", "p-retry": "^4.2.0", diff --git a/x-pack/plugins/apm/scripts/package.json b/x-pack/plugins/apm/scripts/package.json index d3e2d42f972a9..c68dc49cd9370 100644 --- a/x-pack/plugins/apm/scripts/package.json +++ b/x-pack/plugins/apm/scripts/package.json @@ -4,7 +4,7 @@ "main": "index.js", "license": "MIT", "dependencies": { - "@elastic/elasticsearch": "7.9.0-rc.1", + "@elastic/elasticsearch": "7.9.1", "@octokit/rest": "^16.35.0", "console-stamp": "^0.2.9", "hdr-histogram-js": "^1.2.0" diff --git a/x-pack/plugins/reporting/server/browsers/extract/unzip.js b/x-pack/plugins/reporting/server/browsers/extract/unzip.js index d57d04a52f46e..d5166f149372a 100644 --- a/x-pack/plugins/reporting/server/browsers/extract/unzip.js +++ b/x-pack/plugins/reporting/server/browsers/extract/unzip.js @@ -7,14 +7,10 @@ import extractZip from 'extract-zip'; import { ExtractError } from './extract_error'; -export function unzip(filepath, target) { - return new Promise(function (resolve, reject) { - extractZip(filepath, { dir: target }, (err) => { - if (err) { - return reject(new ExtractError(err)); - } - - resolve(); - }); - }); +export async function unzip(filepath, target) { + try { + await extractZip(filepath, { dir: target }); + } catch (err) { + throw new ExtractError(err); + } } diff --git a/x-pack/plugins/security_solution/public/common/mock/timeline_results.ts b/x-pack/plugins/security_solution/public/common/mock/timeline_results.ts index 9f26fc22ede53..ed226fb0c984f 100644 --- a/x-pack/plugins/security_solution/public/common/mock/timeline_results.ts +++ b/x-pack/plugins/security_solution/public/common/mock/timeline_results.ts @@ -32,7 +32,7 @@ export interface MockedProvidedQuery { export const mockOpenTimelineQueryResults: MockedProvidedQuery[] = [ { request: { - query: allTimelinesQuery, + query: (allTimelinesQuery as unknown) as GetAllTimeline.Query, variables: { onlyUserFavorite: false, pageInfo: { diff --git a/x-pack/plugins/security_solution/scripts/beat_docs/build.js b/x-pack/plugins/security_solution/scripts/beat_docs/build.js index 9b3607593a5db..3dbfb75fbe32e 100644 --- a/x-pack/plugins/security_solution/scripts/beat_docs/build.js +++ b/x-pack/plugins/security_solution/scripts/beat_docs/build.js @@ -135,25 +135,25 @@ const convertSchemaToHash = (schema, beatFields) => { }, beatFields); }; -const manageZipFields = async (beat, filePath, beatFields) => - new Promise((resolve, reject) => { - extract(filePath, { dir: beat.outputDir }, (err) => { - if (err) { - return reject(new Error(err)); - } - console.log('building fields', beat.index); - const obj = yaml.load( - fs.readFileSync(`${beat.outputDir}/winlogbeat-7.9.0-windows-x86_64/fields.yml`, { - encoding: 'utf-8', - }) - ); - const eBeatFields = convertSchemaToHash(obj, beatFields); - console.log('deleting files', beat.index); - rimraf.sync(`${beat.outputDir}/winlogbeat-7.9.0-windows-x86_64`); - rimraf.sync(beat.filePath); - resolve(eBeatFields); - }); - }); +const manageZipFields = async (beat, filePath, beatFields) => { + try { + await extract(filePath, { dir: beat.outputDir }); + console.log('building fields', beat.index); + const obj = yaml.load( + fs.readFileSync(`${beat.outputDir}/winlogbeat-7.9.0-windows-x86_64/fields.yml`, { + encoding: 'utf-8', + }) + ); + const eBeatFields = convertSchemaToHash(obj, beatFields); + console.log('deleting files', beat.index); + rimraf.sync(`${beat.outputDir}/winlogbeat-7.9.0-windows-x86_64`); + rimraf.sync(beat.filePath); + + return eBeatFields; + } catch (err) { + throw new Error(err); + } +}; const manageTarFields = async (beat, filePath, beatFields) => new Promise((resolve, reject) => { diff --git a/yarn.lock b/yarn.lock index d795a174cfaa0..2d72b6d6c3bb6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -63,7 +63,7 @@ semver "^5.4.1" source-map "^0.5.0" -"@babel/core@^7.0.1", "@babel/core@^7.1.0", "@babel/core@^7.11.1", "@babel/core@^7.7.5", "@babel/core@^7.9.0": +"@babel/core@^7.1.0", "@babel/core@^7.11.1", "@babel/core@^7.7.5", "@babel/core@^7.9.0": version "7.11.1" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.11.1.tgz#2c55b604e73a40dc21b0e52650b11c65cf276643" integrity sha512-XqF7F6FWQdKGGWAzGELL+aCO1p+lRY5Tj5/tbT3St1G8NaH70jhhDIKknIZaDans0OQBG5wRAldROLHSt44BgQ== @@ -926,7 +926,7 @@ "@babel/helper-create-regexp-features-plugin" "^7.10.4" "@babel/helper-plugin-utils" "^7.10.4" -"@babel/preset-env@^7.0.0", "@babel/preset-env@^7.11.0", "@babel/preset-env@^7.9.5", "@babel/preset-env@^7.9.6": +"@babel/preset-env@^7.11.0", "@babel/preset-env@^7.9.5", "@babel/preset-env@^7.9.6": version "7.11.0" resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.11.0.tgz#860ee38f2ce17ad60480c2021ba9689393efb796" integrity sha512-2u1/k7rG/gTh02dylX2kL3S0IJNF+J6bfDSp4DI2Ma8QN6Y9x9pmAax59fsCk6QUQG0yqH47yJWA+u1I1LccAg== @@ -1168,17 +1168,14 @@ tunnel-agent "^0.6.0" uuid "^3.3.2" -"@cypress/webpack-preprocessor@^4.1.0": - version "4.1.0" - resolved "https://registry.yarnpkg.com/@cypress/webpack-preprocessor/-/webpack-preprocessor-4.1.0.tgz#8c4debc0b1abf045b62524d1996dd9aeaf7e86a8" - integrity sha512-LbxsdYVpHGoC2fMOdW0aQvuvVRD7aZx8p8DrP53HISpl7bD1PqLGWKzhHn7cGG24UHycBJrbaEeKEosW29W1dg== +"@cypress/webpack-preprocessor@^5.4.1": + version "5.4.6" + resolved "https://registry.yarnpkg.com/@cypress/webpack-preprocessor/-/webpack-preprocessor-5.4.6.tgz#667f8007cbe6ee219ce7e45a7f1400d3e2401032" + integrity sha512-78hWoTUUEncv647badwVbyszvmwI1r9GaY/xy7V0sz0VVC90ByuDkLpvN+J0VP6enthob4dIPXcm0f9Tb1UKQQ== dependencies: - bluebird "3.5.0" - debug "3.1.0" - optionalDependencies: - "@babel/core" "^7.0.1" - "@babel/preset-env" "^7.0.0" - babel-loader "^8.0.2" + bluebird "^3.7.1" + debug "^4.1.1" + lodash "^4.17.20" "@cypress/xvfb@^1.2.4": version "1.2.4" @@ -1246,17 +1243,6 @@ utility-types "^3.10.0" uuid "^3.3.2" -"@elastic/elasticsearch@7.9.0-rc.1": - version "7.9.0-rc.1" - resolved "https://registry.yarnpkg.com/@elastic/elasticsearch/-/elasticsearch-7.9.0-rc.1.tgz#50205507ec84ccb95cb7a6d36e5570808749fee9" - integrity sha512-rVjiVj7VPLCusJPfywpb3gvcaA99uylYSum1Frcq4vi2Iqg118KXgYW6GOis2Y70oDZ6w6XRlT0ze5NA6SBa+g== - dependencies: - debug "^4.1.1" - decompress-response "^4.2.0" - ms "^2.1.1" - pump "^3.0.0" - secure-json-parse "^2.1.0" - "@elastic/elasticsearch@7.9.1": version "7.9.1" resolved "https://registry.yarnpkg.com/@elastic/elasticsearch/-/elasticsearch-7.9.1.tgz#40f1c38e8f70d783851c13be78a7cb346891c15e" @@ -4487,14 +4473,6 @@ "@types/node" "*" "@types/webpack" "*" -"@types/loader-utils@^2.0.1": - version "2.0.1" - resolved "https://registry.yarnpkg.com/@types/loader-utils/-/loader-utils-2.0.1.tgz#4073425aca25762099823f7b922e86599c2b85ec" - integrity sha512-X3jTNi/I2AEd2WrHdSqRppPkYzWkRMNGxJzeMwS0o3hVi8ZB6JCnf/XyQmqpUuCidld5lC/1VxVgTktEweRK+w== - dependencies: - "@types/node" "*" - "@types/webpack" "*" - "@types/lodash.difference@^4.5.6": version "4.5.6" resolved "https://registry.yarnpkg.com/@types/lodash.difference/-/lodash.difference-4.5.6.tgz#41ec5c4e684eeacf543848a9a1b2a4856ccf9853" @@ -5085,11 +5063,6 @@ resolved "https://registry.yarnpkg.com/@types/stats-lite/-/stats-lite-2.2.0.tgz#bc8190bf9dfa1e16b89eaa2b433c99dff0804de9" integrity sha512-YV6SS4QC+pbzqjMIV8qVSTDOOazgKBLTVaN+7PfuxELjz/eyzc20KwDVGPrbHt2OcYMA7K2ezLB45Cp6DpNOSQ== -"@types/strip-ansi@^3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@types/strip-ansi/-/strip-ansi-3.0.0.tgz#9b63d453a6b54aa849182207711a08be8eea48ae" - integrity sha1-m2PUU6a1SqhJGCIHcRoIvo7qSK4= - "@types/strip-ansi@^5.2.1": version "5.2.1" resolved "https://registry.yarnpkg.com/@types/strip-ansi/-/strip-ansi-5.2.1.tgz#acd97f1f091e332bb7ce697c4609eb2370fa2a92" @@ -5339,7 +5312,7 @@ "@types/webpack-sources" "*" source-map "^0.6.0" -"@types/webpack@^4.41.21", "@types/webpack@^4.41.5", "@types/webpack@^4.41.8": +"@types/webpack@^4.41.8": version "4.41.21" resolved "https://registry.yarnpkg.com/@types/webpack/-/webpack-4.41.21.tgz#cc685b332c33f153bb2f5fc1fa3ac8adeb592dee" integrity sha512-2j9WVnNrr/8PLAB5csW44xzQSJwS26aOnICsP3pSGCEdsu6KYtfQ6QJsVUKHWRnm1bL7HziJsfh5fHqth87yKA== @@ -6283,11 +6256,6 @@ ansi-escapes@^1.0.0, ansi-escapes@^1.1.0: resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" integrity sha1-06ioOzGapneTZisT52HHkRQiMG4= -ansi-escapes@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-2.0.0.tgz#5bae52be424878dd9783e8910e3fc2922e83c81b" - integrity sha1-W65SvkJIeN2Xg+iRDj/Cki6DyBs= - ansi-escapes@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.0.0.tgz#ec3e8b4e9f8064fc02c3ac9b65f1c275bda8ef92" @@ -7348,7 +7316,7 @@ babel-jest@^26.3.0: graceful-fs "^4.2.4" slash "^3.0.0" -babel-loader@^8.0.2, babel-loader@^8.0.6: +babel-loader@^8.0.6: version "8.0.6" resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.0.6.tgz#e33bdb6f362b03f4bb141a0c21ab87c501b70dfb" integrity sha512-4BmWKtBOBm13uoUwd08UwjZlaw3O9GWf456R9j+5YykFZ6LUIjIKLc0zEZf+hauxPOJs96C8k6FvYD09vWzhYw== @@ -7985,17 +7953,12 @@ bluebird-retry@^0.11.0: resolved "https://registry.yarnpkg.com/bluebird-retry/-/bluebird-retry-0.11.0.tgz#1289ab22cbbc3a02587baad35595351dd0c1c047" integrity sha1-EomrIsu8OgJYe6rTVZU1HdDBwEc= -bluebird@3.5.0: - version "3.5.0" - resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.0.tgz#791420d7f551eea2897453a8a77653f96606d67c" - integrity sha1-eRQg1/VR7qKJdFOop3ZT+WYG1nw= - bluebird@3.5.5, bluebird@^3.5.0, bluebird@^3.5.1, bluebird@^3.5.5: version "3.5.5" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.5.tgz#a8d0afd73251effbbd5fe384a77d73003c17a71f" integrity sha512-5am6HnnfN+urzt4yfg7IgTbotDjIT/u8AJpEt0sIU9FtXfVeezXAPKswrG+xKUCOYAINpSdgZVDU6QFh+cuH3w== -bluebird@3.7.2, bluebird@^3.7.2: +bluebird@3.7.2, bluebird@^3.7.1, bluebird@^3.7.2: version "3.7.2" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== @@ -8672,15 +8635,6 @@ camelcase-keys@^2.0.0: camelcase "^2.0.0" map-obj "^1.0.0" -camelcase-keys@^4.0.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-4.2.0.tgz#a2aa5fb1af688758259c32c141426d78923b9b77" - integrity sha1-oqpfsa9oh1glnDLBQUJteJI7m3c= - dependencies: - camelcase "^4.1.0" - map-obj "^2.0.0" - quick-lru "^1.0.0" - camelcase-keys@^6.2.2: version "6.2.2" resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-6.2.2.tgz#5e755d6ba51aa223ec7d3d52f25778210f9dc3c0" @@ -8705,7 +8659,7 @@ camelcase@^3.0.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a" integrity sha1-MvxLn82vhF/N9+c7uXysImHwqwo= -camelcase@^4.0.0, camelcase@^4.1.0: +camelcase@^4.0.0: version "4.1.0" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" integrity sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0= @@ -9245,17 +9199,12 @@ cli-spinners@^0.1.2: resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-0.1.2.tgz#bb764d88e185fb9e1e6a2a1f19772318f605e31c" integrity sha1-u3ZNiOGF+54eaiofGXcjGPYF4xw= -cli-spinners@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-1.1.0.tgz#f1847b168844d917a671eb9d147e3df497c90d06" - integrity sha1-8YR7FohE2RemceudFH499JfJDQY= - cli-spinners@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.1.0.tgz#22c34b4d51f573240885b201efda4e4ec9fff3c7" integrity sha512-8B00fJOEh1HPrx4fo5eW16XmE1PcL1tGpGrxy63CXGP9nHdPBN63X75hA1zhvQuhVztJWLqV58Roj2qlNM7cAA== -cli-spinners@^2.4.0: +cli-spinners@^2.2.0, cli-spinners@^2.4.0: version "2.4.0" resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.4.0.tgz#c6256db216b878cfba4720e719cec7cf72685d7f" integrity sha512-sJAofoarcm76ZGpuooaO0eDy8saEy+YoZBLjC4h8srt4jeBnkYeOgqxgsJQTpyt2LjI5PTfLJHSL+41Yu4fEJA== @@ -10219,7 +10168,7 @@ create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4: safe-buffer "^5.0.1" sha.js "^2.4.8" -create-react-class@^15.5.1, create-react-class@^15.5.2: +create-react-class@^15.5.2: version "15.6.3" resolved "https://registry.yarnpkg.com/create-react-class/-/create-react-class-15.6.3.tgz#2d73237fb3f970ae6ebe011a9e66f46dbca80036" integrity sha512-M+/3Q6E6DLO6Yx3OwrWjwHBnvfXXYA7W+dFjt/ZDBemHO1DDZhsalX/NUtnTYclN6GfnBDRh4qRHjcDHmlJBJg== @@ -10586,10 +10535,10 @@ cypress-promise@^1.1.0: resolved "https://registry.yarnpkg.com/cypress-promise/-/cypress-promise-1.1.0.tgz#f2d66965945fe198431aaf692d5157cea9d47b25" integrity sha512-DhIf5PJ/a0iY+Yii6n7Rbwq+9TJxU4pupXYzf9mZd8nPG0AzQrj9i+pqINv4xbI2EV1p+PKW3maCkR7oPG4GrA== -cypress@5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/cypress/-/cypress-5.0.0.tgz#6957e299b790af8b1cd7bea68261b8935646f72e" - integrity sha512-jhPd0PMO1dPSBNpx6pHVLkmnnaTfMy3wCoacHAKJ9LJG06y16zqUNSFri64N4BjuGe8y6mNMt8TdgKnmy9muCg== +cypress@^5.0.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/cypress/-/cypress-5.2.0.tgz#6902efd90703242a2539f0623c6e1118aff01f95" + integrity sha512-9S2spcrpIXrQ+CQIKHsjRoLQyRc2ehB06clJXPXXp1zyOL/uZMM3Qc20ipNki4CcNwY0nBTQZffPbRpODeGYQg== dependencies: "@cypress/listr-verbose-renderer" "^0.4.1" "@cypress/request" "^2.88.5" @@ -11042,7 +10991,7 @@ debuglog@^1.0.1: resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492" integrity sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI= -decamelize-keys@^1.0.0, decamelize-keys@^1.1.0: +decamelize-keys@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/decamelize-keys/-/decamelize-keys-1.1.0.tgz#d171a87933252807eb3cb61dc1c1445d078df2d9" integrity sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk= @@ -11098,7 +11047,7 @@ deep-eql@^0.1.3: dependencies: type-detect "0.1.1" -deep-equal@^1.0.0, deep-equal@^1.1.1, deep-equal@~1.1.1: +deep-equal@^1.0.0, deep-equal@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.1.1.tgz#b5c98c942ceffaf7cb051e24e1434a25a2e6076a" integrity sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g== @@ -11843,7 +11792,7 @@ dotenv@^8.1.0: resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.2.0.tgz#97e619259ada750eea3e4ea3e26bceea5424b16a" integrity sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw== -dotignore@^0.1.2, dotignore@~0.1.2: +dotignore@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/dotignore/-/dotignore-0.1.2.tgz#f942f2200d28c3a76fbdd6f0ee9f3257c8a2e905" integrity sha512-UGGGWfSauusaVJC+8fgV+NVvBXkCTmVv7sk6nojDZZvuOUNGUy0Zk4UpHQD6EDjS0jpBwcACvH4eofvyzBcRDw== @@ -12640,17 +12589,6 @@ eslint-config-prettier@^6.11.0: dependencies: get-stdin "^6.0.0" -eslint-formatter-pretty@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/eslint-formatter-pretty/-/eslint-formatter-pretty-1.3.0.tgz#985d9e41c1f8475f4a090c5dbd2dfcf2821d607e" - integrity sha512-5DY64Y1rYCm7cfFDHEGUn54bvCnK+wSUVF07N8oXeqUJFSd+gnYOTXbzelQ1HurESluY6gnEQPmXOIkB4Wa+gA== - dependencies: - ansi-escapes "^2.0.0" - chalk "^2.1.0" - log-symbols "^2.0.0" - plur "^2.1.2" - string-width "^2.0.0" - eslint-formatter-pretty@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/eslint-formatter-pretty/-/eslint-formatter-pretty-4.0.0.tgz#dc15f3bf4fb51b7ba5fbedb77f57ba8841140ce2" @@ -14801,7 +14739,7 @@ glob@^6.0.1, glob@^6.0.4: once "^1.3.0" path-is-absolute "^1.0.0" -glob@^7.0.0, glob@^7.0.3, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6, glob@~7.1.1, glob@~7.1.4, glob@~7.1.6: +glob@^7.0.0, glob@^7.0.3, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6, glob@~7.1.1, glob@~7.1.4: version "7.1.6" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== @@ -15015,7 +14953,7 @@ globby@^6.1.0: pify "^2.0.0" pinkie-promise "^2.0.0" -globby@^9.1.0, globby@^9.2.0: +globby@^9.2.0: version "9.2.0" resolved "https://registry.yarnpkg.com/globby/-/globby-9.2.0.tgz#fd029a706c703d29bdd170f4b6db3a3f7a7cb63d" integrity sha512-ollPHROa5mcxDEkwg6bPt3QbEf4pDQSNtd6JPL1YvOvAo/7/0VAm9TccUeoTmarjPw4pfUthSCqcyfNB1I3ZSg== @@ -15383,7 +15321,7 @@ graphql-tag-pluck@0.6.0: source-map-support "^0.5.9" typescript "^3.2.2" -graphql-tag@2.10.1, graphql-tag@^2.9.2: +graphql-tag@2.10.1: version "2.10.1" resolved "https://registry.yarnpkg.com/graphql-tag/-/graphql-tag-2.10.1.tgz#10aa41f1cd8fae5373eaf11f1f67260a3cad5e02" integrity sha512-jApXqWBzNXQ8jYa/HLkZJaVw9jgwNqZkywa2zfFn16Iv1Zb7ELNHkJaXHR7Quvd5SIGsy6Ny7SUKATgnu05uEg== @@ -15439,13 +15377,6 @@ graphql@^0.13.2: dependencies: iterall "^1.2.1" -graphql@^14.0.0: - version "14.6.0" - resolved "https://registry.yarnpkg.com/graphql/-/graphql-14.6.0.tgz#57822297111e874ea12f5cd4419616930cd83e49" - integrity sha512-VKzfvHEKybTKjQVpTFrA5yUq2S9ihcZvfJAtsDBBCuV6wauPu1xl/f9ehgVf0FcEJJs4vz6ysb/ZMkGigQZseg== - dependencies: - iterall "^1.2.2" - graphviz@^0.0.8: version "0.0.8" resolved "https://registry.yarnpkg.com/graphviz/-/graphviz-0.0.8.tgz#e599e40733ef80e1653bfe89a5f031ecf2aa4aaa" @@ -16102,16 +16033,6 @@ history-extra@^5.0.1: resolved "https://registry.yarnpkg.com/history-extra/-/history-extra-5.0.1.tgz#95a2e59dda526c4241d0ae1b124a77a5e4675ce8" integrity sha512-6XV1L1lHgporVWgppa/Kq+Fnz4lhBew7iMxYCTfzVmoEywsAKJnTjdw1zOd+EGLHGYp0/V8jSVMEgqx4QbHLTw== -history@^3.0.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/history/-/history-3.3.0.tgz#fcedcce8f12975371545d735461033579a6dae9c" - integrity sha1-/O3M6PEpdTcVRdc1RhAzV5ptrpw= - dependencies: - invariant "^2.2.1" - loose-envify "^1.2.0" - query-string "^4.2.2" - warning "^3.0.0" - history@^4.9.0: version "4.9.0" resolved "https://registry.yarnpkg.com/history/-/history-4.9.0.tgz#84587c2068039ead8af769e9d6a6860a14fa1bca" @@ -16773,7 +16694,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.4, inherits@^2.0.4, inherits@~2.0.3, inherits@~2.0.4: +inherits@2, inherits@2.0.4, inherits@^2.0.4, inherits@~2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -16870,7 +16791,7 @@ inquirer@^0.12.0: strip-ansi "^3.0.0" through "^2.3.6" -inquirer@^1.0.2, inquirer@^1.2.2: +inquirer@^1.0.2: version "1.2.3" resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-1.2.3.tgz#4dec6f32f37ef7bb0b2ed3f1d1a5c3f545074918" integrity sha1-TexvMvN+97sLLtPx0aXD9UUHSRg= @@ -17038,7 +16959,7 @@ invariant@2.2.4, invariant@^2.1.0, invariant@^2.1.1, invariant@^2.2.3, invariant dependencies: loose-envify "^1.0.0" -invariant@^2.2.1, invariant@^2.2.2: +invariant@^2.2.2: version "2.2.2" resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.2.tgz#9e1f56ac0acdb6bf303306f338be3b204ae60360" integrity sha1-nh9WrArNtr8wMwbzOL47IErmA2A= @@ -17089,11 +17010,6 @@ iron@5.x.x: cryptiles "4.x.x" hoek "5.x.x" -irregular-plurals@^1.0.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/irregular-plurals/-/irregular-plurals-1.4.0.tgz#2ca9b033651111855412f16be5d77c62a458a766" - integrity sha1-LKmwM2UREYVUEvFr5dd8YqRYp2Y= - irregular-plurals@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/irregular-plurals/-/irregular-plurals-3.2.0.tgz#b19c490a0723798db51b235d7e39add44dab0822" @@ -17637,7 +17553,7 @@ is-redirect@^1.0.0: resolved "https://registry.yarnpkg.com/is-redirect/-/is-redirect-1.0.0.tgz#1d03dded53bd8db0f30c26e4f95d36fc7c87dc24" integrity sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ= -is-regex@^1.0.4, is-regex@^1.0.5, is-regex@~1.0.5: +is-regex@^1.0.4, is-regex@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.5.tgz#39d589a358bf18967f726967120b8fc1aed74eae" integrity sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ== @@ -18066,11 +17982,6 @@ iterall@^1.1.3, iterall@^1.2.1: resolved "https://registry.yarnpkg.com/iterall/-/iterall-1.2.2.tgz#92d70deb8028e0c39ff3164fdbf4d8b088130cd7" integrity sha512-yynBb1g+RFUPY64fTrFv7nsjRrENBQJaX2UL+2Szc9REFrSNm1rpSXHGzhmAy7a9uv3vlvgBlXnf9RqmPH1/DA== -iterall@^1.2.2: - version "1.3.0" - resolved "https://registry.yarnpkg.com/iterall/-/iterall-1.3.0.tgz#afcb08492e2915cbd8a0884eb93a8c94d0d72fea" - integrity sha512-QZ9qOMdF+QLHxy1QIpUHUU1D5pS2CG2P69LF6L6CPjPYA/XMOmKV3PZpawHoAjHNyB0swdVTRxdYT4tbBbxqwg== - iterate-iterator@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/iterate-iterator/-/iterate-iterator-1.0.1.tgz#1693a768c1ddd79c969051459453f082fe82e9f6" @@ -19737,7 +19648,7 @@ locutus@^2.0.5: resolved "https://registry.yarnpkg.com/locutus/-/locutus-2.0.10.tgz#f903619466a98a4ab76e8b87a5854b55a743b917" integrity sha512-AZg2kCqrquMJ5FehDsBidV0qHl98NrsYtseUClzjAQ3HFnsDBJTCwGVplSQ82t9/QfgahqvTjaKcZqZkHmS0wQ== -lodash-es@^4.17.11, lodash-es@^4.2.1: +lodash-es@^4.17.11: version "4.17.15" resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.15.tgz#21bd96839354412f23d7a10340e5eac6ee455d78" integrity sha512-rlrc3yU3+JNOpZ9zj5pQtxnx2THmvRykwL4Xlxoa8I9lHBlVbbyPhgyPMioxVZ4NqyxaVVtaJnzsyOidQIhyyQ== @@ -19997,7 +19908,7 @@ lodash.uniq@4.5.0, lodash.uniq@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= -lodash@4.17.11, lodash@4.17.15, lodash@>4.17.4, lodash@^4, lodash@^4.0.0, lodash@^4.0.1, lodash@^4.10.0, lodash@^4.11.1, lodash@^4.15.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.2, lodash@^4.17.20, lodash@^4.17.4, lodash@^4.2.0, lodash@^4.2.1, lodash@^4.3.0, lodash@~4.17.10, lodash@~4.17.15, lodash@~4.17.5: +lodash@4.17.11, lodash@4.17.15, lodash@>4.17.4, lodash@^4, lodash@^4.0.0, lodash@^4.0.1, lodash@^4.10.0, lodash@^4.11.1, lodash@^4.15.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.2, lodash@^4.17.20, lodash@^4.17.4, lodash@^4.2.0, lodash@^4.3.0, lodash@~4.17.10, lodash@~4.17.15, lodash@~4.17.5: version "4.17.20" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52" integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA== @@ -20010,14 +19921,14 @@ log-ok@^0.1.1: ansi-green "^0.1.1" success-symbol "^0.1.0" -log-symbols@2.2.0, log-symbols@^2.0.0, log-symbols@^2.1.0, log-symbols@^2.2.0: +log-symbols@2.2.0, log-symbols@^2.1.0, log-symbols@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a" integrity sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg== dependencies: chalk "^2.0.1" -log-symbols@3.0.0: +log-symbols@3.0.0, log-symbols@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-3.0.0.tgz#f3a08516a5dea893336a7dee14d18a1cfdab77c4" integrity sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ== @@ -20326,11 +20237,6 @@ map-obj@^1.0.0, map-obj@^1.0.1: resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" integrity sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0= -map-obj@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-2.0.0.tgz#a65cd29087a92598b8791257a523e021222ac1f9" - integrity sha1-plzSkIepJZi4eRJXpSPgISIqwfk= - map-obj@^4.0.0: version "4.1.0" resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-4.1.0.tgz#b91221b542734b9f14256c0132c897c5d7256fd5" @@ -20647,21 +20553,6 @@ meow@^3.0.0, meow@^3.3.0, meow@^3.7.0: redent "^1.0.0" trim-newlines "^1.0.0" -meow@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/meow/-/meow-5.0.0.tgz#dfc73d63a9afc714a5e371760eb5c88b91078aa4" - integrity sha512-CbTqYU17ABaLefO8vCU153ZZlprKYWDljcndKKDCFcYQITzWCXZAVk4QMFZPgvzrnUQ3uItnIE/LoUOwrT15Ig== - dependencies: - camelcase-keys "^4.0.0" - decamelize-keys "^1.0.0" - loud-rejection "^1.0.0" - minimist-options "^3.0.1" - normalize-package-data "^2.3.4" - read-pkg-up "^3.0.0" - redent "^2.0.0" - trim-newlines "^2.0.0" - yargs-parser "^10.0.0" - meow@^6.1.1: version "6.1.1" resolved "https://registry.yarnpkg.com/meow/-/meow-6.1.1.tgz#1ad64c4b76b2a24dfb2f635fddcadf320d251467" @@ -20927,14 +20818,6 @@ minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: dependencies: brace-expansion "^1.1.7" -minimist-options@^3.0.1: - version "3.0.2" - resolved "https://registry.yarnpkg.com/minimist-options/-/minimist-options-3.0.2.tgz#fba4c8191339e13ecf4d61beb03f070103f3d954" - integrity sha512-FyBrT/d0d4+uiZRbqznPXqw3IpZZG3gl3wKWiX784FycUKVwBt0uLBFkQrtE4tZOrgo78nZp2jnKz3L65T5LdQ== - dependencies: - arrify "^1.0.1" - is-plain-obj "^1.1.0" - minimist-options@^4.0.2: version "4.1.0" resolved "https://registry.yarnpkg.com/minimist-options/-/minimist-options-4.1.0.tgz#c0655713c53a8a2ebd77ffa247d342c40f010619" @@ -22161,7 +22044,7 @@ object-identity-map@^1.0.2: dependencies: object.entries "^1.1.0" -object-inspect@^1.6.0, object-inspect@^1.7.0, object-inspect@~1.7.0: +object-inspect@^1.6.0, object-inspect@^1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.7.0.tgz#f4f6bd181ad77f006b5ece60bd0b6f398ff74a67" integrity sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw== @@ -22485,16 +22368,6 @@ ora@^0.2.3: cli-spinners "^0.1.2" object-assign "^4.0.1" -ora@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/ora/-/ora-1.4.0.tgz#884458215b3a5d4097592285f93321bb7a79e2e5" - integrity sha512-iMK1DOQxzzh2MBlVsU42G80mnrvUhqsMh74phHtDlrcTZPK0pH6o7l7DRshK+0YsxDyEuaOkziVdvM3T0QTzpw== - dependencies: - chalk "^2.1.0" - cli-cursor "^2.1.0" - cli-spinners "^1.0.1" - log-symbols "^2.1.0" - ora@^3.0.0: version "3.4.0" resolved "https://registry.yarnpkg.com/ora/-/ora-3.4.0.tgz#bf0752491059a3ef3ed4c85097531de9fdbcd318" @@ -22507,6 +22380,20 @@ ora@^3.0.0: strip-ansi "^5.2.0" wcwidth "^1.0.1" +ora@^4.0.4: + version "4.1.1" + resolved "https://registry.yarnpkg.com/ora/-/ora-4.1.1.tgz#566cc0348a15c36f5f0e979612842e02ba9dddbc" + integrity sha512-sjYP8QyVWBpBZWD6Vr1M/KwknSw6kJOz41tvGMlwWeClHBtYKTbHMki1PsLZnxKpXMPbTKv9b3pjQu3REib96A== + dependencies: + chalk "^3.0.0" + cli-cursor "^3.1.0" + cli-spinners "^2.2.0" + is-interactive "^1.0.0" + log-symbols "^3.0.0" + mute-stream "0.0.8" + strip-ansi "^6.0.0" + wcwidth "^1.0.1" + ora@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/ora/-/ora-5.1.0.tgz#b188cf8cd2d4d9b13fd25383bc3e5cba352c94f8" @@ -23450,13 +23337,6 @@ plugin-error@^1.0.1: arr-union "^3.1.0" extend-shallow "^3.0.2" -plur@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/plur/-/plur-2.1.2.tgz#7482452c1a0f508e3e344eaec312c91c29dc655a" - integrity sha1-dIJFLBoPUI4+NE6uwxLJHCncZVo= - dependencies: - irregular-plurals "^1.0.0" - plur@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/plur/-/plur-4.0.0.tgz#729aedb08f452645fe8c58ef115bf16b0a73ef84" @@ -23911,7 +23791,7 @@ prop-types-exact@^1.2.0: object.assign "^4.1.0" reflect.ownkeys "^0.2.0" -prop-types@15.7.2, prop-types@15.x, prop-types@^15.5.10, prop-types@^15.5.6, prop-types@^15.5.7, prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2: +prop-types@15.7.2, prop-types@15.x, prop-types@^15.5.10, prop-types@^15.5.7, prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2: version "15.7.2" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== @@ -24149,7 +24029,7 @@ qs@^6.6.0: resolved "https://registry.yarnpkg.com/qs/-/qs-6.8.0.tgz#87b763f0d37ca54200334cd57bb2ef8f68a1d081" integrity sha512-tPSkj8y92PfZVbinY1n84i1Qdx75lZjMQYx9WZhnkofyxzw2r7Ho39G3/aEvSUdebxpnnM4LZJCtvE/Aq3+s9w== -query-string@^4.1.0, query-string@^4.2.2: +query-string@^4.1.0: version "4.3.4" resolved "https://registry.yarnpkg.com/query-string/-/query-string-4.3.4.tgz#bbb693b9ca915c232515b228b1a02b609043dbeb" integrity sha1-u7aTucqRXCMlFbIosaArYJBD2+s= @@ -24197,11 +24077,6 @@ queue@6.0.1: dependencies: inherits "~2.0.3" -quick-lru@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-1.1.0.tgz#4360b17c61136ad38078397ff11416e186dcfbb8" - integrity sha1-Q2CxfGETatOAeDl/8RQW4Ybc+7g= - quick-lru@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-4.0.1.tgz#5b8878f113a58217848c6482026c73e1ba57727f" @@ -24706,7 +24581,7 @@ react-lib-adler32@^1.0.3: resolved "https://registry.yarnpkg.com/react-lib-adler32/-/react-lib-adler32-1.0.3.tgz#63df1aed274eabcc1c5067077ea281ec30888ba7" integrity sha512-AqFqdt4cP0RPffHNjVHZ7tyIgnoSzNxgFhG8XKMXCtA1dZ72gTPO4iYFwWDKHqvE8sHS14rhltQTdbXU5G4BFA== -react-lifecycles-compat@^3.0.0, react-lifecycles-compat@^3.0.4: +react-lifecycles-compat@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362" integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA== @@ -24783,19 +24658,6 @@ react-portal@^3.2.0: dependencies: prop-types "^15.5.8" -react-redux@^5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-5.1.2.tgz#b19cf9e21d694422727bf798e934a916c4080f57" - integrity sha512-Ns1G0XXc8hDyH/OcBHOxNgQx9ayH3SPxBnFCOidGKSle8pKihysQw2rG/PmciUQRoclhVBO8HMhiRmGXnDja9Q== - dependencies: - "@babel/runtime" "^7.1.2" - hoist-non-react-statics "^3.3.0" - invariant "^2.2.4" - loose-envify "^1.1.0" - prop-types "^15.6.1" - react-is "^16.6.0" - react-lifecycles-compat "^3.0.0" - react-redux@^7.1.0, react-redux@^7.1.1, react-redux@^7.2.0: version "7.2.0" resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-7.2.0.tgz#f970f62192b3981642fec46fd0db18a074fe879d" @@ -24884,19 +24746,6 @@ react-router@5.2.0, react-router@^5.2.0: tiny-invariant "^1.0.2" tiny-warning "^1.0.0" -react-router@^3.2.0: - version "3.2.1" - resolved "https://registry.yarnpkg.com/react-router/-/react-router-3.2.1.tgz#b9a3279962bdfbe684c8bd0482b81ef288f0f244" - integrity sha512-SXkhC0nr3G0ltzVU07IN8jYl0bB6FsrDIqlLC9dK3SITXqyTJyM7yhXlUqs89w3Nqi5OkXsfRUeHX+P874HQrg== - dependencies: - create-react-class "^15.5.1" - history "^3.0.0" - hoist-non-react-statics "^2.3.1" - invariant "^2.2.1" - loose-envify "^1.2.0" - prop-types "^15.5.6" - warning "^3.0.0" - react-select@^3.0.8: version "3.1.0" resolved "https://registry.yarnpkg.com/react-select/-/react-select-3.1.0.tgz#ab098720b2e9fe275047c993f0d0caf5ded17c27" @@ -25174,14 +25023,6 @@ read-pkg-up@^2.0.0: find-up "^2.0.0" read-pkg "^2.0.0" -read-pkg-up@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-3.0.0.tgz#3ed496685dba0f8fe118d0691dc51f4a1ff96f07" - integrity sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc= - dependencies: - find-up "^2.0.0" - read-pkg "^3.0.0" - read-pkg-up@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-4.0.0.tgz#1b221c6088ba7799601c808f91161c66e58f8978" @@ -25389,14 +25230,6 @@ redent@^1.0.0: indent-string "^2.1.0" strip-indent "^1.0.1" -redent@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/redent/-/redent-2.0.0.tgz#c1b2007b42d57eb1389079b3c8333639d5e1ccaa" - integrity sha1-wbIAe0LVfrE4kHmzyDM2OdXhzKo= - dependencies: - indent-string "^3.0.0" - strip-indent "^2.0.0" - redent@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/redent/-/redent-3.0.0.tgz#e557b7998316bb53c9f1f56fa626352c6963059f" @@ -25460,16 +25293,6 @@ redux-thunks@^1.0.0: resolved "https://registry.yarnpkg.com/redux-thunks/-/redux-thunks-1.0.0.tgz#56e03b86d281a2664c884ab05c543d9ab1673658" integrity sha1-VuA7htKBomZMiEqwXFQ9mrFnNlg= -redux@3.7.2: - version "3.7.2" - resolved "https://registry.yarnpkg.com/redux/-/redux-3.7.2.tgz#06b73123215901d25d065be342eb026bc1c8537b" - integrity sha512-pNqnf9q1hI5HHZRBkj3bAngGZW/JMCmexDlOxw4XagXY2o1327nHH54LoTjiPJ0gizoqPDRqWyX/00g0hD6w+A== - dependencies: - lodash "^4.2.1" - lodash-es "^4.2.1" - loose-envify "^1.1.0" - symbol-observable "^1.0.3" - redux@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/redux/-/redux-4.0.0.tgz#aa698a92b729315d22b34a0553d7e6533555cc03" @@ -26216,13 +26039,6 @@ resolve@~1.10.1: dependencies: path-parse "^1.0.6" -resolve@~1.14.2: - version "1.14.2" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.14.2.tgz#dbf31d0fa98b1f29aa5169783b9c290cb865fea2" - integrity sha512-EjlOBLBO1kxsUxsKjLt7TAECyKW6fOh1VRkykQkKGzcBbjjPIxBqGh0jf7GJ3k/f5mxMqW3htMD3WdTUVtW8HQ== - dependencies: - path-parse "^1.0.6" - responselike@1.0.2, responselike@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7" @@ -26352,11 +26168,6 @@ ripemd160@^2.0.0, ripemd160@^2.0.1: hash-base "^2.0.0" inherits "^2.0.1" -rison-node@0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/rison-node/-/rison-node-0.3.1.tgz#fc540015500fc146f3b27d8d25dd5742122552a6" - integrity sha1-/FQAFVAPwUbzsn2NJd1XQhIlUqY= - rison-node@1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/rison-node/-/rison-node-1.0.2.tgz#b7b5f37f39f5ae2a51a973a33c9aa17239a33e4b" @@ -27877,7 +27688,7 @@ string.prototype.padstart@^3.0.0: es-abstract "^1.4.3" function-bind "^1.0.2" -string.prototype.trim@^1.2.1, string.prototype.trim@~1.2.1: +string.prototype.trim@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.1.tgz#141233dff32c82bfad80684d7e5f0869ee0fb782" integrity sha512-MjGFEeqixw47dAMFMtgUro/I0+wNqZB5GKXGt1fFr24u3TzDXCPu7J9Buppzoe3r/LqkSDLDDJzE15RGWDGAVw== @@ -28053,11 +27864,6 @@ strip-indent@^1.0.1: dependencies: get-stdin "^4.0.1" -strip-indent@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-2.0.0.tgz#5ef8db295d01e6ed6cbf7aab96998d7822527b68" - integrity sha1-XvjbKV0B5u1sv3qrlpmNeCJSe2g= - strip-indent@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-3.0.0.tgz#c32e1cee940b6b3432c771bc2c54bcce73cd3001" @@ -28358,7 +28164,7 @@ symbol-observable@1.0.1: resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.0.1.tgz#8340fc4702c3122df5d22288f88283f513d3fdd4" integrity sha1-g0D8RwLDEi310iKI+IKD9RPT/dQ= -symbol-observable@^1.0.2, symbol-observable@^1.0.3, symbol-observable@^1.0.4, symbol-observable@^1.1.0, symbol-observable@^1.2.0: +symbol-observable@^1.0.2, symbol-observable@^1.0.4, symbol-observable@^1.1.0, symbol-observable@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ== @@ -28452,27 +28258,6 @@ tapable@^1.1.3: resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2" integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA== -tape@^4.13.0: - version "4.13.0" - resolved "https://registry.yarnpkg.com/tape/-/tape-4.13.0.tgz#e2f581ff5f12a7cbd787e9f83c76c2851782fce2" - integrity sha512-J/hvA+GJnuWJ0Sj8Z0dmu3JgMNU+MmusvkCT7+SN4/2TklW18FNCp/UuHIEhPZwHfy4sXfKYgC7kypKg4umbOw== - dependencies: - deep-equal "~1.1.1" - defined "~1.0.0" - dotignore "~0.1.2" - for-each "~0.3.3" - function-bind "~1.1.1" - glob "~7.1.6" - has "~1.0.3" - inherits "~2.0.4" - is-regex "~1.0.5" - minimist "~1.2.0" - object-inspect "~1.7.0" - resolve "~1.14.2" - resumer "~0.0.0" - string.prototype.trim "~1.2.1" - through "~2.3.8" - tape@^4.5.1: version "4.10.2" resolved "https://registry.yarnpkg.com/tape/-/tape-4.10.2.tgz#129fcf62f86df92687036a52cce7b8ddcaffd7a6" @@ -29176,11 +28961,6 @@ trim-newlines@^1.0.0: resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613" integrity sha1-WIeWa7WCpFA6QetST301ARgVphM= -trim-newlines@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-2.0.0.tgz#b403d0b91be50c331dfc4b82eeceb22c3de16d20" - integrity sha1-tAPQuRvlDDMd/EuC7s6yLD3hbSA= - trim-newlines@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-3.0.0.tgz#79726304a6a898aa8373427298d54c2ee8b1cb30" @@ -29259,10 +29039,10 @@ ts-invariant@^0.4.0: dependencies: tslib "^1.9.3" -ts-loader@^6.0.4: - version "6.0.4" - resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-6.0.4.tgz#bc331ad91a887a60632d94c9f79448666f2c4b63" - integrity sha512-p2zJYe7OtwR+49kv4gs7v4dMrfYD1IPpOtqiSPCbe8oR+4zEBtdHwzM7A7M91F+suReqgzZrlClk4LRSSp882g== +ts-loader@^7.0.5: + version "7.0.5" + resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-7.0.5.tgz#789338fb01cb5dc0a33c54e50558b34a73c9c4c5" + integrity sha512-zXypEIT6k3oTc+OZNx/cqElrsbBtYqDknf48OZos0NQ3RTt045fBIU8RRSu+suObBzYB355aIPGOe/3kj9h7Ig== dependencies: chalk "^2.3.0" enhanced-resolve "^4.0.0" @@ -29292,19 +29072,6 @@ tsd@^0.13.1: read-pkg-up "^7.0.0" update-notifier "^4.1.0" -tsd@^0.7.4: - version "0.7.4" - resolved "https://registry.yarnpkg.com/tsd/-/tsd-0.7.4.tgz#d9aba567f1394641821a6800dcee60746c87bd03" - integrity sha512-cqr1s2GHtVkU3L/4BXDaeJOjFEuZ7iOVC+hwmyx4G7Eo26mSXCFNnwFm4EasK/MW2HdY3AQWux+AjYzDYLzZow== - dependencies: - eslint-formatter-pretty "^1.3.0" - globby "^9.1.0" - meow "^5.0.0" - path-exists "^3.0.0" - read-pkg-up "^4.0.0" - typescript "^3.0.1" - update-notifier "^2.5.0" - tslib@^1, tslib@^1.0.0, tslib@^1.10.0, tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3: version "1.13.0" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.13.0.tgz#c881e13cc7015894ed914862d276436fa9a47043" @@ -29476,7 +29243,7 @@ typescript-tuple@^2.2.1: dependencies: typescript-compare "^0.0.2" -typescript@4.0.2, typescript@^3.0.1, typescript@^3.0.3, typescript@^3.2.2, typescript@^3.3.3333, typescript@^3.4.5, typescript@~3.7.2: +typescript@4.0.2, typescript@^3.0.3, typescript@^3.2.2, typescript@^3.3.3333, typescript@^3.4.5, typescript@~3.7.2: version "4.0.2" resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.0.2.tgz#7ea7c88777c723c681e33bf7988be5d008d05ac2" integrity sha512-e4ERvRV2wb+rRZ/IQeb3jm2VxBsirQLpQhdxplZ2MEzGvDkkMmPglecnNDfSUBivMjP93vRbngYYDQqQ/78bcQ== @@ -30982,13 +30749,6 @@ walker@^1.0.7, walker@~1.0.5: dependencies: makeerror "1.0.x" -warning@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/warning/-/warning-3.0.0.tgz#32e5377cb572de4ab04753bdf8821c01ed605b7c" - integrity sha1-MuU3fLVy3kqwR1O9+IIcAe1gW3w= - dependencies: - loose-envify "^1.0.0" - warning@^4.0.2, warning@^4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/warning/-/warning-4.0.3.tgz#16e9e077eb8a86d6af7d64aa1e05fd85b4678ca3" @@ -31868,13 +31628,6 @@ yargs-parser@5.0.0-security.0: camelcase "^3.0.0" object.assign "^4.1.0" -yargs-parser@^10.0.0: - version "10.1.0" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-10.1.0.tgz#7202265b89f7e9e9f2e5765e0fe735a905edbaa8" - integrity sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ== - dependencies: - camelcase "^4.1.0" - yargs-parser@^18.1.2, yargs-parser@^18.1.3: version "18.1.3" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0" From 1841495322d4abe63c3985e9c7456bda01652292 Mon Sep 17 00:00:00 2001 From: Phillip Burch Date: Thu, 1 Oct 2020 18:54:46 -0500 Subject: [PATCH 23/50] [Metrics UI] Override anomaly detection partition field (#79214) * Add ability to override datafeeds and job config for partition field * Remove debug * UX cleanup * Fix types, delete dead code * Fix types --- .../containers/ml/infra_ml_module_types.ts | 4 +- .../containers/ml/infra_ml_setup_state.ts | 289 ------------------ .../metrics_hosts/module_descriptor.ts | 135 +++++--- .../modules/metrics_k8s/module_descriptor.ts | 143 ++++++--- .../anomoly_detection_flyout.tsx | 4 +- .../ml/anomaly_detection/flyout_home.tsx | 113 +++---- .../ml/anomaly_detection/job_setup_screen.tsx | 3 +- 7 files changed, 247 insertions(+), 444 deletions(-) delete mode 100644 x-pack/plugins/infra/public/containers/ml/infra_ml_setup_state.ts diff --git a/x-pack/plugins/infra/public/containers/ml/infra_ml_module_types.ts b/x-pack/plugins/infra/public/containers/ml/infra_ml_module_types.ts index a9f2671de8259..e36f38add641a 100644 --- a/x-pack/plugins/infra/public/containers/ml/infra_ml_module_types.ts +++ b/x-pack/plugins/infra/public/containers/ml/infra_ml_module_types.ts @@ -33,11 +33,11 @@ export interface ModuleDescriptor { partitionField?: string ) => Promise; cleanUpModule: (spaceId: string, sourceId: string) => Promise; - validateSetupIndices: ( + validateSetupIndices?: ( indices: string[], timestampField: string ) => Promise; - validateSetupDatasets: ( + validateSetupDatasets?: ( indices: string[], timestampField: string, startTime: number, diff --git a/x-pack/plugins/infra/public/containers/ml/infra_ml_setup_state.ts b/x-pack/plugins/infra/public/containers/ml/infra_ml_setup_state.ts deleted file mode 100644 index 0dfe3b301f240..0000000000000 --- a/x-pack/plugins/infra/public/containers/ml/infra_ml_setup_state.ts +++ /dev/null @@ -1,289 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { isEqual } from 'lodash'; -import { useCallback, useEffect, useMemo, useState } from 'react'; -import { usePrevious } from 'react-use'; -import { - combineDatasetFilters, - DatasetFilter, - filterDatasetFilter, - isExampleDataIndex, -} from '../../../common/infra_ml'; -import { - AvailableIndex, - ValidationIndicesError, - ValidationUIError, -} from '../../components/logging/log_analysis_setup/initial_configuration_step'; -import { useTrackedPromise } from '../../utils/use_tracked_promise'; -import { ModuleDescriptor, ModuleSourceConfiguration } from './infra_ml_module_types'; - -type SetupHandler = ( - indices: string[], - startTime: number | undefined, - endTime: number | undefined, - datasetFilter: DatasetFilter -) => void; - -interface AnalysisSetupStateArguments { - cleanUpAndSetUpModule: SetupHandler; - moduleDescriptor: ModuleDescriptor; - setUpModule: SetupHandler; - sourceConfiguration: ModuleSourceConfiguration; -} - -const fourWeeksInMs = 86400000 * 7 * 4; - -export const useAnalysisSetupState = ({ - cleanUpAndSetUpModule, - moduleDescriptor: { validateSetupDatasets, validateSetupIndices }, - setUpModule, - sourceConfiguration, -}: AnalysisSetupStateArguments) => { - const [startTime, setStartTime] = useState(Date.now() - fourWeeksInMs); - const [endTime, setEndTime] = useState(undefined); - - const isTimeRangeValid = useMemo( - () => (startTime != null && endTime != null ? startTime < endTime : true), - [endTime, startTime] - ); - - const [validatedIndices, setValidatedIndices] = useState( - sourceConfiguration.indices.map((indexName) => ({ - name: indexName, - validity: 'unknown' as const, - })) - ); - - const updateIndicesWithValidationErrors = useCallback( - (validationErrors: ValidationIndicesError[]) => - setValidatedIndices((availableIndices) => - availableIndices.map((previousAvailableIndex) => { - const indexValiationErrors = validationErrors.filter( - ({ index }) => index === previousAvailableIndex.name - ); - - if (indexValiationErrors.length > 0) { - return { - validity: 'invalid', - name: previousAvailableIndex.name, - errors: indexValiationErrors, - }; - } else if (previousAvailableIndex.validity === 'valid') { - return { - ...previousAvailableIndex, - validity: 'valid', - errors: [], - }; - } else { - return { - validity: 'valid', - name: previousAvailableIndex.name, - isSelected: !isExampleDataIndex(previousAvailableIndex.name), - availableDatasets: [], - datasetFilter: { - type: 'includeAll' as const, - }, - }; - } - }) - ), - [] - ); - - const updateIndicesWithAvailableDatasets = useCallback( - (availableDatasets: Array<{ indexName: string; datasets: string[] }>) => - setValidatedIndices((availableIndices) => - availableIndices.map((previousAvailableIndex) => { - if (previousAvailableIndex.validity !== 'valid') { - return previousAvailableIndex; - } - - const availableDatasetsForIndex = availableDatasets.filter( - ({ indexName }) => indexName === previousAvailableIndex.name - ); - const newAvailableDatasets = availableDatasetsForIndex.flatMap( - ({ datasets }) => datasets - ); - - // filter out datasets that have disappeared if this index' datasets were updated - const newDatasetFilter: DatasetFilter = - availableDatasetsForIndex.length > 0 - ? filterDatasetFilter(previousAvailableIndex.datasetFilter, (dataset) => - newAvailableDatasets.includes(dataset) - ) - : previousAvailableIndex.datasetFilter; - - return { - ...previousAvailableIndex, - availableDatasets: newAvailableDatasets, - datasetFilter: newDatasetFilter, - }; - }) - ), - [] - ); - - const validIndexNames = useMemo( - () => validatedIndices.filter((index) => index.validity === 'valid').map((index) => index.name), - [validatedIndices] - ); - - const selectedIndexNames = useMemo( - () => - validatedIndices - .filter((index) => index.validity === 'valid' && index.isSelected) - .map((i) => i.name), - [validatedIndices] - ); - - const datasetFilter = useMemo( - () => - validatedIndices - .flatMap((validatedIndex) => - validatedIndex.validity === 'valid' - ? validatedIndex.datasetFilter - : { type: 'includeAll' as const } - ) - .reduce(combineDatasetFilters, { type: 'includeAll' as const }), - [validatedIndices] - ); - - const [validateIndicesRequest, validateIndices] = useTrackedPromise( - { - cancelPreviousOn: 'resolution', - createPromise: async () => { - return await validateSetupIndices( - sourceConfiguration.indices, - sourceConfiguration.timestampField - ); - }, - onResolve: ({ data: { errors } }) => { - updateIndicesWithValidationErrors(errors); - }, - onReject: () => { - setValidatedIndices([]); - }, - }, - [sourceConfiguration.indices, sourceConfiguration.timestampField] - ); - - const [validateDatasetsRequest, validateDatasets] = useTrackedPromise( - { - cancelPreviousOn: 'resolution', - createPromise: async () => { - if (validIndexNames.length === 0) { - return { data: { datasets: [] } }; - } - - return await validateSetupDatasets( - validIndexNames, - sourceConfiguration.timestampField, - startTime ?? 0, - endTime ?? Date.now() - ); - }, - onResolve: ({ data: { datasets } }) => { - updateIndicesWithAvailableDatasets(datasets); - }, - }, - [validIndexNames, sourceConfiguration.timestampField, startTime, endTime] - ); - - const setUp = useCallback(() => { - return setUpModule(selectedIndexNames, startTime, endTime, datasetFilter); - }, [setUpModule, selectedIndexNames, startTime, endTime, datasetFilter]); - - const cleanUpAndSetUp = useCallback(() => { - return cleanUpAndSetUpModule(selectedIndexNames, startTime, endTime, datasetFilter); - }, [cleanUpAndSetUpModule, selectedIndexNames, startTime, endTime, datasetFilter]); - - const isValidating = useMemo( - () => validateIndicesRequest.state === 'pending' || validateDatasetsRequest.state === 'pending', - [validateDatasetsRequest.state, validateIndicesRequest.state] - ); - - const validationErrors = useMemo(() => { - if (isValidating) { - return []; - } - - return [ - // validate request status - ...(validateIndicesRequest.state === 'rejected' || - validateDatasetsRequest.state === 'rejected' - ? [{ error: 'NETWORK_ERROR' as const }] - : []), - // validation request results - ...validatedIndices.reduce((errors, index) => { - return index.validity === 'invalid' && selectedIndexNames.includes(index.name) - ? [...errors, ...index.errors] - : errors; - }, []), - // index count - ...(selectedIndexNames.length === 0 ? [{ error: 'TOO_FEW_SELECTED_INDICES' as const }] : []), - // time range - ...(!isTimeRangeValid ? [{ error: 'INVALID_TIME_RANGE' as const }] : []), - ]; - }, [ - isValidating, - validateIndicesRequest.state, - validateDatasetsRequest.state, - validatedIndices, - selectedIndexNames, - isTimeRangeValid, - ]); - - const prevStartTime = usePrevious(startTime); - const prevEndTime = usePrevious(endTime); - const prevValidIndexNames = usePrevious(validIndexNames); - - useEffect(() => { - if (!isTimeRangeValid) { - return; - } - - validateIndices(); - }, [isTimeRangeValid, validateIndices]); - - useEffect(() => { - if (!isTimeRangeValid) { - return; - } - - if ( - startTime !== prevStartTime || - endTime !== prevEndTime || - !isEqual(validIndexNames, prevValidIndexNames) - ) { - validateDatasets(); - } - }, [ - endTime, - isTimeRangeValid, - prevEndTime, - prevStartTime, - prevValidIndexNames, - startTime, - validIndexNames, - validateDatasets, - ]); - - return { - cleanUpAndSetUp, - datasetFilter, - endTime, - isValidating, - selectedIndexNames, - setEndTime, - setStartTime, - setUp, - startTime, - validatedIndices, - setValidatedIndices, - validationErrors, - }; -}; diff --git a/x-pack/plugins/infra/public/containers/ml/modules/metrics_hosts/module_descriptor.ts b/x-pack/plugins/infra/public/containers/ml/modules/metrics_hosts/module_descriptor.ts index cec87fb1144e3..7ea87c3d21322 100644 --- a/x-pack/plugins/infra/public/containers/ml/modules/metrics_hosts/module_descriptor.ts +++ b/x-pack/plugins/infra/public/containers/ml/modules/metrics_hosts/module_descriptor.ts @@ -10,17 +10,27 @@ import { cleanUpJobsAndDatafeeds } from '../../infra_ml_cleanup'; import { callJobsSummaryAPI } from '../../api/ml_get_jobs_summary_api'; import { callGetMlModuleAPI } from '../../api/ml_get_module'; import { callSetupMlModuleAPI } from '../../api/ml_setup_module_api'; -import { callValidateIndicesAPI } from '../../../logs/log_analysis/api/validate_indices'; -import { callValidateDatasetsAPI } from '../../../logs/log_analysis/api/validate_datasets'; import { metricsHostsJobTypes, getJobId, MetricsHostsJobType, DatasetFilter, bucketSpan, - partitionField, } from '../../../../../common/infra_ml'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import MemoryJob from '../../../../../../ml/server/models/data_recognizer/modules/metrics_ui_hosts/ml/hosts_memory_usage.json'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import MemoryDatafeed from '../../../../../../ml/server/models/data_recognizer/modules/metrics_ui_hosts/ml/datafeed_hosts_memory_usage.json'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import NetworkInJob from '../../../../../../ml/server/models/data_recognizer/modules/metrics_ui_hosts/ml/hosts_network_in.json'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import NetworkInDatafeed from '../../../../../../ml/server/models/data_recognizer/modules/metrics_ui_hosts/ml/datafeed_hosts_network_in.json'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import NetworkOutJob from '../../../../../../ml/server/models/data_recognizer/modules/metrics_ui_hosts/ml/hosts_network_out.json'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import NetworkOutDatafeed from '../../../../../../ml/server/models/data_recognizer/modules/metrics_ui_hosts/ml/datafeed_hosts_network_out.json'; +type JobType = 'hosts_memory_usage' | 'hosts_network_in' | 'hosts_network_out'; const moduleId = 'metrics_ui_hosts'; const moduleName = i18n.translate('xpack.infra.ml.metricsModuleName', { defaultMessage: 'Metrics anomanly detection', @@ -54,23 +64,68 @@ const setUpModule = async ( end: number | undefined, datasetFilter: DatasetFilter, { spaceId, sourceId, indices, timestampField }: ModuleSourceConfiguration, - pField?: string + partitionField?: string ) => { const indexNamePattern = indices.join(','); - const jobIds = ['hosts_memory_usage', 'hosts_network_in', 'hosts_network_out']; - const jobOverrides = jobIds.map((id) => ({ - job_id: id, - data_description: { - time_field: timestampField, - }, - custom_settings: { - metrics_source_config: { - indexPattern: indexNamePattern, - timestampField, - bucketSpan, + const jobIds: JobType[] = ['hosts_memory_usage', 'hosts_network_in', 'hosts_network_out']; + + const jobOverrides = jobIds.map((id) => { + const { job: defaultJobConfig } = getDefaultJobConfigs(id); + + // eslint-disable-next-line @typescript-eslint/naming-convention + const analysis_config: any = { + ...defaultJobConfig.analysis_config, + }; + + if (partitionField) { + analysis_config.detectors[0].partition_field_name = partitionField; + if (analysis_config.influencers.indexOf(partitionField) === -1) { + analysis_config.influencers.push(partitionField); + } + } + + return { + job_id: id, + data_description: { + time_field: timestampField, + }, + analysis_config, + custom_settings: { + metrics_source_config: { + indexPattern: indexNamePattern, + timestampField, + bucketSpan, + }, + }, + }; + }); + + const datafeedOverrides = jobIds.map((id) => { + const { datafeed: defaultDatafeedConfig } = getDefaultJobConfigs(id); + + if (!partitionField || id === 'hosts_memory_usage') { + // Since the host memory usage doesn't have custom aggs, we don't need to do anything to add a partition field + return defaultDatafeedConfig; + } + + // If we have a partition field, we need to change the aggregation to do a terms agg at the top level + const aggregations = { + [partitionField]: { + terms: { + field: partitionField, + }, + aggregations: { + ...defaultDatafeedConfig.aggregations, + }, }, - }, - })); + }; + + return { + ...defaultDatafeedConfig, + job_id: id, + aggregations, + }; + }); return callSetupMlModuleAPI( moduleId, @@ -80,34 +135,32 @@ const setUpModule = async ( sourceId, indexNamePattern, jobOverrides, - [] + datafeedOverrides ); }; -const cleanUpModule = async (spaceId: string, sourceId: string) => { - return await cleanUpJobsAndDatafeeds(spaceId, sourceId, metricsHostsJobTypes); -}; - -const validateSetupIndices = async (indices: string[], timestampField: string) => { - return await callValidateIndicesAPI(indices, [ - { - name: timestampField, - validTypes: ['date'], - }, - { - name: partitionField, - validTypes: ['keyword'], - }, - ]); +const getDefaultJobConfigs = (jobId: JobType): { datafeed: any; job: any } => { + switch (jobId) { + case 'hosts_memory_usage': + return { + datafeed: MemoryDatafeed, + job: MemoryJob, + }; + case 'hosts_network_in': + return { + datafeed: NetworkInDatafeed, + job: NetworkInJob, + }; + case 'hosts_network_out': + return { + datafeed: NetworkOutDatafeed, + job: NetworkOutJob, + }; + } }; -const validateSetupDatasets = async ( - indices: string[], - timestampField: string, - startTime: number, - endTime: number -) => { - return await callValidateDatasetsAPI(indices, timestampField, startTime, endTime); +const cleanUpModule = async (spaceId: string, sourceId: string) => { + return await cleanUpJobsAndDatafeeds(spaceId, sourceId, metricsHostsJobTypes); }; export const metricHostsModule: ModuleDescriptor = { @@ -121,6 +174,4 @@ export const metricHostsModule: ModuleDescriptor = { getModuleDefinition, setUpModule, cleanUpModule, - validateSetupDatasets, - validateSetupIndices, }; diff --git a/x-pack/plugins/infra/public/containers/ml/modules/metrics_k8s/module_descriptor.ts b/x-pack/plugins/infra/public/containers/ml/modules/metrics_k8s/module_descriptor.ts index cbcff1c307af6..eaf7489c84eb4 100644 --- a/x-pack/plugins/infra/public/containers/ml/modules/metrics_k8s/module_descriptor.ts +++ b/x-pack/plugins/infra/public/containers/ml/modules/metrics_k8s/module_descriptor.ts @@ -10,17 +10,28 @@ import { cleanUpJobsAndDatafeeds } from '../../infra_ml_cleanup'; import { callJobsSummaryAPI } from '../../api/ml_get_jobs_summary_api'; import { callGetMlModuleAPI } from '../../api/ml_get_module'; import { callSetupMlModuleAPI } from '../../api/ml_setup_module_api'; -import { callValidateIndicesAPI } from '../../../logs/log_analysis/api/validate_indices'; -import { callValidateDatasetsAPI } from '../../../logs/log_analysis/api/validate_datasets'; import { metricsK8SJobTypes, getJobId, MetricK8sJobType, DatasetFilter, bucketSpan, - partitionField, } from '../../../../../common/infra_ml'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import MemoryJob from '../../../../../../ml/server/models/data_recognizer/modules/metrics_ui_k8s/ml/k8s_memory_usage.json'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import MemoryDatafeed from '../../../../../../ml/server/models/data_recognizer/modules/metrics_ui_k8s/ml/datafeed_k8s_memory_usage.json'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import NetworkInJob from '../../../../../../ml/server/models/data_recognizer/modules/metrics_ui_k8s/ml/k8s_network_in.json'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import NetworkInDatafeed from '../../../../../../ml/server/models/data_recognizer/modules/metrics_ui_k8s/ml/datafeed_k8s_network_in.json'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import NetworkOutJob from '../../../../../../ml/server/models/data_recognizer/modules/metrics_ui_k8s/ml/k8s_network_out.json'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import NetworkOutDatafeed from '../../../../../../ml/server/models/data_recognizer/modules/metrics_ui_k8s/ml/datafeed_k8s_network_out.json'; +type JobType = 'k8s_memory_usage' | 'k8s_network_in' | 'k8s_network_out'; +export const DEFAULT_K8S_PARTITION_FIELD = 'kubernetes.namespace'; const moduleId = 'metrics_ui_k8s'; const moduleName = i18n.translate('xpack.infra.ml.metricsModuleName', { defaultMessage: 'Metrics anomanly detection', @@ -54,26 +65,72 @@ const setUpModule = async ( end: number | undefined, datasetFilter: DatasetFilter, { spaceId, sourceId, indices, timestampField }: ModuleSourceConfiguration, - pField?: string + partitionField?: string ) => { const indexNamePattern = indices.join(','); - const jobIds = ['k8s_memory_usage', 'k8s_network_in', 'k8s_network_out']; - const jobOverrides = jobIds.map((id) => ({ - job_id: id, - analysis_config: { - bucket_span: `${bucketSpan}ms`, - }, - data_description: { - time_field: timestampField, - }, - custom_settings: { - metrics_source_config: { - indexPattern: indexNamePattern, - timestampField, - bucketSpan, + const jobIds: JobType[] = ['k8s_memory_usage', 'k8s_network_in', 'k8s_network_out']; + const jobOverrides = jobIds.map((id) => { + const { job: defaultJobConfig } = getDefaultJobConfigs(id); + + // eslint-disable-next-line @typescript-eslint/naming-convention + const analysis_config: any = { + ...defaultJobConfig.analysis_config, + }; + + if (partitionField) { + analysis_config.detectors[0].partition_field_name = partitionField; + if (analysis_config.influencers.indexOf(partitionField) === -1) { + analysis_config.influencers.push(partitionField); + } + } + + return { + job_id: id, + data_description: { + time_field: timestampField, + }, + analysis_config, + custom_settings: { + metrics_source_config: { + indexPattern: indexNamePattern, + timestampField, + bucketSpan, + }, + }, + }; + }); + + const datafeedOverrides = jobIds.map((id) => { + const { datafeed: defaultDatafeedConfig } = getDefaultJobConfigs(id); + + if (!partitionField || id === 'k8s_memory_usage') { + // Since the host memory usage doesn't have custom aggs, we don't need to do anything to add a partition field + return defaultDatafeedConfig; + } + + // Because the ML K8s jobs ship with a default partition field of {kubernetes.namespace}, ignore that agg and wrap it in our own agg. + const innerAggregation = + defaultDatafeedConfig.aggregations[DEFAULT_K8S_PARTITION_FIELD].aggregations; + + // If we have a partition field, we need to change the aggregation to do a terms agg to partition the data at the top level + const aggregations = { + [partitionField]: { + terms: { + field: partitionField, + size: 25, // 25 is arbitratry and only used to keep the number of buckets to a managable level in the event that the user choose a high cardinality partition field. + }, + aggregations: { + ...innerAggregation, + }, }, - }, - })); + }; + + return { + ...defaultDatafeedConfig, + job_id: id, + aggregations, + }; + }); return callSetupMlModuleAPI( moduleId, @@ -83,34 +140,32 @@ const setUpModule = async ( sourceId, indexNamePattern, jobOverrides, - [] + datafeedOverrides ); }; -const cleanUpModule = async (spaceId: string, sourceId: string) => { - return await cleanUpJobsAndDatafeeds(spaceId, sourceId, metricsK8SJobTypes); -}; - -const validateSetupIndices = async (indices: string[], timestampField: string) => { - return await callValidateIndicesAPI(indices, [ - { - name: timestampField, - validTypes: ['date'], - }, - { - name: partitionField, - validTypes: ['keyword'], - }, - ]); +const getDefaultJobConfigs = (jobId: JobType): { datafeed: any; job: any } => { + switch (jobId) { + case 'k8s_memory_usage': + return { + datafeed: MemoryDatafeed, + job: MemoryJob, + }; + case 'k8s_network_in': + return { + datafeed: NetworkInDatafeed, + job: NetworkInJob, + }; + case 'k8s_network_out': + return { + datafeed: NetworkOutDatafeed, + job: NetworkOutJob, + }; + } }; -const validateSetupDatasets = async ( - indices: string[], - timestampField: string, - startTime: number, - endTime: number -) => { - return await callValidateDatasetsAPI(indices, timestampField, startTime, endTime); +const cleanUpModule = async (spaceId: string, sourceId: string) => { + return await cleanUpJobsAndDatafeeds(spaceId, sourceId, metricsK8SJobTypes); }; export const metricHostsModule: ModuleDescriptor = { @@ -124,6 +179,4 @@ export const metricHostsModule: ModuleDescriptor = { getModuleDefinition, setUpModule, cleanUpModule, - validateSetupDatasets, - validateSetupIndices, }; diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/ml/anomaly_detection/anomoly_detection_flyout.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/ml/anomaly_detection/anomoly_detection_flyout.tsx index b063713fa2c97..b5d224910e819 100644 --- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/ml/anomaly_detection/anomoly_detection_flyout.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/ml/anomaly_detection/anomoly_detection_flyout.tsx @@ -50,10 +50,10 @@ export const AnomalyDetectionFlyout = () => { return ( <> - + {showFlyout && ( diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/ml/anomaly_detection/flyout_home.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/ml/anomaly_detection/flyout_home.tsx index 801dff9c4a17a..5b520084ebb74 100644 --- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/ml/anomaly_detection/flyout_home.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/ml/anomaly_detection/flyout_home.tsx @@ -5,7 +5,7 @@ */ import React, { useState, useCallback, useEffect } from 'react'; -import { EuiFlyoutHeader, EuiTitle, EuiFlyoutBody, EuiTabs, EuiTab, EuiSpacer } from '@elastic/eui'; +import { EuiFlyoutHeader, EuiTitle, EuiFlyoutBody, EuiSpacer } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import { EuiText, EuiFlexGroup, EuiFlexItem, EuiCard, EuiIcon } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; @@ -30,7 +30,7 @@ interface Props { } export const FlyoutHome = (props: Props) => { - const [tab, setTab] = useState<'jobs' | 'anomalies'>('jobs'); + const [tab] = useState<'jobs' | 'anomalies'>('jobs'); const { goToSetup } = props; const { fetchJobStatus: fetchHostJobStatus, @@ -56,18 +56,10 @@ export const FlyoutHome = (props: Props) => { goToSetup('kubernetes'); }, [goToSetup]); - const goToJobs = useCallback(() => { - setTab('jobs'); - }, []); - const jobIds = [ ...(k8sJobSummaries || []).map((k) => k.id), ...(hostJobSummaries || []).map((h) => h.id), ]; - const anomaliesUrl = useLinkProps({ - app: 'ml', - pathname: `/explorer?_g=${createResultsUrl(jobIds)}`, - }); useEffect(() => { if (hasInfraMLReadCapabilities) { @@ -105,30 +97,24 @@ export const FlyoutHome = (props: Props) => { - - - - - - - - +
    + +

    + +

    +
    +
    + {hostJobSummaries.length > 0 && ( <> 0} hasK8sJobs={k8sJobSummaries.length > 0} + jobIds={jobIds} /> @@ -151,6 +137,7 @@ export const FlyoutHome = (props: Props) => { interface CalloutProps { hasHostJobs: boolean; hasK8sJobs: boolean; + jobIds: string[]; } const JobsEnabledCallout = (props: CalloutProps) => { let target = ''; @@ -175,8 +162,34 @@ const JobsEnabledCallout = (props: CalloutProps) => { pathname: '/jobs', }); + const anomaliesUrl = useLinkProps({ + app: 'ml', + pathname: `/explorer?_g=${createResultsUrl(props.jobIds)}`, + }); + return ( <> + + + + + + + + + + + + + + + { } iconType="check" /> - - - - ); }; @@ -211,30 +217,11 @@ interface CreateJobTab { const CreateJobTab = (props: CreateJobTab) => { return ( <> -
    - -

    - -

    -
    - -

    - -

    -
    -
    - - + {/* */} } // title="Hosts" title={ @@ -245,7 +232,7 @@ const CreateJobTab = (props: CreateJobTab) => { } description={ } @@ -254,7 +241,7 @@ const CreateJobTab = (props: CreateJobTab) => { {props.hasHostJobs && ( @@ -262,7 +249,7 @@ const CreateJobTab = (props: CreateJobTab) => { {!props.hasHostJobs && ( @@ -273,7 +260,7 @@ const CreateJobTab = (props: CreateJobTab) => { } title={ { } description={ } @@ -292,7 +279,7 @@ const CreateJobTab = (props: CreateJobTab) => { {props.hasK8sJobs && ( @@ -300,7 +287,7 @@ const CreateJobTab = (props: CreateJobTab) => { {!props.hasK8sJobs && ( diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/ml/anomaly_detection/job_setup_screen.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/ml/anomaly_detection/job_setup_screen.tsx index 428c002da6383..c327d187f6bc2 100644 --- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/ml/anomaly_detection/job_setup_screen.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/ml/anomaly_detection/job_setup_screen.tsx @@ -20,6 +20,7 @@ import { useSourceViaHttp } from '../../../../../../containers/source/use_source import { useMetricK8sModuleContext } from '../../../../../../containers/ml/modules/metrics_k8s/module'; import { useMetricHostsModuleContext } from '../../../../../../containers/ml/modules/metrics_hosts/module'; import { FixedDatePicker } from '../../../../../../components/fixed_datepicker'; +import { DEFAULT_K8S_PARTITION_FIELD } from '../../../../../../containers/ml/modules/metrics_k8s/module_descriptor'; interface Props { jobType: 'hosts' | 'kubernetes'; @@ -107,7 +108,7 @@ export const JobSetupScreen = (props: Props) => { useEffect(() => { if (props.jobType === 'kubernetes') { - setPartitionField(['kubernetes.namespace']); + setPartitionField([DEFAULT_K8S_PARTITION_FIELD]); } }, [props.jobType]); From 6c015cfbef12189eb5aec8fa42f5ea2743be2971 Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Thu, 1 Oct 2020 19:04:26 -0600 Subject: [PATCH 24/50] Convert VectorLayer to typescript (#78490) * [maps] convert VectorLayer to TS * more tslint fixes * clean up * more tslint fixes * more tslint fixes * remove unneeded casts * remove unneeded VectorStyle casts * revert changes to layer.getQuery * fix * update tile layer constructor * review feedback Co-authored-by: Elastic Machine --- .../data_request_descriptor_types.ts | 19 +- .../common/descriptor_types/map_descriptor.ts | 2 +- .../common/elasticsearch_util/es_agg_utils.ts | 4 +- .../public/actions/data_request_actions.ts | 2 +- .../maps/public/classes/joins/inner_join.d.ts | 23 +- .../plugins/maps/public/classes/joins/join.ts | 32 +- .../blended_vector_layer.ts | 11 +- .../layers/heatmap_layer/heatmap_layer.js | 12 + .../maps/public/classes/layers/layer.test.ts | 6 - .../maps/public/classes/layers/layer.tsx | 19 +- .../classes/layers/tile_layer/tile_layer.js | 15 +- .../tiled_vector_layer/tiled_vector_layer.tsx | 43 +-- .../layers/vector_layer/vector_layer.d.ts | 85 ----- .../{vector_layer.js => vector_layer.tsx} | 291 ++++++++++++------ .../sources/es_agg_source/es_agg_source.ts | 2 +- .../es_geo_grid_source.d.ts | 9 +- .../es_geo_grid_source.test.ts | 3 +- .../classes/sources/es_source/es_source.d.ts | 48 ++- .../classes/sources/es_source/es_source.js | 15 +- .../es_term_source/es_term_source.d.ts | 13 +- .../sources/es_term_source/es_term_source.js | 4 +- .../kibana_regionmap_source.js | 1 + .../mvt_single_layer_vector_source.tsx | 14 +- .../sources/vector_source/vector_source.d.ts | 28 +- .../classes/styles/vector/vector_style.tsx | 55 +++- .../toc_entry_actions_popover.test.tsx | 14 +- 26 files changed, 478 insertions(+), 292 deletions(-) delete mode 100644 x-pack/plugins/maps/public/classes/layers/vector_layer/vector_layer.d.ts rename x-pack/plugins/maps/public/classes/layers/vector_layer/{vector_layer.js => vector_layer.tsx} (78%) 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 f3521cca2e456..16b60492c9b78 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 @@ -38,15 +38,21 @@ export type VectorSourceRequestMeta = MapFilters & { applyGlobalQuery: boolean; fieldNames: string[]; geogridPrecision?: number; - sourceQuery: MapQuery; + sourceQuery?: MapQuery; sourceMeta: VectorSourceSyncMeta; }; +export type VectorJoinSourceRequestMeta = MapFilters & { + applyGlobalQuery: boolean; + fieldNames: string[]; + sourceQuery: MapQuery; +}; + export type VectorStyleRequestMeta = MapFilters & { dynamicStyleFields: string[]; isTimeAware: boolean; sourceQuery: MapQuery; - timeFilters: unknown; + timeFilters: TimeRange; }; export type ESSearchSourceResponseMeta = { @@ -59,9 +65,12 @@ export type ESSearchSourceResponseMeta = { }; // Partial because objects are justified downstream in constructors -export type DataMeta = Partial & - Partial & - Partial; +export type DataMeta = Partial< + VectorSourceRequestMeta & + VectorJoinSourceRequestMeta & + VectorStyleRequestMeta & + ESSearchSourceResponseMeta +>; type NumericalStyleFieldData = { avg: number; diff --git a/x-pack/plugins/maps/common/descriptor_types/map_descriptor.ts b/x-pack/plugins/maps/common/descriptor_types/map_descriptor.ts index d064dfb1c4a37..b769b125cf0f8 100644 --- a/x-pack/plugins/maps/common/descriptor_types/map_descriptor.ts +++ b/x-pack/plugins/maps/common/descriptor_types/map_descriptor.ts @@ -17,7 +17,7 @@ export type MapExtent = { }; export type MapQuery = Query & { - queryLastTriggeredAt: string; + queryLastTriggeredAt?: string; }; export type MapRefreshConfig = { diff --git a/x-pack/plugins/maps/common/elasticsearch_util/es_agg_utils.ts b/x-pack/plugins/maps/common/elasticsearch_util/es_agg_utils.ts index 7828c3cc6410b..f157ffe9f1c80 100644 --- a/x-pack/plugins/maps/common/elasticsearch_util/es_agg_utils.ts +++ b/x-pack/plugins/maps/common/elasticsearch_util/es_agg_utils.ts @@ -33,8 +33,10 @@ export function addFieldToDSL(dsl: object, field: IFieldType) { }; } +export type BucketProperties = Record; + export function extractPropertiesFromBucket(bucket: any, ignoreKeys: string[] = []) { - const properties: Record = {}; + const properties: BucketProperties = {}; for (const key in bucket) { if (ignoreKeys.includes(key) || !bucket.hasOwnProperty(key)) { continue; diff --git a/x-pack/plugins/maps/public/actions/data_request_actions.ts b/x-pack/plugins/maps/public/actions/data_request_actions.ts index 14d8196900506..d7d9259e1539e 100644 --- a/x-pack/plugins/maps/public/actions/data_request_actions.ts +++ b/x-pack/plugins/maps/public/actions/data_request_actions.ts @@ -47,7 +47,7 @@ const FIT_TO_BOUNDS_SCALE_FACTOR = 0.1; export type DataRequestContext = { startLoading(dataId: string, requestToken: symbol, meta: DataMeta): void; - stopLoading(dataId: string, requestToken: symbol, data: object, meta: DataMeta): void; + stopLoading(dataId: string, requestToken: symbol, data: object, meta?: DataMeta): void; onLoadError(dataId: string, requestToken: symbol, errorMessage: string): void; updateSourceData(newData: unknown): void; isRequestStillActive(dataId: string, requestToken: symbol): boolean; diff --git a/x-pack/plugins/maps/public/classes/joins/inner_join.d.ts b/x-pack/plugins/maps/public/classes/joins/inner_join.d.ts index befff0965fb70..3e2ceac4971c4 100644 --- a/x-pack/plugins/maps/public/classes/joins/inner_join.d.ts +++ b/x-pack/plugins/maps/public/classes/joins/inner_join.d.ts @@ -4,19 +4,40 @@ * you may not use this file except in compliance with the Elastic License. */ +import { Feature, GeoJsonProperties } from 'geojson'; import { IESTermSource } from '../sources/es_term_source'; -import { IJoin } from './join'; +import { IJoin, PropertiesMap } from './join'; import { JoinDescriptor } from '../../../common/descriptor_types'; import { ISource } from '../sources/source'; +import { ITooltipProperty } from '../tooltips/tooltip_property'; +import { IField } from '../fields/field'; export class InnerJoin implements IJoin { constructor(joinDescriptor: JoinDescriptor, leftSource: ISource); + destroy: () => void; + getRightJoinSource(): IESTermSource; toDescriptor(): JoinDescriptor; + getJoinFields: () => IField[]; + + getLeftField: () => IField; + + getIndexPatternIds: () => string[]; + + getQueryableIndexPatternIds: () => string[]; + + getSourceDataRequestId: () => string; + getSourceMetaDataRequestId(): string; getSourceFormattersDataRequestId(): string; + + getTooltipProperties(properties: GeoJsonProperties): Promise; + + hasCompleteConfig: () => boolean; + + joinPropertiesToFeature: (feature: Feature, propertiesMap?: PropertiesMap) => boolean; } diff --git a/x-pack/plugins/maps/public/classes/joins/join.ts b/x-pack/plugins/maps/public/classes/joins/join.ts index 5bcc4bfdec87e..df6f6f684f4d2 100644 --- a/x-pack/plugins/maps/public/classes/joins/join.ts +++ b/x-pack/plugins/maps/public/classes/joins/join.ts @@ -4,15 +4,39 @@ * you may not use this file except in compliance with the Elastic License. */ +import { Feature, GeoJsonProperties } from 'geojson'; import { IESTermSource } from '../sources/es_term_source'; import { JoinDescriptor } from '../../../common/descriptor_types'; +import { ITooltipProperty } from '../tooltips/tooltip_property'; +import { IField } from '../fields/field'; +import { BucketProperties } from '../../../common/elasticsearch_util'; + +export type PropertiesMap = Map; export interface IJoin { - getRightJoinSource(): IESTermSource; + destroy: () => void; + + getRightJoinSource: () => IESTermSource; + + toDescriptor: () => JoinDescriptor; + + getJoinFields: () => IField[]; + + getLeftField: () => IField; + + getIndexPatternIds: () => string[]; + + getQueryableIndexPatternIds: () => string[]; + + getSourceDataRequestId: () => string; + + getSourceMetaDataRequestId: () => string; + + getSourceFormattersDataRequestId: () => string; - toDescriptor(): JoinDescriptor; + getTooltipProperties: (properties: GeoJsonProperties) => Promise; - getSourceMetaDataRequestId(): string; + hasCompleteConfig: () => boolean; - getSourceFormattersDataRequestId(): string; + joinPropertiesToFeature: (feature: Feature, propertiesMap?: PropertiesMap) => boolean; } diff --git a/x-pack/plugins/maps/public/classes/layers/blended_vector_layer/blended_vector_layer.ts b/x-pack/plugins/maps/public/classes/layers/blended_vector_layer/blended_vector_layer.ts index 90e8d25a77958..9b6a67ac28ad0 100644 --- a/x-pack/plugins/maps/public/classes/layers/blended_vector_layer/blended_vector_layer.ts +++ b/x-pack/plugins/maps/public/classes/layers/blended_vector_layer/blended_vector_layer.ts @@ -37,7 +37,6 @@ import { LayerDescriptor, VectorLayerDescriptor, } from '../../../../common/descriptor_types'; -import { IStyle } from '../../styles/style'; import { IVectorSource } from '../../sources/vector_source'; const ACTIVE_COUNT_DATA_ID = 'ACTIVE_COUNT_DATA_ID'; @@ -257,7 +256,7 @@ export class BlendedVectorLayer extends VectorLayer implements IVectorLayer { return clonedDescriptor; } - getSource() { + getSource(): IVectorSource { return this._isClustered ? this._clusterSource : this._documentSource; } @@ -268,11 +267,11 @@ export class BlendedVectorLayer extends VectorLayer implements IVectorLayer { return this._documentSource; } - getCurrentStyle(): IStyle { + getCurrentStyle(): IVectorStyle { return this._isClustered ? this._clusterStyle : this._documentStyle; } - getStyleForEditing(): IStyle { + getStyleForEditing(): IVectorStyle { return this._documentStyle; } @@ -281,8 +280,8 @@ export class BlendedVectorLayer extends VectorLayer implements IVectorLayer { const requestToken = Symbol(`layer-active-count:${this.getId()}`); const searchFilters = this._getSearchFilters( syncContext.dataFilters, - this.getSource() as IVectorSource, - this.getCurrentStyle() as IVectorStyle + this.getSource(), + this.getCurrentStyle() ); const canSkipFetch = await canSkipSourceUpdate({ source: this.getSource(), diff --git a/x-pack/plugins/maps/public/classes/layers/heatmap_layer/heatmap_layer.js b/x-pack/plugins/maps/public/classes/layers/heatmap_layer/heatmap_layer.js index adcc86b9d1546..33e82db79f3cf 100644 --- a/x-pack/plugins/maps/public/classes/layers/heatmap_layer/heatmap_layer.js +++ b/x-pack/plugins/maps/public/classes/layers/heatmap_layer/heatmap_layer.js @@ -31,6 +31,18 @@ export class HeatmapLayer extends VectorLayer { } } + getStyleForEditing() { + return this._style; + } + + getStyle() { + return this._style; + } + + getCurrentStyle() { + return this._style; + } + _getPropKeyOfSelectedMetric() { const metricfields = this.getSource().getMetricFields(); return metricfields[0].getName(); diff --git a/x-pack/plugins/maps/public/classes/layers/layer.test.ts b/x-pack/plugins/maps/public/classes/layers/layer.test.ts index 7bc91d71f83e2..76df7c2af840a 100644 --- a/x-pack/plugins/maps/public/classes/layers/layer.test.ts +++ b/x-pack/plugins/maps/public/classes/layers/layer.test.ts @@ -7,7 +7,6 @@ import { AbstractLayer } from './layer'; import { ISource } from '../sources/source'; -import { IStyle } from '../styles/style'; import { AGG_TYPE, FIELD_ORIGIN, LAYER_STYLE_TYPE, VECTOR_STYLES } from '../../../common/constants'; import { ESTermSourceDescriptor, VectorStyleDescriptor } from '../../../common/descriptor_types'; import { getDefaultDynamicProperties } from '../styles/vector/vector_style_defaults'; @@ -38,8 +37,6 @@ class MockSource { } } -class MockStyle {} - describe('cloneDescriptor', () => { describe('with joins', () => { const styleDescriptor = { @@ -84,7 +81,6 @@ describe('cloneDescriptor', () => { const layer = new MockLayer({ layerDescriptor, source: (new MockSource() as unknown) as ISource, - style: (new MockStyle() as unknown) as IStyle, }); const clonedDescriptor = await layer.cloneDescriptor(); const clonedStyleProps = (clonedDescriptor.style as VectorStyleDescriptor).properties; @@ -122,7 +118,6 @@ describe('cloneDescriptor', () => { const layer = new MockLayer({ layerDescriptor, source: (new MockSource() as unknown) as ISource, - style: (new MockStyle() as unknown) as IStyle, }); const clonedDescriptor = await layer.cloneDescriptor(); const clonedStyleProps = (clonedDescriptor.style as VectorStyleDescriptor).properties; @@ -165,7 +160,6 @@ describe('isFittable', () => { const layer = new MockLayer({ layerDescriptor, source: (new MockSource({ fitToBounds: test.fitToBounds }) as unknown) as ISource, - style: (new MockStyle() as unknown) as IStyle, }); expect(await layer.isFittable()).toBe(test.canFit); }); diff --git a/x-pack/plugins/maps/public/classes/layers/layer.tsx b/x-pack/plugins/maps/public/classes/layers/layer.tsx index cd720063c6703..d6bd5180375ce 100644 --- a/x-pack/plugins/maps/public/classes/layers/layer.tsx +++ b/x-pack/plugins/maps/public/classes/layers/layer.tsx @@ -110,13 +110,11 @@ export type CustomIconAndTooltipContent = { export interface ILayerArguments { layerDescriptor: LayerDescriptor; source: ISource; - style: IStyle; } export class AbstractLayer implements ILayer { protected readonly _descriptor: LayerDescriptor; protected readonly _source: ISource; - protected readonly _style: IStyle; protected readonly _dataRequests: DataRequest[]; static createDescriptor(options: Partial): LayerDescriptor { @@ -140,10 +138,9 @@ export class AbstractLayer implements ILayer { } } - constructor({ layerDescriptor, source, style }: ILayerArguments) { + constructor({ layerDescriptor, source }: ILayerArguments) { this._descriptor = AbstractLayer.createDescriptor(layerDescriptor); this._source = source; - this._style = style; if (this._descriptor.__dataRequests) { this._dataRequests = this._descriptor.__dataRequests.map( (dataRequest) => new DataRequest(dataRequest) @@ -257,11 +254,15 @@ export class AbstractLayer implements ILayer { } getStyleForEditing(): IStyle { - return this._style; + throw new Error('Should implement AbstractLayer#getStyleForEditing'); } - getStyle() { - return this._style; + getStyle(): IStyle { + throw new Error('Should implement AbstractLayer#getStyle'); + } + + getCurrentStyle(): IStyle { + throw new Error('Should implement AbstractLayer#getCurrentStyle'); } getLabel(): string { @@ -412,10 +413,6 @@ export class AbstractLayer implements ILayer { return this._descriptor.query ? this._descriptor.query : null; } - getCurrentStyle(): IStyle { - return this._style; - } - async getImmutableSourceProperties() { const source = this.getSource(); return await source.getImmutableProperties(); diff --git a/x-pack/plugins/maps/public/classes/layers/tile_layer/tile_layer.js b/x-pack/plugins/maps/public/classes/layers/tile_layer/tile_layer.js index 3e2009c24a2e4..fa60017f0eaf7 100644 --- a/x-pack/plugins/maps/public/classes/layers/tile_layer/tile_layer.js +++ b/x-pack/plugins/maps/public/classes/layers/tile_layer/tile_layer.js @@ -21,7 +21,20 @@ export class TileLayer extends AbstractLayer { } constructor({ source, layerDescriptor }) { - super({ source, layerDescriptor, style: new TileStyle() }); + super({ source, layerDescriptor }); + this._style = new TileStyle(); + } + + getStyleForEditing() { + return this._style; + } + + getStyle() { + return this._style; + } + + getCurrentStyle() { + return this._style; } async syncData({ startLoading, stopLoading, onLoadError, dataFilters }) { 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 70bf8ea3883b7..68b9f2931f398 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 @@ -5,9 +5,14 @@ */ import React from 'react'; +import { + Map as MbMap, + GeoJSONSource as MbGeoJSONSource, + VectorSource as MbVectorSource, +} from 'mapbox-gl'; import { EuiIcon } from '@elastic/eui'; import { Feature } from 'geojson'; -import { VectorStyle } from '../../styles/vector/vector_style'; +import { IVectorStyle, VectorStyle } from '../../styles/vector/vector_style'; import { SOURCE_DATA_REQUEST_ID, LAYER_TYPE } from '../../../../common/constants'; import { VectorLayer, VectorLayerArguments } from '../vector_layer/vector_layer'; import { ITiledSingleLayerVectorSource } from '../../sources/vector_source'; @@ -59,7 +64,7 @@ export class TiledVectorLayer extends VectorLayer { const searchFilters: VectorSourceRequestMeta = this._getSearchFilters( dataFilters, this.getSource(), - this._style + this._style as IVectorStyle ); const prevDataRequest = this.getSourceDataRequest(); @@ -88,13 +93,12 @@ export class TiledVectorLayer extends VectorLayer { } async syncData(syncContext: DataRequestContext) { - await this._syncSourceStyleMeta(syncContext, this._source, this._style); - await this._syncSourceFormatters(syncContext, this._source, this._style); + await this._syncSourceStyleMeta(syncContext, this._source, this._style as IVectorStyle); + await this._syncSourceFormatters(syncContext, this._source, this._style as IVectorStyle); await this._syncMVTUrlTemplate(syncContext); } - _syncSourceBindingWithMb(mbMap: unknown) { - // @ts-expect-error + _syncSourceBindingWithMb(mbMap: MbMap) { const mbSource = mbMap.getSource(this._getMbSourceId()); if (mbSource) { return; @@ -113,7 +117,6 @@ export class TiledVectorLayer extends VectorLayer { } const mbSourceId = this._getMbSourceId(); - // @ts-expect-error mbMap.addSource(mbSourceId, { type: 'vector', tiles: [sourceMeta.urlTemplate], @@ -126,7 +129,7 @@ export class TiledVectorLayer extends VectorLayer { return this._getMbSourceId() === mbSourceId; } - _syncStylePropertiesWithMb(mbMap: unknown) { + _syncStylePropertiesWithMb(mbMap: MbMap) { // @ts-ignore const mbSource = mbMap.getSource(this._getMbSourceId()); if (!mbSource) { @@ -146,12 +149,16 @@ export class TiledVectorLayer extends VectorLayer { this._setMbLinePolygonProperties(mbMap, sourceMeta.layerName); } - _requiresPrevSourceCleanup(mbMap: unknown): boolean { - // @ts-expect-error - const mbTileSource = mbMap.getSource(this._getMbSourceId()); - if (!mbTileSource) { + _requiresPrevSourceCleanup(mbMap: MbMap): boolean { + const mbSource = mbMap.getSource(this._getMbSourceId()) as MbVectorSource | MbGeoJSONSource; + if (!mbSource) { return false; } + if (!('tiles' in mbSource)) { + // Expected source is not compatible, so remove. + return true; + } + const mbTileSource = mbSource as MbVectorSource; const dataRequest = this.getSourceDataRequest(); if (!dataRequest) { @@ -163,13 +170,8 @@ export class TiledVectorLayer extends VectorLayer { return false; } - if (!mbTileSource.tiles) { - // Expected source is not compatible, so remove. - return true; - } - const isSourceDifferent = - mbTileSource.tiles[0] !== tiledSourceMeta.urlTemplate || + mbTileSource.tiles?.[0] !== tiledSourceMeta.urlTemplate || mbTileSource.minzoom !== tiledSourceMeta.minSourceZoom || mbTileSource.maxzoom !== tiledSourceMeta.maxSourceZoom; @@ -179,9 +181,8 @@ export class TiledVectorLayer extends VectorLayer { const layerIds = this.getMbLayerIds(); for (let i = 0; i < layerIds.length; i++) { - // @ts-expect-error const mbLayer = mbMap.getLayer(layerIds[i]); - if (mbLayer && mbLayer.sourceLayer !== tiledSourceMeta.layerName) { + if (mbLayer && mbLayer['source-layer'] !== tiledSourceMeta.layerName) { // If the source-pointer of one of the layers is stale, they will all be stale. // In this case, all the mb-layers need to be removed and re-added. return true; @@ -191,7 +192,7 @@ export class TiledVectorLayer extends VectorLayer { return false; } - syncLayerWithMB(mbMap: unknown) { + syncLayerWithMB(mbMap: MbMap) { this._removeStaleMbSourcesAndLayers(mbMap); this._syncSourceBindingWithMb(mbMap); this._syncStylePropertiesWithMb(mbMap); diff --git a/x-pack/plugins/maps/public/classes/layers/vector_layer/vector_layer.d.ts b/x-pack/plugins/maps/public/classes/layers/vector_layer/vector_layer.d.ts deleted file mode 100644 index fa614ae87b290..0000000000000 --- a/x-pack/plugins/maps/public/classes/layers/vector_layer/vector_layer.d.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; - * you may not use this file except in compliance with the Elastic License. - */ -/* eslint-disable @typescript-eslint/consistent-type-definitions */ - -import { Feature, GeoJsonProperties } from 'geojson'; -import { AbstractLayer } from '../layer'; -import { IVectorSource } from '../../sources/vector_source'; -import { - MapFilters, - VectorLayerDescriptor, - VectorSourceRequestMeta, -} from '../../../../common/descriptor_types'; -import { ILayer } from '../layer'; -import { IJoin } from '../../joins/join'; -import { IVectorStyle } from '../../styles/vector/vector_style'; -import { IField } from '../../fields/field'; -import { DataRequestContext } from '../../../actions'; -import { ITooltipProperty } from '../../tooltips/tooltip_property'; - -export type VectorLayerArguments = { - source: IVectorSource; - joins?: IJoin[]; - layerDescriptor: VectorLayerDescriptor; -}; - -export interface IVectorLayer extends ILayer { - getFields(): Promise; - getStyleEditorFields(): Promise; - getJoins(): IJoin[]; - getValidJoins(): IJoin[]; - getSource(): IVectorSource; - getFeatureById(id: string | number): Feature | null; - getPropertiesForTooltip(properties: GeoJsonProperties): Promise; - hasJoins(): boolean; -} - -export class VectorLayer extends AbstractLayer implements IVectorLayer { - static type: string; - - protected readonly _style: IVectorStyle; - static createDescriptor( - options: Partial, - mapColors?: string[] - ): VectorLayerDescriptor; - - constructor(options: VectorLayerArguments); - getLayerTypeIconName(): string; - getFields(): Promise; - getStyleEditorFields(): Promise; - getJoins(): IJoin[]; - getValidJoins(): IJoin[]; - _syncSourceStyleMeta( - syncContext: DataRequestContext, - source: IVectorSource, - style: IVectorStyle - ): Promise; - _syncSourceFormatters( - syncContext: DataRequestContext, - source: IVectorSource, - style: IVectorStyle - ): Promise; - syncLayerWithMB(mbMap: unknown): void; - _getSearchFilters( - dataFilters: MapFilters, - source: IVectorSource, - style: IVectorStyle - ): VectorSourceRequestMeta; - _syncData( - syncContext: DataRequestContext, - source: IVectorSource, - style: IVectorStyle - ): Promise; - ownsMbSourceId(sourceId: string): boolean; - ownsMbLayerId(sourceId: string): boolean; - _setMbPointsProperties(mbMap: unknown, mvtSourceLayer?: string): void; - _setMbLinePolygonProperties(mbMap: unknown, mvtSourceLayer?: string): void; - getSource(): IVectorSource; - getFeatureById(id: string | number): Feature | null; - getPropertiesForTooltip(properties: GeoJsonProperties): Promise; - hasJoins(): boolean; - isFittable(): Promise; -} diff --git a/x-pack/plugins/maps/public/classes/layers/vector_layer/vector_layer.js b/x-pack/plugins/maps/public/classes/layers/vector_layer/vector_layer.tsx similarity index 78% rename from x-pack/plugins/maps/public/classes/layers/vector_layer/vector_layer.js rename to x-pack/plugins/maps/public/classes/layers/vector_layer/vector_layer.tsx index 27c344b713a60..a2532d4e7b10e 100644 --- a/x-pack/plugins/maps/public/classes/layers/vector_layer/vector_layer.js +++ b/x-pack/plugins/maps/public/classes/layers/vector_layer/vector_layer.tsx @@ -5,8 +5,13 @@ */ import React from 'react'; +import { Map as MbMap, Layer as MbLayer, GeoJSONSource as MbGeoJSONSource } from 'mapbox-gl'; +import { Feature, FeatureCollection, GeoJsonProperties } from 'geojson'; +import _ from 'lodash'; +import { EuiIcon } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import { AbstractLayer } from '../layer'; -import { VectorStyle } from '../../styles/vector/vector_style'; +import { IVectorStyle, VectorStyle } from '../../styles/vector/vector_style'; import { FEATURE_ID_PROPERTY_NAME, SOURCE_DATA_REQUEST_ID, @@ -20,11 +25,9 @@ import { FIELD_ORIGIN, LAYER_STYLE_TYPE, KBN_TOO_MANY_FEATURES_IMAGE_ID, + FieldFormatter, } from '../../../../common/constants'; -import _ from 'lodash'; import { JoinTooltipProperty } from '../../tooltips/join_tooltip_property'; -import { EuiIcon } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; import { DataRequestAbortError } from '../../util/data_request'; import { canSkipSourceUpdate, @@ -39,15 +42,66 @@ import { getPointFilterExpression, } from '../../util/mb_filter_expressions'; +import { + DynamicStylePropertyOptions, + MapFilters, + MapQuery, + VectorLayerDescriptor, + VectorSourceRequestMeta, + VectorStyleRequestMeta, +} from '../../../../common/descriptor_types'; +import { IVectorSource } from '../../sources/vector_source'; +import { CustomIconAndTooltipContent, ILayer } from '../layer'; +import { IJoin, PropertiesMap } from '../../joins/join'; +import { IField } from '../../fields/field'; +import { DataRequestContext } from '../../../actions'; +import { ITooltipProperty } from '../../tooltips/tooltip_property'; +import { IDynamicStyleProperty } from '../../styles/vector/properties/dynamic_style_property'; +import { IESSource } from '../../sources/es_source'; + +interface SourceResult { + refreshed: boolean; + featureCollection?: FeatureCollection; +} + +interface JoinState { + dataHasChanged: boolean; + join: IJoin; + propertiesMap?: PropertiesMap; +} + +export interface VectorLayerArguments { + source: IVectorSource; + joins?: IJoin[]; + layerDescriptor: VectorLayerDescriptor; +} + +export interface IVectorLayer extends ILayer { + getFields(): Promise; + getStyleEditorFields(): Promise; + getJoins(): IJoin[]; + getValidJoins(): IJoin[]; + getSource(): IVectorSource; + getFeatureById(id: string | number): Feature | null; + getPropertiesForTooltip(properties: GeoJsonProperties): Promise; + hasJoins(): boolean; +} + export class VectorLayer extends AbstractLayer { static type = LAYER_TYPE.VECTOR; - static createDescriptor(options, mapColors) { + protected readonly _style: IVectorStyle; + private readonly _joins: IJoin[]; + + static createDescriptor( + options: Partial, + mapColors?: string[] + ): VectorLayerDescriptor { const layerDescriptor = super.createDescriptor(options); layerDescriptor.type = VectorLayer.type; if (!options.style) { - const styleProperties = VectorStyle.createDefaultStyleProperties(mapColors); + const styleProperties = VectorStyle.createDefaultStyleProperties(mapColors ? mapColors : []); layerDescriptor.style = VectorStyle.createDescriptor(styleProperties); } @@ -55,16 +109,31 @@ export class VectorLayer extends AbstractLayer { layerDescriptor.joins = []; } - return layerDescriptor; + return layerDescriptor as VectorLayerDescriptor; } - constructor({ layerDescriptor, source, joins = [] }) { - super({ layerDescriptor, source }); + constructor({ layerDescriptor, source, joins = [] }: VectorLayerArguments) { + super({ + layerDescriptor, + source, + }); this._joins = joins; - this._style = new VectorStyle(this._descriptor.style, source, this); + this._style = new VectorStyle(layerDescriptor.style, source, this); + } + + getSource(): IVectorSource { + return super.getSource() as IVectorSource; + } + + getStyleForEditing(): IVectorStyle { + return this._style; + } + + getStyle(): IVectorStyle { + return this._style; } - getStyle() { + getCurrentStyle(): IVectorStyle { return this._style; } @@ -108,7 +177,7 @@ export class VectorLayer extends AbstractLayer { return true; } - getCustomIconAndTooltipContent() { + getCustomIconAndTooltipContent(): CustomIconAndTooltipContent { const featureCollection = this._getSourceFeatureCollection(); const noResultsIcon = ; @@ -124,7 +193,7 @@ export class VectorLayer extends AbstractLayer { if ( this.getJoins().length && !featureCollection.features.some( - (feature) => feature.properties[FEATURE_VISIBLE_PROPERTY_NAME] + (feature) => feature.properties?.[FEATURE_VISIBLE_PROPERTY_NAME] ) ) { return { @@ -141,8 +210,8 @@ export class VectorLayer extends AbstractLayer { ); return { icon: this.getCurrentStyle().getIcon(), - tooltipContent: tooltipContent, - areResultsTrimmed: areResultsTrimmed, + tooltipContent, + areResultsTrimmed, }; } @@ -158,7 +227,12 @@ export class VectorLayer extends AbstractLayer { return this.getCurrentStyle().renderLegendDetails(); } - async getBounds({ startLoading, stopLoading, registerCancelCallback, dataFilters }) { + async getBounds({ + startLoading, + stopLoading, + registerCancelCallback, + dataFilters, + }: DataRequestContext) { const isStaticLayer = !this.getSource().isBoundsAware(); if (isStaticLayer || this.hasJoins()) { return getFeatureCollectionBounds(this._getSourceFeatureCollection(), this.hasJoins()); @@ -190,7 +264,7 @@ export class VectorLayer extends AbstractLayer { } finally { // Use stopLoading callback instead of onLoadError callback. // Function is loading bounds and not feature data. - stopLoading(SOURCE_BOUNDS_DATA_REQUEST_ID, requestToken, bounds, boundsFilters); + stopLoading(SOURCE_BOUNDS_DATA_REQUEST_ID, requestToken, bounds ? bounds : {}, boundsFilters); } return bounds; } @@ -205,7 +279,7 @@ export class VectorLayer extends AbstractLayer { } _getJoinFields() { - const joinFields = []; + const joinFields: IField[] = []; this.getValidJoins().forEach((join) => { const fields = join.getJoinFields(); joinFields.push(...fields); @@ -219,7 +293,7 @@ export class VectorLayer extends AbstractLayer { } async getStyleEditorFields() { - const sourceFields = await this.getSourceForEditing().getFields(); + const sourceFields = await (this.getSourceForEditing() as IVectorSource).getFields(); return [...sourceFields, ...this._getJoinFields()]; } @@ -246,7 +320,7 @@ export class VectorLayer extends AbstractLayer { onLoadError, registerCancelCallback, dataFilters, - }) { + }: { join: IJoin } & DataRequestContext): Promise { const joinSource = join.getRightJoinSource(); const sourceDataId = join.getSourceDataRequestId(); const requestToken = Symbol(`layer-join-refresh:${this.getId()} - ${sourceDataId}`); @@ -266,15 +340,15 @@ export class VectorLayer extends AbstractLayer { if (canSkipFetch) { return { dataHasChanged: false, - join: join, - propertiesMap: prevDataRequest.getData(), + join, + propertiesMap: prevDataRequest?.getData() as PropertiesMap, }; } try { startLoading(sourceDataId, requestToken, searchFilters); const leftSourceName = await this._source.getDisplayName(); - const { propertiesMap } = await joinSource.getPropertiesMap( + const propertiesMap = await joinSource.getPropertiesMap( searchFilters, leftSourceName, join.getLeftField().getName(), @@ -283,8 +357,8 @@ export class VectorLayer extends AbstractLayer { stopLoading(sourceDataId, requestToken, propertiesMap); return { dataHasChanged: true, - join: join, - propertiesMap: propertiesMap, + join, + propertiesMap, }; } catch (e) { if (!(e instanceof DataRequestAbortError)) { @@ -292,13 +366,12 @@ export class VectorLayer extends AbstractLayer { } return { dataHasChanged: true, - join: join, - propertiesMap: null, + join, }; } } - async _syncJoins(syncContext, style) { + async _syncJoins(syncContext: DataRequestContext, style: IVectorStyle) { const joinSyncs = this.getValidJoins().map(async (join) => { await this._syncJoinStyleMeta(syncContext, join, style); await this._syncJoinFormatters(syncContext, join, style); @@ -308,28 +381,37 @@ export class VectorLayer extends AbstractLayer { return await Promise.all(joinSyncs); } - _getSearchFilters(dataFilters, source, style) { + _getSearchFilters( + dataFilters: MapFilters, + source: IVectorSource, + style: IVectorStyle + ): VectorSourceRequestMeta { const fieldNames = [ ...source.getFieldNames(), ...(style.getType() === LAYER_STYLE_TYPE.VECTOR ? style.getSourceFieldNames() : []), ...this.getValidJoins().map((join) => join.getLeftField().getName()), ]; + const sourceQuery = this.getQuery() as MapQuery; return { ...dataFilters, fieldNames: _.uniq(fieldNames).sort(), geogridPrecision: source.getGeoGridPrecision(dataFilters.zoom), - sourceQuery: this.getQuery(), + sourceQuery: sourceQuery ? sourceQuery : undefined, applyGlobalQuery: source.getApplyGlobalQuery(), sourceMeta: source.getSyncMeta(), }; } - async _performInnerJoins(sourceResult, joinStates, updateSourceData) { - //should update the store if - //-- source result was refreshed - //-- any of the join configurations changed (joinState changed) - //-- visibility of any of the features has changed + async _performInnerJoins( + sourceResult: SourceResult, + joinStates: JoinState[], + updateSourceData: DataRequestContext['updateSourceData'] + ) { + // should update the store if + // -- source result was refreshed + // -- any of the join configurations changed (joinState changed) + // -- visibility of any of the features has changed let shouldUpdateStore = sourceResult.refreshed || joinStates.some((joinState) => joinState.dataHasChanged); @@ -338,8 +420,11 @@ export class VectorLayer extends AbstractLayer { return; } - for (let i = 0; i < sourceResult.featureCollection.features.length; i++) { - const feature = sourceResult.featureCollection.features[i]; + for (let i = 0; i < sourceResult.featureCollection!.features.length; i++) { + const feature = sourceResult.featureCollection!.features[i]; + if (!feature.properties) { + feature.properties = {}; + } const oldVisbility = feature.properties[FEATURE_VISIBLE_PROPERTY_NAME]; let isFeatureVisible = true; for (let j = 0; j < joinStates.length; j++) { @@ -364,7 +449,11 @@ export class VectorLayer extends AbstractLayer { } } - async _syncSource(syncContext, source, style) { + async _syncSource( + syncContext: DataRequestContext, + source: IVectorSource, + style: IVectorStyle + ): Promise { const { startLoading, stopLoading, @@ -385,7 +474,9 @@ export class VectorLayer extends AbstractLayer { if (canSkipFetch) { return { refreshed: false, - featureCollection: prevDataRequest.getData(), + featureCollection: prevDataRequest + ? (prevDataRequest.getData() as FeatureCollection) + : EMPTY_FEATURE_COLLECTION, }; } @@ -416,15 +507,20 @@ export class VectorLayer extends AbstractLayer { } } - async _syncSourceStyleMeta(syncContext, source, style) { + async _syncSourceStyleMeta( + syncContext: DataRequestContext, + source: IVectorSource, + style: IVectorStyle + ) { if (this.getCurrentStyle().getType() !== LAYER_STYLE_TYPE.VECTOR) { return; } + const sourceQuery = this.getQuery() as MapQuery; return this._syncStyleMeta({ source, style, - sourceQuery: this.getQuery(), + sourceQuery: sourceQuery ? sourceQuery : undefined, dataRequestId: SOURCE_META_DATA_REQUEST_ID, dynamicStyleProps: style.getDynamicPropertiesArray().filter((dynamicStyleProp) => { return ( @@ -436,7 +532,7 @@ export class VectorLayer extends AbstractLayer { }); } - async _syncJoinStyleMeta(syncContext, join, style) { + async _syncJoinStyleMeta(syncContext: DataRequestContext, join: IJoin, style: IVectorStyle) { const joinSource = join.getRightJoinSource(); return this._syncStyleMeta({ source: joinSource, @@ -446,9 +542,7 @@ export class VectorLayer extends AbstractLayer { dynamicStyleProps: this.getCurrentStyle() .getDynamicPropertiesArray() .filter((dynamicStyleProp) => { - const matchingField = joinSource.getMetricFieldForName( - dynamicStyleProp.getField().getName() - ); + const matchingField = joinSource.getMetricFieldForName(dynamicStyleProp.getFieldName()); return ( dynamicStyleProp.getFieldOrigin() === FIELD_ORIGIN.JOIN && !!matchingField && @@ -470,13 +564,19 @@ export class VectorLayer extends AbstractLayer { stopLoading, onLoadError, registerCancelCallback, - }) { + }: { + dataRequestId: string; + dynamicStyleProps: Array>; + source: IVectorSource; + sourceQuery?: MapQuery; + style: IVectorStyle; + } & DataRequestContext) { if (!source.isESSource() || dynamicStyleProps.length === 0) { return; } const dynamicStyleFields = dynamicStyleProps.map((dynamicStyleProp) => { - return `${dynamicStyleProp.getField().getName()}${dynamicStyleProp.getNumberOfCategories()}`; + return `${dynamicStyleProp.getFieldName()}${dynamicStyleProp.getNumberOfCategories()}`; }); const nextMeta = { @@ -484,7 +584,7 @@ export class VectorLayer extends AbstractLayer { sourceQuery, isTimeAware: this.getCurrentStyle().isTimeAware() && (await source.isTimeAware()), timeFilters: dataFilters.timeFilters, - }; + } as VectorStyleRequestMeta; const prevDataRequest = this.getDataRequest(dataRequestId); const canSkipFetch = canSkipStyleMetaUpdate({ prevDataRequest, nextMeta }); if (canSkipFetch) { @@ -496,14 +596,14 @@ export class VectorLayer extends AbstractLayer { startLoading(dataRequestId, requestToken, nextMeta); const layerName = await this.getDisplayName(source); - //todo: cast source to ESSource when migrating to TS - const styleMeta = await source.loadStylePropsMeta( + const styleMeta = await (source as IESSource).loadStylePropsMeta({ layerName, style, dynamicStyleProps, - registerCancelCallback.bind(null, requestToken), - nextMeta - ); + registerCancelCallback: registerCancelCallback.bind(null, requestToken), + sourceQuery: nextMeta.sourceQuery, + timeFilters: nextMeta.timeFilters, + }); stopLoading(dataRequestId, requestToken, styleMeta, nextMeta); } catch (error) { if (!(error instanceof DataRequestAbortError)) { @@ -512,7 +612,11 @@ export class VectorLayer extends AbstractLayer { } } - async _syncSourceFormatters(syncContext, source, style) { + async _syncSourceFormatters( + syncContext: DataRequestContext, + source: IVectorSource, + style: IVectorStyle + ) { if (style.getType() !== LAYER_STYLE_TYPE.VECTOR) { return; } @@ -526,13 +630,13 @@ export class VectorLayer extends AbstractLayer { return dynamicStyleProp.getFieldOrigin() === FIELD_ORIGIN.SOURCE; }) .map((dynamicStyleProp) => { - return dynamicStyleProp.getField(); + return dynamicStyleProp.getField()!; }), ...syncContext, }); } - async _syncJoinFormatters(syncContext, join, style) { + async _syncJoinFormatters(syncContext: DataRequestContext, join: IJoin, style: IVectorStyle) { const joinSource = join.getRightJoinSource(); return this._syncFormatters({ source: joinSource, @@ -540,19 +644,28 @@ export class VectorLayer extends AbstractLayer { fields: style .getDynamicPropertiesArray() .filter((dynamicStyleProp) => { - const matchingField = joinSource.getMetricFieldForName( - dynamicStyleProp.getField().getName() - ); + const matchingField = joinSource.getMetricFieldForName(dynamicStyleProp.getFieldName()); return dynamicStyleProp.getFieldOrigin() === FIELD_ORIGIN.JOIN && !!matchingField; }) .map((dynamicStyleProp) => { - return dynamicStyleProp.getField(); + return dynamicStyleProp.getField()!; }), ...syncContext, }); } - async _syncFormatters({ source, dataRequestId, fields, startLoading, stopLoading, onLoadError }) { + async _syncFormatters({ + source, + dataRequestId, + fields, + startLoading, + stopLoading, + onLoadError, + }: { + dataRequestId: string; + fields: IField[]; + source: IVectorSource; + } & DataRequestContext) { if (fields.length === 0) { return; } @@ -573,7 +686,7 @@ export class VectorLayer extends AbstractLayer { try { startLoading(dataRequestId, requestToken, nextMeta); - const formatters = {}; + const formatters: { [key: string]: FieldFormatter | null } = {}; const promises = fields .filter((field) => { return field.canValueBeFormatted(); @@ -589,7 +702,7 @@ export class VectorLayer extends AbstractLayer { } } - async syncData(syncContext) { + async syncData(syncContext: DataRequestContext) { await this._syncData(syncContext, this.getSource(), this.getCurrentStyle()); } @@ -603,7 +716,7 @@ export class VectorLayer extends AbstractLayer { // Given 1 above, which source/style to use can not be stored in Layer instance state. // Given 2 above, which source/style to use can not be pulled from data request state. // Therefore, source and style are provided as arugments and must be used instead of calling getSource or getCurrentStyle. - async _syncData(syncContext, source, style) { + async _syncData(syncContext: DataRequestContext, source: IVectorSource, style: IVectorStyle) { if (this.isLoadingBounds()) { return; } @@ -624,11 +737,11 @@ export class VectorLayer extends AbstractLayer { _getSourceFeatureCollection() { const sourceDataRequest = this.getSourceDataRequest(); - return sourceDataRequest ? sourceDataRequest.getData() : null; + return sourceDataRequest ? (sourceDataRequest.getData() as FeatureCollection) : null; } - _syncFeatureCollectionWithMb(mbMap) { - const mbGeoJSONSource = mbMap.getSource(this.getId()); + _syncFeatureCollectionWithMb(mbMap: MbMap) { + const mbGeoJSONSource = mbMap.getSource(this.getId()) as MbGeoJSONSource; const featureCollection = this._getSourceFeatureCollection(); const featureCollectionOnMap = AbstractLayer.getBoundDataForSource(mbMap, this.getId()); @@ -653,7 +766,7 @@ export class VectorLayer extends AbstractLayer { } } - _setMbPointsProperties(mbMap, mvtSourceLayer) { + _setMbPointsProperties(mbMap: MbMap, mvtSourceLayer?: string) { const pointLayerId = this._getMbPointLayerId(); const symbolLayerId = this._getMbSymbolLayerId(); const pointLayer = mbMap.getLayer(pointLayerId); @@ -689,12 +802,12 @@ export class VectorLayer extends AbstractLayer { } } - _setMbCircleProperties(mbMap, mvtSourceLayer) { + _setMbCircleProperties(mbMap: MbMap, mvtSourceLayer?: string) { const sourceId = this.getId(); const pointLayerId = this._getMbPointLayerId(); const pointLayer = mbMap.getLayer(pointLayerId); if (!pointLayer) { - const mbLayer = { + const mbLayer: MbLayer = { id: pointLayerId, type: 'circle', source: sourceId, @@ -710,7 +823,7 @@ export class VectorLayer extends AbstractLayer { const textLayerId = this._getMbTextLayerId(); const textLayer = mbMap.getLayer(textLayerId); if (!textLayer) { - const mbLayer = { + const mbLayer: MbLayer = { id: textLayerId, type: 'symbol', source: sourceId, @@ -740,13 +853,13 @@ export class VectorLayer extends AbstractLayer { }); } - _setMbSymbolProperties(mbMap, mvtSourceLayer) { + _setMbSymbolProperties(mbMap: MbMap, mvtSourceLayer?: string) { const sourceId = this.getId(); const symbolLayerId = this._getMbSymbolLayerId(); const symbolLayer = mbMap.getLayer(symbolLayerId); if (!symbolLayer) { - const mbLayer = { + const mbLayer: MbLayer = { id: symbolLayerId, type: 'symbol', source: sourceId, @@ -775,7 +888,7 @@ export class VectorLayer extends AbstractLayer { }); } - _setMbLinePolygonProperties(mbMap, mvtSourceLayer) { + _setMbLinePolygonProperties(mbMap: MbMap, mvtSourceLayer?: string) { const sourceId = this.getId(); const fillLayerId = this._getMbPolygonLayerId(); const lineLayerId = this._getMbLineLayerId(); @@ -783,7 +896,7 @@ export class VectorLayer extends AbstractLayer { const hasJoins = this.hasJoins(); if (!mbMap.getLayer(fillLayerId)) { - const mbLayer = { + const mbLayer: MbLayer = { id: fillLayerId, type: 'fill', source: sourceId, @@ -795,7 +908,7 @@ export class VectorLayer extends AbstractLayer { mbMap.addLayer(mbLayer); } if (!mbMap.getLayer(lineLayerId)) { - const mbLayer = { + const mbLayer: MbLayer = { id: lineLayerId, type: 'line', source: sourceId, @@ -807,7 +920,7 @@ export class VectorLayer extends AbstractLayer { mbMap.addLayer(mbLayer); } if (!mbMap.getLayer(tooManyFeaturesLayerId)) { - const mbLayer = { + const mbLayer: MbLayer = { id: tooManyFeaturesLayerId, type: 'fill', source: sourceId, @@ -855,12 +968,12 @@ export class VectorLayer extends AbstractLayer { mbMap.setLayerZoomRange(tooManyFeaturesLayerId, this.getMinZoom(), this.getMaxZoom()); } - _syncStylePropertiesWithMb(mbMap) { + _syncStylePropertiesWithMb(mbMap: MbMap) { this._setMbPointsProperties(mbMap); this._setMbLinePolygonProperties(mbMap); } - _syncSourceBindingWithMb(mbMap) { + _syncSourceBindingWithMb(mbMap: MbMap) { const mbSource = mbMap.getSource(this._getMbSourceId()); if (!mbSource) { mbMap.addSource(this._getMbSourceId(), { @@ -883,7 +996,7 @@ export class VectorLayer extends AbstractLayer { } } - syncLayerWithMB(mbMap) { + syncLayerWithMB(mbMap: MbMap) { this._syncSourceBindingWithMb(mbMap); this._syncFeatureCollectionWithMb(mbMap); this._syncStylePropertiesWithMb(mbMap); @@ -924,15 +1037,15 @@ export class VectorLayer extends AbstractLayer { ]; } - ownsMbLayerId(mbLayerId) { + ownsMbLayerId(mbLayerId: string) { return this.getMbLayerIds().includes(mbLayerId); } - ownsMbSourceId(mbSourceId) { + ownsMbSourceId(mbSourceId: string) { return this.getId() === mbSourceId; } - _addJoinsToSourceTooltips(tooltipsFromSource) { + _addJoinsToSourceTooltips(tooltipsFromSource: ITooltipProperty[]) { for (let i = 0; i < tooltipsFromSource.length; i++) { const tooltipProperty = tooltipsFromSource[i]; const matchingJoins = []; @@ -947,7 +1060,7 @@ export class VectorLayer extends AbstractLayer { } } - async getPropertiesForTooltip(properties) { + async getPropertiesForTooltip(properties: GeoJsonProperties) { const vectorSource = this.getSource(); let allProperties = await vectorSource.getTooltipProperties(properties); this._addJoinsToSourceTooltips(allProperties); @@ -961,18 +1074,20 @@ export class VectorLayer extends AbstractLayer { canShowTooltip() { return ( - this.isVisible() && (this.getSource().canFormatFeatureProperties() || this.getJoins().length) + this.isVisible() && + (this.getSource().canFormatFeatureProperties() || this.getJoins().length > 0) ); } - getFeatureById(id) { + getFeatureById(id: string | number) { const featureCollection = this._getSourceFeatureCollection(); if (!featureCollection) { return null; } - return featureCollection.features.find((feature) => { - return feature.properties[FEATURE_ID_PROPERTY_NAME] === id; + const targetFeature = featureCollection.features.find((feature) => { + return feature.properties?.[FEATURE_ID_PROPERTY_NAME] === id; }); + return targetFeature ? targetFeature : null; } } diff --git a/x-pack/plugins/maps/public/classes/sources/es_agg_source/es_agg_source.ts b/x-pack/plugins/maps/public/classes/sources/es_agg_source/es_agg_source.ts index be947d79f4e39..5c062f3419e28 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_agg_source/es_agg_source.ts +++ b/x-pack/plugins/maps/public/classes/sources/es_agg_source/es_agg_source.ts @@ -29,7 +29,7 @@ export interface IESAggSource extends IESSource { getValueAggsDsl(indexPattern: IndexPattern): { [key: string]: unknown }; } -export class AbstractESAggSource extends AbstractESSource { +export abstract class AbstractESAggSource extends AbstractESSource { private readonly _metricFields: IESAggField[]; private readonly _canReadFromGeoJson: boolean; diff --git a/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/es_geo_grid_source.d.ts b/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/es_geo_grid_source.d.ts index ada76b8e4e674..b221d13bb0f8a 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/es_geo_grid_source.d.ts +++ b/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/es_geo_grid_source.d.ts @@ -10,6 +10,7 @@ import { MapFilters, MapQuery, VectorSourceSyncMeta, + VectorSourceRequestMeta, } from '../../../../common/descriptor_types'; import { GRID_RESOLUTION } from '../../../../common/constants'; import { IField } from '../../fields/field'; @@ -35,13 +36,7 @@ export class ESGeoGridSource extends AbstractESAggSource implements ITiledSingle getLayerName(): string; getUrlTemplateWithMeta( - searchFilters: MapFilters & { - applyGlobalQuery: boolean; - fieldNames: string[]; - geogridPrecision?: number; - sourceQuery: MapQuery; - sourceMeta: VectorSourceSyncMeta; - } + searchFilters: VectorSourceRequestMeta ): Promise<{ layerName: string; urlTemplate: string; diff --git a/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/es_geo_grid_source.test.ts b/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/es_geo_grid_source.test.ts index 189e7dea1b0c1..06df68283c434 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/es_geo_grid_source.test.ts +++ b/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/es_geo_grid_source.test.ts @@ -160,7 +160,8 @@ describe('ESGeoGridSource', () => { const { data, meta } = await geogridSource.getGeoJsonWithMeta( 'foobarLayer', vectorSourceRequestMeta, - () => {} + () => {}, + () => true ); expect(meta && meta.areResultsTrimmed).toEqual(false); diff --git a/x-pack/plugins/maps/public/classes/sources/es_source/es_source.d.ts b/x-pack/plugins/maps/public/classes/sources/es_source/es_source.d.ts index 01fde589dcb84..c11b6f0853cc7 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_source/es_source.d.ts +++ b/x-pack/plugins/maps/public/classes/sources/es_source/es_source.d.ts @@ -6,12 +6,14 @@ import { AbstractVectorSource } from '../vector_source'; import { IVectorSource } from '../vector_source'; +import { TimeRange } from '../../../../../../../src/plugins/data/common'; import { IndexPattern, ISearchSource } from '../../../../../../../src/plugins/data/public'; import { DynamicStylePropertyOptions, + MapQuery, VectorSourceRequestMeta, } from '../../../../common/descriptor_types'; -import { VectorStyle } from '../../styles/vector/vector_style'; +import { IVectorStyle } from '../../styles/vector/vector_style'; import { IDynamicStyleProperty } from '../../styles/vector/properties/dynamic_style_property'; export interface IESSource extends IVectorSource { @@ -25,13 +27,21 @@ export interface IESSource extends IVectorSource { limit: number, initialSearchContext?: object ): Promise; - loadStylePropsMeta( - layerName: string, - style: VectorStyle, - dynamicStyleProps: Array>, - registerCancelCallback: (requestToken: symbol, callback: () => void) => void, - searchFilters: VectorSourceRequestMeta - ): Promise; + loadStylePropsMeta({ + layerName, + style, + dynamicStyleProps, + registerCancelCallback, + sourceQuery, + timeFilters, + }: { + layerName: string; + style: IVectorStyle; + dynamicStyleProps: Array>; + registerCancelCallback: (callback: () => void) => void; + sourceQuery?: MapQuery; + timeFilters: TimeRange; + }): Promise; } export class AbstractESSource extends AbstractVectorSource implements IESSource { @@ -45,13 +55,21 @@ export class AbstractESSource extends AbstractVectorSource implements IESSource limit: number, initialSearchContext?: object ): Promise; - loadStylePropsMeta( - layerName: string, - style: VectorStyle, - dynamicStyleProps: Array>, - registerCancelCallback: (requestToken: symbol, callback: () => void) => void, - searchFilters: VectorSourceRequestMeta - ): Promise; + loadStylePropsMeta({ + layerName, + style, + dynamicStyleProps, + registerCancelCallback, + sourceQuery, + timeFilters, + }: { + layerName: string; + style: IVectorStyle; + dynamicStyleProps: Array>; + registerCancelCallback: (callback: () => void) => void; + sourceQuery?: MapQuery; + timeFilters: TimeRange; + }): Promise; _runEsQuery: ({ requestId, requestName, diff --git a/x-pack/plugins/maps/public/classes/sources/es_source/es_source.js b/x-pack/plugins/maps/public/classes/sources/es_source/es_source.js index ab56ceeab4e77..0c8cb5f514247 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_source/es_source.js +++ b/x-pack/plugins/maps/public/classes/sources/es_source/es_source.js @@ -284,13 +284,14 @@ export class AbstractESSource extends AbstractVectorSource { return indexPattern.getFormatterForField(fieldFromIndexPattern).getConverterFor('text'); } - async loadStylePropsMeta( + async loadStylePropsMeta({ layerName, style, dynamicStyleProps, registerCancelCallback, - searchFilters - ) { + sourceQuery, + timeFilters, + }) { const promises = dynamicStyleProps.map((dynamicStyleProp) => { return dynamicStyleProp.getFieldMetaRequest(); }); @@ -307,13 +308,11 @@ export class AbstractESSource extends AbstractVectorSource { searchSource.setField('index', indexPattern); searchSource.setField('size', 0); searchSource.setField('aggs', aggs); - if (searchFilters.sourceQuery) { - searchSource.setField('query', searchFilters.sourceQuery); + if (sourceQuery) { + searchSource.setField('query', sourceQuery); } if (style.isTimeAware() && (await this.isTimeAware())) { - searchSource.setField('filter', [ - getTimeFilter().createFilter(indexPattern, searchFilters.timeFilters), - ]); + searchSource.setField('filter', [getTimeFilter().createFilter(indexPattern, timeFilters)]); } const resp = await this._runEsQuery({ diff --git a/x-pack/plugins/maps/public/classes/sources/es_term_source/es_term_source.d.ts b/x-pack/plugins/maps/public/classes/sources/es_term_source/es_term_source.d.ts index 248ca2b9212b4..ef1ada8da8289 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_term_source/es_term_source.d.ts +++ b/x-pack/plugins/maps/public/classes/sources/es_term_source/es_term_source.d.ts @@ -4,10 +4,19 @@ * you may not use this file except in compliance with the Elastic License. */ +import { MapQuery, VectorJoinSourceRequestMeta } from '../../../../common/descriptor_types'; import { IField } from '../../fields/field'; import { IESAggSource } from '../es_agg_source'; +import { PropertiesMap } from '../../joins/join'; export interface IESTermSource extends IESAggSource { - getTermField(): IField; - hasCompleteConfig(): boolean; + getTermField: () => IField; + hasCompleteConfig: () => boolean; + getWhereQuery: () => MapQuery; + getPropertiesMap: ( + searchFilters: VectorJoinSourceRequestMeta, + leftSourceName: string, + leftFieldName: string, + registerCancelCallback: (callback: () => void) => void + ) => PropertiesMap; } diff --git a/x-pack/plugins/maps/public/classes/sources/es_term_source/es_term_source.js b/x-pack/plugins/maps/public/classes/sources/es_term_source/es_term_source.js index 359d22d2c44ce..ff52dccdd2ef4 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_term_source/es_term_source.js +++ b/x-pack/plugins/maps/public/classes/sources/es_term_source/es_term_source.js @@ -119,9 +119,7 @@ export class ESTermSource extends AbstractESAggSource { }); const countPropertyName = this.getAggKey(AGG_TYPE.COUNT); - return { - propertiesMap: extractPropertiesMap(rawEsData, countPropertyName), - }; + return extractPropertiesMap(rawEsData, countPropertyName); } isFilterByMapBounds() { diff --git a/x-pack/plugins/maps/public/classes/sources/kibana_regionmap_source/kibana_regionmap_source.js b/x-pack/plugins/maps/public/classes/sources/kibana_regionmap_source/kibana_regionmap_source.js index eeb34ed672221..d937edb4ed362 100644 --- a/x-pack/plugins/maps/public/classes/sources/kibana_regionmap_source/kibana_regionmap_source.js +++ b/x-pack/plugins/maps/public/classes/sources/kibana_regionmap_source/kibana_regionmap_source.js @@ -74,6 +74,7 @@ export class KibanaRegionmapSource extends AbstractVectorSource { }); return { data: featureCollection, + meta: {}, }; } diff --git a/x-pack/plugins/maps/public/classes/sources/mvt_single_layer_vector_source/mvt_single_layer_vector_source.tsx b/x-pack/plugins/maps/public/classes/sources/mvt_single_layer_vector_source/mvt_single_layer_vector_source.tsx index 3e515613b3fd0..440f0cb4457e8 100644 --- a/x-pack/plugins/maps/public/classes/sources/mvt_single_layer_vector_source/mvt_single_layer_vector_source.tsx +++ b/x-pack/plugins/maps/public/classes/sources/mvt_single_layer_vector_source/mvt_single_layer_vector_source.tsx @@ -179,7 +179,7 @@ export class MVTSingleLayerVectorSource getBoundsForFilters( boundsFilters: BoundsFilters, - registerCancelCallback: (requestToken: symbol, callback: () => void) => void + registerCancelCallback: (callback: () => void) => void ): MapExtent | null { return null; } @@ -192,6 +192,18 @@ export class MVTSingleLayerVectorSource return false; } + isBoundsAware() { + return false; + } + + getSourceTooltipContent() { + return { tooltipContent: null, areResultsTrimmed: false }; + } + + async getLeftJoinFields() { + return []; + } + async getTooltipProperties( properties: GeoJsonProperties, featureId?: string | number diff --git a/x-pack/plugins/maps/public/classes/sources/vector_source/vector_source.d.ts b/x-pack/plugins/maps/public/classes/sources/vector_source/vector_source.d.ts index a481e273bc33e..7bf1db43c2871 100644 --- a/x-pack/plugins/maps/public/classes/sources/vector_source/vector_source.d.ts +++ b/x-pack/plugins/maps/public/classes/sources/vector_source/vector_source.d.ts @@ -19,6 +19,12 @@ import { } from '../../../../common/descriptor_types'; import { VECTOR_SHAPE_TYPE } from '../../../../common/constants'; import { ITooltipProperty } from '../../tooltips/tooltip_property'; +import { DataRequest } from '../../util/data_request'; + +export interface SourceTooltipConfig { + tooltipContent: string | null; + areResultsTrimmed: boolean; +} export type GeoJsonFetchMeta = ESSearchSourceResponseMeta; @@ -30,8 +36,8 @@ export type GeoJsonWithMeta = { export type BoundsFilters = { applyGlobalQuery: boolean; filters: Filter[]; - query: MapQuery; - sourceQuery: MapQuery; + query?: MapQuery; + sourceQuery?: MapQuery; timeFilters: TimeRange; }; @@ -39,44 +45,52 @@ export interface IVectorSource extends ISource { getTooltipProperties(properties: GeoJsonProperties): Promise; getBoundsForFilters( boundsFilters: BoundsFilters, - registerCancelCallback: (requestToken: symbol, callback: () => void) => void + registerCancelCallback: (callback: () => void) => void ): MapExtent | null; getGeoJsonWithMeta( - layerName: 'string', + layerName: string, searchFilters: MapFilters, - registerCancelCallback: (callback: () => void) => void + registerCancelCallback: (callback: () => void) => void, + isRequestStillActive: () => boolean ): Promise; getFields(): Promise; getFieldByName(fieldName: string): IField | null; + getLeftJoinFields(): Promise; getSyncMeta(): VectorSourceSyncMeta; getFieldNames(): string[]; getApplyGlobalQuery(): boolean; createField({ fieldName }: { fieldName: string }): IField; canFormatFeatureProperties(): boolean; getSupportedShapeTypes(): Promise; + isBoundsAware(): boolean; + getSourceTooltipContent(sourceDataRequest?: DataRequest): SourceTooltipConfig; } export class AbstractVectorSource extends AbstractSource implements IVectorSource { getTooltipProperties(properties: GeoJsonProperties): Promise; getBoundsForFilters( boundsFilters: BoundsFilters, - registerCancelCallback: (requestToken: symbol, callback: () => void) => void + registerCancelCallback: (callback: () => void) => void ): MapExtent | null; getGeoJsonWithMeta( layerName: string, searchFilters: VectorSourceRequestMeta, - registerCancelCallback: (callback: () => void) => void + registerCancelCallback: (callback: () => void) => void, + isRequestStillActive: () => boolean ): Promise; getFields(): Promise; getFieldByName(fieldName: string): IField | null; + getLeftJoinFields(): Promise; getSyncMeta(): VectorSourceSyncMeta; getSupportedShapeTypes(): Promise; canFormatFeatureProperties(): boolean; getApplyGlobalQuery(): boolean; getFieldNames(): string[]; createField({ fieldName }: { fieldName: string }): IField; + isBoundsAware(): boolean; + getSourceTooltipContent(sourceDataRequest?: DataRequest): SourceTooltipConfig; } export interface ITiledSingleLayerVectorSource extends IVectorSource { 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 1244c53afe9a6..5d0d9712ef988 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 @@ -5,7 +5,7 @@ */ import _ from 'lodash'; -import React from 'react'; +import React, { ReactElement } from 'react'; import { Map as MbMap, FeatureIdentifier } from 'mapbox-gl'; import { FeatureCollection } from 'geojson'; // @ts-expect-error @@ -92,6 +92,55 @@ export interface IVectorStyle extends IStyle { mapColors: string[] ): { hasChanges: boolean; nextStyleDescriptor?: VectorStyleDescriptor }; pluckStyleMetaFromSourceDataRequest(sourceDataRequest: DataRequest): Promise; + isTimeAware: () => boolean; + getIcon: () => ReactElement; + hasLegendDetails: () => Promise; + renderLegendDetails: () => ReactElement; + clearFeatureState: (featureCollection: FeatureCollection, mbMap: MbMap, sourceId: string) => void; + setFeatureStateAndStyleProps: ( + featureCollection: FeatureCollection, + mbMap: MbMap, + mbSourceId: string + ) => boolean; + arePointsSymbolizedAsCircles: () => boolean; + setMBPaintProperties: ({ + alpha, + mbMap, + fillLayerId, + lineLayerId, + }: { + alpha: number; + mbMap: MbMap; + fillLayerId: string; + lineLayerId: string; + }) => void; + setMBPaintPropertiesForPoints: ({ + alpha, + mbMap, + pointLayerId, + }: { + alpha: number; + mbMap: MbMap; + pointLayerId: string; + }) => void; + setMBPropertiesForLabelText: ({ + alpha, + mbMap, + textLayerId, + }: { + alpha: number; + mbMap: MbMap; + textLayerId: string; + }) => void; + setMBSymbolPropertiesForPoints: ({ + mbMap, + symbolLayerId, + alpha, + }: { + alpha: number; + mbMap: MbMap; + symbolLayerId: string; + }) => void; } export class VectorStyle implements IVectorStyle { @@ -594,12 +643,12 @@ export class VectorStyle implements IVectorStyle { mbSourceId: string ) { if (!featureCollection) { - return; + return false; } const dynamicStyleProps = this.getDynamicPropertiesArray(); if (dynamicStyleProps.length === 0) { - return; + return false; } const tmpFeatureIdentifier: FeatureIdentifier = { diff --git a/x-pack/plugins/maps/public/connected_components/widget_overlay/layer_control/layer_toc/toc_entry/toc_entry_actions_popover/toc_entry_actions_popover.test.tsx b/x-pack/plugins/maps/public/connected_components/widget_overlay/layer_control/layer_toc/toc_entry/toc_entry_actions_popover/toc_entry_actions_popover.test.tsx index 6c6cb6ba143cd..24728465de3bd 100644 --- a/x-pack/plugins/maps/public/connected_components/widget_overlay/layer_control/layer_toc/toc_entry/toc_entry_actions_popover/toc_entry_actions_popover.test.tsx +++ b/x-pack/plugins/maps/public/connected_components/widget_overlay/layer_control/layer_toc/toc_entry/toc_entry_actions_popover/toc_entry_actions_popover.test.tsx @@ -9,7 +9,6 @@ import React from 'react'; import { shallow } from 'enzyme'; import { AbstractLayer, ILayer } from '../../../../../../classes/layers/layer'; import { AbstractSource, ISource } from '../../../../../../classes/sources/source'; -import { IStyle } from '../../../../../../classes/styles/style'; import { TOCEntryActionsPopover } from './toc_entry_actions_popover'; @@ -17,28 +16,17 @@ let supportsFitToBounds: boolean; class MockSource extends AbstractSource implements ISource {} -class MockStyle implements IStyle { - renderEditor() { - return null; - } - - getType() { - return 'mockStyle'; - } -} - class LayerMock extends AbstractLayer implements ILayer { constructor() { const sourceDescriptor = { type: 'mySourceType', }; const source = new MockSource(sourceDescriptor); - const style = new MockStyle(); const layerDescriptor = { id: 'testLayer', sourceDescriptor, }; - super({ layerDescriptor, source, style }); + super({ layerDescriptor, source }); } async supportsFitToBounds(): Promise { From e92a4ab4bf5ec175fc572f4d14b5da173de266a7 Mon Sep 17 00:00:00 2001 From: Ashik Meerankutty Date: Fri, 2 Oct 2020 07:34:22 +0530 Subject: [PATCH 25/50] [APM] Service Inventory Updated the `EuiBadge` to use the `behind_text` vars instead of the base colors for the health status badges (#77844) * Use behind_text colors in health status * Separated badge color usage from getSeverityColor --- .../plugins/apm/common/service_health_status.ts | 16 ++++++++++++++++ .../ServiceOverview/ServiceList/HealthBadge.tsx | 4 ++-- .../__snapshots__/ServiceOverview.test.tsx.snap | 2 +- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/apm/common/service_health_status.ts b/x-pack/plugins/apm/common/service_health_status.ts index 1d4bcfb3b0e07..f66e03a9733a3 100644 --- a/x-pack/plugins/apm/common/service_health_status.ts +++ b/x-pack/plugins/apm/common/service_health_status.ts @@ -54,6 +54,22 @@ export function getServiceHealthStatusColor( } } +export function getServiceHealthStatusBadgeColor( + theme: EuiTheme, + status: ServiceHealthStatus +) { + switch (status) { + case ServiceHealthStatus.healthy: + return theme.eui.euiColorVis0_behindText; + case ServiceHealthStatus.warning: + return theme.eui.euiColorVis5_behindText; + case ServiceHealthStatus.critical: + return theme.eui.euiColorVis9_behindText; + case ServiceHealthStatus.unknown: + return theme.eui.euiColorMediumShade; + } +} + export function getServiceHealthStatusLabel(status: ServiceHealthStatus) { switch (status) { case ServiceHealthStatus.critical: diff --git a/x-pack/plugins/apm/public/components/app/ServiceOverview/ServiceList/HealthBadge.tsx b/x-pack/plugins/apm/public/components/app/ServiceOverview/ServiceList/HealthBadge.tsx index c6be0a352ef66..e8ad3e65b1a47 100644 --- a/x-pack/plugins/apm/public/components/app/ServiceOverview/ServiceList/HealthBadge.tsx +++ b/x-pack/plugins/apm/public/components/app/ServiceOverview/ServiceList/HealthBadge.tsx @@ -6,7 +6,7 @@ import React from 'react'; import { EuiBadge } from '@elastic/eui'; import { - getServiceHealthStatusColor, + getServiceHealthStatusBadgeColor, getServiceHealthStatusLabel, ServiceHealthStatus, } from '../../../../../common/service_health_status'; @@ -20,7 +20,7 @@ export function HealthBadge({ const theme = useTheme(); return ( - + {getServiceHealthStatusLabel(healthStatus)} ); diff --git a/x-pack/plugins/apm/public/components/app/ServiceOverview/__test__/__snapshots__/ServiceOverview.test.tsx.snap b/x-pack/plugins/apm/public/components/app/ServiceOverview/__test__/__snapshots__/ServiceOverview.test.tsx.snap index 40a2b6a5fa81b..ee3a4fce0dbaa 100644 --- a/x-pack/plugins/apm/public/components/app/ServiceOverview/__test__/__snapshots__/ServiceOverview.test.tsx.snap +++ b/x-pack/plugins/apm/public/components/app/ServiceOverview/__test__/__snapshots__/ServiceOverview.test.tsx.snap @@ -153,7 +153,7 @@ NodeList [ > Date: Fri, 2 Oct 2020 09:03:08 +0300 Subject: [PATCH 26/50] [Functional] Add retry on custom formatter test (#78729) Co-authored-by: Elastic Machine --- test/functional/apps/visualize/_tsvb_time_series.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/functional/apps/visualize/_tsvb_time_series.ts b/test/functional/apps/visualize/_tsvb_time_series.ts index 0b2a52b367a20..d4a079a38c814 100644 --- a/test/functional/apps/visualize/_tsvb_time_series.ts +++ b/test/functional/apps/visualize/_tsvb_time_series.ts @@ -84,8 +84,10 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { await visualBuilder.clickSeriesOption(); await visualBuilder.enterSeriesTemplate('$ {{value}}'); - const actualCount = await visualBuilder.getRhythmChartLegendValue(); - expect(actualCount).to.be(expectedLegendValue); + await retry.try(async () => { + const actualCount = await visualBuilder.getRhythmChartLegendValue(); + expect(actualCount).to.be(expectedLegendValue); + }); }); it('should show the correct count in the legend with percent formatter', async () => { From 4ddcd1d2a6bf3ffbec37844468c4e4af827f739f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B8ren=20Louv-Jansen?= Date: Fri, 2 Oct 2020 09:45:50 +0200 Subject: [PATCH 27/50] [APM] Fix anomalies not showing up on transaction charts (#76930) * [APM] Fix anomalies not showing up on transaction charts * Added API tests to check transaction groups charts for anomaly data * Improve test names and assertions from PR feedback * Updated the transaction groups chart API to make `environment` a required param while making `uiFilters` optional * updates the basic API tests for transaction_groups/charts with the required `environment` param * makes uiFIltersES default to [] on core setup and removes SetupUIFilters type * fixes vertical shade * - replaces uiFiltersES with esFilter & uiFilters and cleans up related code around these - deduplicates the required environment in the transaction_groups/charts API * updates basic apm_api_integration tests * pr feedback * updates api test snapshots with correct anomaly data * removed environment query param from useTransactionCharts and ensures it's included in uiFilters returned from useUrlParams Co-authored-by: Oliver Gupte --- .../example_response_opbeans_beats.json | 42 ++--- .../public/context/UrlParamsContext/index.tsx | 7 +- .../plugins/apm/public/utils/testHelpers.tsx | 7 +- .../errors/__snapshots__/queries.test.ts.snap | 6 +- .../__snapshots__/queries.test.ts.snap | 4 +- .../__tests__/get_buckets.test.ts | 5 +- .../lib/errors/distribution/get_buckets.ts | 12 +- .../errors/distribution/get_distribution.ts | 8 +- .../apm/server/lib/errors/get_error_group.ts | 12 +- .../apm/server/lib/errors/get_error_groups.ts | 8 +- ...{get_ui_filters_es.ts => get_es_filter.ts} | 2 +- .../get_parsed_ui_filters.ts | 23 --- .../apm/server/lib/helpers/setup_request.ts | 41 ++--- .../__snapshots__/queries.test.ts.snap | 54 +++--- .../server/lib/metrics/by_agent/default.ts | 8 +- .../java/gc/fetch_and_transform_gc_metrics.ts | 8 +- .../by_agent/java/gc/get_gc_rate_chart.ts | 8 +- .../by_agent/java/gc/get_gc_time_chart.ts | 8 +- .../by_agent/java/heap_memory/index.ts | 8 +- .../server/lib/metrics/by_agent/java/index.ts | 8 +- .../by_agent/java/non_heap_memory/index.ts | 8 +- .../by_agent/java/thread_count/index.ts | 8 +- .../lib/metrics/by_agent/shared/cpu/index.ts | 8 +- .../metrics/by_agent/shared/memory/index.ts | 10 +- .../metrics/fetch_and_transform_metrics.ts | 8 +- .../get_metrics_chart_data_by_agent.ts | 8 +- .../__snapshots__/queries.test.ts.snap | 14 +- .../lib/rum_client/get_client_metrics.ts | 8 +- .../server/lib/rum_client/get_js_errors.ts | 8 +- .../lib/rum_client/get_long_task_metrics.ts | 8 +- .../rum_client/get_page_load_distribution.ts | 10 +- .../lib/rum_client/get_page_view_trends.ts | 8 +- .../lib/rum_client/get_pl_dist_breakdown.ts | 8 +- .../server/lib/rum_client/get_rum_services.ts | 8 +- .../server/lib/rum_client/get_url_search.ts | 8 +- .../lib/rum_client/get_visitor_breakdown.ts | 8 +- .../lib/rum_client/get_web_core_vitals.ts | 8 +- .../server/lib/service_map/get_service_map.ts | 2 +- .../get_service_map_service_node_info.test.ts | 6 +- .../get_service_map_service_node_info.ts | 9 +- .../group_resource_nodes_grouped.json | 4 +- .../group_resource_nodes_pregrouped.json | 4 +- .../__snapshots__/queries.test.ts.snap | 6 +- .../apm/server/lib/service_nodes/index.ts | 8 +- .../__snapshots__/queries.test.ts.snap | 10 +- .../lib/services/get_service_node_metadata.ts | 8 +- .../get_services/get_services_items.ts | 12 +- .../server/lib/services/get_services/index.ts | 11 +- .../__snapshots__/queries.test.ts.snap | 14 +- .../server/lib/transaction_groups/fetcher.ts | 8 +- .../lib/transaction_groups/get_error_rate.ts | 12 +- .../get_transaction_sample_for_group.ts | 12 +- .../server/lib/transaction_groups/index.ts | 8 +- .../__snapshots__/queries.test.ts.snap | 12 +- .../lib/transactions/breakdown/index.test.ts | 3 +- .../lib/transactions/breakdown/index.ts | 12 +- .../charts/get_anomaly_data/fetcher.ts | 11 +- .../charts/get_anomaly_data/index.ts | 40 ++--- .../get_timeseries_data/fetcher.test.ts | 5 +- .../charts/get_timeseries_data/fetcher.ts | 12 +- .../charts/get_timeseries_data/index.ts | 8 +- .../server/lib/transactions/charts/index.ts | 10 +- .../distribution/get_buckets/index.ts | 12 +- .../distribution/get_distribution_max.ts | 12 +- .../lib/transactions/distribution/index.ts | 8 +- .../lib/transactions/get_transaction/index.ts | 8 +- .../server/lib/transactions/queries.test.ts | 3 - .../__snapshots__/queries.test.ts.snap | 2 +- .../get_local_filter_query.ts | 4 +- .../local_ui_filters/queries.test.ts | 2 +- .../plugins/apm/server/projections/errors.ts | 12 +- .../plugins/apm/server/projections/metrics.ts | 12 +- .../projections/rum_page_load_transactions.ts | 18 +- .../apm/server/projections/service_nodes.ts | 8 +- .../apm/server/projections/services.ts | 12 +- .../server/projections/transaction_groups.ts | 8 +- .../apm/server/projections/transactions.ts | 12 +- .../plugins/apm/server/routes/service_map.ts | 5 - x-pack/plugins/apm/server/routes/services.ts | 12 +- .../apm/server/routes/transaction_groups.ts | 21 +-- .../plugins/apm/server/routes/ui_filters.ts | 13 +- .../plugins/apm/server/utils/test_helpers.tsx | 7 +- .../basic/tests/feature_controls.ts | 6 +- .../transaction_groups/transaction_charts.ts | 2 +- .../apm_api_integration/trial/tests/index.ts | 1 + .../transaction_groups_charts.snap | 43 +++++ .../services/transaction_groups_charts.ts | 161 ++++++++++++++++++ 87 files changed, 528 insertions(+), 548 deletions(-) rename x-pack/plugins/apm/server/lib/helpers/convert_ui_filters/{get_ui_filters_es.ts => get_es_filter.ts} (96%) delete mode 100644 x-pack/plugins/apm/server/lib/helpers/convert_ui_filters/get_parsed_ui_filters.ts create mode 100644 x-pack/test/apm_api_integration/trial/tests/services/__snapshots__/transaction_groups_charts.snap create mode 100644 x-pack/test/apm_api_integration/trial/tests/services/transaction_groups_charts.ts diff --git a/x-pack/plugins/apm/public/components/app/ServiceMap/__stories__/example_response_opbeans_beats.json b/x-pack/plugins/apm/public/components/app/ServiceMap/__stories__/example_response_opbeans_beats.json index 153fa57bb05e7..cfd905f145fe2 100644 --- a/x-pack/plugins/apm/public/components/app/ServiceMap/__stories__/example_response_opbeans_beats.json +++ b/x-pack/plugins/apm/public/components/app/ServiceMap/__stories__/example_response_opbeans_beats.json @@ -83,7 +83,7 @@ "id": "opbeans-go~>postgresql", "sourceData": { "id": "opbeans-go", - "service.environment": "testing", + "service.environment": "test", "service.name": "opbeans-go", "agent.name": "go" }, @@ -103,7 +103,7 @@ "id": "opbeans-go~opbeans-java", "sourceData": { "id": "opbeans-go", - "service.environment": "testing", + "service.environment": "test", "service.name": "opbeans-go", "agent.name": "go" }, @@ -123,13 +123,13 @@ "id": "opbeans-go~opbeans-node", "sourceData": { "id": "opbeans-go", - "service.environment": "testing", + "service.environment": "test", "service.name": "opbeans-go", "agent.name": "go" }, "targetData": { "id": "opbeans-node", - "service.environment": "testing", + "service.environment": "test", "service.name": "opbeans-node", "agent.name": "nodejs" }, @@ -143,7 +143,7 @@ "id": "opbeans-go~opbeans-ruby", "sourceData": { "id": "opbeans-go", - "service.environment": "testing", + "service.environment": "test", "service.name": "opbeans-go", "agent.name": "go" }, @@ -189,7 +189,7 @@ }, "targetData": { "id": "opbeans-go", - "service.environment": "testing", + "service.environment": "test", "service.name": "opbeans-go", "agent.name": "go" }, @@ -209,7 +209,7 @@ }, "targetData": { "id": "opbeans-node", - "service.environment": "testing", + "service.environment": "test", "service.name": "opbeans-node", "agent.name": "nodejs" } @@ -242,7 +242,7 @@ "id": "opbeans-node~>postgresql", "sourceData": { "id": "opbeans-node", - "service.environment": "testing", + "service.environment": "test", "service.name": "opbeans-node", "agent.name": "nodejs" }, @@ -262,7 +262,7 @@ "id": "opbeans-node~>redis", "sourceData": { "id": "opbeans-node", - "service.environment": "testing", + "service.environment": "test", "service.name": "opbeans-node", "agent.name": "nodejs" }, @@ -282,13 +282,13 @@ "id": "opbeans-node~opbeans-go", "sourceData": { "id": "opbeans-node", - "service.environment": "testing", + "service.environment": "test", "service.name": "opbeans-node", "agent.name": "nodejs" }, "targetData": { "id": "opbeans-go", - "service.environment": "testing", + "service.environment": "test", "service.name": "opbeans-go", "agent.name": "go" }, @@ -302,7 +302,7 @@ "id": "opbeans-node~opbeans-python", "sourceData": { "id": "opbeans-node", - "service.environment": "testing", + "service.environment": "test", "service.name": "opbeans-node", "agent.name": "nodejs" }, @@ -322,7 +322,7 @@ "id": "opbeans-node~opbeans-ruby", "sourceData": { "id": "opbeans-node", - "service.environment": "testing", + "service.environment": "test", "service.name": "opbeans-node", "agent.name": "nodejs" }, @@ -408,7 +408,7 @@ }, "targetData": { "id": "opbeans-go", - "service.environment": "testing", + "service.environment": "test", "service.name": "opbeans-go", "agent.name": "go" } @@ -427,7 +427,7 @@ }, "targetData": { "id": "opbeans-node", - "service.environment": "testing", + "service.environment": "test", "service.name": "opbeans-node", "agent.name": "nodejs" }, @@ -487,7 +487,7 @@ }, "targetData": { "id": "opbeans-go", - "service.environment": "testing", + "service.environment": "test", "service.name": "opbeans-go", "agent.name": "go" }, @@ -527,7 +527,7 @@ }, "targetData": { "id": "opbeans-node", - "service.environment": "testing", + "service.environment": "test", "service.name": "opbeans-node", "agent.name": "nodejs" }, @@ -566,7 +566,7 @@ }, "targetData": { "id": "opbeans-go", - "service.environment": "testing", + "service.environment": "test", "service.name": "opbeans-go", "agent.name": "go" } @@ -602,7 +602,7 @@ }, "targetData": { "id": "opbeans-node", - "service.environment": "testing", + "service.environment": "test", "service.name": "opbeans-node", "agent.name": "nodejs" } @@ -673,7 +673,7 @@ { "data": { "id": "opbeans-node", - "service.environment": "testing", + "service.environment": "test", "service.name": "opbeans-node", "agent.name": "nodejs", "anomaly_score": 41.31593099784474, @@ -733,7 +733,7 @@ { "data": { "id": "opbeans-go", - "service.environment": "testing", + "service.environment": "test", "service.name": "opbeans-go", "agent.name": "go", "anomaly_score": 0.2633884161762746, diff --git a/x-pack/plugins/apm/public/context/UrlParamsContext/index.tsx b/x-pack/plugins/apm/public/context/UrlParamsContext/index.tsx index 9eb4704a2ca29..5682009019d7f 100644 --- a/x-pack/plugins/apm/public/context/UrlParamsContext/index.tsx +++ b/x-pack/plugins/apm/public/context/UrlParamsContext/index.tsx @@ -25,6 +25,7 @@ import { import { pickKeys } from '../../../common/utils/pick_keys'; import { useDeepObjectIdentity } from '../../hooks/useDeepObjectIdentity'; import { LocalUIFilterName } from '../../../common/ui_filter'; +import { ENVIRONMENT_ALL } from '../../../common/environment_filter_values'; interface TimeRange { rangeFrom: string; @@ -38,7 +39,11 @@ function useUiFilters(params: IUrlParams): UIFilters { (val) => (val ? val.split(',') : []) ) as Partial>; - return useDeepObjectIdentity({ kuery, environment, ...localUiFilters }); + return useDeepObjectIdentity({ + kuery, + environment: environment || ENVIRONMENT_ALL.value, + ...localUiFilters, + }); } const defaultRefresh = (_time: TimeRange) => {}; diff --git a/x-pack/plugins/apm/public/utils/testHelpers.tsx b/x-pack/plugins/apm/public/utils/testHelpers.tsx index 971455fde3946..7826e9672a3bb 100644 --- a/x-pack/plugins/apm/public/utils/testHelpers.tsx +++ b/x-pack/plugins/apm/public/utils/testHelpers.tsx @@ -25,6 +25,7 @@ import { } from '../../typings/elasticsearch'; import { MockApmPluginContextWrapper } from '../context/ApmPluginContext/MockApmPluginContext'; import { UrlParamsProvider } from '../context/UrlParamsContext'; +import { UIFilters } from '../../typings/ui_filters'; const originalConsoleWarn = console.warn; // eslint-disable-line no-console /** @@ -118,7 +119,8 @@ interface MockSetup { apmEventClient: any; internalClient: any; config: APMConfig; - uiFiltersES: ESFilter[]; + uiFilters: UIFilters; + esFilter: ESFilter[]; indices: { /* eslint-disable @typescript-eslint/naming-convention */ 'apm_oss.sourcemapIndices': string; @@ -179,7 +181,8 @@ export async function inspectSearchParams( }, } ) as APMConfig, - uiFiltersES: [{ term: { 'my.custom.ui.filter': 'foo-bar' } }], + uiFilters: { environment: 'test' }, + esFilter: [{ term: { 'service.environment': 'test' } }], indices: { /* eslint-disable @typescript-eslint/naming-convention */ 'apm_oss.sourcemapIndices': 'myIndex', diff --git a/x-pack/plugins/apm/server/lib/errors/__snapshots__/queries.test.ts.snap b/x-pack/plugins/apm/server/lib/errors/__snapshots__/queries.test.ts.snap index 63b6c9cde4d0d..632232ffb075d 100644 --- a/x-pack/plugins/apm/server/lib/errors/__snapshots__/queries.test.ts.snap +++ b/x-pack/plugins/apm/server/lib/errors/__snapshots__/queries.test.ts.snap @@ -32,7 +32,7 @@ Object { }, Object { "term": Object { - "my.custom.ui.filter": "foo-bar", + "service.environment": "test", }, }, ], @@ -119,7 +119,7 @@ Object { }, Object { "term": Object { - "my.custom.ui.filter": "foo-bar", + "service.environment": "test", }, }, ], @@ -194,7 +194,7 @@ Object { }, Object { "term": Object { - "my.custom.ui.filter": "foo-bar", + "service.environment": "test", }, }, ], diff --git a/x-pack/plugins/apm/server/lib/errors/distribution/__snapshots__/queries.test.ts.snap b/x-pack/plugins/apm/server/lib/errors/distribution/__snapshots__/queries.test.ts.snap index ea142ca2acc00..b329499c8b045 100644 --- a/x-pack/plugins/apm/server/lib/errors/distribution/__snapshots__/queries.test.ts.snap +++ b/x-pack/plugins/apm/server/lib/errors/distribution/__snapshots__/queries.test.ts.snap @@ -40,7 +40,7 @@ Object { }, Object { "term": Object { - "my.custom.ui.filter": "foo-bar", + "service.environment": "test", }, }, ], @@ -91,7 +91,7 @@ Object { }, Object { "term": Object { - "my.custom.ui.filter": "foo-bar", + "service.environment": "test", }, }, Object { diff --git a/x-pack/plugins/apm/server/lib/errors/distribution/__tests__/get_buckets.test.ts b/x-pack/plugins/apm/server/lib/errors/distribution/__tests__/get_buckets.test.ts index 1a83113de35f2..50da1f9c20d16 100644 --- a/x-pack/plugins/apm/server/lib/errors/distribution/__tests__/get_buckets.test.ts +++ b/x-pack/plugins/apm/server/lib/errors/distribution/__tests__/get_buckets.test.ts @@ -41,7 +41,10 @@ describe('timeseriesFetcher', () => { get: () => 'myIndex', } ) as APMConfig, - uiFiltersES: [ + uiFilters: { + environment: 'prod', + }, + esFilter: [ { term: { 'service.environment': 'prod' }, }, diff --git a/x-pack/plugins/apm/server/lib/errors/distribution/get_buckets.ts b/x-pack/plugins/apm/server/lib/errors/distribution/get_buckets.ts index de6df15354e79..a42710947a792 100644 --- a/x-pack/plugins/apm/server/lib/errors/distribution/get_buckets.ts +++ b/x-pack/plugins/apm/server/lib/errors/distribution/get_buckets.ts @@ -11,11 +11,7 @@ import { SERVICE_NAME, } from '../../../../common/elasticsearch_fieldnames'; import { rangeFilter } from '../../../../common/utils/range_filter'; -import { - Setup, - SetupTimeRange, - SetupUIFilters, -} from '../../helpers/setup_request'; +import { Setup, SetupTimeRange } from '../../helpers/setup_request'; export async function getBuckets({ serviceName, @@ -26,13 +22,13 @@ export async function getBuckets({ serviceName: string; groupId?: string; bucketSize: number; - setup: Setup & SetupTimeRange & SetupUIFilters; + setup: Setup & SetupTimeRange; }) { - const { start, end, uiFiltersES, apmEventClient } = setup; + const { start, end, esFilter, apmEventClient } = setup; const filter: ESFilter[] = [ { term: { [SERVICE_NAME]: serviceName } }, { range: rangeFilter(start, end) }, - ...uiFiltersES, + ...esFilter, ]; if (groupId) { diff --git a/x-pack/plugins/apm/server/lib/errors/distribution/get_distribution.ts b/x-pack/plugins/apm/server/lib/errors/distribution/get_distribution.ts index 3b48b6c5be594..dea518cad8e40 100644 --- a/x-pack/plugins/apm/server/lib/errors/distribution/get_distribution.ts +++ b/x-pack/plugins/apm/server/lib/errors/distribution/get_distribution.ts @@ -5,11 +5,7 @@ */ import { PromiseReturnType } from '../../../../typings/common'; -import { - Setup, - SetupTimeRange, - SetupUIFilters, -} from '../../helpers/setup_request'; +import { Setup, SetupTimeRange } from '../../helpers/setup_request'; import { getBuckets } from './get_buckets'; import { BUCKET_TARGET_COUNT } from '../../transactions/constants'; @@ -28,7 +24,7 @@ export async function getErrorDistribution({ }: { serviceName: string; groupId?: string; - setup: Setup & SetupTimeRange & SetupUIFilters; + setup: Setup & SetupTimeRange; }) { const bucketSize = getBucketSize({ start: setup.start, end: setup.end }); const { buckets, noHits } = await getBuckets({ diff --git a/x-pack/plugins/apm/server/lib/errors/get_error_group.ts b/x-pack/plugins/apm/server/lib/errors/get_error_group.ts index b23c955b57183..0fbc7720f7111 100644 --- a/x-pack/plugins/apm/server/lib/errors/get_error_group.ts +++ b/x-pack/plugins/apm/server/lib/errors/get_error_group.ts @@ -12,11 +12,7 @@ import { } from '../../../common/elasticsearch_fieldnames'; import { PromiseReturnType } from '../../../typings/common'; import { rangeFilter } from '../../../common/utils/range_filter'; -import { - Setup, - SetupTimeRange, - SetupUIFilters, -} from '../helpers/setup_request'; +import { Setup, SetupTimeRange } from '../helpers/setup_request'; import { getTransaction } from '../transactions/get_transaction'; export type ErrorGroupAPIResponse = PromiseReturnType; @@ -29,9 +25,9 @@ export async function getErrorGroup({ }: { serviceName: string; groupId: string; - setup: Setup & SetupTimeRange & SetupUIFilters; + setup: Setup & SetupTimeRange; }) { - const { start, end, uiFiltersES, apmEventClient } = setup; + const { start, end, esFilter, apmEventClient } = setup; const params = { apm: { @@ -45,7 +41,7 @@ export async function getErrorGroup({ { term: { [SERVICE_NAME]: serviceName } }, { term: { [ERROR_GROUP_ID]: groupId } }, { range: rangeFilter(start, end) }, - ...uiFiltersES, + ...esFilter, ], should: [{ term: { [TRANSACTION_SAMPLED]: true } }], }, diff --git a/x-pack/plugins/apm/server/lib/errors/get_error_groups.ts b/x-pack/plugins/apm/server/lib/errors/get_error_groups.ts index ab1c2149be343..006d2fae3d4fb 100644 --- a/x-pack/plugins/apm/server/lib/errors/get_error_groups.ts +++ b/x-pack/plugins/apm/server/lib/errors/get_error_groups.ts @@ -13,11 +13,7 @@ import { ERROR_LOG_MESSAGE, } from '../../../common/elasticsearch_fieldnames'; import { PromiseReturnType } from '../../../typings/common'; -import { - Setup, - SetupTimeRange, - SetupUIFilters, -} from '../helpers/setup_request'; +import { Setup, SetupTimeRange } from '../helpers/setup_request'; import { getErrorGroupsProjection } from '../../projections/errors'; import { mergeProjection } from '../../projections/util/merge_projection'; import { SortOptions } from '../../../typings/elasticsearch/aggregations'; @@ -35,7 +31,7 @@ export async function getErrorGroups({ serviceName: string; sortField?: string; sortDirection?: 'asc' | 'desc'; - setup: Setup & SetupTimeRange & SetupUIFilters; + setup: Setup & SetupTimeRange; }) { const { apmEventClient } = setup; diff --git a/x-pack/plugins/apm/server/lib/helpers/convert_ui_filters/get_ui_filters_es.ts b/x-pack/plugins/apm/server/lib/helpers/convert_ui_filters/get_es_filter.ts similarity index 96% rename from x-pack/plugins/apm/server/lib/helpers/convert_ui_filters/get_ui_filters_es.ts rename to x-pack/plugins/apm/server/lib/helpers/convert_ui_filters/get_es_filter.ts index c1405b44f2a8a..1b8f32d4de8b9 100644 --- a/x-pack/plugins/apm/server/lib/helpers/convert_ui_filters/get_ui_filters_es.ts +++ b/x-pack/plugins/apm/server/lib/helpers/convert_ui_filters/get_es_filter.ts @@ -13,7 +13,7 @@ import { } from '../../ui_filters/local_ui_filters/config'; import { esKuery } from '../../../../../../../src/plugins/data/server'; -export function getUiFiltersES(uiFilters: UIFilters) { +export function getEsFilter(uiFilters: UIFilters) { const { kuery, environment, ...localFilterValues } = uiFilters; const mappedFilters = localUIFilterNames .filter((name) => name in localFilterValues) diff --git a/x-pack/plugins/apm/server/lib/helpers/convert_ui_filters/get_parsed_ui_filters.ts b/x-pack/plugins/apm/server/lib/helpers/convert_ui_filters/get_parsed_ui_filters.ts deleted file mode 100644 index 324da199807c7..0000000000000 --- a/x-pack/plugins/apm/server/lib/helpers/convert_ui_filters/get_parsed_ui_filters.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; - * you may not use this file except in compliance with the Elastic License. - */ - -import { Logger } from 'src/core/server'; -import { UIFilters } from '../../../../typings/ui_filters'; - -export function getParsedUiFilters({ - uiFilters, - logger, -}: { - uiFilters: string; - logger: Logger; -}): UIFilters { - try { - return JSON.parse(uiFilters); - } catch (error) { - logger.error(error); - } - return {}; -} diff --git a/x-pack/plugins/apm/server/lib/helpers/setup_request.ts b/x-pack/plugins/apm/server/lib/helpers/setup_request.ts index eba75433a5148..26896a050dd88 100644 --- a/x-pack/plugins/apm/server/lib/helpers/setup_request.ts +++ b/x-pack/plugins/apm/server/lib/helpers/setup_request.ts @@ -5,6 +5,7 @@ */ import moment from 'moment'; +import { Logger } from 'kibana/server'; import { isActivePlatinumLicense } from '../../../common/service_map'; import { UI_SETTINGS } from '../../../../../../src/plugins/data/common'; import { KibanaRequest } from '../../../../../../src/core/server'; @@ -14,7 +15,7 @@ import { ApmIndicesConfig, } from '../settings/apm_indices/get_apm_indices'; import { ESFilter } from '../../../typings/elasticsearch'; -import { getUiFiltersES } from './convert_ui_filters/get_ui_filters_es'; +import { getEsFilter } from './convert_ui_filters/get_es_filter'; import { APMRequestHandlerContext } from '../../routes/typings'; import { ProcessorEvent } from '../../../common/processor_event'; import { @@ -25,14 +26,8 @@ import { APMInternalClient, createInternalESClient, } from './create_es_client/create_internal_es_client'; +import { UIFilters } from '../../../typings/ui_filters'; -function decodeUiFilters(uiFiltersEncoded?: string) { - if (!uiFiltersEncoded) { - return []; - } - const uiFilters = JSON.parse(uiFiltersEncoded); - return getUiFiltersES(uiFilters); -} // Explicitly type Setup to prevent TS initialization errors // https://github.com/microsoft/TypeScript/issues/34933 @@ -42,6 +37,8 @@ export interface Setup { ml?: ReturnType; config: APMConfig; indices: ApmIndicesConfig; + uiFilters: UIFilters; + esFilter: ESFilter[]; } export interface SetupTimeRange { @@ -49,10 +46,6 @@ export interface SetupTimeRange { end: number; } -export interface SetupUIFilters { - uiFiltersES: ESFilter[]; -} - interface SetupRequestParams { query?: { _debug?: boolean; @@ -65,16 +58,13 @@ interface SetupRequestParams { type InferSetup = Setup & (TParams extends { query: { start: string } } ? { start: number } : {}) & - (TParams extends { query: { end: string } } ? { end: number } : {}) & - (TParams extends { query: { uiFilters: string } } - ? { uiFiltersES: ESFilter[] } - : {}); + (TParams extends { query: { end: string } } ? { end: number } : {}); export async function setupRequest( context: APMRequestHandlerContext, request: KibanaRequest ): Promise> { - const { config } = context; + const { config, logger } = context; const { query } = context.params; const [indices, includeFrozen] = await Promise.all([ @@ -85,7 +75,7 @@ export async function setupRequest( context.core.uiSettings.client.get(UI_SETTINGS.SEARCH_INCLUDE_FROZEN), ]); - const uiFiltersES = decodeUiFilters(query.uiFilters); + const uiFilters = decodeUiFilters(logger, query.uiFilters); const coreSetupRequest = { indices, @@ -108,12 +98,13 @@ export async function setupRequest( ) : undefined, config, + uiFilters, + esFilter: getEsFilter(uiFilters), }; return { ...('start' in query ? { start: moment.utc(query.start).valueOf() } : {}), ...('end' in query ? { end: moment.utc(query.end).valueOf() } : {}), - ...('uiFilters' in query ? { uiFiltersES } : {}), ...coreSetupRequest, } as InferSetup; } @@ -129,3 +120,15 @@ function getMlSetup( modules: ml.modulesProvider(request, savedObjectsClient), }; } + +function decodeUiFilters(logger: Logger, uiFiltersEncoded?: string): UIFilters { + if (!uiFiltersEncoded) { + return {}; + } + try { + return JSON.parse(uiFiltersEncoded); + } catch (error) { + logger.error(error); + return {}; + } +} diff --git a/x-pack/plugins/apm/server/lib/metrics/__snapshots__/queries.test.ts.snap b/x-pack/plugins/apm/server/lib/metrics/__snapshots__/queries.test.ts.snap index 2868dcfda97b6..961a1eee61d1d 100644 --- a/x-pack/plugins/apm/server/lib/metrics/__snapshots__/queries.test.ts.snap +++ b/x-pack/plugins/apm/server/lib/metrics/__snapshots__/queries.test.ts.snap @@ -87,7 +87,7 @@ Object { }, Object { "term": Object { - "my.custom.ui.filter": "foo-bar", + "service.environment": "test", }, }, ], @@ -175,7 +175,7 @@ Object { }, Object { "term": Object { - "my.custom.ui.filter": "foo-bar", + "service.environment": "test", }, }, Object { @@ -206,7 +206,7 @@ Object { "lang": "painless", "source": " /* - When no limit is specified in the container, docker allows the app as much memory / swap memory as it wants. + When no limit is specified in the container, docker allows the app as much memory / swap memory as it wants. This number represents the max possible value for the limit field. */ double CGROUP_LIMIT_MAX_VALUE = 9223372036854771712L; @@ -231,7 +231,7 @@ Object { "lang": "painless", "source": " /* - When no limit is specified in the container, docker allows the app as much memory / swap memory as it wants. + When no limit is specified in the container, docker allows the app as much memory / swap memory as it wants. This number represents the max possible value for the limit field. */ double CGROUP_LIMIT_MAX_VALUE = 9223372036854771712L; @@ -258,7 +258,7 @@ Object { "lang": "painless", "source": " /* - When no limit is specified in the container, docker allows the app as much memory / swap memory as it wants. + When no limit is specified in the container, docker allows the app as much memory / swap memory as it wants. This number represents the max possible value for the limit field. */ double CGROUP_LIMIT_MAX_VALUE = 9223372036854771712L; @@ -283,7 +283,7 @@ Object { "lang": "painless", "source": " /* - When no limit is specified in the container, docker allows the app as much memory / swap memory as it wants. + When no limit is specified in the container, docker allows the app as much memory / swap memory as it wants. This number represents the max possible value for the limit field. */ double CGROUP_LIMIT_MAX_VALUE = 9223372036854771712L; @@ -338,7 +338,7 @@ Object { }, Object { "term": Object { - "my.custom.ui.filter": "foo-bar", + "service.environment": "test", }, }, Object { @@ -431,7 +431,7 @@ Object { }, Object { "term": Object { - "my.custom.ui.filter": "foo-bar", + "service.environment": "test", }, }, Object { @@ -514,7 +514,7 @@ Object { }, Object { "term": Object { - "my.custom.ui.filter": "foo-bar", + "service.environment": "test", }, }, Object { @@ -623,7 +623,7 @@ Object { }, Object { "term": Object { - "my.custom.ui.filter": "foo-bar", + "service.environment": "test", }, }, ], @@ -717,7 +717,7 @@ Object { }, Object { "term": Object { - "my.custom.ui.filter": "foo-bar", + "service.environment": "test", }, }, Object { @@ -748,7 +748,7 @@ Object { "lang": "painless", "source": " /* - When no limit is specified in the container, docker allows the app as much memory / swap memory as it wants. + When no limit is specified in the container, docker allows the app as much memory / swap memory as it wants. This number represents the max possible value for the limit field. */ double CGROUP_LIMIT_MAX_VALUE = 9223372036854771712L; @@ -773,7 +773,7 @@ Object { "lang": "painless", "source": " /* - When no limit is specified in the container, docker allows the app as much memory / swap memory as it wants. + When no limit is specified in the container, docker allows the app as much memory / swap memory as it wants. This number represents the max possible value for the limit field. */ double CGROUP_LIMIT_MAX_VALUE = 9223372036854771712L; @@ -800,7 +800,7 @@ Object { "lang": "painless", "source": " /* - When no limit is specified in the container, docker allows the app as much memory / swap memory as it wants. + When no limit is specified in the container, docker allows the app as much memory / swap memory as it wants. This number represents the max possible value for the limit field. */ double CGROUP_LIMIT_MAX_VALUE = 9223372036854771712L; @@ -825,7 +825,7 @@ Object { "lang": "painless", "source": " /* - When no limit is specified in the container, docker allows the app as much memory / swap memory as it wants. + When no limit is specified in the container, docker allows the app as much memory / swap memory as it wants. This number represents the max possible value for the limit field. */ double CGROUP_LIMIT_MAX_VALUE = 9223372036854771712L; @@ -886,7 +886,7 @@ Object { }, Object { "term": Object { - "my.custom.ui.filter": "foo-bar", + "service.environment": "test", }, }, Object { @@ -985,7 +985,7 @@ Object { }, Object { "term": Object { - "my.custom.ui.filter": "foo-bar", + "service.environment": "test", }, }, Object { @@ -1074,7 +1074,7 @@ Object { }, Object { "term": Object { - "my.custom.ui.filter": "foo-bar", + "service.environment": "test", }, }, Object { @@ -1172,7 +1172,7 @@ Object { }, Object { "term": Object { - "my.custom.ui.filter": "foo-bar", + "service.environment": "test", }, }, ], @@ -1255,7 +1255,7 @@ Object { }, Object { "term": Object { - "my.custom.ui.filter": "foo-bar", + "service.environment": "test", }, }, Object { @@ -1286,7 +1286,7 @@ Object { "lang": "painless", "source": " /* - When no limit is specified in the container, docker allows the app as much memory / swap memory as it wants. + When no limit is specified in the container, docker allows the app as much memory / swap memory as it wants. This number represents the max possible value for the limit field. */ double CGROUP_LIMIT_MAX_VALUE = 9223372036854771712L; @@ -1311,7 +1311,7 @@ Object { "lang": "painless", "source": " /* - When no limit is specified in the container, docker allows the app as much memory / swap memory as it wants. + When no limit is specified in the container, docker allows the app as much memory / swap memory as it wants. This number represents the max possible value for the limit field. */ double CGROUP_LIMIT_MAX_VALUE = 9223372036854771712L; @@ -1338,7 +1338,7 @@ Object { "lang": "painless", "source": " /* - When no limit is specified in the container, docker allows the app as much memory / swap memory as it wants. + When no limit is specified in the container, docker allows the app as much memory / swap memory as it wants. This number represents the max possible value for the limit field. */ double CGROUP_LIMIT_MAX_VALUE = 9223372036854771712L; @@ -1363,7 +1363,7 @@ Object { "lang": "painless", "source": " /* - When no limit is specified in the container, docker allows the app as much memory / swap memory as it wants. + When no limit is specified in the container, docker allows the app as much memory / swap memory as it wants. This number represents the max possible value for the limit field. */ double CGROUP_LIMIT_MAX_VALUE = 9223372036854771712L; @@ -1413,7 +1413,7 @@ Object { }, Object { "term": Object { - "my.custom.ui.filter": "foo-bar", + "service.environment": "test", }, }, Object { @@ -1501,7 +1501,7 @@ Object { }, Object { "term": Object { - "my.custom.ui.filter": "foo-bar", + "service.environment": "test", }, }, Object { @@ -1579,7 +1579,7 @@ Object { }, Object { "term": Object { - "my.custom.ui.filter": "foo-bar", + "service.environment": "test", }, }, Object { diff --git a/x-pack/plugins/apm/server/lib/metrics/by_agent/default.ts b/x-pack/plugins/apm/server/lib/metrics/by_agent/default.ts index 6ee507d7b9bb1..fbcbc9f12791f 100644 --- a/x-pack/plugins/apm/server/lib/metrics/by_agent/default.ts +++ b/x-pack/plugins/apm/server/lib/metrics/by_agent/default.ts @@ -4,16 +4,12 @@ * you may not use this file except in compliance with the Elastic License. */ -import { - Setup, - SetupTimeRange, - SetupUIFilters, -} from '../../helpers/setup_request'; +import { Setup, SetupTimeRange } from '../../helpers/setup_request'; import { getCPUChartData } from './shared/cpu'; import { getMemoryChartData } from './shared/memory'; export async function getDefaultMetricsCharts( - setup: Setup & SetupTimeRange & SetupUIFilters, + setup: Setup & SetupTimeRange, serviceName: string ) { const charts = await Promise.all([ diff --git a/x-pack/plugins/apm/server/lib/metrics/by_agent/java/gc/fetch_and_transform_gc_metrics.ts b/x-pack/plugins/apm/server/lib/metrics/by_agent/java/gc/fetch_and_transform_gc_metrics.ts index d7e64bdcacd12..2ed11480a7585 100644 --- a/x-pack/plugins/apm/server/lib/metrics/by_agent/java/gc/fetch_and_transform_gc_metrics.ts +++ b/x-pack/plugins/apm/server/lib/metrics/by_agent/java/gc/fetch_and_transform_gc_metrics.ts @@ -11,11 +11,7 @@ import { sum, round } from 'lodash'; import theme from '@elastic/eui/dist/eui_theme_light.json'; -import { - Setup, - SetupTimeRange, - SetupUIFilters, -} from '../../../../helpers/setup_request'; +import { Setup, SetupTimeRange } from '../../../../helpers/setup_request'; import { getMetricsDateHistogramParams } from '../../../../helpers/metrics'; import { ChartBase } from '../../../types'; import { getMetricsProjection } from '../../../../../projections/metrics'; @@ -36,7 +32,7 @@ export async function fetchAndTransformGcMetrics({ chartBase, fieldName, }: { - setup: Setup & SetupTimeRange & SetupUIFilters; + setup: Setup & SetupTimeRange; serviceName: string; serviceNodeName?: string; chartBase: ChartBase; diff --git a/x-pack/plugins/apm/server/lib/metrics/by_agent/java/gc/get_gc_rate_chart.ts b/x-pack/plugins/apm/server/lib/metrics/by_agent/java/gc/get_gc_rate_chart.ts index 6e562b9a8ee87..7cedeb828e3b7 100644 --- a/x-pack/plugins/apm/server/lib/metrics/by_agent/java/gc/get_gc_rate_chart.ts +++ b/x-pack/plugins/apm/server/lib/metrics/by_agent/java/gc/get_gc_rate_chart.ts @@ -7,11 +7,7 @@ import theme from '@elastic/eui/dist/eui_theme_light.json'; import { i18n } from '@kbn/i18n'; import { METRIC_JAVA_GC_COUNT } from '../../../../../../common/elasticsearch_fieldnames'; -import { - Setup, - SetupTimeRange, - SetupUIFilters, -} from '../../../../helpers/setup_request'; +import { Setup, SetupTimeRange } from '../../../../helpers/setup_request'; import { fetchAndTransformGcMetrics } from './fetch_and_transform_gc_metrics'; import { ChartBase } from '../../../types'; @@ -35,7 +31,7 @@ const chartBase: ChartBase = { }; const getGcRateChart = ( - setup: Setup & SetupTimeRange & SetupUIFilters, + setup: Setup & SetupTimeRange, serviceName: string, serviceNodeName?: string ) => { diff --git a/x-pack/plugins/apm/server/lib/metrics/by_agent/java/gc/get_gc_time_chart.ts b/x-pack/plugins/apm/server/lib/metrics/by_agent/java/gc/get_gc_time_chart.ts index 0b9d6240fc1c9..f21d3d8e7c056 100644 --- a/x-pack/plugins/apm/server/lib/metrics/by_agent/java/gc/get_gc_time_chart.ts +++ b/x-pack/plugins/apm/server/lib/metrics/by_agent/java/gc/get_gc_time_chart.ts @@ -7,11 +7,7 @@ import theme from '@elastic/eui/dist/eui_theme_light.json'; import { i18n } from '@kbn/i18n'; import { METRIC_JAVA_GC_TIME } from '../../../../../../common/elasticsearch_fieldnames'; -import { - Setup, - SetupTimeRange, - SetupUIFilters, -} from '../../../../helpers/setup_request'; +import { Setup, SetupTimeRange } from '../../../../helpers/setup_request'; import { fetchAndTransformGcMetrics } from './fetch_and_transform_gc_metrics'; import { ChartBase } from '../../../types'; @@ -35,7 +31,7 @@ const chartBase: ChartBase = { }; const getGcTimeChart = ( - setup: Setup & SetupTimeRange & SetupUIFilters, + setup: Setup & SetupTimeRange, serviceName: string, serviceNodeName?: string ) => { diff --git a/x-pack/plugins/apm/server/lib/metrics/by_agent/java/heap_memory/index.ts b/x-pack/plugins/apm/server/lib/metrics/by_agent/java/heap_memory/index.ts index ba3183c0fa7d7..eb79897f9f055 100644 --- a/x-pack/plugins/apm/server/lib/metrics/by_agent/java/heap_memory/index.ts +++ b/x-pack/plugins/apm/server/lib/metrics/by_agent/java/heap_memory/index.ts @@ -12,11 +12,7 @@ import { METRIC_JAVA_HEAP_MEMORY_USED, AGENT_NAME, } from '../../../../../../common/elasticsearch_fieldnames'; -import { - Setup, - SetupTimeRange, - SetupUIFilters, -} from '../../../../helpers/setup_request'; +import { Setup, SetupTimeRange } from '../../../../helpers/setup_request'; import { fetchAndTransformMetrics } from '../../../fetch_and_transform_metrics'; import { ChartBase } from '../../../types'; @@ -55,7 +51,7 @@ const chartBase: ChartBase = { }; export async function getHeapMemoryChart( - setup: Setup & SetupTimeRange & SetupUIFilters, + setup: Setup & SetupTimeRange, serviceName: string, serviceNodeName?: string ) { diff --git a/x-pack/plugins/apm/server/lib/metrics/by_agent/java/index.ts b/x-pack/plugins/apm/server/lib/metrics/by_agent/java/index.ts index 21caab6590fc4..d4084701f0f49 100644 --- a/x-pack/plugins/apm/server/lib/metrics/by_agent/java/index.ts +++ b/x-pack/plugins/apm/server/lib/metrics/by_agent/java/index.ts @@ -5,11 +5,7 @@ */ import { getHeapMemoryChart } from './heap_memory'; -import { - Setup, - SetupTimeRange, - SetupUIFilters, -} from '../../../helpers/setup_request'; +import { Setup, SetupTimeRange } from '../../../helpers/setup_request'; import { getNonHeapMemoryChart } from './non_heap_memory'; import { getThreadCountChart } from './thread_count'; import { getCPUChartData } from '../shared/cpu'; @@ -18,7 +14,7 @@ import { getGcRateChart } from './gc/get_gc_rate_chart'; import { getGcTimeChart } from './gc/get_gc_time_chart'; export async function getJavaMetricsCharts( - setup: Setup & SetupTimeRange & SetupUIFilters, + setup: Setup & SetupTimeRange, serviceName: string, serviceNodeName?: string ) { diff --git a/x-pack/plugins/apm/server/lib/metrics/by_agent/java/non_heap_memory/index.ts b/x-pack/plugins/apm/server/lib/metrics/by_agent/java/non_heap_memory/index.ts index 1a2d5bd0b0e68..50cc449da3c15 100644 --- a/x-pack/plugins/apm/server/lib/metrics/by_agent/java/non_heap_memory/index.ts +++ b/x-pack/plugins/apm/server/lib/metrics/by_agent/java/non_heap_memory/index.ts @@ -12,11 +12,7 @@ import { METRIC_JAVA_NON_HEAP_MEMORY_USED, AGENT_NAME, } from '../../../../../../common/elasticsearch_fieldnames'; -import { - Setup, - SetupTimeRange, - SetupUIFilters, -} from '../../../../helpers/setup_request'; +import { Setup, SetupTimeRange } from '../../../../helpers/setup_request'; import { ChartBase } from '../../../types'; import { fetchAndTransformMetrics } from '../../../fetch_and_transform_metrics'; @@ -52,7 +48,7 @@ const chartBase: ChartBase = { }; export async function getNonHeapMemoryChart( - setup: Setup & SetupUIFilters & SetupTimeRange, + setup: Setup & SetupTimeRange, serviceName: string, serviceNodeName?: string ) { diff --git a/x-pack/plugins/apm/server/lib/metrics/by_agent/java/thread_count/index.ts b/x-pack/plugins/apm/server/lib/metrics/by_agent/java/thread_count/index.ts index 01cc6d8495244..0062f0a423970 100644 --- a/x-pack/plugins/apm/server/lib/metrics/by_agent/java/thread_count/index.ts +++ b/x-pack/plugins/apm/server/lib/metrics/by_agent/java/thread_count/index.ts @@ -10,11 +10,7 @@ import { METRIC_JAVA_THREAD_COUNT, AGENT_NAME, } from '../../../../../../common/elasticsearch_fieldnames'; -import { - Setup, - SetupTimeRange, - SetupUIFilters, -} from '../../../../helpers/setup_request'; +import { Setup, SetupTimeRange } from '../../../../helpers/setup_request'; import { ChartBase } from '../../../types'; import { fetchAndTransformMetrics } from '../../../fetch_and_transform_metrics'; @@ -44,7 +40,7 @@ const chartBase: ChartBase = { }; export async function getThreadCountChart( - setup: Setup & SetupTimeRange & SetupUIFilters, + setup: Setup & SetupTimeRange, serviceName: string, serviceNodeName?: string ) { diff --git a/x-pack/plugins/apm/server/lib/metrics/by_agent/shared/cpu/index.ts b/x-pack/plugins/apm/server/lib/metrics/by_agent/shared/cpu/index.ts index 066ef40b4ab6c..ca642aa12fff1 100644 --- a/x-pack/plugins/apm/server/lib/metrics/by_agent/shared/cpu/index.ts +++ b/x-pack/plugins/apm/server/lib/metrics/by_agent/shared/cpu/index.ts @@ -10,11 +10,7 @@ import { METRIC_SYSTEM_CPU_PERCENT, METRIC_PROCESS_CPU_PERCENT, } from '../../../../../../common/elasticsearch_fieldnames'; -import { - Setup, - SetupTimeRange, - SetupUIFilters, -} from '../../../../helpers/setup_request'; +import { Setup, SetupTimeRange } from '../../../../helpers/setup_request'; import { ChartBase } from '../../../types'; import { fetchAndTransformMetrics } from '../../../fetch_and_transform_metrics'; @@ -56,7 +52,7 @@ const chartBase: ChartBase = { }; export async function getCPUChartData( - setup: Setup & SetupTimeRange & SetupUIFilters, + setup: Setup & SetupTimeRange, serviceName: string, serviceNodeName?: string ) { diff --git a/x-pack/plugins/apm/server/lib/metrics/by_agent/shared/memory/index.ts b/x-pack/plugins/apm/server/lib/metrics/by_agent/shared/memory/index.ts index a60576ca0c175..e6ee47cc815ef 100644 --- a/x-pack/plugins/apm/server/lib/metrics/by_agent/shared/memory/index.ts +++ b/x-pack/plugins/apm/server/lib/metrics/by_agent/shared/memory/index.ts @@ -11,11 +11,7 @@ import { METRIC_SYSTEM_FREE_MEMORY, METRIC_SYSTEM_TOTAL_MEMORY, } from '../../../../../../common/elasticsearch_fieldnames'; -import { - Setup, - SetupTimeRange, - SetupUIFilters, -} from '../../../../helpers/setup_request'; +import { Setup, SetupTimeRange } from '../../../../helpers/setup_request'; import { fetchAndTransformMetrics } from '../../../fetch_and_transform_metrics'; import { ChartBase } from '../../../types'; @@ -54,7 +50,7 @@ export const percentCgroupMemoryUsedScript = { lang: 'painless', source: ` /* - When no limit is specified in the container, docker allows the app as much memory / swap memory as it wants. + When no limit is specified in the container, docker allows the app as much memory / swap memory as it wants. This number represents the max possible value for the limit field. */ double CGROUP_LIMIT_MAX_VALUE = 9223372036854771712L; @@ -73,7 +69,7 @@ export const percentCgroupMemoryUsedScript = { }; export async function getMemoryChartData( - setup: Setup & SetupTimeRange & SetupUIFilters, + setup: Setup & SetupTimeRange, serviceName: string, serviceNodeName?: string ) { diff --git a/x-pack/plugins/apm/server/lib/metrics/fetch_and_transform_metrics.ts b/x-pack/plugins/apm/server/lib/metrics/fetch_and_transform_metrics.ts index a42a10d6518a0..3ccba8c7586dc 100644 --- a/x-pack/plugins/apm/server/lib/metrics/fetch_and_transform_metrics.ts +++ b/x-pack/plugins/apm/server/lib/metrics/fetch_and_transform_metrics.ts @@ -5,11 +5,7 @@ */ import { Unionize, Overwrite } from 'utility-types'; -import { - Setup, - SetupTimeRange, - SetupUIFilters, -} from '../helpers/setup_request'; +import { Setup, SetupTimeRange } from '../helpers/setup_request'; import { getMetricsDateHistogramParams } from '../helpers/metrics'; import { ChartBase } from './types'; import { transformDataToMetricsChart } from './transform_metrics_chart'; @@ -58,7 +54,7 @@ export async function fetchAndTransformMetrics({ aggs, additionalFilters = [], }: { - setup: Setup & SetupTimeRange & SetupUIFilters; + setup: Setup & SetupTimeRange; serviceName: string; serviceNodeName?: string; chartBase: ChartBase; diff --git a/x-pack/plugins/apm/server/lib/metrics/get_metrics_chart_data_by_agent.ts b/x-pack/plugins/apm/server/lib/metrics/get_metrics_chart_data_by_agent.ts index 059e1ce48c83d..72cd65deebff6 100644 --- a/x-pack/plugins/apm/server/lib/metrics/get_metrics_chart_data_by_agent.ts +++ b/x-pack/plugins/apm/server/lib/metrics/get_metrics_chart_data_by_agent.ts @@ -3,11 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import { - Setup, - SetupTimeRange, - SetupUIFilters, -} from '../helpers/setup_request'; +import { Setup, SetupTimeRange } from '../helpers/setup_request'; import { getJavaMetricsCharts } from './by_agent/java'; import { getDefaultMetricsCharts } from './by_agent/default'; import { GenericMetricsChart } from './transform_metrics_chart'; @@ -22,7 +18,7 @@ export async function getMetricsChartDataByAgent({ serviceNodeName, agentName, }: { - setup: Setup & SetupTimeRange & SetupUIFilters; + setup: Setup & SetupTimeRange; serviceName: string; serviceNodeName?: string; agentName: string; diff --git a/x-pack/plugins/apm/server/lib/rum_client/__snapshots__/queries.test.ts.snap b/x-pack/plugins/apm/server/lib/rum_client/__snapshots__/queries.test.ts.snap index dcafe09221164..1fafa08082443 100644 --- a/x-pack/plugins/apm/server/lib/rum_client/__snapshots__/queries.test.ts.snap +++ b/x-pack/plugins/apm/server/lib/rum_client/__snapshots__/queries.test.ts.snap @@ -61,7 +61,7 @@ Object { }, Object { "term": Object { - "my.custom.ui.filter": "foo-bar", + "service.environment": "test", }, }, ], @@ -151,7 +151,7 @@ Object { }, Object { "term": Object { - "my.custom.ui.filter": "foo-bar", + "service.environment": "test", }, }, ], @@ -230,7 +230,7 @@ Object { }, Object { "term": Object { - "my.custom.ui.filter": "foo-bar", + "service.environment": "test", }, }, ], @@ -500,7 +500,7 @@ Object { }, Object { "term": Object { - "my.custom.ui.filter": "foo-bar", + "service.environment": "test", }, }, ], @@ -552,7 +552,7 @@ Object { }, Object { "term": Object { - "my.custom.ui.filter": "foo-bar", + "service.environment": "test", }, }, ], @@ -667,7 +667,7 @@ Object { }, Object { "term": Object { - "my.custom.ui.filter": "foo-bar", + "service.environment": "test", }, }, Object { @@ -723,7 +723,7 @@ Object { }, Object { "term": Object { - "my.custom.ui.filter": "foo-bar", + "service.environment": "test", }, }, ], diff --git a/x-pack/plugins/apm/server/lib/rum_client/get_client_metrics.ts b/x-pack/plugins/apm/server/lib/rum_client/get_client_metrics.ts index 6566ea4f5e29b..6d596246d6af9 100644 --- a/x-pack/plugins/apm/server/lib/rum_client/get_client_metrics.ts +++ b/x-pack/plugins/apm/server/lib/rum_client/get_client_metrics.ts @@ -7,11 +7,7 @@ import { TRANSACTION_DURATION } from '../../../common/elasticsearch_fieldnames'; import { getRumPageLoadTransactionsProjection } from '../../projections/rum_page_load_transactions'; import { mergeProjection } from '../../projections/util/merge_projection'; -import { - Setup, - SetupTimeRange, - SetupUIFilters, -} from '../helpers/setup_request'; +import { Setup, SetupTimeRange } from '../helpers/setup_request'; import { TRANSACTION_DOM_INTERACTIVE, TRANSACTION_TIME_TO_FIRST_BYTE, @@ -22,7 +18,7 @@ export async function getClientMetrics({ urlQuery, percentile = 50, }: { - setup: Setup & SetupTimeRange & SetupUIFilters; + setup: Setup & SetupTimeRange; urlQuery?: string; percentile?: number; }) { diff --git a/x-pack/plugins/apm/server/lib/rum_client/get_js_errors.ts b/x-pack/plugins/apm/server/lib/rum_client/get_js_errors.ts index 0540ea4bf09dd..a8a4e2714c86e 100644 --- a/x-pack/plugins/apm/server/lib/rum_client/get_js_errors.ts +++ b/x-pack/plugins/apm/server/lib/rum_client/get_js_errors.ts @@ -5,11 +5,7 @@ */ import { mergeProjection } from '../../projections/util/merge_projection'; -import { - Setup, - SetupTimeRange, - SetupUIFilters, -} from '../helpers/setup_request'; +import { Setup, SetupTimeRange } from '../helpers/setup_request'; import { getRumErrorsProjection } from '../../projections/rum_page_load_transactions'; import { ERROR_EXC_MESSAGE, @@ -23,7 +19,7 @@ export async function getJSErrors({ pageSize, pageIndex, }: { - setup: Setup & SetupTimeRange & SetupUIFilters; + setup: Setup & SetupTimeRange; pageSize: number; pageIndex: number; }) { diff --git a/x-pack/plugins/apm/server/lib/rum_client/get_long_task_metrics.ts b/x-pack/plugins/apm/server/lib/rum_client/get_long_task_metrics.ts index c2c86ae05d57c..dfb31de8f10f7 100644 --- a/x-pack/plugins/apm/server/lib/rum_client/get_long_task_metrics.ts +++ b/x-pack/plugins/apm/server/lib/rum_client/get_long_task_metrics.ts @@ -6,11 +6,7 @@ import { getRumPageLoadTransactionsProjection } from '../../projections/rum_page_load_transactions'; import { mergeProjection } from '../../projections/util/merge_projection'; -import { - Setup, - SetupTimeRange, - SetupUIFilters, -} from '../helpers/setup_request'; +import { Setup, SetupTimeRange } from '../helpers/setup_request'; const LONG_TASK_SUM_FIELD = 'transaction.experience.longtask.sum'; const LONG_TASK_COUNT_FIELD = 'transaction.experience.longtask.count'; @@ -21,7 +17,7 @@ export async function getLongTaskMetrics({ urlQuery, percentile = 50, }: { - setup: Setup & SetupTimeRange & SetupUIFilters; + setup: Setup & SetupTimeRange; urlQuery?: string; percentile?: number; }) { diff --git a/x-pack/plugins/apm/server/lib/rum_client/get_page_load_distribution.ts b/x-pack/plugins/apm/server/lib/rum_client/get_page_load_distribution.ts index 5f666feb8a18f..225afff2818ab 100644 --- a/x-pack/plugins/apm/server/lib/rum_client/get_page_load_distribution.ts +++ b/x-pack/plugins/apm/server/lib/rum_client/get_page_load_distribution.ts @@ -7,11 +7,7 @@ import { TRANSACTION_DURATION } from '../../../common/elasticsearch_fieldnames'; import { getRumPageLoadTransactionsProjection } from '../../projections/rum_page_load_transactions'; import { mergeProjection } from '../../projections/util/merge_projection'; -import { - Setup, - SetupTimeRange, - SetupUIFilters, -} from '../helpers/setup_request'; +import { Setup, SetupTimeRange } from '../helpers/setup_request'; export const MICRO_TO_SEC = 1000000; @@ -56,7 +52,7 @@ export async function getPageLoadDistribution({ maxPercentile, urlQuery, }: { - setup: Setup & SetupTimeRange & SetupUIFilters; + setup: Setup & SetupTimeRange; minPercentile?: string; maxPercentile?: string; urlQuery?: string; @@ -168,7 +164,7 @@ const getPercentilesDistribution = async ({ minDuration, maxDuration, }: { - setup: Setup & SetupTimeRange & SetupUIFilters; + setup: Setup & SetupTimeRange; minDuration: number; maxDuration: number; }) => { diff --git a/x-pack/plugins/apm/server/lib/rum_client/get_page_view_trends.ts b/x-pack/plugins/apm/server/lib/rum_client/get_page_view_trends.ts index 40f8a8bc58a54..c1a602c33feae 100644 --- a/x-pack/plugins/apm/server/lib/rum_client/get_page_view_trends.ts +++ b/x-pack/plugins/apm/server/lib/rum_client/get_page_view_trends.ts @@ -5,11 +5,7 @@ */ import { getRumPageLoadTransactionsProjection } from '../../projections/rum_page_load_transactions'; import { mergeProjection } from '../../projections/util/merge_projection'; -import { - Setup, - SetupTimeRange, - SetupUIFilters, -} from '../helpers/setup_request'; +import { Setup, SetupTimeRange } from '../helpers/setup_request'; import { BreakdownItem } from '../../../typings/ui_filters'; export async function getPageViewTrends({ @@ -17,7 +13,7 @@ export async function getPageViewTrends({ breakdowns, urlQuery, }: { - setup: Setup & SetupTimeRange & SetupUIFilters; + setup: Setup & SetupTimeRange; breakdowns?: string; urlQuery?: string; }) { diff --git a/x-pack/plugins/apm/server/lib/rum_client/get_pl_dist_breakdown.ts b/x-pack/plugins/apm/server/lib/rum_client/get_pl_dist_breakdown.ts index bebf9c0bc99c9..e2ec59d232b21 100644 --- a/x-pack/plugins/apm/server/lib/rum_client/get_pl_dist_breakdown.ts +++ b/x-pack/plugins/apm/server/lib/rum_client/get_pl_dist_breakdown.ts @@ -7,11 +7,7 @@ import { getRumPageLoadTransactionsProjection } from '../../projections/rum_page_load_transactions'; import { ProcessorEvent } from '../../../common/processor_event'; import { mergeProjection } from '../../projections/util/merge_projection'; -import { - Setup, - SetupTimeRange, - SetupUIFilters, -} from '../helpers/setup_request'; +import { Setup, SetupTimeRange } from '../helpers/setup_request'; import { CLIENT_GEO_COUNTRY_ISO_CODE, USER_AGENT_DEVICE, @@ -46,7 +42,7 @@ export const getPageLoadDistBreakdown = async ({ breakdown, urlQuery, }: { - setup: Setup & SetupTimeRange & SetupUIFilters; + setup: Setup & SetupTimeRange; minPercentile: number; maxPercentile: number; breakdown: string; diff --git a/x-pack/plugins/apm/server/lib/rum_client/get_rum_services.ts b/x-pack/plugins/apm/server/lib/rum_client/get_rum_services.ts index 3adad0868ed4b..e9bd203e354cb 100644 --- a/x-pack/plugins/apm/server/lib/rum_client/get_rum_services.ts +++ b/x-pack/plugins/apm/server/lib/rum_client/get_rum_services.ts @@ -5,18 +5,14 @@ */ import { SERVICE_NAME } from '../../../common/elasticsearch_fieldnames'; -import { - Setup, - SetupTimeRange, - SetupUIFilters, -} from '../helpers/setup_request'; +import { Setup, SetupTimeRange } from '../helpers/setup_request'; import { getRumPageLoadTransactionsProjection } from '../../projections/rum_page_load_transactions'; import { mergeProjection } from '../../projections/util/merge_projection'; export async function getRumServices({ setup, }: { - setup: Setup & SetupTimeRange & SetupUIFilters; + setup: Setup & SetupTimeRange; }) { const projection = getRumPageLoadTransactionsProjection({ setup, diff --git a/x-pack/plugins/apm/server/lib/rum_client/get_url_search.ts b/x-pack/plugins/apm/server/lib/rum_client/get_url_search.ts index 6aa39c7ef961f..febfd66897e18 100644 --- a/x-pack/plugins/apm/server/lib/rum_client/get_url_search.ts +++ b/x-pack/plugins/apm/server/lib/rum_client/get_url_search.ts @@ -5,11 +5,7 @@ */ import { mergeProjection } from '../../projections/util/merge_projection'; -import { - Setup, - SetupTimeRange, - SetupUIFilters, -} from '../helpers/setup_request'; +import { Setup, SetupTimeRange } from '../helpers/setup_request'; import { getRumPageLoadTransactionsProjection } from '../../projections/rum_page_load_transactions'; import { TRANSACTION_DURATION, @@ -21,7 +17,7 @@ export async function getUrlSearch({ urlQuery, percentile, }: { - setup: Setup & SetupTimeRange & SetupUIFilters; + setup: Setup & SetupTimeRange; urlQuery?: string; percentile: number; }) { diff --git a/x-pack/plugins/apm/server/lib/rum_client/get_visitor_breakdown.ts b/x-pack/plugins/apm/server/lib/rum_client/get_visitor_breakdown.ts index 52d089e4e29c9..6350bc2c07016 100644 --- a/x-pack/plugins/apm/server/lib/rum_client/get_visitor_breakdown.ts +++ b/x-pack/plugins/apm/server/lib/rum_client/get_visitor_breakdown.ts @@ -6,11 +6,7 @@ import { getRumPageLoadTransactionsProjection } from '../../projections/rum_page_load_transactions'; import { mergeProjection } from '../../projections/util/merge_projection'; -import { - Setup, - SetupTimeRange, - SetupUIFilters, -} from '../helpers/setup_request'; +import { Setup, SetupTimeRange } from '../helpers/setup_request'; import { USER_AGENT_NAME, USER_AGENT_OS, @@ -20,7 +16,7 @@ export async function getVisitorBreakdown({ setup, urlQuery, }: { - setup: Setup & SetupTimeRange & SetupUIFilters; + setup: Setup & SetupTimeRange; urlQuery?: string; }) { const projection = getRumPageLoadTransactionsProjection({ diff --git a/x-pack/plugins/apm/server/lib/rum_client/get_web_core_vitals.ts b/x-pack/plugins/apm/server/lib/rum_client/get_web_core_vitals.ts index 676b3506397a7..c5baf0b529eb4 100644 --- a/x-pack/plugins/apm/server/lib/rum_client/get_web_core_vitals.ts +++ b/x-pack/plugins/apm/server/lib/rum_client/get_web_core_vitals.ts @@ -6,11 +6,7 @@ import { getRumPageLoadTransactionsProjection } from '../../projections/rum_page_load_transactions'; import { mergeProjection } from '../../projections/util/merge_projection'; -import { - Setup, - SetupTimeRange, - SetupUIFilters, -} from '../helpers/setup_request'; +import { Setup, SetupTimeRange } from '../helpers/setup_request'; import { CLS_FIELD, FCP_FIELD, @@ -25,7 +21,7 @@ export async function getWebCoreVitals({ urlQuery, percentile = 50, }: { - setup: Setup & SetupTimeRange & SetupUIFilters; + setup: Setup & SetupTimeRange; urlQuery?: string; percentile?: number; }) { diff --git a/x-pack/plugins/apm/server/lib/service_map/get_service_map.ts b/x-pack/plugins/apm/server/lib/service_map/get_service_map.ts index 75acebe7ed56c..330bb936c9e88 100644 --- a/x-pack/plugins/apm/server/lib/service_map/get_service_map.ts +++ b/x-pack/plugins/apm/server/lib/service_map/get_service_map.ts @@ -82,7 +82,7 @@ async function getServicesData(options: IEnvOptions) { const { setup, searchAggregatedTransactions } = options; const projection = getServicesProjection({ - setup: { ...setup, uiFiltersES: [] }, + setup: { ...setup, esFilter: [] }, searchAggregatedTransactions, }); diff --git a/x-pack/plugins/apm/server/lib/service_map/get_service_map_service_node_info.test.ts b/x-pack/plugins/apm/server/lib/service_map/get_service_map_service_node_info.test.ts index 7af1607697ef3..eb2ddbf38b274 100644 --- a/x-pack/plugins/apm/server/lib/service_map/get_service_map_service_node_info.test.ts +++ b/x-pack/plugins/apm/server/lib/service_map/get_service_map_service_node_info.test.ts @@ -19,11 +19,10 @@ describe('getServiceMapServiceNodeInfo', () => { }), }, indices: {}, + uiFilters: { environment: 'test environment' }, } as unknown) as Setup & SetupTimeRange; - const environment = 'test environment'; const serviceName = 'test service name'; const result = await getServiceMapServiceNodeInfo({ - uiFilters: { environment }, setup, serviceName, searchAggregatedTransactions: false, @@ -67,11 +66,10 @@ describe('getServiceMapServiceNodeInfo', () => { config: { 'xpack.apm.metricsInterval': 30, }, + uiFilters: { environment: 'test environment' }, } as unknown) as Setup & SetupTimeRange; - const environment = 'test environment'; const serviceName = 'test service name'; const result = await getServiceMapServiceNodeInfo({ - uiFilters: { environment }, setup, serviceName, searchAggregatedTransactions: false, diff --git a/x-pack/plugins/apm/server/lib/service_map/get_service_map_service_node_info.ts b/x-pack/plugins/apm/server/lib/service_map/get_service_map_service_node_info.ts index 7c2137ce65d83..37b34641435fb 100644 --- a/x-pack/plugins/apm/server/lib/service_map/get_service_map_service_node_info.ts +++ b/x-pack/plugins/apm/server/lib/service_map/get_service_map_service_node_info.ts @@ -8,7 +8,6 @@ import { TRANSACTION_REQUEST, TRANSACTION_PAGE_LOAD, } from '../../../common/transaction_types'; -import { UIFilters } from '../../../typings/ui_filters'; import { SERVICE_NAME, METRIC_SYSTEM_CPU_PERCENT, @@ -53,9 +52,8 @@ export async function getServiceMapServiceNodeInfo({ serviceName, setup, searchAggregatedTransactions, - uiFilters, -}: Options & { serviceName: string; uiFilters: UIFilters }) { - const { start, end } = setup; +}: Options & { serviceName: string }) { + const { start, end, uiFilters } = setup; const filter: ESFilter[] = [ { range: rangeFilter(start, end) }, @@ -105,7 +103,8 @@ async function getErrorStats({ }) { const setupWithBlankUiFilters = { ...setup, - uiFiltersES: getEnvironmentUiFilterES(environment), + uiFilters: { environment }, + esFilter: getEnvironmentUiFilterES(environment), }; const { noHits, average } = await getErrorRate({ setup: setupWithBlankUiFilters, diff --git a/x-pack/plugins/apm/server/lib/service_map/mock_responses/group_resource_nodes_grouped.json b/x-pack/plugins/apm/server/lib/service_map/mock_responses/group_resource_nodes_grouped.json index e7bba585de180..94c508fe90230 100644 --- a/x-pack/plugins/apm/server/lib/service_map/mock_responses/group_resource_nodes_grouped.json +++ b/x-pack/plugins/apm/server/lib/service_map/mock_responses/group_resource_nodes_grouped.json @@ -3,7 +3,7 @@ { "data": { "id": "opbeans-rum", - "service.environment": "testing", + "service.environment": "test", "service.name": "opbeans-rum", "agent.name": "rum-js" } @@ -18,7 +18,7 @@ { "data": { "id": "opbeans-node", - "service.environment": "testing", + "service.environment": "test", "service.name": "opbeans-node", "agent.name": "nodejs" } diff --git a/x-pack/plugins/apm/server/lib/service_map/mock_responses/group_resource_nodes_pregrouped.json b/x-pack/plugins/apm/server/lib/service_map/mock_responses/group_resource_nodes_pregrouped.json index 22c5c50de7472..58469f607ac13 100644 --- a/x-pack/plugins/apm/server/lib/service_map/mock_responses/group_resource_nodes_pregrouped.json +++ b/x-pack/plugins/apm/server/lib/service_map/mock_responses/group_resource_nodes_pregrouped.json @@ -3,7 +3,7 @@ { "data": { "id": "opbeans-rum", - "service.environment": "testing", + "service.environment": "test", "service.name": "opbeans-rum", "agent.name": "rum-js" } @@ -18,7 +18,7 @@ { "data": { "id": "opbeans-node", - "service.environment": "testing", + "service.environment": "test", "service.name": "opbeans-node", "agent.name": "nodejs" } diff --git a/x-pack/plugins/apm/server/lib/service_nodes/__snapshots__/queries.test.ts.snap b/x-pack/plugins/apm/server/lib/service_nodes/__snapshots__/queries.test.ts.snap index 87aca0d056909..d83e558775be4 100644 --- a/x-pack/plugins/apm/server/lib/service_nodes/__snapshots__/queries.test.ts.snap +++ b/x-pack/plugins/apm/server/lib/service_nodes/__snapshots__/queries.test.ts.snap @@ -51,7 +51,7 @@ Object { }, Object { "term": Object { - "my.custom.ui.filter": "foo-bar", + "service.environment": "test", }, }, ], @@ -119,7 +119,7 @@ Object { }, Object { "term": Object { - "my.custom.ui.filter": "foo-bar", + "service.environment": "test", }, }, ], @@ -188,7 +188,7 @@ Object { }, Object { "term": Object { - "my.custom.ui.filter": "foo-bar", + "service.environment": "test", }, }, ], diff --git a/x-pack/plugins/apm/server/lib/service_nodes/index.ts b/x-pack/plugins/apm/server/lib/service_nodes/index.ts index a83aba192dba9..d5e29532e3d7b 100644 --- a/x-pack/plugins/apm/server/lib/service_nodes/index.ts +++ b/x-pack/plugins/apm/server/lib/service_nodes/index.ts @@ -4,11 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { - Setup, - SetupTimeRange, - SetupUIFilters, -} from '../helpers/setup_request'; +import { Setup, SetupTimeRange } from '../helpers/setup_request'; import { getServiceNodesProjection } from '../../projections/service_nodes'; import { mergeProjection } from '../../projections/util/merge_projection'; import { SERVICE_NODE_NAME_MISSING } from '../../../common/service_nodes'; @@ -23,7 +19,7 @@ const getServiceNodes = async ({ setup, serviceName, }: { - setup: Setup & SetupTimeRange & SetupUIFilters; + setup: Setup & SetupTimeRange; serviceName: string; }) => { const { apmEventClient } = setup; diff --git a/x-pack/plugins/apm/server/lib/services/__snapshots__/queries.test.ts.snap b/x-pack/plugins/apm/server/lib/services/__snapshots__/queries.test.ts.snap index 431f11066aaff..3a38f80c87b35 100644 --- a/x-pack/plugins/apm/server/lib/services/__snapshots__/queries.test.ts.snap +++ b/x-pack/plugins/apm/server/lib/services/__snapshots__/queries.test.ts.snap @@ -144,7 +144,7 @@ Array [ }, Object { "term": Object { - "my.custom.ui.filter": "foo-bar", + "service.environment": "test", }, }, ], @@ -194,7 +194,7 @@ Array [ }, Object { "term": Object { - "my.custom.ui.filter": "foo-bar", + "service.environment": "test", }, }, ], @@ -257,7 +257,7 @@ Array [ }, Object { "term": Object { - "my.custom.ui.filter": "foo-bar", + "service.environment": "test", }, }, ], @@ -334,7 +334,7 @@ Array [ }, Object { "term": Object { - "my.custom.ui.filter": "foo-bar", + "service.environment": "test", }, }, Object { @@ -389,7 +389,7 @@ Array [ }, Object { "term": Object { - "my.custom.ui.filter": "foo-bar", + "service.environment": "test", }, }, ], diff --git a/x-pack/plugins/apm/server/lib/services/get_service_node_metadata.ts b/x-pack/plugins/apm/server/lib/services/get_service_node_metadata.ts index fca472b0ce8c2..d6ba9f5447ba5 100644 --- a/x-pack/plugins/apm/server/lib/services/get_service_node_metadata.ts +++ b/x-pack/plugins/apm/server/lib/services/get_service_node_metadata.ts @@ -4,11 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { - Setup, - SetupTimeRange, - SetupUIFilters, -} from '../helpers/setup_request'; +import { Setup, SetupTimeRange } from '../helpers/setup_request'; import { HOST_NAME, CONTAINER_ID, @@ -24,7 +20,7 @@ export async function getServiceNodeMetadata({ }: { serviceName: string; serviceNodeName: string; - setup: Setup & SetupTimeRange & SetupUIFilters; + setup: Setup & SetupTimeRange; }) { const { apmEventClient } = setup; diff --git a/x-pack/plugins/apm/server/lib/services/get_services/get_services_items.ts b/x-pack/plugins/apm/server/lib/services/get_services/get_services_items.ts index c09be7aacc784..092485c46fb08 100644 --- a/x-pack/plugins/apm/server/lib/services/get_services/get_services_items.ts +++ b/x-pack/plugins/apm/server/lib/services/get_services/get_services_items.ts @@ -5,11 +5,7 @@ */ import { joinByKey } from '../../../../common/utils/join_by_key'; import { PromiseReturnType } from '../../../../typings/common'; -import { - Setup, - SetupTimeRange, - SetupUIFilters, -} from '../../helpers/setup_request'; +import { Setup, SetupTimeRange } from '../../helpers/setup_request'; import { getServicesProjection } from '../../../projections/services'; import { getTransactionDurationAverages, @@ -21,17 +17,15 @@ import { } from './get_services_items_stats'; export type ServiceListAPIResponse = PromiseReturnType; -export type ServicesItemsSetup = Setup & SetupTimeRange & SetupUIFilters; +export type ServicesItemsSetup = Setup & SetupTimeRange; export type ServicesItemsProjection = ReturnType; export async function getServicesItems({ setup, searchAggregatedTransactions, - mlAnomaliesEnvironment, }: { setup: ServicesItemsSetup; searchAggregatedTransactions: boolean; - mlAnomaliesEnvironment?: string; }) { const params = { projection: getServicesProjection({ @@ -55,7 +49,7 @@ export async function getServicesItems({ getTransactionRates(params), getTransactionErrorRates(params), getEnvironments(params), - getHealthStatuses(params, mlAnomaliesEnvironment), + getHealthStatuses(params, setup.uiFilters.environment), ]); const allMetrics = [ diff --git a/x-pack/plugins/apm/server/lib/services/get_services/index.ts b/x-pack/plugins/apm/server/lib/services/get_services/index.ts index 351457b2a815e..04744a9c791bb 100644 --- a/x-pack/plugins/apm/server/lib/services/get_services/index.ts +++ b/x-pack/plugins/apm/server/lib/services/get_services/index.ts @@ -6,11 +6,7 @@ import { isEmpty } from 'lodash'; import { PromiseReturnType } from '../../../../typings/common'; -import { - Setup, - SetupTimeRange, - SetupUIFilters, -} from '../../helpers/setup_request'; +import { Setup, SetupTimeRange } from '../../helpers/setup_request'; import { hasHistoricalAgentData } from './has_historical_agent_data'; import { getLegacyDataStatus } from './get_legacy_data_status'; import { getServicesItems } from './get_services_items'; @@ -20,17 +16,14 @@ export type ServiceListAPIResponse = PromiseReturnType; export async function getServices({ setup, searchAggregatedTransactions, - mlAnomaliesEnvironment, }: { - setup: Setup & SetupTimeRange & SetupUIFilters; + setup: Setup & SetupTimeRange; searchAggregatedTransactions: boolean; - mlAnomaliesEnvironment?: string; }) { const [items, hasLegacyData] = await Promise.all([ getServicesItems({ setup, searchAggregatedTransactions, - mlAnomaliesEnvironment, }), getLegacyDataStatus(setup), ]); diff --git a/x-pack/plugins/apm/server/lib/transaction_groups/__snapshots__/queries.test.ts.snap b/x-pack/plugins/apm/server/lib/transaction_groups/__snapshots__/queries.test.ts.snap index bd6cefa793467..c678e7db711b6 100644 --- a/x-pack/plugins/apm/server/lib/transaction_groups/__snapshots__/queries.test.ts.snap +++ b/x-pack/plugins/apm/server/lib/transaction_groups/__snapshots__/queries.test.ts.snap @@ -61,7 +61,7 @@ Array [ }, Object { "term": Object { - "my.custom.ui.filter": "foo-bar", + "service.environment": "test", }, }, ], @@ -128,7 +128,7 @@ Array [ }, Object { "term": Object { - "my.custom.ui.filter": "foo-bar", + "service.environment": "test", }, }, ], @@ -195,7 +195,7 @@ Array [ }, Object { "term": Object { - "my.custom.ui.filter": "foo-bar", + "service.environment": "test", }, }, ], @@ -270,7 +270,7 @@ Array [ }, Object { "term": Object { - "my.custom.ui.filter": "foo-bar", + "service.environment": "test", }, }, ], @@ -325,7 +325,7 @@ Array [ }, Object { "term": Object { - "my.custom.ui.filter": "foo-bar", + "service.environment": "test", }, }, ], @@ -380,7 +380,7 @@ Array [ }, Object { "term": Object { - "my.custom.ui.filter": "foo-bar", + "service.environment": "test", }, }, ], @@ -441,7 +441,7 @@ Array [ }, Object { "term": Object { - "my.custom.ui.filter": "foo-bar", + "service.environment": "test", }, }, ], diff --git a/x-pack/plugins/apm/server/lib/transaction_groups/fetcher.ts b/x-pack/plugins/apm/server/lib/transaction_groups/fetcher.ts index 5d581149db667..0a4d9748f2597 100644 --- a/x-pack/plugins/apm/server/lib/transaction_groups/fetcher.ts +++ b/x-pack/plugins/apm/server/lib/transaction_groups/fetcher.ts @@ -15,11 +15,7 @@ import { getTransactionGroupsProjection } from '../../projections/transaction_gr import { mergeProjection } from '../../projections/util/merge_projection'; import { PromiseReturnType } from '../../../../observability/typings/common'; import { AggregationOptionsByType } from '../../../typings/elasticsearch/aggregations'; -import { - Setup, - SetupTimeRange, - SetupUIFilters, -} from '../helpers/setup_request'; +import { Setup, SetupTimeRange } from '../helpers/setup_request'; import { getAverages, getSums, @@ -57,7 +53,7 @@ export type TransactionGroupRequestBase = ReturnType< }; }; -export type TransactionGroupSetup = Setup & SetupTimeRange & SetupUIFilters; +export type TransactionGroupSetup = Setup & SetupTimeRange; function getItemsWithRelativeImpact( setup: TransactionGroupSetup, diff --git a/x-pack/plugins/apm/server/lib/transaction_groups/get_error_rate.ts b/x-pack/plugins/apm/server/lib/transaction_groups/get_error_rate.ts index 3dc126c45d328..d5289430b2698 100644 --- a/x-pack/plugins/apm/server/lib/transaction_groups/get_error_rate.ts +++ b/x-pack/plugins/apm/server/lib/transaction_groups/get_error_rate.ts @@ -12,11 +12,7 @@ import { EVENT_OUTCOME, } from '../../../common/elasticsearch_fieldnames'; import { rangeFilter } from '../../../common/utils/range_filter'; -import { - Setup, - SetupTimeRange, - SetupUIFilters, -} from '../helpers/setup_request'; +import { Setup, SetupTimeRange } from '../helpers/setup_request'; import { getBucketSize } from '../helpers/get_bucket_size'; import { getProcessorEventForAggregatedTransactions, @@ -33,10 +29,10 @@ export async function getErrorRate({ serviceName: string; transactionType?: string; transactionName?: string; - setup: Setup & SetupTimeRange & SetupUIFilters; + setup: Setup & SetupTimeRange; searchAggregatedTransactions: boolean; }) { - const { start, end, uiFiltersES, apmEventClient } = setup; + const { start, end, esFilter, apmEventClient } = setup; const transactionNamefilter = transactionName ? [{ term: { [TRANSACTION_NAME]: transactionName } }] @@ -53,7 +49,7 @@ export async function getErrorRate({ }, ...transactionNamefilter, ...transactionTypefilter, - ...uiFiltersES, + ...esFilter, ]; const params = { diff --git a/x-pack/plugins/apm/server/lib/transaction_groups/get_transaction_sample_for_group.ts b/x-pack/plugins/apm/server/lib/transaction_groups/get_transaction_sample_for_group.ts index 6c9b23b3dc079..7e1aad075fb16 100644 --- a/x-pack/plugins/apm/server/lib/transaction_groups/get_transaction_sample_for_group.ts +++ b/x-pack/plugins/apm/server/lib/transaction_groups/get_transaction_sample_for_group.ts @@ -12,11 +12,7 @@ import { } from '../../../common/elasticsearch_fieldnames'; import { ProcessorEvent } from '../../../common/processor_event'; import { rangeFilter } from '../../../common/utils/range_filter'; -import { - Setup, - SetupTimeRange, - SetupUIFilters, -} from '../helpers/setup_request'; +import { Setup, SetupTimeRange } from '../helpers/setup_request'; export async function getTransactionSampleForGroup({ serviceName, @@ -25,9 +21,9 @@ export async function getTransactionSampleForGroup({ }: { serviceName: string; transactionName: string; - setup: Setup & SetupTimeRange & SetupUIFilters; + setup: Setup & SetupTimeRange; }) { - const { apmEventClient, start, end, uiFiltersES } = setup; + const { apmEventClient, start, end, esFilter } = setup; const filter = [ { @@ -43,7 +39,7 @@ export async function getTransactionSampleForGroup({ [TRANSACTION_NAME]: transactionName, }, }, - ...uiFiltersES, + ...esFilter, ]; const getSampledTransaction = async () => { diff --git a/x-pack/plugins/apm/server/lib/transaction_groups/index.ts b/x-pack/plugins/apm/server/lib/transaction_groups/index.ts index 6e0d619268d44..3796511029243 100644 --- a/x-pack/plugins/apm/server/lib/transaction_groups/index.ts +++ b/x-pack/plugins/apm/server/lib/transaction_groups/index.ts @@ -4,16 +4,12 @@ * you may not use this file except in compliance with the Elastic License. */ -import { - Setup, - SetupTimeRange, - SetupUIFilters, -} from '../helpers/setup_request'; +import { Setup, SetupTimeRange } from '../helpers/setup_request'; import { transactionGroupsFetcher, Options } from './fetcher'; export async function getTransactionGroupList( options: Options, - setup: Setup & SetupTimeRange & SetupUIFilters + setup: Setup & SetupTimeRange ) { const bucketSize = setup.config['xpack.apm.ui.transactionGroupBucketSize']; return await transactionGroupsFetcher(options, setup, bucketSize); diff --git a/x-pack/plugins/apm/server/lib/transactions/__snapshots__/queries.test.ts.snap b/x-pack/plugins/apm/server/lib/transactions/__snapshots__/queries.test.ts.snap index c63dfcc0c0ec7..3e0a7317afd70 100644 --- a/x-pack/plugins/apm/server/lib/transactions/__snapshots__/queries.test.ts.snap +++ b/x-pack/plugins/apm/server/lib/transactions/__snapshots__/queries.test.ts.snap @@ -161,7 +161,7 @@ Object { }, Object { "term": Object { - "my.custom.ui.filter": "foo-bar", + "service.environment": "test", }, }, ], @@ -295,7 +295,7 @@ Object { }, Object { "term": Object { - "my.custom.ui.filter": "foo-bar", + "service.environment": "test", }, }, Object { @@ -401,7 +401,7 @@ Object { }, Object { "term": Object { - "my.custom.ui.filter": "foo-bar", + "service.environment": "test", }, }, ], @@ -502,7 +502,7 @@ Object { }, Object { "term": Object { - "my.custom.ui.filter": "foo-bar", + "service.environment": "test", }, }, Object { @@ -608,7 +608,7 @@ Object { }, Object { "term": Object { - "my.custom.ui.filter": "foo-bar", + "service.environment": "test", }, }, Object { @@ -673,7 +673,7 @@ Object { }, Object { "term": Object { - "my.custom.ui.filter": "foo-bar", + "service.environment": "test", }, }, ], diff --git a/x-pack/plugins/apm/server/lib/transactions/breakdown/index.test.ts b/x-pack/plugins/apm/server/lib/transactions/breakdown/index.test.ts index 34863c64f9804..8bbcaebe06513 100644 --- a/x-pack/plugins/apm/server/lib/transactions/breakdown/index.test.ts +++ b/x-pack/plugins/apm/server/lib/transactions/breakdown/index.test.ts @@ -36,7 +36,8 @@ function getMockSetup(esResponse: any) { get: () => 'myIndex', } ) as APMConfig, - uiFiltersES: [], + uiFilters: {}, + esFilter: [], indices: mockIndices, dynamicIndexPattern: null as any, }; diff --git a/x-pack/plugins/apm/server/lib/transactions/breakdown/index.ts b/x-pack/plugins/apm/server/lib/transactions/breakdown/index.ts index 9730ddbbf38d7..8febdc898ab97 100644 --- a/x-pack/plugins/apm/server/lib/transactions/breakdown/index.ts +++ b/x-pack/plugins/apm/server/lib/transactions/breakdown/index.ts @@ -16,11 +16,7 @@ import { TRANSACTION_NAME, TRANSACTION_BREAKDOWN_COUNT, } from '../../../../common/elasticsearch_fieldnames'; -import { - Setup, - SetupTimeRange, - SetupUIFilters, -} from '../../helpers/setup_request'; +import { Setup, SetupTimeRange } from '../../helpers/setup_request'; import { rangeFilter } from '../../../../common/utils/range_filter'; import { getMetricsDateHistogramParams } from '../../helpers/metrics'; import { MAX_KPIS } from './constants'; @@ -32,12 +28,12 @@ export async function getTransactionBreakdown({ transactionName, transactionType, }: { - setup: Setup & SetupTimeRange & SetupUIFilters; + setup: Setup & SetupTimeRange; serviceName: string; transactionName?: string; transactionType: string; }) { - const { uiFiltersES, apmEventClient, start, end, config } = setup; + const { esFilter, apmEventClient, start, end, config } = setup; const subAggs = { sum_all_self_times: { @@ -84,7 +80,7 @@ export async function getTransactionBreakdown({ { term: { [SERVICE_NAME]: serviceName } }, { term: { [TRANSACTION_TYPE]: transactionType } }, { range: rangeFilter(start, end) }, - ...uiFiltersES, + ...esFilter, ]; if (transactionName) { diff --git a/x-pack/plugins/apm/server/lib/transactions/charts/get_anomaly_data/fetcher.ts b/x-pack/plugins/apm/server/lib/transactions/charts/get_anomaly_data/fetcher.ts index 3cf9a54e3fe9b..287c7bc2c47f9 100644 --- a/x-pack/plugins/apm/server/lib/transactions/charts/get_anomaly_data/fetcher.ts +++ b/x-pack/plugins/apm/server/lib/transactions/charts/get_anomaly_data/fetcher.ts @@ -5,6 +5,7 @@ */ import { Logger } from 'kibana/server'; +import { ESSearchResponse } from '../../../../../typings/elasticsearch'; import { PromiseReturnType } from '../../../../../../observability/typings/common'; import { Setup, SetupTimeRange } from '../../../helpers/setup_request'; @@ -47,7 +48,7 @@ export async function anomalySeriesFetcher({ filter: [ { term: { job_id: jobId } }, { exists: { field: 'bucket_span' } }, - { term: { result_type: 'model_plot' } }, + { terms: { result_type: ['model_plot', 'record'] } }, { term: { partition_field_value: serviceName } }, { term: { by_field_value: transactionType } }, { @@ -67,7 +68,7 @@ export async function anomalySeriesFetcher({ extended_bounds: { min: newStart, max: end }, }, aggs: { - anomaly_score: { max: { field: 'anomaly_score' } }, + anomaly_score: { max: { field: 'record_score' } }, lower: { min: { field: 'model_lower' } }, upper: { max: { field: 'model_upper' } }, }, @@ -77,7 +78,11 @@ export async function anomalySeriesFetcher({ }; try { - const response = await ml.mlSystem.mlAnomalySearch(params); + const response: ESSearchResponse< + unknown, + typeof params + > = (await ml.mlSystem.mlAnomalySearch(params)) as any; + return response; } catch (err) { const isHttpError = 'statusCode' in err; diff --git a/x-pack/plugins/apm/server/lib/transactions/charts/get_anomaly_data/index.ts b/x-pack/plugins/apm/server/lib/transactions/charts/get_anomaly_data/index.ts index d8865f0049d35..f11623eaa2dae 100644 --- a/x-pack/plugins/apm/server/lib/transactions/charts/get_anomaly_data/index.ts +++ b/x-pack/plugins/apm/server/lib/transactions/charts/get_anomaly_data/index.ts @@ -5,17 +5,13 @@ */ import { Logger } from 'kibana/server'; import { isNumber } from 'lodash'; +import { ENVIRONMENT_ALL } from '../../../../../common/environment_filter_values'; import { getBucketSize } from '../../../helpers/get_bucket_size'; -import { - Setup, - SetupTimeRange, - SetupUIFilters, -} from '../../../helpers/setup_request'; +import { Setup, SetupTimeRange } from '../../../helpers/setup_request'; import { anomalySeriesFetcher } from './fetcher'; import { getMlBucketSize } from './get_ml_bucket_size'; import { anomalySeriesTransform } from './transform'; import { getMLJobIds } from '../../../service_map/get_service_anomalies'; -import { UIFilters } from '../../../../../typings/ui_filters'; export async function getAnomalySeries({ serviceName, @@ -24,15 +20,13 @@ export async function getAnomalySeries({ timeSeriesDates, setup, logger, - uiFilters, }: { serviceName: string; transactionType: string | undefined; transactionName: string | undefined; timeSeriesDates: number[]; - setup: Setup & SetupTimeRange & SetupUIFilters; + setup: Setup & SetupTimeRange; logger: Logger; - uiFilters: UIFilters; }) { // don't fetch anomalies for transaction details page if (transactionName) { @@ -44,12 +38,22 @@ export async function getAnomalySeries({ return; } + const { uiFilters, start, end } = setup; + const { environment } = uiFilters; + + // don't fetch anomalies when no specific environment is selected + if (environment === ENVIRONMENT_ALL.value) { + return; + } + // don't fetch anomalies if unknown uiFilters are applied const knownFilters = ['environment', 'serviceName']; - const uiFilterNames = Object.keys(uiFilters); - if ( - uiFilterNames.some((uiFilterName) => !knownFilters.includes(uiFilterName)) - ) { + const hasUnknownFiltersApplied = Object.entries(setup.uiFilters) + .filter(([key, value]) => !!value) + .map(([key]) => key) + .some((uiFilterName) => !knownFilters.includes(uiFilterName)); + + if (hasUnknownFiltersApplied) { return; } @@ -64,15 +68,8 @@ export async function getAnomalySeries({ return; } - const mlJobIds = await getMLJobIds( - setup.ml.anomalyDetectors, - uiFilters.environment - ); + const mlJobIds = await getMLJobIds(setup.ml.anomalyDetectors, environment); - // don't fetch anomalies if there are isn't exaclty 1 ML job match for the given environment - if (mlJobIds.length !== 1) { - return; - } const jobId = mlJobIds[0]; const mlBucketSize = await getMlBucketSize({ setup, jobId, logger }); @@ -80,7 +77,6 @@ export async function getAnomalySeries({ return; } - const { start, end } = setup; const { intervalString, bucketSize } = getBucketSize(start, end); const esResponse = await anomalySeriesFetcher({ diff --git a/x-pack/plugins/apm/server/lib/transactions/charts/get_timeseries_data/fetcher.test.ts b/x-pack/plugins/apm/server/lib/transactions/charts/get_timeseries_data/fetcher.test.ts index fdbd99bf274d6..75dfae3e7375f 100644 --- a/x-pack/plugins/apm/server/lib/transactions/charts/get_timeseries_data/fetcher.test.ts +++ b/x-pack/plugins/apm/server/lib/transactions/charts/get_timeseries_data/fetcher.test.ts @@ -29,7 +29,10 @@ describe('timeseriesFetcher', () => { get: () => 'myIndex', } ) as APMConfig, - uiFiltersES: [ + uiFilters: { + environment: 'test', + }, + esFilter: [ { term: { 'service.environment': 'test' }, }, diff --git a/x-pack/plugins/apm/server/lib/transactions/charts/get_timeseries_data/fetcher.ts b/x-pack/plugins/apm/server/lib/transactions/charts/get_timeseries_data/fetcher.ts index 5a3948f577430..e2edbbec63d47 100644 --- a/x-pack/plugins/apm/server/lib/transactions/charts/get_timeseries_data/fetcher.ts +++ b/x-pack/plugins/apm/server/lib/transactions/charts/get_timeseries_data/fetcher.ts @@ -14,11 +14,7 @@ import { import { PromiseReturnType } from '../../../../../../observability/typings/common'; import { getBucketSize } from '../../../helpers/get_bucket_size'; import { rangeFilter } from '../../../../../common/utils/range_filter'; -import { - Setup, - SetupTimeRange, - SetupUIFilters, -} from '../../../helpers/setup_request'; +import { Setup, SetupTimeRange } from '../../../helpers/setup_request'; import { getProcessorEventForAggregatedTransactions, getTransactionDurationFieldForAggregatedTransactions, @@ -36,10 +32,10 @@ export function timeseriesFetcher({ serviceName: string; transactionType: string | undefined; transactionName: string | undefined; - setup: Setup & SetupTimeRange & SetupUIFilters; + setup: Setup & SetupTimeRange; searchAggregatedTransactions: boolean; }) { - const { start, end, uiFiltersES, apmEventClient } = setup; + const { start, end, apmEventClient } = setup; const { intervalString } = getBucketSize(start, end); const filter: ESFilter[] = [ @@ -48,7 +44,7 @@ export function timeseriesFetcher({ ...getDocumentTypeFilterForAggregatedTransactions( searchAggregatedTransactions ), - ...uiFiltersES, + ...setup.esFilter, ]; if (transactionName) { diff --git a/x-pack/plugins/apm/server/lib/transactions/charts/get_timeseries_data/index.ts b/x-pack/plugins/apm/server/lib/transactions/charts/get_timeseries_data/index.ts index 81dca447f16ca..c0421005dd06e 100644 --- a/x-pack/plugins/apm/server/lib/transactions/charts/get_timeseries_data/index.ts +++ b/x-pack/plugins/apm/server/lib/transactions/charts/get_timeseries_data/index.ts @@ -5,11 +5,7 @@ */ import { getBucketSize } from '../../../helpers/get_bucket_size'; -import { - Setup, - SetupTimeRange, - SetupUIFilters, -} from '../../../helpers/setup_request'; +import { Setup, SetupTimeRange } from '../../../helpers/setup_request'; import { timeseriesFetcher } from './fetcher'; import { timeseriesTransformer } from './transform'; @@ -17,7 +13,7 @@ export async function getApmTimeseriesData(options: { serviceName: string; transactionType: string | undefined; transactionName: string | undefined; - setup: Setup & SetupTimeRange & SetupUIFilters; + setup: Setup & SetupTimeRange; searchAggregatedTransactions: boolean; }) { const { start, end } = options.setup; diff --git a/x-pack/plugins/apm/server/lib/transactions/charts/index.ts b/x-pack/plugins/apm/server/lib/transactions/charts/index.ts index 43abf0b1a1d33..d8593612c0582 100644 --- a/x-pack/plugins/apm/server/lib/transactions/charts/index.ts +++ b/x-pack/plugins/apm/server/lib/transactions/charts/index.ts @@ -6,15 +6,10 @@ import { Logger } from 'kibana/server'; import { PromiseReturnType } from '../../../../../observability/typings/common'; -import { - Setup, - SetupTimeRange, - SetupUIFilters, -} from '../../helpers/setup_request'; +import { Setup, SetupTimeRange } from '../../helpers/setup_request'; import { getAnomalySeries } from './get_anomaly_data'; import { getApmTimeseriesData } from './get_timeseries_data'; import { ApmTimeSeriesResponse } from './get_timeseries_data/transform'; -import { UIFilters } from '../../../../typings/ui_filters'; function getDates(apmTimeseries: ApmTimeSeriesResponse) { return apmTimeseries.responseTimes.avg.map((p) => p.x); @@ -27,10 +22,9 @@ export async function getTransactionCharts(options: { serviceName: string; transactionType: string | undefined; transactionName: string | undefined; - setup: Setup & SetupTimeRange & SetupUIFilters; + setup: Setup & SetupTimeRange; searchAggregatedTransactions: boolean; logger: Logger; - uiFilters: UIFilters; }) { const apmTimeseries = await getApmTimeseriesData(options); const anomalyTimeseries = await getAnomalySeries({ diff --git a/x-pack/plugins/apm/server/lib/transactions/distribution/get_buckets/index.ts b/x-pack/plugins/apm/server/lib/transactions/distribution/get_buckets/index.ts index 6e2fe34a5f5ef..34d01627a2869 100644 --- a/x-pack/plugins/apm/server/lib/transactions/distribution/get_buckets/index.ts +++ b/x-pack/plugins/apm/server/lib/transactions/distribution/get_buckets/index.ts @@ -17,11 +17,7 @@ import { TRANSACTION_TYPE, } from '../../../../../common/elasticsearch_fieldnames'; import { rangeFilter } from '../../../../../common/utils/range_filter'; -import { - Setup, - SetupTimeRange, - SetupUIFilters, -} from '../../../helpers/setup_request'; +import { Setup, SetupTimeRange } from '../../../helpers/setup_request'; import { getDocumentTypeFilterForAggregatedTransactions, getProcessorEventForAggregatedTransactions, @@ -66,17 +62,17 @@ export async function getBuckets({ traceId: string; distributionMax: number; bucketSize: number; - setup: Setup & SetupTimeRange & SetupUIFilters; + setup: Setup & SetupTimeRange; searchAggregatedTransactions: boolean; }) { - const { start, end, uiFiltersES, apmEventClient } = setup; + const { start, end, esFilter, apmEventClient } = setup; const commonFilters = [ { term: { [SERVICE_NAME]: serviceName } }, { term: { [TRANSACTION_TYPE]: transactionType } }, { term: { [TRANSACTION_NAME]: transactionName } }, { range: rangeFilter(start, end) }, - ...uiFiltersES, + ...esFilter, ]; async function getSamplesForDistributionBuckets() { diff --git a/x-pack/plugins/apm/server/lib/transactions/distribution/get_distribution_max.ts b/x-pack/plugins/apm/server/lib/transactions/distribution/get_distribution_max.ts index 24ca2a4a07b68..249b1c4fbb20a 100644 --- a/x-pack/plugins/apm/server/lib/transactions/distribution/get_distribution_max.ts +++ b/x-pack/plugins/apm/server/lib/transactions/distribution/get_distribution_max.ts @@ -9,11 +9,7 @@ import { TRANSACTION_NAME, TRANSACTION_TYPE, } from '../../../../common/elasticsearch_fieldnames'; -import { - Setup, - SetupTimeRange, - SetupUIFilters, -} from '../../helpers/setup_request'; +import { Setup, SetupTimeRange } from '../../helpers/setup_request'; import { getProcessorEventForAggregatedTransactions, getTransactionDurationFieldForAggregatedTransactions, @@ -29,10 +25,10 @@ export async function getDistributionMax({ serviceName: string; transactionName: string; transactionType: string; - setup: Setup & SetupTimeRange & SetupUIFilters; + setup: Setup & SetupTimeRange; searchAggregatedTransactions: boolean; }) { - const { start, end, uiFiltersES, apmEventClient } = setup; + const { start, end, esFilter, apmEventClient } = setup; const params = { apm: { @@ -59,7 +55,7 @@ export async function getDistributionMax({ }, }, }, - ...uiFiltersES, + ...esFilter, ], }, }, diff --git a/x-pack/plugins/apm/server/lib/transactions/distribution/index.ts b/x-pack/plugins/apm/server/lib/transactions/distribution/index.ts index b9ab36fb08d42..deafc37ee42e2 100644 --- a/x-pack/plugins/apm/server/lib/transactions/distribution/index.ts +++ b/x-pack/plugins/apm/server/lib/transactions/distribution/index.ts @@ -5,11 +5,7 @@ */ import { PromiseReturnType } from '../../../../../observability/typings/common'; -import { - Setup, - SetupTimeRange, - SetupUIFilters, -} from '../../helpers/setup_request'; +import { Setup, SetupTimeRange } from '../../helpers/setup_request'; import { getBuckets } from './get_buckets'; import { getDistributionMax } from './get_distribution_max'; import { roundToNearestFiveOrTen } from '../../helpers/round_to_nearest_five_or_ten'; @@ -39,7 +35,7 @@ export async function getTransactionDistribution({ transactionType: string; transactionId: string; traceId: string; - setup: Setup & SetupTimeRange & SetupUIFilters; + setup: Setup & SetupTimeRange; searchAggregatedTransactions: boolean; }) { const distributionMax = await getDistributionMax({ diff --git a/x-pack/plugins/apm/server/lib/transactions/get_transaction/index.ts b/x-pack/plugins/apm/server/lib/transactions/get_transaction/index.ts index 9aa1a8f4de87f..8958be0819613 100644 --- a/x-pack/plugins/apm/server/lib/transactions/get_transaction/index.ts +++ b/x-pack/plugins/apm/server/lib/transactions/get_transaction/index.ts @@ -9,11 +9,7 @@ import { TRANSACTION_ID, } from '../../../../common/elasticsearch_fieldnames'; import { rangeFilter } from '../../../../common/utils/range_filter'; -import { - Setup, - SetupTimeRange, - SetupUIFilters, -} from '../../helpers/setup_request'; +import { Setup, SetupTimeRange } from '../../helpers/setup_request'; import { ProcessorEvent } from '../../../../common/processor_event'; export async function getTransaction({ @@ -23,7 +19,7 @@ export async function getTransaction({ }: { transactionId: string; traceId: string; - setup: Setup & SetupTimeRange & SetupUIFilters; + setup: Setup & SetupTimeRange; }) { const { start, end, apmEventClient } = setup; diff --git a/x-pack/plugins/apm/server/lib/transactions/queries.test.ts b/x-pack/plugins/apm/server/lib/transactions/queries.test.ts index 87b8bc7c4ae90..eff9451c9e1cd 100644 --- a/x-pack/plugins/apm/server/lib/transactions/queries.test.ts +++ b/x-pack/plugins/apm/server/lib/transactions/queries.test.ts @@ -56,7 +56,6 @@ describe('transaction queries', () => { setup, searchAggregatedTransactions: false, logger: loggerMock.create(), - uiFilters: {}, }) ); expect(mock.params).toMatchSnapshot(); @@ -71,7 +70,6 @@ describe('transaction queries', () => { setup, searchAggregatedTransactions: false, logger: loggerMock.create(), - uiFilters: {}, }) ); expect(mock.params).toMatchSnapshot(); @@ -86,7 +84,6 @@ describe('transaction queries', () => { setup, searchAggregatedTransactions: false, logger: loggerMock.create(), - uiFilters: {}, }) ); diff --git a/x-pack/plugins/apm/server/lib/ui_filters/local_ui_filters/__snapshots__/queries.test.ts.snap b/x-pack/plugins/apm/server/lib/ui_filters/local_ui_filters/__snapshots__/queries.test.ts.snap index 5f38432719280..e7ca65eb740b6 100644 --- a/x-pack/plugins/apm/server/lib/ui_filters/local_ui_filters/__snapshots__/queries.test.ts.snap +++ b/x-pack/plugins/apm/server/lib/ui_filters/local_ui_filters/__snapshots__/queries.test.ts.snap @@ -46,7 +46,7 @@ Object { }, Object { "term": Object { - "my.custom.ui.filter": "foo-bar", + "service.environment": "test", }, }, ], diff --git a/x-pack/plugins/apm/server/lib/ui_filters/local_ui_filters/get_local_filter_query.ts b/x-pack/plugins/apm/server/lib/ui_filters/local_ui_filters/get_local_filter_query.ts index 10f6e93c1cfc1..9fbdba679b667 100644 --- a/x-pack/plugins/apm/server/lib/ui_filters/local_ui_filters/get_local_filter_query.ts +++ b/x-pack/plugins/apm/server/lib/ui_filters/local_ui_filters/get_local_filter_query.ts @@ -8,7 +8,7 @@ import { omit } from 'lodash'; import { mergeProjection } from '../../../projections/util/merge_projection'; import { Projection } from '../../../projections/typings'; import { UIFilters } from '../../../../typings/ui_filters'; -import { getUiFiltersES } from '../../helpers/convert_ui_filters/get_ui_filters_es'; +import { getEsFilter } from '../../helpers/convert_ui_filters/get_es_filter'; import { localUIFilters } from './config'; import { LocalUIFilterName } from '../../../../common/ui_filter'; @@ -22,7 +22,7 @@ export const getLocalFilterQuery = ({ localUIFilterName: LocalUIFilterName; }) => { const field = localUIFilters[localUIFilterName]; - const filter = getUiFiltersES(omit(uiFilters, field.name)); + const filter = getEsFilter(omit(uiFilters, field.name)); const bucketCountAggregation = projection.body.aggs ? { diff --git a/x-pack/plugins/apm/server/lib/ui_filters/local_ui_filters/queries.test.ts b/x-pack/plugins/apm/server/lib/ui_filters/local_ui_filters/queries.test.ts index 22fa20e255f6e..f4e8aafc1bcf5 100644 --- a/x-pack/plugins/apm/server/lib/ui_filters/local_ui_filters/queries.test.ts +++ b/x-pack/plugins/apm/server/lib/ui_filters/local_ui_filters/queries.test.ts @@ -15,7 +15,7 @@ describe('local ui filter queries', () => { let mock: SearchParamsMock; beforeEach(() => { - jest.mock('../../helpers/convert_ui_filters/get_ui_filters_es', () => { + jest.mock('../../helpers/convert_ui_filters/get_es_filter', () => { return []; }); }); diff --git a/x-pack/plugins/apm/server/projections/errors.ts b/x-pack/plugins/apm/server/projections/errors.ts index 49a0e9f479d26..173dc94a0840c 100644 --- a/x-pack/plugins/apm/server/projections/errors.ts +++ b/x-pack/plugins/apm/server/projections/errors.ts @@ -4,11 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { - Setup, - SetupTimeRange, - SetupUIFilters, -} from '../../server/lib/helpers/setup_request'; +import { Setup, SetupTimeRange } from '../../server/lib/helpers/setup_request'; import { SERVICE_NAME, ERROR_GROUP_ID, @@ -20,10 +16,10 @@ export function getErrorGroupsProjection({ setup, serviceName, }: { - setup: Setup & SetupTimeRange & SetupUIFilters; + setup: Setup & SetupTimeRange; serviceName: string; }) { - const { start, end, uiFiltersES } = setup; + const { start, end, esFilter } = setup; return { apm: { @@ -35,7 +31,7 @@ export function getErrorGroupsProjection({ filter: [ { term: { [SERVICE_NAME]: serviceName } }, { range: rangeFilter(start, end) }, - ...uiFiltersES, + ...esFilter, ], }, }, diff --git a/x-pack/plugins/apm/server/projections/metrics.ts b/x-pack/plugins/apm/server/projections/metrics.ts index eb80a6bc73248..c3b5db5be6af8 100644 --- a/x-pack/plugins/apm/server/projections/metrics.ts +++ b/x-pack/plugins/apm/server/projections/metrics.ts @@ -4,11 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { - Setup, - SetupTimeRange, - SetupUIFilters, -} from '../../server/lib/helpers/setup_request'; +import { Setup, SetupTimeRange } from '../../server/lib/helpers/setup_request'; import { SERVICE_NAME, SERVICE_NODE_NAME, @@ -34,17 +30,17 @@ export function getMetricsProjection({ serviceName, serviceNodeName, }: { - setup: Setup & SetupTimeRange & SetupUIFilters; + setup: Setup & SetupTimeRange; serviceName: string; serviceNodeName?: string; }) { - const { start, end, uiFiltersES } = setup; + const { start, end, esFilter } = setup; const filter = [ { term: { [SERVICE_NAME]: serviceName } }, { range: rangeFilter(start, end) }, ...getServiceNodeNameFilters(serviceNodeName), - ...uiFiltersES, + ...esFilter, ]; return { diff --git a/x-pack/plugins/apm/server/projections/rum_page_load_transactions.ts b/x-pack/plugins/apm/server/projections/rum_page_load_transactions.ts index c27314923f6bd..96ee26c6e65f5 100644 --- a/x-pack/plugins/apm/server/projections/rum_page_load_transactions.ts +++ b/x-pack/plugins/apm/server/projections/rum_page_load_transactions.ts @@ -4,11 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { - Setup, - SetupTimeRange, - SetupUIFilters, -} from '../../server/lib/helpers/setup_request'; +import { Setup, SetupTimeRange } from '../../server/lib/helpers/setup_request'; import { AGENT_NAME, TRANSACTION_TYPE, @@ -22,10 +18,10 @@ export function getRumPageLoadTransactionsProjection({ setup, urlQuery, }: { - setup: Setup & SetupTimeRange & SetupUIFilters; + setup: Setup & SetupTimeRange; urlQuery?: string; }) { - const { start, end, uiFiltersES } = setup; + const { start, end, esFilter } = setup; const bool = { filter: [ @@ -49,7 +45,7 @@ export function getRumPageLoadTransactionsProjection({ }, ] : []), - ...uiFiltersES, + ...esFilter, ], }; @@ -68,9 +64,9 @@ export function getRumPageLoadTransactionsProjection({ export function getRumErrorsProjection({ setup, }: { - setup: Setup & SetupTimeRange & SetupUIFilters; + setup: Setup & SetupTimeRange; }) { - const { start, end, uiFiltersES } = setup; + const { start, end, esFilter: esFilter } = setup; const bool = { filter: [ @@ -82,7 +78,7 @@ export function getRumErrorsProjection({ [SERVICE_LANGUAGE_NAME]: 'javascript', }, }, - ...uiFiltersES, + ...esFilter, ], }; diff --git a/x-pack/plugins/apm/server/projections/service_nodes.ts b/x-pack/plugins/apm/server/projections/service_nodes.ts index 87fe815a12d0d..ed8d4c7409eda 100644 --- a/x-pack/plugins/apm/server/projections/service_nodes.ts +++ b/x-pack/plugins/apm/server/projections/service_nodes.ts @@ -4,11 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { - Setup, - SetupTimeRange, - SetupUIFilters, -} from '../../server/lib/helpers/setup_request'; +import { Setup, SetupTimeRange } from '../../server/lib/helpers/setup_request'; import { SERVICE_NODE_NAME } from '../../common/elasticsearch_fieldnames'; import { mergeProjection } from './util/merge_projection'; import { getMetricsProjection } from './metrics'; @@ -18,7 +14,7 @@ export function getServiceNodesProjection({ serviceName, serviceNodeName, }: { - setup: Setup & SetupTimeRange & SetupUIFilters; + setup: Setup & SetupTimeRange; serviceName: string; serviceNodeName?: string; }) { diff --git a/x-pack/plugins/apm/server/projections/services.ts b/x-pack/plugins/apm/server/projections/services.ts index ba61f72519a23..d912a95546515 100644 --- a/x-pack/plugins/apm/server/projections/services.ts +++ b/x-pack/plugins/apm/server/projections/services.ts @@ -4,11 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { - Setup, - SetupUIFilters, - SetupTimeRange, -} from '../../server/lib/helpers/setup_request'; +import { Setup, SetupTimeRange } from '../../server/lib/helpers/setup_request'; import { SERVICE_NAME } from '../../common/elasticsearch_fieldnames'; import { rangeFilter } from '../../common/utils/range_filter'; import { ProcessorEvent } from '../../common/processor_event'; @@ -18,10 +14,10 @@ export function getServicesProjection({ setup, searchAggregatedTransactions, }: { - setup: Setup & SetupTimeRange & SetupUIFilters; + setup: Setup & SetupTimeRange; searchAggregatedTransactions: boolean; }) { - const { start, end, uiFiltersES } = setup; + const { start, end, esFilter } = setup; return { apm: { @@ -37,7 +33,7 @@ export function getServicesProjection({ size: 0, query: { bool: { - filter: [{ range: rangeFilter(start, end) }, ...uiFiltersES], + filter: [{ range: rangeFilter(start, end) }, ...esFilter], }, }, aggs: { diff --git a/x-pack/plugins/apm/server/projections/transaction_groups.ts b/x-pack/plugins/apm/server/projections/transaction_groups.ts index 0cc3a7a35d214..2ce720eb12167 100644 --- a/x-pack/plugins/apm/server/projections/transaction_groups.ts +++ b/x-pack/plugins/apm/server/projections/transaction_groups.ts @@ -4,11 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ import { omit } from 'lodash'; -import { - Setup, - SetupTimeRange, - SetupUIFilters, -} from '../../server/lib/helpers/setup_request'; +import { Setup, SetupTimeRange } from '../../server/lib/helpers/setup_request'; import { TRANSACTION_NAME, PARENT_ID, @@ -22,7 +18,7 @@ export function getTransactionGroupsProjection({ setup, options, }: { - setup: Setup & SetupTimeRange & SetupUIFilters; + setup: Setup & SetupTimeRange; options: Options; }) { const transactionsProjection = getTransactionsProjection({ diff --git a/x-pack/plugins/apm/server/projections/transactions.ts b/x-pack/plugins/apm/server/projections/transactions.ts index 8e9bb3bf321f6..548e77b5d2cd9 100644 --- a/x-pack/plugins/apm/server/projections/transactions.ts +++ b/x-pack/plugins/apm/server/projections/transactions.ts @@ -4,11 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { - Setup, - SetupTimeRange, - SetupUIFilters, -} from '../../server/lib/helpers/setup_request'; +import { Setup, SetupTimeRange } from '../../server/lib/helpers/setup_request'; import { SERVICE_NAME, TRANSACTION_TYPE, @@ -27,13 +23,13 @@ export function getTransactionsProjection({ transactionType, searchAggregatedTransactions, }: { - setup: Setup & SetupTimeRange & SetupUIFilters; + setup: Setup & SetupTimeRange; serviceName?: string; transactionName?: string; transactionType?: string; searchAggregatedTransactions: boolean; }) { - const { start, end, uiFiltersES } = setup; + const { start, end, esFilter } = setup; const transactionNameFilter = transactionName ? [{ term: { [TRANSACTION_NAME]: transactionName } }] @@ -51,7 +47,7 @@ export function getTransactionsProjection({ ...transactionNameFilter, ...transactionTypeFilter, ...serviceNameFilter, - ...uiFiltersES, + ...esFilter, ...getDocumentTypeFilterForAggregatedTransactions( searchAggregatedTransactions ), diff --git a/x-pack/plugins/apm/server/routes/service_map.ts b/x-pack/plugins/apm/server/routes/service_map.ts index 1996d4d4a262d..6e86ececd1bfe 100644 --- a/x-pack/plugins/apm/server/routes/service_map.ts +++ b/x-pack/plugins/apm/server/routes/service_map.ts @@ -17,7 +17,6 @@ import { createRoute } from './create_route'; import { rangeRt, uiFiltersRt } from './default_api_types'; import { notifyFeatureUsage } from '../feature'; import { getSearchAggregatedTransactions } from '../lib/helpers/aggregated_transactions'; -import { getParsedUiFilters } from '../lib/helpers/convert_ui_filters/get_parsed_ui_filters'; export const serviceMapRoute = createRoute(() => ({ path: '/api/apm/service-map', @@ -77,24 +76,20 @@ export const serviceMapServiceNodeRoute = createRoute(() => ({ if (!isActivePlatinumLicense(context.licensing.license)) { throw Boom.forbidden(invalidLicenseMessage); } - const logger = context.logger; const setup = await setupRequest(context, request); const { - query: { uiFilters: uiFiltersJson }, path: { serviceName }, } = context.params; const searchAggregatedTransactions = await getSearchAggregatedTransactions( setup ); - const uiFilters = getParsedUiFilters({ uiFilters: uiFiltersJson, logger }); return getServiceMapServiceNodeInfo({ setup, serviceName, searchAggregatedTransactions, - uiFilters, }); }, })); diff --git a/x-pack/plugins/apm/server/routes/services.ts b/x-pack/plugins/apm/server/routes/services.ts index 4bb10f31ba6a1..538ba3926c792 100644 --- a/x-pack/plugins/apm/server/routes/services.ts +++ b/x-pack/plugins/apm/server/routes/services.ts @@ -17,7 +17,6 @@ import { uiFiltersRt, rangeRt } from './default_api_types'; import { getServiceAnnotations } from '../lib/services/annotations'; import { dateAsStringRt } from '../../common/runtime_types/date_as_string_rt'; import { getSearchAggregatedTransactions } from '../lib/helpers/aggregated_transactions'; -import { getParsedUiFilters } from '../lib/helpers/convert_ui_filters/get_parsed_ui_filters'; export const servicesRoute = createRoute(() => ({ path: '/api/apm/services', @@ -25,22 +24,13 @@ export const servicesRoute = createRoute(() => ({ query: t.intersection([uiFiltersRt, rangeRt]), }, handler: async ({ context, request }) => { - const { environment } = getParsedUiFilters({ - uiFilters: context.params.query.uiFilters, - logger: context.logger, - }); - const setup = await setupRequest(context, request); const searchAggregatedTransactions = await getSearchAggregatedTransactions( setup ); - const services = await getServices({ - setup, - searchAggregatedTransactions, - mlAnomaliesEnvironment: environment, - }); + const services = await getServices({ setup, searchAggregatedTransactions }); return services; }, diff --git a/x-pack/plugins/apm/server/routes/transaction_groups.ts b/x-pack/plugins/apm/server/routes/transaction_groups.ts index dd1335fb2c2a1..18fc73b468cd4 100644 --- a/x-pack/plugins/apm/server/routes/transaction_groups.ts +++ b/x-pack/plugins/apm/server/routes/transaction_groups.ts @@ -5,6 +5,7 @@ */ import * as t from 'io-ts'; +import Boom from 'boom'; import { setupRequest } from '../lib/helpers/setup_request'; import { getTransactionCharts } from '../lib/transactions/charts'; import { getTransactionDistribution } from '../lib/transactions/distribution'; @@ -15,7 +16,6 @@ import { uiFiltersRt, rangeRt } from './default_api_types'; import { getTransactionSampleForGroup } from '../lib/transaction_groups/get_transaction_sample_for_group'; import { getSearchAggregatedTransactions } from '../lib/helpers/aggregated_transactions'; import { getErrorRate } from '../lib/transaction_groups/get_error_rate'; -import { getParsedUiFilters } from '../lib/helpers/convert_ui_filters/get_parsed_ui_filters'; export const transactionGroupsRoute = createRoute(() => ({ path: '/api/apm/services/{serviceName}/transaction_groups', @@ -71,27 +71,28 @@ export const transactionGroupsChartsRoute = createRoute(() => ({ const setup = await setupRequest(context, request); const logger = context.logger; const { serviceName } = context.params.path; - const { - transactionType, - transactionName, - uiFilters: uiFiltersJson, - } = context.params.query; + const { transactionType, transactionName } = context.params.query; - const uiFilters = getParsedUiFilters({ uiFilters: uiFiltersJson, logger }); + if (!setup.uiFilters.environment) { + throw Boom.badRequest( + `environment is a required property of the ?uiFilters JSON for transaction_groups/charts.` + ); + } const searchAggregatedTransactions = await getSearchAggregatedTransactions( setup ); - return getTransactionCharts({ + const options = { serviceName, transactionType, transactionName, setup, searchAggregatedTransactions, logger, - uiFilters, - }); + }; + + return getTransactionCharts(options); }, })); diff --git a/x-pack/plugins/apm/server/routes/ui_filters.ts b/x-pack/plugins/apm/server/routes/ui_filters.ts index 936d460102dce..26fe0118c02ed 100644 --- a/x-pack/plugins/apm/server/routes/ui_filters.ts +++ b/x-pack/plugins/apm/server/routes/ui_filters.ts @@ -9,13 +9,12 @@ import { omit } from 'lodash'; import { setupRequest, Setup, - SetupUIFilters, SetupTimeRange, } from '../lib/helpers/setup_request'; import { getEnvironments } from '../lib/ui_filters/get_environments'; import { Projection } from '../projections/typings'; import { localUIFilterNames } from '../lib/ui_filters/local_ui_filters/config'; -import { getUiFiltersES } from '../lib/helpers/convert_ui_filters/get_ui_filters_es'; +import { getEsFilter } from '../lib/helpers/convert_ui_filters/get_es_filter'; import { getLocalUIFilters } from '../lib/ui_filters/local_ui_filters'; import { getServicesProjection } from '../projections/services'; import { getTransactionGroupsProjection } from '../projections/transaction_groups'; @@ -97,23 +96,23 @@ function createLocalFiltersRoute< }, handler: async ({ context, request }) => { const setup = await setupRequest(context, request); + const { uiFilters } = setup; const { query } = context.params; - const { uiFilters, filterNames } = query; - const parsedUiFilters = JSON.parse(uiFilters); + const { filterNames } = query; const projection = await getProjection({ query, context, setup: { ...setup, - uiFiltersES: getUiFiltersES(omit(parsedUiFilters, filterNames)), + esFilter: getEsFilter(omit(uiFilters, filterNames)), }, }); return getLocalUIFilters({ projection, setup, - uiFilters: parsedUiFilters, + uiFilters, localFilterNames: filterNames, }); }, @@ -271,6 +270,6 @@ type GetProjection< context, }: { query: t.TypeOf; - setup: Setup & SetupUIFilters & SetupTimeRange; + setup: Setup & SetupTimeRange; context: APMRequestHandlerContext; }) => Promise | TProjection; diff --git a/x-pack/plugins/apm/server/utils/test_helpers.tsx b/x-pack/plugins/apm/server/utils/test_helpers.tsx index 98c1436b2b9b8..18b990b35b5a5 100644 --- a/x-pack/plugins/apm/server/utils/test_helpers.tsx +++ b/x-pack/plugins/apm/server/utils/test_helpers.tsx @@ -9,6 +9,7 @@ import { ESSearchRequest, } from '../../typings/elasticsearch'; import { PromiseReturnType } from '../../typings/common'; +import { UIFilters } from '../../typings/ui_filters'; import { APMConfig } from '..'; interface Options { @@ -23,7 +24,8 @@ interface MockSetup { apmEventClient: any; internalClient: any; config: APMConfig; - uiFiltersES: ESFilter[]; + uiFilters: UIFilters; + esFilter: ESFilter[]; indices: { /* eslint-disable @typescript-eslint/naming-convention */ 'apm_oss.sourcemapIndices': string; @@ -78,7 +80,8 @@ export async function inspectSearchParams( }, } ) as APMConfig, - uiFiltersES: [{ term: { 'my.custom.ui.filter': 'foo-bar' } }], + uiFilters: { environment: 'test' }, + esFilter: [{ term: { 'service.environment': 'test' } }], indices: { /* eslint-disable @typescript-eslint/naming-convention */ 'apm_oss.sourcemapIndices': 'myIndex', diff --git a/x-pack/test/apm_api_integration/basic/tests/feature_controls.ts b/x-pack/test/apm_api_integration/basic/tests/feature_controls.ts index e0e13b7b7fb98..a2223e5560288 100644 --- a/x-pack/test/apm_api_integration/basic/tests/feature_controls.ts +++ b/x-pack/test/apm_api_integration/basic/tests/feature_controls.ts @@ -107,21 +107,21 @@ export default function featureControlsTests({ getService }: FtrProviderContext) }, { req: { - url: `/api/apm/services/foo/transaction_groups/charts?start=${start}&end=${end}&transactionType=bar&uiFilters=%7B%7D`, + url: `/api/apm/services/foo/transaction_groups/charts?start=${start}&end=${end}&transactionType=bar&uiFilters=%7B%22environment%22%3A%22testing%22%7D`, }, expectForbidden: expect404, expectResponse: expect200, }, { req: { - url: `/api/apm/services/foo/transaction_groups/charts?start=${start}&end=${end}&uiFilters=%7B%7D`, + url: `/api/apm/services/foo/transaction_groups/charts?start=${start}&end=${end}&uiFilters=%7B%22environment%22%3A%22testing%22%7D`, }, expectForbidden: expect404, expectResponse: expect200, }, { req: { - url: `/api/apm/services/foo/transaction_groups/charts?start=${start}&end=${end}&transactionType=bar&transactionName=baz&uiFilters=%7B%7D`, + url: `/api/apm/services/foo/transaction_groups/charts?start=${start}&end=${end}&transactionType=bar&transactionName=baz&uiFilters=%7B%22environment%22%3A%22testing%22%7D`, }, expectForbidden: expect404, expectResponse: expect200, diff --git a/x-pack/test/apm_api_integration/basic/tests/transaction_groups/transaction_charts.ts b/x-pack/test/apm_api_integration/basic/tests/transaction_groups/transaction_charts.ts index c9581079b9952..d7d6d613281ef 100644 --- a/x-pack/test/apm_api_integration/basic/tests/transaction_groups/transaction_charts.ts +++ b/x-pack/test/apm_api_integration/basic/tests/transaction_groups/transaction_charts.ts @@ -19,7 +19,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { // url parameters const start = encodeURIComponent(metadata.start); const end = encodeURIComponent(metadata.end); - const uiFilters = encodeURIComponent(JSON.stringify({})); + const uiFilters = encodeURIComponent(JSON.stringify({ environment: 'testing' })); describe('Transaction charts', () => { describe('when data is not loaded ', () => { diff --git a/x-pack/test/apm_api_integration/trial/tests/index.ts b/x-pack/test/apm_api_integration/trial/tests/index.ts index a6a031def34ea..e609279366390 100644 --- a/x-pack/test/apm_api_integration/trial/tests/index.ts +++ b/x-pack/test/apm_api_integration/trial/tests/index.ts @@ -16,6 +16,7 @@ export default function observabilityApiIntegrationTests({ loadTestFile }: FtrPr describe('Services', function () { loadTestFile(require.resolve('./services/annotations')); loadTestFile(require.resolve('./services/top_services.ts')); + loadTestFile(require.resolve('./services/transaction_groups_charts')); }); describe('Settings', function () { diff --git a/x-pack/test/apm_api_integration/trial/tests/services/__snapshots__/transaction_groups_charts.snap b/x-pack/test/apm_api_integration/trial/tests/services/__snapshots__/transaction_groups_charts.snap new file mode 100644 index 0000000000000..8169e73202fbc --- /dev/null +++ b/x-pack/test/apm_api_integration/trial/tests/services/__snapshots__/transaction_groups_charts.snap @@ -0,0 +1,43 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`APM Transaction Overview when data is loaded and fetching transaction groups charts with uiFilters when not defined environments selected should return the correct anomaly boundaries 1`] = `Array []`; + +exports[`APM Transaction Overview when data is loaded and fetching transaction groups charts with uiFilters with environment selected and empty kuery filter should return a non-empty anomaly series 1`] = ` +Array [ + Object { + "x": 1601389800000, + "y": 1206111.33487531, + "y0": 10555.1290143587, + }, + Object { + "x": 1601390700000, + "y": 1223987.49321778, + "y0": 10177.4677901726, + }, + Object { + "x": 1601391600000, + "y": 1223987.49321778, + "y0": 10177.4677901726, + }, +] +`; + +exports[`APM Transaction Overview when data is loaded and fetching transaction groups charts with uiFilters with environment selected in uiFilters should return a non-empty anomaly series 1`] = ` +Array [ + Object { + "x": 1601389800000, + "y": 1206111.33487531, + "y0": 10555.1290143587, + }, + Object { + "x": 1601390700000, + "y": 1223987.49321778, + "y0": 10177.4677901726, + }, + Object { + "x": 1601391600000, + "y": 1223987.49321778, + "y0": 10177.4677901726, + }, +] +`; diff --git a/x-pack/test/apm_api_integration/trial/tests/services/transaction_groups_charts.ts b/x-pack/test/apm_api_integration/trial/tests/services/transaction_groups_charts.ts new file mode 100644 index 0000000000000..c35dfcc3817a4 --- /dev/null +++ b/x-pack/test/apm_api_integration/trial/tests/services/transaction_groups_charts.ts @@ -0,0 +1,161 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import expect from '@kbn/expect'; +import { expectSnapshot } from '../../../common/match_snapshot'; +import { PromiseReturnType } from '../../../../../plugins/apm/typings/common'; +import { FtrProviderContext } from '../../../common/ftr_provider_context'; +import archives_metadata from '../../../common/archives_metadata'; + +export default function ApiTest({ getService }: FtrProviderContext) { + const supertest = getService('supertest'); + const esArchiver = getService('esArchiver'); + + const archiveName = 'apm_8.0.0'; + + const range = archives_metadata[archiveName]; + + // url parameters + const start = encodeURIComponent(range.start); + const end = encodeURIComponent(range.end); + const transactionType = 'request'; + + describe('APM Transaction Overview', () => { + describe('when data is loaded', () => { + before(() => esArchiver.load(archiveName)); + after(() => esArchiver.unload(archiveName)); + + describe('and fetching transaction groups charts with uiFilters', () => { + const serviceName = 'opbeans-java'; + let response: PromiseReturnType; + + describe('without environment', () => { + const uiFilters = encodeURIComponent(JSON.stringify({})); + before(async () => { + response = await supertest.get( + `/api/apm/services/${serviceName}/transaction_groups/charts?start=${start}&end=${end}&transactionType=${transactionType}&uiFilters=${uiFilters}` + ); + }); + it('should return an error response', () => { + expect(response.status).to.eql(400); + }); + }); + + describe('without uiFilters', () => { + before(async () => { + response = await supertest.get( + `/api/apm/services/${serviceName}/transaction_groups/charts?start=${start}&end=${end}&transactionType=${transactionType}` + ); + }); + it('should return an error response', () => { + expect(response.status).to.eql(400); + }); + }); + + describe('with environment selected in uiFilters', () => { + const uiFilters = encodeURIComponent(JSON.stringify({ environment: 'production' })); + before(async () => { + response = await supertest.get( + `/api/apm/services/${serviceName}/transaction_groups/charts?start=${start}&end=${end}&transactionType=${transactionType}&uiFilters=${uiFilters}` + ); + }); + + it('should have a successful response', () => { + expect(response.status).to.eql(200); + }); + + it('should return the ML job id for anomalies of the selected environment', () => { + expect(response.body).to.have.property('anomalyTimeseries'); + expect(response.body.anomalyTimeseries).to.have.property('jobId'); + expectSnapshot(response.body.anomalyTimeseries.jobId).toMatchInline( + `"apm-production-229a-high_mean_transaction_duration"` + ); + }); + + it('should return a non-empty anomaly series', () => { + expect(response.body).to.have.property('anomalyTimeseries'); + expect(response.body.anomalyTimeseries.anomalyBoundaries?.length).to.be.greaterThan(0); + expectSnapshot(response.body.anomalyTimeseries.anomalyBoundaries).toMatch(); + }); + }); + + describe('when not defined environments selected', () => { + const uiFilters = encodeURIComponent( + JSON.stringify({ environment: 'ENVIRONMENT_NOT_DEFINED' }) + ); + before(async () => { + response = await supertest.get( + `/api/apm/services/${serviceName}/transaction_groups/charts?start=${start}&end=${end}&transactionType=${transactionType}&uiFilters=${uiFilters}` + ); + }); + + it('should have a successful response', () => { + expect(response.status).to.eql(200); + }); + + it('should return the ML job id for anomalies with no defined environment', () => { + expect(response.body).to.have.property('anomalyTimeseries'); + expect(response.body.anomalyTimeseries).to.have.property('jobId'); + expectSnapshot(response.body.anomalyTimeseries.jobId).toMatchInline( + `"apm-environment_not_defined-7ed6-high_mean_transaction_duration"` + ); + }); + + it('should return the correct anomaly boundaries', () => { + expect(response.body).to.have.property('anomalyTimeseries'); + expectSnapshot(response.body.anomalyTimeseries.anomalyBoundaries).toMatch(); + }); + }); + + describe('with all environments selected', () => { + const uiFilters = encodeURIComponent(JSON.stringify({ environment: 'ENVIRONMENT_ALL' })); + before(async () => { + response = await supertest.get( + `/api/apm/services/${serviceName}/transaction_groups/charts?start=${start}&end=${end}&transactionType=${transactionType}&uiFilters=${uiFilters}` + ); + }); + + it('should have a successful response', () => { + expect(response.status).to.eql(200); + }); + + it('should not return anomaly timeseries data', () => { + expect(response.body).to.not.have.property('anomalyTimeseries'); + }); + }); + + describe('with environment selected and empty kuery filter', () => { + const uiFilters = encodeURIComponent( + JSON.stringify({ kuery: '', environment: 'production' }) + ); + before(async () => { + response = await supertest.get( + `/api/apm/services/${serviceName}/transaction_groups/charts?start=${start}&end=${end}&transactionType=${transactionType}&uiFilters=${uiFilters}` + ); + }); + + it('should have a successful response', () => { + expect(response.status).to.eql(200); + }); + + it('should return the ML job id for anomalies of the selected environment', () => { + expect(response.body).to.have.property('anomalyTimeseries'); + expect(response.body.anomalyTimeseries).to.have.property('jobId'); + expectSnapshot(response.body.anomalyTimeseries.jobId).toMatchInline( + `"apm-production-229a-high_mean_transaction_duration"` + ); + }); + + it('should return a non-empty anomaly series', () => { + expect(response.body).to.have.property('anomalyTimeseries'); + expect(response.body.anomalyTimeseries.anomalyBoundaries?.length).to.be.greaterThan(0); + expectSnapshot(response.body.anomalyTimeseries.anomalyBoundaries).toMatch(); + }); + }); + }); + }); + }); +} From bd9a9a7a2bf65c465dd805815a2b1a6eea03bc9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patryk=20Kopyci=C5=84ski?= Date: Fri, 2 Oct 2020 10:45:53 +0200 Subject: [PATCH 28/50] [Security Solution] Refactor react-beautiful-dnd render props (#78128) --- .../timeline/events/all/index.ts | 7 +- .../common/search_strategy/timeline/index.ts | 18 +- .../add_filter_to_global_search_bar/index.tsx | 56 +- .../drag_drop_context_wrapper.tsx | 13 +- .../drag_and_drop/draggable_wrapper.tsx | 131 +- .../drag_and_drop/droppable_wrapper.tsx | 33 +- .../common/components/draggables/index.tsx | 2 +- .../events_viewer/events_viewer.tsx | 28 +- .../common/components/events_viewer/mock.ts | 2 +- .../common/components/ml/entity_draggable.tsx | 67 +- .../components/ml/score/draggable_score.tsx | 76 +- .../recent_timelines/recent_timelines.tsx | 160 +- .../components/flyout/button/index.tsx | 34 +- .../components/formatted_ip/index.tsx | 157 +- .../__snapshots__/timeline.test.tsx.snap | 34 +- .../timeline/auto_save_warning/index.tsx | 121 +- .../body/column_headers/actions/index.tsx | 29 +- .../body/column_headers/column_header.tsx | 43 +- .../timeline/body/column_headers/index.tsx | 29 +- .../body/events/event_column_view.tsx | 18 +- .../timeline/body/events/stateful_event.tsx | 228 +- .../renderers/suricata/suricata_signature.tsx | 82 +- .../body/renderers/zeek/zeek_signature.tsx | 76 +- .../data_providers.test.tsx.snap | 5 - .../__snapshots__/providers.test.tsx.snap | 2243 +++++++++++++---- .../data_providers/data_providers.test.tsx | 27 +- .../timeline/data_providers/index.tsx | 80 +- .../data_providers/provider_badge.tsx | 4 +- .../data_providers/provider_item_badge.tsx | 47 +- .../data_providers/providers.test.tsx | 264 +- .../timeline/data_providers/providers.tsx | 460 ++-- .../timelines/components/timeline/events.ts | 32 +- .../footer/__snapshots__/index.test.tsx.snap | 2 +- .../components/timeline/footer/index.test.tsx | 39 +- .../components/timeline/footer/index.tsx | 90 +- .../header/__snapshots__/index.test.tsx.snap | 5 - .../components/timeline/header/index.tsx | 27 - .../timelines/components/timeline/index.tsx | 78 +- .../timeline/properties/helpers.tsx | 42 +- .../components/timeline/timeline.test.tsx | 210 -- .../components/timeline/timeline.tsx | 26 +- .../public/timelines/containers/index.tsx | 20 +- .../timeline/epic_local_storage.test.tsx | 5 - .../timelines/store/timeline/helpers.ts | 15 +- .../timeline/factory/events/all/index.ts | 9 +- 45 files changed, 3039 insertions(+), 2135 deletions(-) diff --git a/x-pack/plugins/security_solution/common/search_strategy/timeline/events/all/index.ts b/x-pack/plugins/security_solution/common/search_strategy/timeline/events/all/index.ts index 0503a9c327467..f673fca290a29 100644 --- a/x-pack/plugins/security_solution/common/search_strategy/timeline/events/all/index.ts +++ b/x-pack/plugins/security_solution/common/search_strategy/timeline/events/all/index.ts @@ -6,7 +6,7 @@ import { IEsSearchResponse } from '../../../../../../../../src/plugins/data/common'; import { Ecs } from '../../../../ecs'; -import { CursorType, Inspect, Maybe } from '../../../common'; +import { CursorType, Inspect, Maybe, PageInfoPaginated } from '../../../common'; import { TimelineRequestOptionsPaginated } from '../..'; export interface TimelineEdges { @@ -29,10 +29,7 @@ export interface TimelineNonEcsData { export interface TimelineEventsAllStrategyResponse extends IEsSearchResponse { edges: TimelineEdges[]; totalCount: number; - pageInfo: { - activePage: number; - totalPages: number; - }; + pageInfo: PageInfoPaginated; inspect?: Maybe; } diff --git a/x-pack/plugins/security_solution/common/search_strategy/timeline/index.ts b/x-pack/plugins/security_solution/common/search_strategy/timeline/index.ts index 773ee60855886..6b96783adc25a 100644 --- a/x-pack/plugins/security_solution/common/search_strategy/timeline/index.ts +++ b/x-pack/plugins/security_solution/common/search_strategy/timeline/index.ts @@ -14,7 +14,13 @@ import { TimelineEventsLastEventTimeRequestOptions, TimelineEventsLastEventTimeStrategyResponse, } from './events'; -import { DocValueFields, TimerangeInput, SortField } from '../common'; +import { + DocValueFields, + PaginationInput, + PaginationInputPaginated, + TimerangeInput, + SortField, +} from '../common'; export * from './events'; @@ -29,19 +35,13 @@ export interface TimelineRequestBasicOptions extends IEsSearchRequest { } export interface TimelineRequestOptions extends TimelineRequestBasicOptions { - pagination: { - activePage: number; - querySize: number; - }; + pagination: PaginationInput; sort: SortField; } export interface TimelineRequestOptionsPaginated extends TimelineRequestBasicOptions { - pagination: { - activePage: number; - querySize: number; - }; + pagination: PaginationInputPaginated; sort: SortField; } diff --git a/x-pack/plugins/security_solution/public/common/components/add_filter_to_global_search_bar/index.tsx b/x-pack/plugins/security_solution/public/common/components/add_filter_to_global_search_bar/index.tsx index 8a294ec1b71fd..9f273b4f293ba 100644 --- a/x-pack/plugins/security_solution/public/common/components/add_filter_to_global_search_bar/index.tsx +++ b/x-pack/plugins/security_solution/public/common/components/add_filter_to_global_search_bar/index.tsx @@ -5,7 +5,7 @@ */ import { EuiButtonIcon, EuiToolTip } from '@elastic/eui'; -import React, { useCallback } from 'react'; +import React, { useCallback, useMemo } from 'react'; import { Filter } from '../../../../../../../src/plugins/data/public'; import { WithHoverActions } from '../with_hover_actions'; @@ -47,34 +47,36 @@ export const AddFilterToGlobalSearchBar = React.memo( } }, [filterManager, filter, onFilterAdded]); - return ( - - - - + const HoverContent = useMemo( + () => ( +
    + + + - - - -
    - } - render={() => children} - /> + + + + + ), + [filterForValue, filterOutValue] ); + + const render = useCallback(() => children, [children]); + + return ; } ); diff --git a/x-pack/plugins/security_solution/public/common/components/drag_and_drop/drag_drop_context_wrapper.tsx b/x-pack/plugins/security_solution/public/common/components/drag_and_drop/drag_drop_context_wrapper.tsx index 74efe2d34fcca..4efb662a4aab6 100644 --- a/x-pack/plugins/security_solution/public/common/components/drag_and_drop/drag_drop_context_wrapper.tsx +++ b/x-pack/plugins/security_solution/public/common/components/drag_and_drop/drag_drop_context_wrapper.tsx @@ -9,6 +9,7 @@ import React, { useCallback } from 'react'; import { DropResult, DragDropContext } from 'react-beautiful-dnd'; import { connect, ConnectedProps } from 'react-redux'; import { Dispatch } from 'redux'; +import deepEqual from 'fast-deep-equal'; import { BeforeCapture } from './drag_drop_context'; import { BrowserFields } from '../../containers/source'; @@ -134,13 +135,11 @@ export const DragDropContextWrapperComponent = React.memo ); }, - (prevProps, nextProps) => { - return ( - prevProps.children === nextProps.children && - prevProps.dataProviders === nextProps.dataProviders && - prevProps.activeTimelineDataProviders === nextProps.activeTimelineDataProviders - ); // prevent re-renders when data providers are added or removed, but all other props are the same - } + // prevent re-renders when data providers are added or removed, but all other props are the same + (prevProps, nextProps) => + prevProps.children === nextProps.children && + deepEqual(prevProps.dataProviders, nextProps.dataProviders) && + prevProps.activeTimelineDataProviders === nextProps.activeTimelineDataProviders ); DragDropContextWrapperComponent.displayName = 'DragDropContextWrapperComponent'; diff --git a/x-pack/plugins/security_solution/public/common/components/drag_and_drop/draggable_wrapper.tsx b/x-pack/plugins/security_solution/public/common/components/drag_and_drop/draggable_wrapper.tsx index 64f6699d21dac..bd22811612a67 100644 --- a/x-pack/plugins/security_solution/public/common/components/drag_and_drop/draggable_wrapper.tsx +++ b/x-pack/plugins/security_solution/public/common/components/drag_and_drop/draggable_wrapper.tsx @@ -196,76 +196,93 @@ const DraggableWrapperComponent: React.FC = ({ ] ); - const renderContent = useCallback( + const RenderClone = useCallback( + (provided, snapshot) => ( + +
    + + {render(dataProvider, provided, snapshot)} + +
    +
    + ), + [dataProvider, registerProvider, render] + ); + + const DraggableContent = useCallback( + (provided, snapshot) => ( + { + provided.innerRef(e); + draggableRef.current = e; + }} + data-test-subj="providerContainer" + isDragging={snapshot.isDragging} + registerProvider={registerProvider} + > + {truncate && !snapshot.isDragging ? ( + + {render(dataProvider, provided, snapshot)} + + ) : ( + + {render(dataProvider, provided, snapshot)} + + )} + + ), + [dataProvider, registerProvider, render, truncate] + ); + + const DroppableContent = useCallback( + (droppableProvided) => ( +
    + + {DraggableContent} + + {droppableProvided.placeholder} +
    + ), + [DraggableContent, dataProvider.id, isDisabled] + ); + + const content = useMemo( () => ( ( - -
    - - {render(dataProvider, provided, snapshot)} - -
    -
    - )} + renderClone={RenderClone} > - {(droppableProvided) => ( -
    - - {(provided, snapshot) => ( - { - provided.innerRef(e); - draggableRef.current = e; - }} - data-test-subj="providerContainer" - isDragging={snapshot.isDragging} - registerProvider={registerProvider} - > - {truncate && !snapshot.isDragging ? ( - - {render(dataProvider, provided, snapshot)} - - ) : ( - - {render(dataProvider, provided, snapshot)} - - )} - - )} - - {droppableProvided.placeholder} -
    - )} + {DroppableContent}
    ), - [dataProvider, registerProvider, render, isDisabled, truncate] + [DroppableContent, RenderClone, dataProvider.id, isDisabled] ); - if (isDisabled) return <>{renderContent()}; + const renderContent = useCallback(() => content, [content]); + + if (isDisabled) return <>{content}; return ( ( type, render = null, renderClone, - }) => ( - - {(provided, snapshot) => ( + }) => { + const DroppableContent = useCallback( + (provided, snapshot) => ( ( {render == null ? children : render({ isDraggingOver: snapshot.isDraggingOver })} {provided.placeholder} - )} - - ) + ), + [children, height, render] + ); + + return ( + + {DroppableContent} + + ); + } ); DroppableWrapper.displayName = 'DroppableWrapper'; diff --git a/x-pack/plugins/security_solution/public/common/components/draggables/index.tsx b/x-pack/plugins/security_solution/public/common/components/draggables/index.tsx index 4dc3c6fcbe440..d37de2cd3ec3d 100644 --- a/x-pack/plugins/security_solution/public/common/components/draggables/index.tsx +++ b/x-pack/plugins/security_solution/public/common/components/draggables/index.tsx @@ -135,7 +135,7 @@ DefaultDraggable.displayName = 'DefaultDraggable'; export const Badge = styled(EuiBadge)` vertical-align: top; -` as any; // eslint-disable-line @typescript-eslint/no-explicit-any +`; Badge.displayName = 'Badge'; diff --git a/x-pack/plugins/security_solution/public/common/components/events_viewer/events_viewer.tsx b/x-pack/plugins/security_solution/public/common/components/events_viewer/events_viewer.tsx index 2c8c8136a4733..7859f5584b0e5 100644 --- a/x-pack/plugins/security_solution/public/common/components/events_viewer/events_viewer.tsx +++ b/x-pack/plugins/security_solution/public/common/components/events_viewer/events_viewer.tsx @@ -5,7 +5,7 @@ */ import { EuiFlexGroup, EuiFlexItem, EuiPanel } from '@elastic/eui'; -import { getOr, isEmpty, union } from 'lodash/fp'; +import { isEmpty, union } from 'lodash/fp'; import React, { useEffect, useMemo, useState } from 'react'; import styled from 'styled-components'; import deepEqual from 'fast-deep-equal'; @@ -239,6 +239,19 @@ const EventsViewerComponent: React.FC = ({ events, ]); + const HeaderSectionContent = useMemo( + () => + headerFilterGroup && ( + + {headerFilterGroup} + + ), + [graphEventId, headerFilterGroup] + ); + useEffect(() => { setIsQueryLoading(loading); }, [loading]); @@ -257,14 +270,7 @@ const EventsViewerComponent: React.FC = ({ subtitle={utilityBar ? undefined : subtitle} title={inspect ? justTitle : titleWithExitFullScreen} > - {headerFilterGroup && ( - - {headerFilterGroup} - - )} + {HeaderSectionContent} {utilityBar && !resolverIsShowing(graphEventId) && ( {utilityBar?.(refetch, totalCountMinusDeleted)} @@ -293,7 +299,7 @@ const EventsViewerComponent: React.FC = ({ /** Hide the footer if Resolver is showing. */ !graphEventId && (
    = ({ onChangeItemsPerPage={onChangeItemsPerPage} onChangePage={loadPage} serverSideEventCount={totalCountMinusDeleted} - totalPages={getOr(0, 'totalPages', pageInfo)} + totalCount={pageInfo.fakeTotalCount} /> ) } diff --git a/x-pack/plugins/security_solution/public/common/components/events_viewer/mock.ts b/x-pack/plugins/security_solution/public/common/components/events_viewer/mock.ts index f6fb01be4371f..d2bd940dcc266 100644 --- a/x-pack/plugins/security_solution/public/common/components/events_viewer/mock.ts +++ b/x-pack/plugins/security_solution/public/common/components/events_viewer/mock.ts @@ -8,7 +8,7 @@ export const mockEventViewerResponse = { totalCount: 12, pageInfo: { activePage: 0, - totalPages: 10, + fakeTotalCount: 100, }, events: [], }; diff --git a/x-pack/plugins/security_solution/public/common/components/ml/entity_draggable.tsx b/x-pack/plugins/security_solution/public/common/components/ml/entity_draggable.tsx index 9024aec17400c..1c5b13acb0c22 100644 --- a/x-pack/plugins/security_solution/public/common/components/ml/entity_draggable.tsx +++ b/x-pack/plugins/security_solution/public/common/components/ml/entity_draggable.tsx @@ -4,9 +4,12 @@ * you may not use this file except in compliance with the Elastic License. */ -import React from 'react'; +import React, { useCallback, useMemo } from 'react'; import { DraggableWrapper, DragEffects } from '../drag_and_drop/draggable_wrapper'; -import { IS_OPERATOR } from '../../../timelines/components/timeline/data_providers/data_provider'; +import { + IS_OPERATOR, + QueryOperator, +} from '../../../timelines/components/timeline/data_providers/data_provider'; import { Provider } from '../../../timelines/components/timeline/data_providers/provider'; import { escapeDataProviderId } from '../drag_and_drop/helpers'; @@ -16,39 +19,43 @@ interface Props { entityValue: string; } -export const EntityDraggableComponent = ({ +export const EntityDraggableComponent: React.FC = ({ idPrefix, entityName, entityValue, -}: Props): JSX.Element => { +}) => { const id = escapeDataProviderId(`entity-draggable-${idPrefix}-${entityName}-${entityValue}`); - return ( - - snapshot.isDragging ? ( - - - - ) : ( - <>{`${entityName}: "${entityValue}"`} - ) - } - /> + + const dataProviderProp = useMemo( + () => ({ + and: [], + enabled: true, + id, + name: entityValue, + excluded: false, + kqlQuery: '', + queryMatch: { + field: entityName, + value: entityValue, + operator: IS_OPERATOR as QueryOperator, + }, + }), + [entityName, entityValue, id] + ); + + const render = useCallback( + (dataProvider, _, snapshot) => + snapshot.isDragging ? ( + + + + ) : ( + <>{`${entityName}: "${entityValue}"`} + ), + [entityName, entityValue] ); + + return ; }; EntityDraggableComponent.displayName = 'EntityDraggableComponent'; diff --git a/x-pack/plugins/security_solution/public/common/components/ml/score/draggable_score.tsx b/x-pack/plugins/security_solution/public/common/components/ml/score/draggable_score.tsx index c849476f0c3db..668a374e57f0d 100644 --- a/x-pack/plugins/security_solution/public/common/components/ml/score/draggable_score.tsx +++ b/x-pack/plugins/security_solution/public/common/components/ml/score/draggable_score.tsx @@ -4,10 +4,13 @@ * you may not use this file except in compliance with the Elastic License. */ -import React from 'react'; +import React, { useCallback, useMemo } from 'react'; import { DraggableWrapper, DragEffects } from '../../drag_and_drop/draggable_wrapper'; import { Anomaly } from '../types'; -import { IS_OPERATOR } from '../../../../timelines/components/timeline/data_providers/data_provider'; +import { + IS_OPERATOR, + QueryOperator, +} from '../../../../timelines/components/timeline/data_providers/data_provider'; import { Provider } from '../../../../timelines/components/timeline/data_providers/provider'; import { Spacer } from '../../page'; import { getScoreString } from './score_health'; @@ -23,39 +26,48 @@ export const DraggableScoreComponent = ({ }): JSX.Element => { const scoreString = getScoreString(score.severity); + const dataProviderProp = useMemo( + () => ({ + and: [], + enabled: true, + id, + name: score.entityName, + excluded: false, + kqlQuery: '', + queryMatch: { + field: score.entityName, + value: score.entityValue, + operator: IS_OPERATOR as QueryOperator, + }, + }), + [id, score.entityName, score.entityValue] + ); + + const render = useCallback( + (dataProvider, _, snapshot) => + snapshot.isDragging ? ( + + + + ) : ( + <> + {index !== 0 && ( + <> + {','} + + + )} + {scoreString} + + ), + [index, scoreString] + ); + return ( - snapshot.isDragging ? ( - - - - ) : ( - <> - {index !== 0 && ( - <> - {','} - - - )} - {scoreString} - - ) - } + dataProvider={dataProviderProp} + render={render} /> ); }; diff --git a/x-pack/plugins/security_solution/public/overview/components/recent_timelines/recent_timelines.tsx b/x-pack/plugins/security_solution/public/overview/components/recent_timelines/recent_timelines.tsx index ddad72081645b..598849c917d33 100644 --- a/x-pack/plugins/security_solution/public/overview/components/recent_timelines/recent_timelines.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/recent_timelines/recent_timelines.tsx @@ -12,7 +12,7 @@ import { EuiToolTip, EuiButtonIcon, } from '@elastic/eui'; -import React from 'react'; +import React, { useCallback, useMemo } from 'react'; import { RecentTimelineHeader } from './header'; import { @@ -25,76 +25,110 @@ import { TimelineType } from '../../../../common/types/timeline'; import { RecentTimelineCounts } from './counts'; import * as i18n from './translations'; -export const RecentTimelines = React.memo<{ - noTimelinesMessage: string; +interface RecentTimelinesItemProps { + timeline: OpenTimelineResult; onOpenTimeline: OnOpenTimeline; - timelines: OpenTimelineResult[]; -}>(({ noTimelinesMessage, onOpenTimeline, timelines }) => { - if (timelines.length === 0) { + isLastItem: boolean; +} + +const RecentTimelinesItem = React.memo( + ({ timeline, onOpenTimeline, isLastItem }) => { + const handleClick = useCallback( + () => + onOpenTimeline({ + duplicate: true, + timelineId: `${timeline.savedObjectId}`, + }), + [onOpenTimeline, timeline.savedObjectId] + ); + + const render = useCallback( + (showHoverContent) => ( + + + + + {timeline.description && timeline.description.length && ( + + {timeline.description} + + )} + + + {showHoverContent && ( + + + + + + )} + + ), + [handleClick, onOpenTimeline, timeline] + ); + return ( <> - - {noTimelinesMessage} - + + <>{!isLastItem && } ); } +); - return ( - <> - {timelines.map((t, i) => ( - - ( - - - - - {t.description && t.description.length && ( - - {t.description} - - )} - +RecentTimelinesItem.displayName = 'RecentTimelinesItem'; - {showHoverContent && ( - - - - onOpenTimeline({ - duplicate: true, - timelineId: `${t.savedObjectId}`, - }) - } - size="s" - /> - - - )} - - )} +interface RecentTimelinesProps { + noTimelinesMessage: string; + onOpenTimeline: OnOpenTimeline; + timelines: OpenTimelineResult[]; +} + +export const RecentTimelines = React.memo( + ({ noTimelinesMessage, onOpenTimeline, timelines }) => { + const content = useMemo( + () => + timelines.map((timeline, index) => ( + - <>{i !== timelines.length - 1 && } - - ))} - - ); -}); + )), + [onOpenTimeline, timelines] + ); + + if (timelines.length === 0) { + return ( + <> + + {noTimelinesMessage} + + + ); + } + + return <>{content}; + } +); RecentTimelines.displayName = 'RecentTimelines'; diff --git a/x-pack/plugins/security_solution/public/timelines/components/flyout/button/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/flyout/button/index.tsx index 954ae0b6a0d40..72fa20c9f152d 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/flyout/button/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/flyout/button/index.tsx @@ -4,11 +4,11 @@ * you may not use this file except in compliance with the Elastic License. */ -import { noop } from 'lodash/fp'; import { EuiButton, EuiNotificationBadge, EuiPanel } from '@elastic/eui'; import { rgba } from 'polished'; import React, { useMemo } from 'react'; import styled from 'styled-components'; +import deepEqual from 'fast-deep-equal'; import { IS_DRAGGING_CLASS_NAME } from '../../../../common/components/drag_and_drop/helpers'; import { DataProvider } from '../../timeline/data_providers/data_provider'; @@ -88,6 +88,18 @@ export const FlyoutButton = React.memo( const badgeCount = useMemo(() => getBadgeCount(dataProviders), [dataProviders]); const { browserFields } = useSourcererScope(SourcererScopeName.timeline); + const badgeStyles: React.CSSProperties = useMemo( + () => ({ + left: '-9px', + position: 'relative', + top: '-6px', + transform: 'rotate(90deg)', + visibility: dataProviders.length !== 0 ? 'inherit' : 'hidden', + zIndex: 10, + }), + [dataProviders.length] + ); + if (!show) { return null; } @@ -108,18 +120,7 @@ export const FlyoutButton = React.memo( > {i18n.FLYOUT_BUTTON} - + {badgeCount} @@ -128,11 +129,6 @@ export const FlyoutButton = React.memo( browserFields={browserFields} timelineId={timelineId} dataProviders={dataProviders} - onDataProviderEdited={noop} - onDataProviderRemoved={noop} - onToggleDataProviderEnabled={noop} - onToggleDataProviderExcluded={noop} - onToggleDataProviderType={noop} /> @@ -140,7 +136,7 @@ export const FlyoutButton = React.memo( }, (prevProps, nextProps) => prevProps.show === nextProps.show && - prevProps.dataProviders === nextProps.dataProviders && + deepEqual(prevProps.dataProviders, nextProps.dataProviders) && prevProps.timelineId === nextProps.timelineId ); diff --git a/x-pack/plugins/security_solution/public/timelines/components/formatted_ip/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/formatted_ip/index.tsx index e4148b5581435..091bb41bc2080 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/formatted_ip/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/formatted_ip/index.tsx @@ -5,7 +5,7 @@ */ import { isArray, isEmpty, isString, uniq } from 'lodash/fp'; -import React from 'react'; +import React, { useCallback, useMemo } from 'react'; import { DragEffects, @@ -71,16 +71,25 @@ const NonDecoratedIpComponent: React.FC<{ fieldName: string; truncate?: boolean; value: string | object | null | undefined; -}> = ({ contextId, eventId, fieldName, truncate, value }) => ( - +}> = ({ contextId, eventId, fieldName, truncate, value }) => { + const key = useMemo( + () => + `non-decorated-ip-draggable-wrapper-${getUniqueId({ + contextId, + eventId, + fieldName, + address: value, + })}`, + [contextId, eventId, fieldName, value] + ); + + const dataProviderProp = useMemo( + () => getDataProvider({ contextId, eventId, fieldName, address: value }), + [contextId, eventId, fieldName, value] + ); + + const render = useCallback( + (dataProvider, _, snapshot) => snapshot.isDragging ? ( @@ -89,47 +98,107 @@ const NonDecoratedIpComponent: React.FC<{ getOrEmptyTagFromValue(value) ) : ( getOrEmptyTagFromValue(tryStringify(value)) - ) - } - truncate={truncate} - /> -); + ), + [value] + ); + + return ( + + ); +}; const NonDecoratedIp = React.memo(NonDecoratedIpComponent); -const AddressLinksComponent: React.FC<{ +interface AddressLinksItemProps extends Omit { + address: string; +} + +const AddressLinksItemComponent: React.FC = ({ + address, + contextId, + eventId, + fieldName, + truncate, +}) => { + const key = useMemo( + () => + `address-links-draggable-wrapper-${getUniqueId({ + contextId, + eventId, + fieldName, + address, + })}`, + [address, contextId, eventId, fieldName] + ); + + const dataProviderProp = useMemo( + () => getDataProvider({ contextId, eventId, fieldName, address }), + [address, contextId, eventId, fieldName] + ); + + const render = useCallback( + (_props, _provided, snapshot) => + snapshot.isDragging ? ( + + + + ) : ( + + ), + [address, dataProviderProp] + ); + + return ( + + ); +}; + +const AddressLinksItem = React.memo(AddressLinksItemComponent); + +interface AddressLinksProps { addresses: string[]; contextId: string; eventId: string; fieldName: string; truncate?: boolean; -}> = ({ addresses, contextId, eventId, fieldName, truncate }) => ( - <> - {uniq(addresses).map((address) => ( - - snapshot.isDragging ? ( - - - - ) : ( - - ) - } - truncate={truncate} - /> - ))} - -); +} + +const AddressLinksComponent: React.FC = ({ + addresses, + contextId, + eventId, + fieldName, + truncate, +}) => { + const uniqAddresses = useMemo(() => uniq(addresses), [addresses]); + + const content = useMemo( + () => + uniqAddresses.map((address) => ( + + )), + [contextId, eventId, fieldName, truncate, uniqAddresses] + ); + + return <>{content}; +}; const AddressLinks = React.memo(AddressLinksComponent); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/__snapshots__/timeline.test.tsx.snap b/x-pack/plugins/security_solution/public/timelines/components/timeline/__snapshots__/timeline.test.tsx.snap index 18a648f2abfaa..153128fb41826 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/__snapshots__/timeline.test.tsx.snap +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/__snapshots__/timeline.test.tsx.snap @@ -646,34 +646,7 @@ In other use cases the message field can be used to concatenate different values dataProviders={ Array [ Object { - "and": Array [ - Object { - "and": Array [], - "enabled": true, - "excluded": false, - "id": "id-Provider 2", - "kqlQuery": "", - "name": "Provider 2", - "queryMatch": Object { - "field": "name", - "operator": ":", - "value": "Provider 2", - }, - }, - Object { - "and": Array [], - "enabled": true, - "excluded": false, - "id": "id-Provider 3", - "kqlQuery": "", - "name": "Provider 3", - "queryMatch": Object { - "field": "name", - "operator": ":", - "value": "Provider 3", - }, - }, - ], + "and": Array [], "enabled": true, "excluded": false, "id": "id-Provider 1", @@ -921,11 +894,6 @@ In other use cases the message field can be used to concatenate different values loadingSourcerer={false} onChangeItemsPerPage={[MockFunction]} onClose={[MockFunction]} - onDataProviderEdited={[MockFunction]} - onDataProviderRemoved={[MockFunction]} - onToggleDataProviderEnabled={[MockFunction]} - onToggleDataProviderExcluded={[MockFunction]} - onToggleDataProviderType={[MockFunction]} show={true} showCallOutUnauthorizedMsg={false} sort={ diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/auto_save_warning/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/auto_save_warning/index.tsx index 210af7a571569..98faa84db851e 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/auto_save_warning/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/auto_save_warning/index.tsx @@ -11,84 +11,69 @@ import { EuiGlobalToastListToast as Toast, } from '@elastic/eui'; import { getOr } from 'lodash/fp'; -import React from 'react'; -import { connect, ConnectedProps } from 'react-redux'; +import React, { useCallback, useMemo } from 'react'; +import { useDispatch, useSelector, shallowEqual } from 'react-redux'; -import { State } from '../../../../common/store'; -import { setTimelineRangeDatePicker as dispatchSetTimelineRangeDatePicker } from '../../../../common/store/inputs/actions'; +import { setTimelineRangeDatePicker } from '../../../../common/store/inputs/actions'; import { timelineActions, timelineSelectors } from '../../../store/timeline'; -import { AutoSavedWarningMsg } from '../../../store/timeline/types'; import { useStateToaster } from '../../../../common/components/toasters'; import * as i18n from './translations'; -const AutoSaveWarningMsgComponent = React.memo( - ({ - newTimelineModel, - setTimelineRangeDatePicker, - timelineId, - updateAutoSaveMsg, - updateTimeline, - }) => { - const dispatchToaster = useStateToaster()[1]; +const AutoSaveWarningMsgComponent = () => { + const dispatch = useDispatch(); + const dispatchToaster = useStateToaster()[1]; + const { timelineId, newTimelineModel } = useSelector( + timelineSelectors.autoSaveMsgSelector, + shallowEqual + ); + + const handleClick = useCallback(() => { if (timelineId != null && newTimelineModel != null) { - const toast: Toast = { - id: 'AutoSaveWarningMsg', - title: i18n.TITLE, - color: 'warning', - iconType: 'alert', - toastLifeTimeMs: 10000, - text: ( - <> -

    {i18n.DESCRIPTION}

    - - - { - updateTimeline({ id: timelineId, timeline: newTimelineModel }); - updateAutoSaveMsg({ timelineId: null, newTimelineModel: null }); - setTimelineRangeDatePicker({ - from: getOr(0, 'dateRange.start', newTimelineModel), - to: getOr(0, 'dateRange.end', newTimelineModel), - }); - }} - > - {i18n.REFRESH_TIMELINE} - - - - - ), - }; - dispatchToaster({ - type: 'addToaster', - toast, - }); + dispatch(timelineActions.updateTimeline({ id: timelineId, timeline: newTimelineModel })); + dispatch(timelineActions.updateAutoSaveMsg({ timelineId: null, newTimelineModel: null })); + dispatch( + setTimelineRangeDatePicker({ + from: getOr(0, 'dateRange.start', newTimelineModel), + to: getOr(0, 'dateRange.end', newTimelineModel), + }) + ); } + }, [dispatch, newTimelineModel, timelineId]); - return null; - } -); - -AutoSaveWarningMsgComponent.displayName = 'AutoSaveWarningMsgComponent'; - -const mapStateToProps = (state: State) => { - const autoSaveMessage: AutoSavedWarningMsg = timelineSelectors.autoSaveMsgSelector(state); + const TextComponent = useMemo( + () => ( + <> +

    {i18n.DESCRIPTION}

    + + + + {i18n.REFRESH_TIMELINE} + + + + + ), + [handleClick] + ); - return { - timelineId: autoSaveMessage.timelineId, - newTimelineModel: autoSaveMessage.newTimelineModel, - }; -}; + if (timelineId != null && newTimelineModel != null) { + const toast: Toast = { + id: 'AutoSaveWarningMsg', + title: i18n.TITLE, + color: 'warning', + iconType: 'alert', + toastLifeTimeMs: 10000, + text: TextComponent, + }; + dispatchToaster({ + type: 'addToaster', + toast, + }); + } -const mapDispatchToProps = { - setTimelineRangeDatePicker: dispatchSetTimelineRangeDatePicker, - updateAutoSaveMsg: timelineActions.updateAutoSaveMsg, - updateTimeline: timelineActions.updateTimeline, + return null; }; -const connector = connect(mapStateToProps, mapDispatchToProps); - -type PropsFromRedux = ConnectedProps; +AutoSaveWarningMsgComponent.displayName = 'AutoSaveWarningMsgComponent'; -export const AutoSaveWarningMsg = connector(AutoSaveWarningMsgComponent); +export const AutoSaveWarningMsg = React.memo(AutoSaveWarningMsgComponent); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/actions/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/actions/index.tsx index 3352639fa95f8..c4c4e0e0c7065 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/actions/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/actions/index.tsx @@ -5,7 +5,7 @@ */ import { EuiButtonIcon } from '@elastic/eui'; -import React from 'react'; +import React, { useCallback } from 'react'; import { ColumnHeaderOptions } from '../../../../../../timelines/store/timeline/model'; import { OnColumnRemoved } from '../../../events'; @@ -26,20 +26,27 @@ interface Props { export const CloseButton = React.memo<{ columnId: string; onColumnRemoved: OnColumnRemoved; -}>(({ columnId, onColumnRemoved }) => ( - ) => { +}>(({ columnId, onColumnRemoved }) => { + const handleClick = useCallback( + (event: React.MouseEvent) => { // To avoid a re-sorting when you delete a column event.preventDefault(); event.stopPropagation(); onColumnRemoved(columnId); - }} - /> -)); + }, + [columnId, onColumnRemoved] + ); + + return ( + + ); +}); CloseButton.displayName = 'CloseButton'; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/column_header.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/column_header.tsx index 617b2935ee75c..6e21446944573 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/column_header.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/column_header.tsx @@ -78,6 +78,29 @@ const ColumnHeaderComponent: React.FC = ({ [timelineId, header.id] ); + const DraggableContent = useCallback( + (dragProvided) => ( + + +
    + + + ), + [header, onColumnRemoved, onColumnSorted, onFilterChange, sort, timelineId] + ); + return ( = ({ index={draggableIndex} key={header.id} > - {(dragProvided) => ( - - -
    - - - )} + {DraggableContent} ); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/index.tsx index 6e802053ab29f..f4d4cf29ba38b 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/index.tsx @@ -200,6 +200,22 @@ export const ColumnHeadersComponent = ({ [globalFullScreen, timelineId, timelineFullScreen] ); + const DroppableContent = useCallback( + (dropProvided, snapshot) => ( + <> + + {ColumnHeaderList} + + + ), + [ColumnHeaderList] + ); + return ( @@ -275,18 +291,7 @@ export const ColumnHeadersComponent = ({ type={DRAG_TYPE_FIELD} renderClone={renderClone} > - {(dropProvided, snapshot) => ( - <> - - {ColumnHeaderList} - - - )} + {DroppableContent} diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/events/event_column_view.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/events/event_column_view.tsx index 3b6585013c8d3..df5c48ad012a6 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/events/event_column_view.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/events/event_column_view.tsx @@ -151,13 +151,17 @@ export const EventColumnView = React.memo( />, ] : []), - , + ...(eventType !== 'raw' + ? [ + , + ] + : []), ], [ associateNote, diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/events/stateful_event.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/events/stateful_event.tsx index d71af86c80247..ee68c270e9aba 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/events/stateful_event.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/events/stateful_event.tsx @@ -97,6 +97,8 @@ const TOP_OFFSET = 50; */ const BOTTOM_OFFSET = -500; +const VISIBILITY_SENSOR_OFFSET = { top: TOP_OFFSET, bottom: BOTTOM_OFFSET }; + const emptyNotes: string[] = []; const EventsTrSupplementContainerWrapper = React.memo(({ children }) => { @@ -173,105 +175,145 @@ const StatefulEventComponent: React.FC = ({ // Number of current columns plus one for actions. const columnCount = columnHeaders.length + 1; + const VisibilitySensorContent = useCallback( + ({ isVisible }) => { + if (isVisible || disableSensorVisibility) { + return ( + + + + + + + + + {getRowRenderer(event.ecs, rowRenderers).renderRow({ + browserFields, + data: event.ecs, + timelineId, + })} + + + + + + + ); + } else { + // Height place holder for visibility detection as well as re-rendering sections. + const height = + divElement.current != null && divElement.current!.clientHeight + ? `${divElement.current!.clientHeight}px` + : DEFAULT_ROW_HEIGHT; + + return ; + } + }, + [ + actionsColumnWidth, + associateNote, + browserFields, + columnCount, + columnHeaders, + columnRenderers, + detailsData, + disableSensorVisibility, + event._id, + event.data, + event.ecs, + eventIdToNoteIds, + expanded, + getNotesByIds, + isEventPinned, + isEventViewer, + loading, + loadingEventIds, + onColumnResized, + onPinEvent, + onRowSelected, + onToggleExpanded, + onToggleShowNotes, + onUnPinEvent, + onUpdateColumns, + refetch, + rowRenderers, + selectedEventIds, + showCheckboxes, + showNotes, + timelineId, + timelineStatus, + toggleColumn, + updateNote, + ] + ); + return ( - {({ isVisible }) => { - if (isVisible || disableSensorVisibility) { - return ( - - - - - - - - - {getRowRenderer(event.ecs, rowRenderers).renderRow({ - browserFields, - data: event.ecs, - timelineId, - })} - - - - - - - ); - } else { - // Height place holder for visibility detection as well as re-rendering sections. - const height = - divElement.current != null && divElement.current!.clientHeight - ? `${divElement.current!.clientHeight}px` - : DEFAULT_ROW_HEIGHT; - - return ; - } - }} + {VisibilitySensorContent} ); }; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/suricata/suricata_signature.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/suricata/suricata_signature.tsx index 1cd78178d017f..5d4821757d774 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/suricata/suricata_signature.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/suricata/suricata_signature.tsx @@ -5,7 +5,7 @@ */ import { EuiBadge, EuiFlexGroup, EuiFlexItem, EuiToolTip } from '@elastic/eui'; -import React from 'react'; +import React, { useCallback, useMemo } from 'react'; import styled from 'styled-components'; import { @@ -19,7 +19,7 @@ import { Provider } from '../../../data_providers/provider'; import { TokensFlexItem } from '../helpers'; import { getBeginningTokens } from './suricata_links'; import { DefaultDraggable } from '../../../../../../common/components/draggables'; -import { IS_OPERATOR } from '../../../data_providers/data_provider'; +import { IS_OPERATOR, QueryOperator } from '../../../data_providers/data_provider'; export const SURICATA_SIGNATURE_FIELD_NAME = 'suricata.eve.alert.signature'; export const SURICATA_SIGNATURE_ID_FIELD_NAME = 'suricata.eve.alert.signature_id'; @@ -57,41 +57,49 @@ export const Tokens = React.memo<{ tokens: string[] }>(({ tokens }) => ( Tokens.displayName = 'Tokens'; export const DraggableSignatureId = React.memo<{ id: string; signatureId: number }>( - ({ id, signatureId }) => ( - - - snapshot.isDragging ? ( - - - - ) : ( - - - {signatureId} - - - ) - } - /> - - ) + ({ id, signatureId }) => { + const dataProviderProp = useMemo( + () => ({ + and: [], + enabled: true, + id: escapeDataProviderId(`suricata-draggable-signature-id-${id}-sig-${signatureId}`), + name: String(signatureId), + excluded: false, + kqlQuery: '', + queryMatch: { + field: SURICATA_SIGNATURE_ID_FIELD_NAME, + value: signatureId, + operator: IS_OPERATOR as QueryOperator, + }, + }), + [id, signatureId] + ); + + const render = useCallback( + (dataProvider, _, snapshot) => + snapshot.isDragging ? ( + + + + ) : ( + + + {signatureId} + + + ), + [signatureId] + ); + + return ( + + + + ); + } ); DraggableSignatureId.displayName = 'DraggableSignatureId'; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/zeek/zeek_signature.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/zeek/zeek_signature.tsx index 07e32a9a4e5d1..9ef579706f118 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/zeek/zeek_signature.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/zeek/zeek_signature.tsx @@ -6,7 +6,7 @@ import { EuiBadge, EuiFlexGroup, EuiFlexItem, EuiToolTip } from '@elastic/eui'; import { get } from 'lodash/fp'; -import React from 'react'; +import React, { useCallback, useMemo } from 'react'; import styled from 'styled-components'; import { Ecs } from '../../../../../../../common/ecs'; @@ -17,7 +17,7 @@ import { import { escapeDataProviderId } from '../../../../../../common/components/drag_and_drop/helpers'; import { GoogleLink, ReputationLink } from '../../../../../../common/components/links'; import { Provider } from '../../../data_providers/provider'; -import { IS_OPERATOR } from '../../../data_providers/data_provider'; +import { IS_OPERATOR, QueryOperator } from '../../../data_providers/data_provider'; import * as i18n from './translations'; @@ -68,42 +68,46 @@ export const DraggableZeekElement = React.memo<{ field: string; value: string | null | undefined; stringRenderer?: StringRenderer; -}>(({ id, field, value, stringRenderer = defaultStringRenderer }) => - value != null ? ( +}>(({ id, field, value, stringRenderer = defaultStringRenderer }) => { + const dataProviderProp = useMemo( + () => ({ + and: [], + enabled: true, + id: escapeDataProviderId(`draggable-zeek-element-draggable-wrapper-${id}-${field}-${value}`), + name: value!, + excluded: false, + kqlQuery: '', + queryMatch: { + field, + value: value!, + operator: IS_OPERATOR as QueryOperator, + }, + }), + [field, id, value] + ); + + const render = useCallback( + (dataProvider, _, snapshot) => + snapshot.isDragging ? ( + + + + ) : ( + + + {stringRenderer(value!)} + + + ), + [field, stringRenderer, value] + ); + + return value != null ? ( - - snapshot.isDragging ? ( - - - - ) : ( - - - {stringRenderer(value)} - - - ) - } - /> + - ) : null -); + ) : null; +}); DraggableZeekElement.displayName = 'DraggableZeekElement'; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/__snapshots__/data_providers.test.tsx.snap b/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/__snapshots__/data_providers.test.tsx.snap index 14304b99263ac..a8818517fb94b 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/__snapshots__/data_providers.test.tsx.snap +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/__snapshots__/data_providers.test.tsx.snap @@ -144,11 +144,6 @@ exports[`DataProviders rendering renders correctly against snapshot 1`] = ` }, ] } - onDataProviderEdited={[MockFunction]} - onDataProviderRemoved={[MockFunction]} - onToggleDataProviderEnabled={[MockFunction]} - onToggleDataProviderExcluded={[MockFunction]} - onToggleDataProviderType={[MockFunction]} timelineId="foo" /> diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/__snapshots__/providers.test.tsx.snap b/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/__snapshots__/providers.test.tsx.snap index a86c99cbc094a..281a26b08df67 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/__snapshots__/providers.test.tsx.snap +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/__snapshots__/providers.test.tsx.snap @@ -2,556 +2,1717 @@ exports[`Providers rendering renders correctly against snapshot 1`] = `
    - - - - - - - - - ( - - - - - - - - - - ) - - - - - - - - - - - - - ( - - - - - - - - - - ) - - - - - - - - - - - - - ( - - - - - - - - - - ) - - - - - - - - - - - - - ( - - - - - - - - - - ) - - - - - - - - - - - - - ( - - - - - - - - - - ) - - - - - - - - - - - - - ( - - - - - - - - - - ) - - - - - - - - - - - - - ( - - - - - - - - - - ) - - - - - - - - - - - - - ( - - - - - - - - - - ) - - - - - - - - - - - - - ( - - - - - - - - - - ) - - - - - - - - - - - - - ( - - - - - - - - - - ) - - - - + - - - - - - - - - ( - - - - - - - - - - ) - - - -
    `; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/data_providers.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/data_providers.test.tsx index d48be25b08897..a7ae14dea510f 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/data_providers.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/data_providers.test.tsx @@ -41,11 +41,6 @@ describe('DataProviders', () => { data-test-subj="dataProviders-container" dataProviders={mockDataProviders} timelineId="foo" - onDataProviderEdited={jest.fn()} - onDataProviderRemoved={jest.fn()} - onToggleDataProviderEnabled={jest.fn()} - onToggleDataProviderExcluded={jest.fn()} - onToggleDataProviderType={jest.fn()} /> @@ -58,16 +53,7 @@ describe('DataProviders', () => { const wrapper = mount( - + ); @@ -77,16 +63,7 @@ describe('DataProviders', () => { test('it renders the data providers', () => { const wrapper = mount( - + ); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/index.tsx index c9e06f89af41c..b892ca089eb4c 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/index.tsx @@ -14,13 +14,6 @@ import { droppableTimelineProvidersPrefix, IS_DRAGGING_CLASS_NAME, } from '../../../../common/components/drag_and_drop/helpers'; -import { - OnDataProviderEdited, - OnDataProviderRemoved, - OnToggleDataProviderEnabled, - OnToggleDataProviderExcluded, - OnToggleDataProviderType, -} from '../events'; import { DataProvider } from './data_provider'; import { Empty } from './empty'; @@ -31,11 +24,6 @@ interface Props { browserFields: BrowserFields; timelineId: string; dataProviders: DataProvider[]; - onDataProviderEdited: OnDataProviderEdited; - onDataProviderRemoved: OnDataProviderRemoved; - onToggleDataProviderEnabled: OnToggleDataProviderEnabled; - onToggleDataProviderExcluded: OnToggleDataProviderExcluded; - onToggleDataProviderType: OnToggleDataProviderType; } const DropTargetDataProvidersContainer = styled.div` @@ -91,48 +79,32 @@ const getDroppableId = (id: string): string => `${droppableTimelineProvidersPref * the user to drop anything with a facet count into * the data pro section. */ -export const DataProviders = React.memo( - ({ - browserFields, - dataProviders, +export const DataProviders = React.memo(({ browserFields, dataProviders, timelineId }) => { + const { getManageTimelineById } = useManageTimeline(); + const isLoading = useMemo(() => getManageTimelineById(timelineId).isLoading, [ + getManageTimelineById, timelineId, - onDataProviderEdited, - onDataProviderRemoved, - onToggleDataProviderEnabled, - onToggleDataProviderExcluded, - onToggleDataProviderType, - }) => { - const { getManageTimelineById } = useManageTimeline(); - const isLoading = useMemo(() => getManageTimelineById(timelineId).isLoading, [ - getManageTimelineById, - timelineId, - ]); - return ( - - - {dataProviders != null && dataProviders.length ? ( - - ) : ( - - - - )} - - - ); - } -); + ]); + return ( + + + {dataProviders != null && dataProviders.length ? ( + + ) : ( + + + + )} + + + ); +}); DataProviders.displayName = 'DataProviders'; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/provider_badge.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/provider_badge.tsx index bf2094e7659ee..b66a332fc977d 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/provider_badge.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/provider_badge.tsx @@ -91,7 +91,7 @@ const ConvertFieldBadge = styled(ProviderFieldBadge)` } `; -const TemplateFieldBadge: React.FC = ({ type, toggleType }) => { +const TemplateFieldBadgeComponent: React.FC = ({ type, toggleType }) => { if (type !== DataProviderType.template) { return ( {i18n.CONVERT_TO_TEMPLATE_FIELD} @@ -101,6 +101,8 @@ const TemplateFieldBadge: React.FC = ({ type, toggleTyp return {i18n.TEMPLATE_FIELD_LABEL}; }; +const TemplateFieldBadge = React.memo(TemplateFieldBadgeComponent); + interface ProviderBadgeProps { deleteProvider: () => void; field: string; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/provider_item_badge.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/provider_item_badge.tsx index 0093c43a17137..fc06d37b9663f 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/provider_item_badge.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/provider_item_badge.tsx @@ -117,21 +117,38 @@ export const ProviderItemBadge = React.memo( [unRegisterProvider] ); - const button = ( - + const button = useMemo( + () => ( + + ), + [ + deleteProvider, + field, + isEnabled, + isExcluded, + isLoading, + kqlQuery, + onToggleTypeProvider, + operator, + providerId, + timelineType, + togglePopover, + type, + val, + ] ); return ( diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/providers.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/providers.test.tsx index 3f371349aa750..2df19605f813c 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/providers.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/providers.test.tsx @@ -12,6 +12,7 @@ import { TestProviders } from '../../../../common/mock/test_providers'; import { DroppableWrapper } from '../../../../common/components/drag_and_drop/droppable_wrapper'; import { FilterManager } from '../../../../../../../../src/plugins/data/public'; +import { timelineActions } from '../../../store/timeline'; import { mockDataProviders } from './mock/mock_data_providers'; import { Providers } from './providers'; import { DELETE_CLASS_NAME, ENABLE_CLASS_NAME, EXCLUDE_CLASS_NAME } from './provider_item_actions'; @@ -24,27 +25,24 @@ describe('Providers', () => { const isLoading: boolean = true; const mount = useMountAppended(); const filterManager = new FilterManager(mockUiSettingsForFilterManager); + const mockOnDataProviderRemoved = jest.spyOn(timelineActions, 'removeProvider'); const manageTimelineForTesting = { - foo: { - ...getTimelineDefaults('foo'), + test: { + ...getTimelineDefaults('test'), filterManager, isLoading, }, }; + + beforeEach(() => { + jest.clearAllMocks(); + }); + describe('rendering', () => { test('renders correctly against snapshot', () => { const wrapper = shallow( - + ); expect(wrapper).toMatchSnapshot(); }); @@ -53,16 +51,7 @@ describe('Providers', () => { const wrapper = mount( - + ); @@ -77,20 +66,10 @@ describe('Providers', () => { describe('#onDataProviderRemoved', () => { test('it invokes the onDataProviderRemoved callback when the close button is clicked', () => { - const mockOnDataProviderRemoved = jest.fn(); const wrapper = mount( - + ); @@ -98,25 +77,15 @@ describe('Providers', () => { .find('[data-test-subj="providerBadge"] [data-euiicon-type]') .first() .simulate('click'); - expect(mockOnDataProviderRemoved.mock.calls[0][0]).toEqual('id-Provider 1'); + expect(mockOnDataProviderRemoved.mock.calls[0][0].providerId).toEqual('id-Provider 1'); }); test('while loading data, it does NOT invoke the onDataProviderRemoved callback when the close button is clicked', () => { - const mockOnDataProviderRemoved = jest.fn(); const wrapper = mount( - + @@ -131,20 +100,10 @@ describe('Providers', () => { }); test('it invokes the onDataProviderRemoved callback when you click on the option "Delete" in the provider menu', () => { - const mockOnDataProviderRemoved = jest.fn(); const wrapper = mount( - + ); @@ -156,25 +115,15 @@ describe('Providers', () => { .find(`[data-test-subj="providerActions"] .${DELETE_CLASS_NAME}`) .first() .simulate('click'); - expect(mockOnDataProviderRemoved.mock.calls[0][0]).toEqual('id-Provider 1'); + expect(mockOnDataProviderRemoved.mock.calls[0][0].providerId).toEqual('id-Provider 1'); }); test('while loading data, it does NOT invoke the onDataProviderRemoved callback when you click on the option "Delete" in the provider menu', () => { - const mockOnDataProviderRemoved = jest.fn(); const wrapper = mount( - + @@ -194,20 +143,14 @@ describe('Providers', () => { describe('#onToggleDataProviderEnabled', () => { test('it invokes the onToggleDataProviderEnabled callback when you click on the option "Temporary disable" in the provider menu', () => { - const mockOnToggleDataProviderEnabled = jest.fn(); + const mockOnToggleDataProviderEnabled = jest.spyOn( + timelineActions, + 'updateDataProviderEnabled' + ); const wrapper = mount( - + ); @@ -220,27 +163,23 @@ describe('Providers', () => { .first() .simulate('click'); expect(mockOnToggleDataProviderEnabled.mock.calls[0][0]).toEqual({ + andProviderId: undefined, enabled: false, + id: 'test', providerId: 'id-Provider 1', }); }); test('while loading data, it does NOT invoke the onToggleDataProviderEnabled callback when you click on the option "Temporary disable" in the provider menu', () => { - const mockOnToggleDataProviderEnabled = jest.fn(); + const mockOnToggleDataProviderEnabled = jest.spyOn( + timelineActions, + 'updateDataProviderEnabled' + ); const wrapper = mount( - + @@ -260,21 +199,15 @@ describe('Providers', () => { describe('#onToggleDataProviderExcluded', () => { test('it invokes the onToggleDataProviderExcluded callback when you click on the option "Exclude results" in the provider menu', () => { - const onToggleDataProviderExcluded = jest.fn(); + const mockOnToggleDataProviderExcluded = jest.spyOn( + timelineActions, + 'updateDataProviderExcluded' + ); const wrapper = mount( - + ); @@ -288,29 +221,25 @@ describe('Providers', () => { .first() .simulate('click'); - expect(onToggleDataProviderExcluded.mock.calls[0][0]).toEqual({ + expect(mockOnToggleDataProviderExcluded.mock.calls[0][0]).toEqual({ + andProviderId: undefined, excluded: true, + id: 'test', providerId: 'id-Provider 1', }); }); test('while loading data, it does NOT invoke the onToggleDataProviderExcluded callback when you click on the option "Exclude results" in the provider menu', () => { - const onToggleDataProviderExcluded = jest.fn(); + const mockOnToggleDataProviderExcluded = jest.spyOn( + timelineActions, + 'updateDataProviderExcluded' + ); const wrapper = mount( - + @@ -325,7 +254,7 @@ describe('Providers', () => { .first() .simulate('click'); - expect(onToggleDataProviderExcluded).not.toBeCalled(); + expect(mockOnToggleDataProviderExcluded).not.toBeCalled(); }); }); @@ -337,16 +266,7 @@ describe('Providers', () => { const wrapper = mount( - + ); @@ -364,21 +284,11 @@ describe('Providers', () => { test('it invokes the onDataProviderRemoved callback when you click on the close button is clicked', () => { const dataProviders = mockDataProviders.slice(0, 1); dataProviders[0].and = mockDataProviders.slice(1, 3); - const mockOnDataProviderRemoved = jest.fn(); const wrapper = mount( - + ); @@ -392,28 +302,22 @@ describe('Providers', () => { wrapper.update(); - expect(mockOnDataProviderRemoved.mock.calls[0]).toEqual(['id-Provider 1', 'id-Provider 2']); + expect(mockOnDataProviderRemoved.mock.calls[0][0]).toEqual({ + andProviderId: 'id-Provider 2', + id: 'test', + providerId: 'id-Provider 1', + }); }); test('while loading data, it does NOT invoke the onDataProviderRemoved callback when you click on the close button is clicked', () => { const dataProviders = mockDataProviders.slice(0, 1); dataProviders[0].and = mockDataProviders.slice(1, 3); - const mockOnDataProviderRemoved = jest.fn(); const wrapper = mount( - + @@ -434,21 +338,15 @@ describe('Providers', () => { test('it invokes the onToggleDataProviderEnabled callback when you click on the option "Temporary disable" in the provider menu', () => { const dataProviders = mockDataProviders.slice(0, 1); dataProviders[0].and = mockDataProviders.slice(1, 3); - const mockOnToggleDataProviderEnabled = jest.fn(); + const mockOnToggleDataProviderEnabled = jest.spyOn( + timelineActions, + 'updateDataProviderEnabled' + ); const wrapper = mount( - + ); @@ -470,6 +368,7 @@ describe('Providers', () => { expect(mockOnToggleDataProviderEnabled.mock.calls[0][0]).toEqual({ andProviderId: 'id-Provider 2', enabled: false, + id: 'test', providerId: 'id-Provider 1', }); }); @@ -477,22 +376,16 @@ describe('Providers', () => { test('while loading data, it does NOT invoke the onToggleDataProviderEnabled callback when you click on the option "Temporary disable" in the provider menu', () => { const dataProviders = mockDataProviders.slice(0, 1); dataProviders[0].and = mockDataProviders.slice(1, 3); - const mockOnToggleDataProviderEnabled = jest.fn(); + const mockOnToggleDataProviderEnabled = jest.spyOn( + timelineActions, + 'updateDataProviderEnabled' + ); const wrapper = mount( - + @@ -518,21 +411,15 @@ describe('Providers', () => { test('it invokes the onToggleDataProviderExcluded callback when you click on the option "Exclude results" in the provider menu', () => { const dataProviders = mockDataProviders.slice(0, 1); dataProviders[0].and = mockDataProviders.slice(1, 3); - const mockOnToggleDataProviderExcluded = jest.fn(); + const mockOnToggleDataProviderExcluded = jest.spyOn( + timelineActions, + 'updateDataProviderExcluded' + ); const wrapper = mount( - + ); @@ -554,6 +441,7 @@ describe('Providers', () => { expect(mockOnToggleDataProviderExcluded.mock.calls[0][0]).toEqual({ andProviderId: 'id-Provider 2', excluded: true, + id: 'test', providerId: 'id-Provider 1', }); }); @@ -561,22 +449,16 @@ describe('Providers', () => { test('while loading data, it does NOT invoke the onToggleDataProviderExcluded callback when you click on the option "Exclude results" in the provider menu', () => { const dataProviders = mockDataProviders.slice(0, 1); dataProviders[0].and = mockDataProviders.slice(1, 3); - const mockOnToggleDataProviderExcluded = jest.fn(); + const mockOnToggleDataProviderExcluded = jest.spyOn( + timelineActions, + 'updateDataProviderExcluded' + ); const wrapper = mount( - + diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/providers.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/providers.tsx index 1142bbc214d74..4b6f3c6701794 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/providers.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/providers.tsx @@ -6,9 +6,12 @@ import { EuiFlexGroup, EuiFlexItem, EuiFormHelpText, EuiSpacer } from '@elastic/eui'; import { rgba } from 'polished'; -import React, { Fragment, useMemo } from 'react'; +import React, { useCallback, useMemo } from 'react'; import { Draggable, DraggingStyle, Droppable, NotDraggingStyle } from 'react-beautiful-dnd'; -import styled, { css } from 'styled-components'; +import styled from 'styled-components'; +import { useDispatch } from 'react-redux'; + +import { timelineActions } from '../../../store/timeline'; import { AndOrBadge } from '../../../../common/components/and_or_badge'; import { AddDataProviderPopover } from './add_data_provider_popover'; @@ -18,13 +21,6 @@ import { IS_DRAGGING_CLASS_NAME, getTimelineProviderDraggableId, } from '../../../../common/components/drag_and_drop/helpers'; -import { - OnDataProviderEdited, - OnDataProviderRemoved, - OnToggleDataProviderEnabled, - OnToggleDataProviderExcluded, - OnToggleDataProviderType, -} from '../events'; import { DataProvider, DataProviderType, DataProvidersAnd, IS_OPERATOR } from './data_provider'; import { EMPTY_GROUP, flattenIntoAndGroups } from './helpers'; @@ -36,11 +32,6 @@ interface Props { browserFields: BrowserFields; timelineId: string; dataProviders: DataProvider[]; - onDataProviderEdited: OnDataProviderEdited; - onDataProviderRemoved: OnDataProviderRemoved; - onToggleDataProviderEnabled: OnToggleDataProviderEnabled; - onToggleDataProviderExcluded: OnToggleDataProviderExcluded; - onToggleDataProviderType: OnToggleDataProviderType; } /** @@ -74,12 +65,10 @@ const DroppableContainer = styled.div` `; const Parens = styled.span` - ${({ theme }) => css` - color: ${theme.eui.euiColorMediumShade}; - font-size: 32px; - padding: 2px; - user-select: none; - `} + color: ${({ theme }) => theme.eui.euiColorMediumShade}; + font-size: 32px; + padding: 2px; + user-select: none; `; const AndOrBadgeContainer = styled.div<{ hideBadge: boolean }>` @@ -123,182 +112,269 @@ const getDataProviderValue = (dataProvider: DataProvidersAnd) => * 2) temporarily disabling a data provider * 3) applying boolean negation to the data provider */ -export const Providers = React.memo( - ({ - browserFields, - timelineId, - dataProviders, - onDataProviderEdited, - onDataProviderRemoved, - onToggleDataProviderEnabled, - onToggleDataProviderExcluded, - onToggleDataProviderType, - }) => { - // Transform the dataProviders into flattened groups, and append an empty group - const dataProviderGroups: DataProvidersAnd[][] = useMemo( - () => [...flattenIntoAndGroups(dataProviders), ...EMPTY_GROUP], - [dataProviders] +export const Providers = React.memo(({ browserFields, timelineId, dataProviders }) => { + // Transform the dataProviders into flattened groups, and append an empty group + const dataProviderGroups: DataProvidersAnd[][] = useMemo( + () => [...flattenIntoAndGroups(dataProviders), ...EMPTY_GROUP], + [dataProviders] + ); + + const content = useMemo( + () => + dataProviderGroups.map((group, groupIndex) => ( + + )), + [browserFields, dataProviderGroups, dataProviders, timelineId] + ); + + return
    {content}
    ; +}); + +Providers.displayName = 'Providers'; + +interface DataProvidersGroupItem extends Omit { + index: number; + dataProvider: DataProvidersAnd; + group: DataProvidersAnd[]; + groupIndex: number; +} + +export const DataProvidersGroupItem = React.memo( + ({ browserFields, group, groupIndex, dataProvider, index, timelineId }) => { + const dispatch = useDispatch(); + const draggableId = useMemo( + () => + getTimelineProviderDraggableId({ + dataProviderId: dataProvider.id, + groupIndex, + timelineId, + }), + [dataProvider.id, groupIndex, timelineId] + ); + + const handleDeleteProvider = useCallback(() => { + const payload = { + id: timelineId, + providerId: index > 0 ? group[0].id : dataProvider.id, + andProviderId: index > 0 ? dataProvider.id : undefined, + }; + + dispatch(timelineActions.removeProvider(payload)); + }, [dataProvider.id, dispatch, group, index, timelineId]); + + const handleToggleEnabledProvider = useCallback(() => { + const payload = { + id: timelineId, + providerId: index > 0 ? group[0].id : dataProvider.id, + enabled: !dataProvider.enabled, + andProviderId: index > 0 ? dataProvider.id : undefined, + }; + + dispatch(timelineActions.updateDataProviderEnabled(payload)); + }, [dataProvider.enabled, dataProvider.id, dispatch, group, index, timelineId]); + + const handleToggleExcludedProvider = useCallback(() => { + const payload = { + id: timelineId, + providerId: index > 0 ? group[0].id : dataProvider.id, + excluded: !dataProvider.excluded, + andProviderId: index > 0 ? dataProvider.id : undefined, + }; + + dispatch(timelineActions.updateDataProviderExcluded(payload)); + }, [dataProvider.excluded, dataProvider.id, dispatch, group, index, timelineId]); + + const handleToggleTypeProvider = useCallback(() => { + const payload = { + id: timelineId, + providerId: index > 0 ? group[0].id : dataProvider.id, + type: + dataProvider.type === DataProviderType.template + ? DataProviderType.default + : DataProviderType.template, + andProviderId: index > 0 ? dataProvider.id : undefined, + }; + + dispatch(timelineActions.updateDataProviderType(payload)); + }, [dataProvider.id, dataProvider.type, dispatch, group, index, timelineId]); + + const handleDataProviderEdited = useCallback( + ({ andProviderId, excluded, field, operator, providerId, value }) => + dispatch( + timelineActions.dataProviderEdited({ + andProviderId, + excluded, + field, + id: timelineId, + operator, + providerId, + value, + }) + ), + [dispatch, timelineId] + ); + + const DraggableContent = useCallback( + (provided, snapshot) => ( +
    + + + 0 ? dataProvider.id : undefined} + browserFields={browserFields} + deleteProvider={handleDeleteProvider} + field={ + index > 0 + ? dataProvider.queryMatch.displayField ?? dataProvider.queryMatch.field + : group[0].queryMatch.displayField ?? group[0].queryMatch.field + } + kqlQuery={index > 0 ? dataProvider.kqlQuery : group[0].kqlQuery} + isEnabled={index > 0 ? dataProvider.enabled : group[0].enabled} + isExcluded={index > 0 ? dataProvider.excluded : group[0].excluded} + onDataProviderEdited={handleDataProviderEdited} + operator={ + index > 0 + ? dataProvider.queryMatch.operator ?? IS_OPERATOR + : group[0].queryMatch.operator ?? IS_OPERATOR + } + register={dataProvider} + providerId={index > 0 ? group[0].id : dataProvider.id} + timelineId={timelineId} + toggleEnabledProvider={handleToggleEnabledProvider} + toggleExcludedProvider={handleToggleExcludedProvider} + toggleTypeProvider={handleToggleTypeProvider} + val={getDataProviderValue(dataProvider)} + type={dataProvider.type} + /> + + + {!snapshot.isDragging && + (index < group.length - 1 ? ( + + ) : ( + + + + ))} + + +
    + ), + [ + browserFields, + dataProvider, + group, + handleDataProviderEdited, + handleDeleteProvider, + handleToggleEnabledProvider, + handleToggleExcludedProvider, + handleToggleTypeProvider, + index, + timelineId, + ] ); return ( -
    - {dataProviderGroups.map((group, groupIndex) => ( - - {groupIndex !== 0 && } - - - - - - - - - {'('} - - - - {(droppableProvided) => ( - - {group.map((dataProvider, index) => ( - - {(provided, snapshot) => ( -
    - - - 0 ? dataProvider.id : undefined} - browserFields={browserFields} - deleteProvider={() => - index > 0 - ? onDataProviderRemoved(group[0].id, dataProvider.id) - : onDataProviderRemoved(dataProvider.id) - } - field={ - index > 0 - ? dataProvider.queryMatch.displayField ?? - dataProvider.queryMatch.field - : group[0].queryMatch.displayField ?? - group[0].queryMatch.field - } - kqlQuery={index > 0 ? dataProvider.kqlQuery : group[0].kqlQuery} - isEnabled={index > 0 ? dataProvider.enabled : group[0].enabled} - isExcluded={ - index > 0 ? dataProvider.excluded : group[0].excluded - } - onDataProviderEdited={onDataProviderEdited} - operator={ - index > 0 - ? dataProvider.queryMatch.operator ?? IS_OPERATOR - : group[0].queryMatch.operator ?? IS_OPERATOR - } - register={dataProvider} - providerId={index > 0 ? group[0].id : dataProvider.id} - timelineId={timelineId} - toggleEnabledProvider={() => - index > 0 - ? onToggleDataProviderEnabled({ - providerId: group[0].id, - enabled: !dataProvider.enabled, - andProviderId: dataProvider.id, - }) - : onToggleDataProviderEnabled({ - providerId: dataProvider.id, - enabled: !dataProvider.enabled, - }) - } - toggleExcludedProvider={() => - index > 0 - ? onToggleDataProviderExcluded({ - providerId: group[0].id, - excluded: !dataProvider.excluded, - andProviderId: dataProvider.id, - }) - : onToggleDataProviderExcluded({ - providerId: dataProvider.id, - excluded: !dataProvider.excluded, - }) - } - toggleTypeProvider={() => - index > 0 - ? onToggleDataProviderType({ - providerId: group[0].id, - type: - dataProvider.type === DataProviderType.template - ? DataProviderType.default - : DataProviderType.template, - andProviderId: dataProvider.id, - }) - : onToggleDataProviderType({ - providerId: dataProvider.id, - type: - dataProvider.type === DataProviderType.template - ? DataProviderType.default - : DataProviderType.template, - }) - } - val={getDataProviderValue(dataProvider)} - type={dataProvider.type} - /> - - - {!snapshot.isDragging && - (index < group.length - 1 ? ( - - ) : ( - - - - ))} - - -
    - )} -
    - ))} - {droppableProvided.placeholder} -
    - )} -
    -
    - - {')'} - - {groupIndex === dataProviderGroups.length - 1 && ( - - )} -
    -
    - ))} -
    + + {DraggableContent} + ); } ); -Providers.displayName = 'Providers'; +DataProvidersGroupItem.displayName = 'DataProvidersGroupItem'; + +interface DataProvidersGroup extends Props { + group: DataProvidersAnd[]; + groupIndex: number; + isLastGroup: boolean; +} + +const DataProvidersGroup = React.memo( + ({ browserFields, timelineId, group, groupIndex, isLastGroup }) => { + const droppableId = useMemo(() => getTimelineProviderDroppableId({ groupIndex, timelineId }), [ + groupIndex, + timelineId, + ]); + + const GroupDataProviders = useMemo( + () => + group.map((dataProvider, index) => ( + + )), + [browserFields, group, groupIndex, timelineId] + ); + + const DroppableContent = useCallback( + (droppableProvided) => ( + + {GroupDataProviders} + {droppableProvided.placeholder} + + ), + [GroupDataProviders, isLastGroup] + ); + + return ( + <> + {groupIndex !== 0 && } + + + + + + + + + {'('} + + + + {DroppableContent} + + + + {')'} + + {isLastGroup && ( + + )} + + + ); + } +); + +DataProvidersGroup.displayName = 'DataProvidersGroup'; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/events.ts b/x-pack/plugins/security_solution/public/timelines/components/timeline/events.ts index f894ac4e73939..8ab3a71604bf1 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/events.ts +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/events.ts @@ -7,33 +7,8 @@ import { ColumnHeaderOptions } from '../../../timelines/store/timeline/model'; import { ColumnId } from './body/column_id'; import { SortDirection } from './body/sort'; -import { DataProvider, DataProviderType, QueryOperator } from './data_providers/data_provider'; +import { DataProvider, QueryOperator } from './data_providers/data_provider'; -/** Invoked when a user clicks the close button to remove a data provider */ -export type OnDataProviderRemoved = (providerId: string, andProviderId?: string) => void; - -/** Invoked when a user temporarily disables or re-enables a data provider */ -export type OnToggleDataProviderEnabled = (toggled: { - providerId: string; - enabled: boolean; - andProviderId?: string; -}) => void; - -/** Invoked when a user toggles negation ("boolean NOT") of a data provider */ -export type OnToggleDataProviderExcluded = (excluded: { - providerId: string; - excluded: boolean; - andProviderId?: string; -}) => void; - -/** Invoked when a user toggles type (can "default" or "template") of a data provider */ -export type OnToggleDataProviderType = (type: { - providerId: string; - type: DataProviderType; - andProviderId?: string; -}) => void; - -/** Invoked when a user edits the properties of a data provider */ export type OnDataProviderEdited = ({ andProviderId, excluded, @@ -54,9 +29,6 @@ export type OnDataProviderEdited = ({ type: DataProvider['type']; }) => void; -/** Invoked when a user change the kql query of our data provider */ -export type OnChangeDataProviderKqlQuery = (edit: { providerId: string; kqlQuery: string }) => void; - /** Invoked when a user selects a new minimap time range */ export type OnRangeSelected = (range: string) => void; @@ -76,8 +48,6 @@ export type OnChangeItemsPerPage = (itemsPerPage: number) => void; /** Invoked when a user clicks to load more item */ export type OnChangePage = (nextPage: number) => void; -export type OnChangeDroppableAndProvider = (providerId: string) => void; - /** Invoked when a user pins an event */ export type OnPinEvent = (eventId: string) => void; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/footer/__snapshots__/index.test.tsx.snap b/x-pack/plugins/security_solution/public/timelines/components/timeline/footer/__snapshots__/index.test.tsx.snap index f81934f9a1d91..5b14edf818fdc 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/footer/__snapshots__/index.test.tsx.snap +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/footer/__snapshots__/index.test.tsx.snap @@ -77,7 +77,7 @@ exports[`Footer Timeline Component rendering it renders the default timeline foo data-test-subj="paging-control" isLoading={false} onPageClick={[Function]} - totalPages={2} + totalPages={5} /> { const loadMore = jest.fn(); const onChangeItemsPerPage = jest.fn(); const updatedAt = 1546878704036; - const totalCount = 15546; + const serverSideEventCount = 15546; const itemsCount = 2; + const totalCount = 10; describe('rendering', () => { test('it renders the default timeline footer', () => { @@ -33,8 +34,8 @@ describe('Footer Timeline Component', () => { itemsPerPageOptions={[1, 5, 10, 20]} onChangeItemsPerPage={onChangeItemsPerPage} onChangePage={loadMore} - serverSideEventCount={totalCount} - totalPages={2} + serverSideEventCount={serverSideEventCount} + totalCount={totalCount} /> ); @@ -55,8 +56,8 @@ describe('Footer Timeline Component', () => { itemsPerPageOptions={[1, 5, 10, 20]} onChangeItemsPerPage={onChangeItemsPerPage} onChangePage={loadMore} - serverSideEventCount={totalCount} - totalPages={2} + serverSideEventCount={serverSideEventCount} + totalCount={totalCount} /> ); @@ -78,8 +79,8 @@ describe('Footer Timeline Component', () => { itemsPerPageOptions={[1, 5, 10, 20]} onChangeItemsPerPage={onChangeItemsPerPage} onChangePage={loadMore} - serverSideEventCount={totalCount} - totalPages={2} + serverSideEventCount={serverSideEventCount} + totalCount={totalCount} /> ); @@ -129,8 +130,8 @@ describe('Footer Timeline Component', () => { itemsPerPageOptions={[1, 5, 10, 20]} onChangeItemsPerPage={onChangeItemsPerPage} onChangePage={loadMore} - serverSideEventCount={totalCount} - totalPages={2} + serverSideEventCount={serverSideEventCount} + totalCount={totalCount} /> ); @@ -152,8 +153,8 @@ describe('Footer Timeline Component', () => { itemsPerPageOptions={[1, 5, 10, 20]} onChangeItemsPerPage={onChangeItemsPerPage} onChangePage={loadMore} - serverSideEventCount={totalCount} - totalPages={2} + serverSideEventCount={serverSideEventCount} + totalCount={totalCount} /> ); @@ -179,8 +180,8 @@ describe('Footer Timeline Component', () => { itemsPerPageOptions={[1, 5, 10, 20]} onChangeItemsPerPage={onChangeItemsPerPage} onChangePage={loadMore} - serverSideEventCount={totalCount} - totalPages={2} + serverSideEventCount={serverSideEventCount} + totalCount={totalCount} /> ); @@ -204,8 +205,8 @@ describe('Footer Timeline Component', () => { itemsPerPageOptions={[1, 5, 10, 20]} onChangeItemsPerPage={onChangeItemsPerPage} onChangePage={loadMore} - serverSideEventCount={totalCount} - totalPages={2} + serverSideEventCount={serverSideEventCount} + totalCount={totalCount} /> ); @@ -231,8 +232,8 @@ describe('Footer Timeline Component', () => { itemsPerPageOptions={[1, 5, 10, 20]} onChangeItemsPerPage={onChangeItemsPerPage} onChangePage={loadMore} - serverSideEventCount={totalCount} - totalPages={2} + serverSideEventCount={serverSideEventCount} + totalCount={totalCount} /> ); @@ -256,8 +257,8 @@ describe('Footer Timeline Component', () => { itemsPerPageOptions={[1, 5, 10, 20]} onChangeItemsPerPage={onChangeItemsPerPage} onChangePage={loadMore} - serverSideEventCount={totalCount} - totalPages={2} + serverSideEventCount={serverSideEventCount} + totalCount={totalCount} /> ); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/footer/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/footer/index.tsx index 7174e9b2121e5..7c10168da3c62 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/footer/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/footer/index.tsx @@ -174,30 +174,36 @@ export const EventsCount = React.memo(EventsCountComponent); EventsCount.displayName = 'EventsCount'; -export const PagingControlComponent = ({ - activePage, - isLoading, - onPageClick, - totalPages, -}: { +interface PagingControlProps { activePage: number; isLoading: boolean; onPageClick: OnChangePage; totalPages: number; -}) => ( - <> - {isLoading ? ( - `${i18n.LOADING}...` - ) : ( - - )} - -); +} + +export const PagingControlComponent: React.FC = ({ + activePage, + isLoading, + onPageClick, + totalPages, +}) => { + if (isLoading) { + return <>{`${i18n.LOADING}...`}; + } + + if (!totalPages) { + return null; + } + + return ( + + ); +}; PagingControlComponent.displayName = 'PagingControlComponent'; @@ -217,7 +223,7 @@ interface FooterProps { onChangeItemsPerPage: OnChangeItemsPerPage; onChangePage: OnChangePage; serverSideEventCount: number; - totalPages: number; + totalCount: number; } /** Renders a loading indicator and paging controls */ @@ -234,7 +240,7 @@ export const FooterComponent = ({ onChangeItemsPerPage, onChangePage, serverSideEventCount, - totalPages, + totalCount, }: FooterProps) => { const [isPopoverOpen, setIsPopoverOpen] = useState(false); const [paginationLoading, setPaginationLoading] = useState(false); @@ -259,6 +265,30 @@ export const FooterComponent = ({ ]); const closePopover = useCallback(() => setIsPopoverOpen(false), [setIsPopoverOpen]); + const rowItems = useMemo( + () => + itemsPerPageOptions && + itemsPerPageOptions.map((item) => ( + { + closePopover(); + onChangeItemsPerPage(item); + }} + > + {`${item} ${i18n.ROWS}`} + + )), + [closePopover, itemsPerPage, itemsPerPageOptions, onChangeItemsPerPage] + ); + + const totalPages = useMemo(() => Math.ceil(totalCount / itemsPerPage), [ + itemsPerPage, + totalCount, + ]); + useEffect(() => { if (paginationLoading && !isLoading) { setPaginationLoading(false); @@ -279,22 +309,6 @@ export const FooterComponent = ({ ); } - const rowItems = - itemsPerPageOptions && - itemsPerPageOptions.map((item) => ( - { - closePopover(); - onChangeItemsPerPage(item); - }} - > - {`${item} ${i18n.ROWS}`} - - )); - return ( = ({ dataProviders, filterManager, graphEventId, - onDataProviderEdited, - onDataProviderRemoved, - onToggleDataProviderEnabled, - onToggleDataProviderExcluded, - onToggleDataProviderType, show, showCallOutUnauthorizedMsg, status, @@ -85,11 +68,6 @@ const TimelineHeaderComponent: React.FC = ({ browserFields={browserFields} timelineId={timelineId} dataProviders={dataProviders} - onDataProviderEdited={onDataProviderEdited} - onDataProviderRemoved={onDataProviderRemoved} - onToggleDataProviderEnabled={onToggleDataProviderEnabled} - onToggleDataProviderExcluded={onToggleDataProviderExcluded} - onToggleDataProviderType={onToggleDataProviderType} /> ( kqlMode, kqlQueryExpression, onClose, - onDataProviderEdited, removeColumn, - removeProvider, show, showCallOutUnauthorizedMsg, sort, start, status, timelineType, - updateDataProviderEnabled, - updateDataProviderExcluded, - updateDataProviderType, updateItemsPerPage, upsertColumn, usersViewing, @@ -75,59 +63,6 @@ const StatefulTimelineComponent = React.memo( selectedPatterns, } = useSourcererScope(SourcererScopeName.timeline); - const onDataProviderRemoved: OnDataProviderRemoved = useCallback( - (providerId: string, andProviderId?: string) => - removeProvider!({ id, providerId, andProviderId }), - [id, removeProvider] - ); - - const onToggleDataProviderEnabled: OnToggleDataProviderEnabled = useCallback( - ({ providerId, enabled, andProviderId }) => - updateDataProviderEnabled!({ - id, - enabled, - providerId, - andProviderId, - }), - [id, updateDataProviderEnabled] - ); - - const onToggleDataProviderExcluded: OnToggleDataProviderExcluded = useCallback( - ({ providerId, excluded, andProviderId }) => - updateDataProviderExcluded!({ - id, - excluded, - providerId, - andProviderId, - }), - [id, updateDataProviderExcluded] - ); - - const onToggleDataProviderType: OnToggleDataProviderType = useCallback( - ({ providerId, type, andProviderId }) => - updateDataProviderType!({ - id, - type, - providerId, - andProviderId, - }), - [id, updateDataProviderType] - ); - - const onDataProviderEditedLocal: OnDataProviderEdited = useCallback( - ({ andProviderId, excluded, field, operator, providerId, value }) => - onDataProviderEdited!({ - andProviderId, - excluded, - field, - id, - operator, - providerId, - value, - }), - [id, onDataProviderEdited] - ); - const onChangeItemsPerPage: OnChangeItemsPerPage = useCallback( (itemsChangedPerPage) => updateItemsPerPage!({ id, itemsPerPage: itemsChangedPerPage }), [id, updateItemsPerPage] @@ -183,11 +118,6 @@ const StatefulTimelineComponent = React.memo( loadingSourcerer={loading} onChangeItemsPerPage={onChangeItemsPerPage} onClose={onClose} - onDataProviderEdited={onDataProviderEditedLocal} - onDataProviderRemoved={onDataProviderRemoved} - onToggleDataProviderEnabled={onToggleDataProviderEnabled} - onToggleDataProviderExcluded={onToggleDataProviderExcluded} - onToggleDataProviderType={onToggleDataProviderType} show={show!} showCallOutUnauthorizedMsg={showCallOutUnauthorizedMsg} sort={sort!} @@ -287,14 +217,8 @@ const makeMapStateToProps = () => { const mapDispatchToProps = { addProvider: timelineActions.addProvider, createTimeline: timelineActions.createTimeline, - onDataProviderEdited: timelineActions.dataProviderEdited, removeColumn: timelineActions.removeColumn, - removeProvider: timelineActions.removeProvider, updateColumns: timelineActions.updateColumns, - updateDataProviderEnabled: timelineActions.updateDataProviderEnabled, - updateDataProviderExcluded: timelineActions.updateDataProviderExcluded, - updateDataProviderKqlQuery: timelineActions.updateDataProviderKqlQuery, - updateDataProviderType: timelineActions.updateDataProviderType, updateHighlightedDropAndProviderId: timelineActions.updateHighlightedDropAndProviderId, updateItemsPerPage: timelineActions.updateItemsPerPage, updateItemsPerPageOptions: timelineActions.updateItemsPerPageOptions, diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/properties/helpers.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/properties/helpers.tsx index 43ab8ab203e11..a28f4240d3a2f 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/properties/helpers.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/properties/helpers.tsx @@ -73,23 +73,31 @@ export const StarIcon = React.memo<{ isFavorite: boolean; timelineId: string; updateIsFavorite: UpdateIsFavorite; -}>(({ isFavorite, timelineId: id, updateIsFavorite }) => ( - // TODO: 1 error is: Visible, non-interactive elements with click handlers must have at least one keyboard listener - // TODO: 2 error is: Elements with the 'button' interactive role must be focusable - // TODO: Investigate this error - // eslint-disable-next-line -
    updateIsFavorite({ id, isFavorite: !isFavorite })}> - {isFavorite ? ( - - - - ) : ( - - - - )} -
    -)); +}>(({ isFavorite, timelineId: id, updateIsFavorite }) => { + const handleClick = useCallback(() => updateIsFavorite({ id, isFavorite: !isFavorite }), [ + id, + isFavorite, + updateIsFavorite, + ]); + + return ( + // TODO: 1 error is: Visible, non-interactive elements with click handlers must have at least one keyboard listener + // TODO: 2 error is: Elements with the 'button' interactive role must be focusable + // TODO: Investigate this error + // eslint-disable-next-line +
    + {isFavorite ? ( + + + + ) : ( + + + + )} +
    + ); +}); StarIcon.displayName = 'StarIcon'; interface DescriptionProps { diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/timeline.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/timeline.test.tsx index bde1e7bf5829a..630a71693d182 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/timeline.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/timeline.test.tsx @@ -19,11 +19,6 @@ import { import '../../../common/mock/match_media'; import { TestProviders } from '../../../common/mock/test_providers'; -import { - DELETE_CLASS_NAME, - ENABLE_CLASS_NAME, - EXCLUDE_CLASS_NAME, -} from './data_providers/provider_item_actions'; import { TimelineComponent, Props as TimelineComponentProps } from './timeline'; import { Sort } from './body/sort'; import { mockDataProviders } from './data_providers/mock/mock_data_providers'; @@ -115,11 +110,6 @@ describe('Timeline', () => { loadingSourcerer: false, onChangeItemsPerPage: jest.fn(), onClose: jest.fn(), - onDataProviderEdited: jest.fn(), - onDataProviderRemoved: jest.fn(), - onToggleDataProviderEnabled: jest.fn(), - onToggleDataProviderExcluded: jest.fn(), - onToggleDataProviderType: jest.fn(), show: true, showCallOutUnauthorizedMsg: false, sort, @@ -238,204 +228,4 @@ describe('Timeline', () => { }); }); }); - - describe('event wire up', () => { - describe('onDataProviderRemoved', () => { - test('it invokes the onDataProviderRemoved callback when the delete button on a provider is clicked', () => { - const wrapper = mount( - - - - ); - - wrapper - .find('[data-test-subj="providerBadge"] [data-euiicon-type]') - .first() - .simulate('click'); - - expect((props.onDataProviderRemoved as jest.Mock).mock.calls[0][0]).toEqual( - 'id-Provider 1' - ); - }); - - test('it invokes the onDataProviderRemoved callback when you click on the option "Delete" in the provider menu', () => { - const wrapper = mount( - - - - ); - wrapper.find('button[data-test-subj="providerBadge"]').first().simulate('click'); - - wrapper.update(); - - wrapper - .find(`[data-test-subj="providerActions"] .${DELETE_CLASS_NAME}`) - .first() - .simulate('click'); - - expect((props.onDataProviderRemoved as jest.Mock).mock.calls[0][0]).toEqual( - 'id-Provider 1' - ); - }); - }); - - describe('onToggleDataProviderEnabled', () => { - test('it invokes the onToggleDataProviderEnabled callback when you click on the option "Temporary disable" in the provider menu', () => { - const wrapper = mount( - - - - ); - - wrapper.find('button[data-test-subj="providerBadge"]').first().simulate('click'); - - wrapper.update(); - - wrapper - .find(`[data-test-subj="providerActions"] .${ENABLE_CLASS_NAME}`) - .first() - .simulate('click'); - - expect((props.onToggleDataProviderEnabled as jest.Mock).mock.calls[0][0]).toEqual({ - providerId: 'id-Provider 1', - enabled: false, - }); - }); - }); - - describe('onToggleDataProviderExcluded', () => { - test('it invokes the onToggleDataProviderExcluded callback when you click on the option "Exclude results" in the provider menu', () => { - const wrapper = mount( - - - - ); - - wrapper - .find('[data-test-subj="providerBadge"]') - .first() - .find('button') - .first() - .simulate('click'); - - wrapper.update(); - - wrapper - .find(`[data-test-subj="providerActions"] .${EXCLUDE_CLASS_NAME}`) - .first() - .simulate('click'); - - expect((props.onToggleDataProviderExcluded as jest.Mock).mock.calls[0][0]).toEqual({ - providerId: 'id-Provider 1', - excluded: true, - }); - }); - }); - - describe('#ProviderWithAndProvider', () => { - const dataProviders = mockDataProviders.slice(0, 1); - dataProviders[0].and = mockDataProviders.slice(1, 3); - - test('Rendering And Provider', () => { - const wrapper = mount( - - - - ); - - const andProviderBadges = wrapper.find( - '[data-test-subj="providerBadge"] .euiBadge__content span.field-value' - ); - - const andProviderBadgesText = andProviderBadges.map((node) => node.text()).join(' '); - expect(andProviderBadges.length).toEqual(3); - expect(andProviderBadgesText).toEqual( - 'name: "Provider 1" name: "Provider 2" name: "Provider 3"' - ); - }); - - test('it invokes the onDataProviderRemoved callback when you click on the option "Delete" in the accordion menu', () => { - const wrapper = mount( - - - - ); - - wrapper - .find('[data-test-subj="providerBadge"]') - .at(3) - .find('button') - .first() - .simulate('click'); - - wrapper.update(); - - wrapper - .find(`[data-test-subj="providerActions"] .${DELETE_CLASS_NAME}`) - .first() - .simulate('click'); - - expect((props.onDataProviderRemoved as jest.Mock).mock.calls[0]).toEqual([ - 'id-Provider 1', - 'id-Provider 2', - ]); - }); - - test('it invokes the onToggleDataProviderEnabled callback when you click on the option "Temporary disable" in the accordion menu', () => { - const wrapper = mount( - - - - ); - - wrapper - .find('[data-test-subj="providerBadge"]') - .at(3) - .find('button') - .first() - .simulate('click'); - - wrapper.update(); - - wrapper - .find(`[data-test-subj="providerActions"] .${ENABLE_CLASS_NAME}`) - .first() - .simulate('click'); - - expect((props.onToggleDataProviderEnabled as jest.Mock).mock.calls[0][0]).toEqual({ - andProviderId: 'id-Provider 2', - enabled: false, - providerId: 'id-Provider 1', - }); - }); - - test('it invokes the onToggleDataProviderExcluded callback when you click on the option "Exclude results" in the accordion menu', () => { - const wrapper = mount( - - - - ); - - wrapper - .find('[data-test-subj="providerBadge"]') - .at(3) - .find('button') - .first() - .simulate('click'); - - wrapper.update(); - - wrapper - .find(`[data-test-subj="providerActions"] .${EXCLUDE_CLASS_NAME}`) - .first() - .simulate('click'); - - expect((props.onToggleDataProviderExcluded as jest.Mock).mock.calls[0][0]).toEqual({ - andProviderId: 'id-Provider 2', - excluded: true, - providerId: 'id-Provider 1', - }); - }); - }); - }); }); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/timeline.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/timeline.tsx index d1a25e6f3e1a4..1097d58b227a8 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/timeline.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/timeline.tsx @@ -19,14 +19,7 @@ import { defaultHeaders } from './body/column_headers/default_headers'; import { Sort } from './body/sort'; import { StatefulBody } from './body/stateful_body'; import { DataProvider } from './data_providers/data_provider'; -import { - OnChangeItemsPerPage, - OnDataProviderRemoved, - OnDataProviderEdited, - OnToggleDataProviderEnabled, - OnToggleDataProviderExcluded, - OnToggleDataProviderType, -} from './events'; +import { OnChangeItemsPerPage } from './events'; import { TimelineKqlFetch } from './fetch_kql_timeline'; import { Footer, footerHeight } from './footer'; import { TimelineHeader } from './header'; @@ -113,11 +106,6 @@ export interface Props { loadingSourcerer: boolean; onChangeItemsPerPage: OnChangeItemsPerPage; onClose: () => void; - onDataProviderEdited: OnDataProviderEdited; - onDataProviderRemoved: OnDataProviderRemoved; - onToggleDataProviderEnabled: OnToggleDataProviderEnabled; - onToggleDataProviderExcluded: OnToggleDataProviderExcluded; - onToggleDataProviderType: OnToggleDataProviderType; show: boolean; showCallOutUnauthorizedMsg: boolean; sort: Sort; @@ -149,11 +137,6 @@ export const TimelineComponent: React.FC = ({ kqlQueryExpression, onChangeItemsPerPage, onClose, - onDataProviderEdited, - onDataProviderRemoved, - onToggleDataProviderEnabled, - onToggleDataProviderExcluded, - onToggleDataProviderType, show, showCallOutUnauthorizedMsg, start, @@ -270,11 +253,6 @@ export const TimelineComponent: React.FC = ({ dataProviders={dataProviders} filterManager={filterManager} graphEventId={graphEventId} - onDataProviderEdited={onDataProviderEdited} - onDataProviderRemoved={onDataProviderRemoved} - onToggleDataProviderEnabled={onToggleDataProviderEnabled} - onToggleDataProviderExcluded={onToggleDataProviderExcluded} - onToggleDataProviderType={onToggleDataProviderType} show={show} showCallOutUnauthorizedMsg={showCallOutUnauthorizedMsg} timelineId={id} @@ -324,7 +302,7 @@ export const TimelineComponent: React.FC = ({ onChangeItemsPerPage={onChangeItemsPerPage} onChangePage={loadPage} serverSideEventCount={totalCount} - totalPages={pageInfo.totalPages} + totalCount={pageInfo.fakeTotalCount} /> ) 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 54db52b985c31..53944fd29a687 100644 --- a/x-pack/plugins/security_solution/public/timelines/containers/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/containers/index.tsx @@ -15,11 +15,13 @@ import { inputsModel } from '../../common/store'; import { useKibana } from '../../common/lib/kibana'; import { createFilter } from '../../common/containers/helpers'; import { DocValueFields } from '../../common/containers/query_template'; +import { generateTablePaginationOptions } from '../../common/components/paginated_table/helpers'; import { timelineActions } from '../../timelines/store/timeline'; import { detectionsTimelineIds, skipQueryForDetectionsPage } from './helpers'; import { getInspectResponse } from '../../helpers'; import { Direction, + PageInfoPaginated, TimelineEventsQueries, TimelineEventsAllStrategyResponse, TimelineEventsAllRequestOptions, @@ -35,10 +37,7 @@ export interface TimelineArgs { id: string; inspect: InspectResponse; loadPage: LoadPage; - pageInfo: { - activePage: number; - totalPages: number; - }; + pageInfo: PageInfoPaginated; refetch: inputsModel.Refetch; totalCount: number; updatedAt: number; @@ -97,10 +96,7 @@ export const useTimelineEvents = ({ from: startDate, to: endDate, }, - pagination: { - activePage, - querySize: limit, - }, + pagination: generateTablePaginationOptions(activePage, limit), sort, defaultIndex: indexNames, docValueFields: docValueFields ?? [], @@ -134,7 +130,8 @@ export const useTimelineEvents = ({ totalCount: -1, pageInfo: { activePage: 0, - totalPages: 0, + fakeTotalCount: 0, + showMorePagesIndicator: false, }, events: [], loadPage: wrappedLoadPage, @@ -218,10 +215,7 @@ export const useTimelineEvents = ({ defaultIndex: indexNames, docValueFields: docValueFields ?? [], filterQuery: createFilter(filterQuery), - pagination: { - activePage, - querySize: limit, - }, + pagination: generateTablePaginationOptions(activePage, limit), timerange: { interval: '12h', from: startDate, diff --git a/x-pack/plugins/security_solution/public/timelines/store/timeline/epic_local_storage.test.tsx b/x-pack/plugins/security_solution/public/timelines/store/timeline/epic_local_storage.test.tsx index 1f79b26394a69..1992b1f88f064 100644 --- a/x-pack/plugins/security_solution/public/timelines/store/timeline/epic_local_storage.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/store/timeline/epic_local_storage.test.tsx @@ -96,11 +96,6 @@ describe('epicLocalStorage', () => { loadingSourcerer: false, onChangeItemsPerPage: jest.fn(), onClose: jest.fn(), - onDataProviderEdited: jest.fn(), - onDataProviderRemoved: jest.fn(), - onToggleDataProviderEnabled: jest.fn(), - onToggleDataProviderExcluded: jest.fn(), - onToggleDataProviderType: jest.fn(), show: true, showCallOutUnauthorizedMsg: false, start: startDate, diff --git a/x-pack/plugins/security_solution/public/timelines/store/timeline/helpers.ts b/x-pack/plugins/security_solution/public/timelines/store/timeline/helpers.ts index fc178df86362b..30d0796443ab5 100644 --- a/x-pack/plugins/security_solution/public/timelines/store/timeline/helpers.ts +++ b/x-pack/plugins/security_solution/public/timelines/store/timeline/helpers.ts @@ -1209,17 +1209,20 @@ export const updateTimelinePerPageOptions = ({ const removeAndProvider = (andProviderId: string, providerId: string, timeline: TimelineModel) => { const providerIndex = timeline.dataProviders.findIndex((p) => p.id === providerId); - const providerAndIndex = timeline.dataProviders[providerIndex].and.findIndex( + const providerAndIndex = timeline.dataProviders[providerIndex]?.and.findIndex( (p) => p.id === andProviderId ); + return [ ...timeline.dataProviders.slice(0, providerIndex), { ...timeline.dataProviders[providerIndex], - and: [ - ...timeline.dataProviders[providerIndex].and.slice(0, providerAndIndex), - ...timeline.dataProviders[providerIndex].and.slice(providerAndIndex + 1), - ], + and: timeline.dataProviders[providerIndex]?.and + ? [ + ...timeline.dataProviders[providerIndex]?.and.slice(0, providerAndIndex), + ...timeline.dataProviders[providerIndex]?.and.slice(providerAndIndex + 1), + ] + : [], }, ...timeline.dataProviders.slice(providerIndex + 1), ]; @@ -1229,7 +1232,7 @@ const removeProvider = (providerId: string, timeline: TimelineModel) => { const providerIndex = timeline.dataProviders.findIndex((p) => p.id === providerId); return [ ...timeline.dataProviders.slice(0, providerIndex), - ...(timeline.dataProviders[providerIndex].and.length + ...(timeline.dataProviders[providerIndex]?.and.length ? [ { ...timeline.dataProviders[providerIndex].and.slice(0, 1)[0], diff --git a/x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/all/index.ts b/x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/all/index.ts index 12729eb88a666..6b28fc2598d41 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/all/index.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/all/index.ts @@ -42,17 +42,19 @@ export const timelineEventsAll: SecuritySolutionTimelineFactory + const edges: TimelineEdges[] = hits.splice(cursorStart, querySize - cursorStart).map((hit) => // @ts-expect-error formatTimelineData(options.fieldRequested, TIMELINE_EVENTS_FIELDS, hit, eventFieldsMap) ); const inspect = { dsl: [inspectStringifyObject(buildTimelineEventsAllQuery(queryOptions))], }; + const fakeTotalCount = fakePossibleCount <= totalCount ? fakePossibleCount : totalCount; + const showMorePagesIndicator = totalCount > fakeTotalCount; return { ...response, @@ -61,7 +63,8 @@ export const timelineEventsAll: SecuritySolutionTimelineFactory Date: Fri, 2 Oct 2020 11:22:41 +0200 Subject: [PATCH 29/50] [Discover] Change context query to prevent duplicates (#77014) --- .../application/angular/context/api/_stubs.js | 2 +- .../context/api/context.predecessors.test.js | 8 ++++++-- .../context/api/context.successors.test.js | 8 ++++++-- .../angular/context/api/context.ts | 4 +++- .../api/utils/fetch_hits_in_interval.ts | 20 ++++++++++++++----- 5 files changed, 31 insertions(+), 11 deletions(-) diff --git a/src/plugins/discover/public/application/angular/context/api/_stubs.js b/src/plugins/discover/public/application/angular/context/api/_stubs.js index 35ddf396c2dba..d82189db60935 100644 --- a/src/plugins/discover/public/application/angular/context/api/_stubs.js +++ b/src/plugins/discover/public/application/angular/context/api/_stubs.js @@ -74,7 +74,7 @@ export function createContextSearchSourceStub(hits, timeField = '@timestamp') { searchSourceStub.fetch = sinon.spy(() => { const timeField = searchSourceStub._stubTimeField; const lastQuery = searchSourceStub.setField.withArgs('query').lastCall.args[1]; - const timeRange = lastQuery.query.constant_score.filter.range[timeField]; + const timeRange = lastQuery.query.bool.must.constant_score.filter.range[timeField]; const lastSort = searchSourceStub.setField.withArgs('sort').lastCall.args[1]; const sortDirection = lastSort[0][timeField]; const sortFunction = diff --git a/src/plugins/discover/public/application/angular/context/api/context.predecessors.test.js b/src/plugins/discover/public/application/angular/context/api/context.predecessors.test.js index 4987c77f4bf25..4c0515906a494 100644 --- a/src/plugins/discover/public/application/angular/context/api/context.predecessors.test.js +++ b/src/plugins/discover/public/application/angular/context/api/context.predecessors.test.js @@ -124,7 +124,9 @@ describe('context app', function () { ).then((hits) => { const intervals = mockSearchSource.setField.args .filter(([property]) => property === 'query') - .map(([, { query }]) => get(query, ['constant_score', 'filter', 'range', '@timestamp'])); + .map(([, { query }]) => + get(query, ['bool', 'must', 'constant_score', 'filter', 'range', '@timestamp']) + ); expect( intervals.every(({ gte, lte }) => (gte && lte ? moment(gte).isBefore(lte) : true)) @@ -160,7 +162,9 @@ describe('context app', function () { ).then((hits) => { const intervals = mockSearchSource.setField.args .filter(([property]) => property === 'query') - .map(([, { query }]) => get(query, ['constant_score', 'filter', 'range', '@timestamp'])); + .map(([, { query }]) => + get(query, ['bool', 'must', 'constant_score', 'filter', 'range', '@timestamp']) + ); // should have started at the given time expect(intervals[0].gte).toEqual(moment(MS_PER_DAY * 1000).toISOString()); diff --git a/src/plugins/discover/public/application/angular/context/api/context.successors.test.js b/src/plugins/discover/public/application/angular/context/api/context.successors.test.js index ebf6e78585962..285d39cd4d8a4 100644 --- a/src/plugins/discover/public/application/angular/context/api/context.successors.test.js +++ b/src/plugins/discover/public/application/angular/context/api/context.successors.test.js @@ -125,7 +125,9 @@ describe('context app', function () { ).then((hits) => { const intervals = mockSearchSource.setField.args .filter(([property]) => property === 'query') - .map(([, { query }]) => get(query, ['constant_score', 'filter', 'range', '@timestamp'])); + .map(([, { query }]) => + get(query, ['bool', 'must', 'constant_score', 'filter', 'range', '@timestamp']) + ); expect( intervals.every(({ gte, lte }) => (gte && lte ? moment(gte).isBefore(lte) : true)) @@ -163,7 +165,9 @@ describe('context app', function () { ).then((hits) => { const intervals = mockSearchSource.setField.args .filter(([property]) => property === 'query') - .map(([, { query }]) => get(query, ['constant_score', 'filter', 'range', '@timestamp'])); + .map(([, { query }]) => + get(query, ['bool', 'must', 'constant_score', 'filter', 'range', '@timestamp']) + ); // should have started at the given time expect(intervals[0].lte).toEqual(moment(MS_PER_DAY * 3000).toISOString()); diff --git a/src/plugins/discover/public/application/angular/context/api/context.ts b/src/plugins/discover/public/application/angular/context/api/context.ts index e244176914a9b..ba8cffd1d7558 100644 --- a/src/plugins/discover/public/application/angular/context/api/context.ts +++ b/src/plugins/discover/public/application/angular/context/api/context.ts @@ -31,6 +31,7 @@ export interface EsHitRecord { fields: Record; sort: number[]; _source: Record; + _id: string; } export type EsHitRecordList = EsHitRecord[]; @@ -100,7 +101,8 @@ function fetchContextProvider(indexPatterns: IndexPatternsContract) { interval, searchAfter, remainingSize, - nanos + nanos, + anchor._id ); documents = diff --git a/src/plugins/discover/public/application/angular/context/api/utils/fetch_hits_in_interval.ts b/src/plugins/discover/public/application/angular/context/api/utils/fetch_hits_in_interval.ts index 9a199ea4a62fc..5ac4164191633 100644 --- a/src/plugins/discover/public/application/angular/context/api/utils/fetch_hits_in_interval.ts +++ b/src/plugins/discover/public/application/angular/context/api/utils/fetch_hits_in_interval.ts @@ -43,7 +43,8 @@ export async function fetchHitsInInterval( interval: IntervalValue[], searchAfter: EsQuerySearchAfter, maxCount: number, - nanosValue: string + nanosValue: string, + anchorId: string ): Promise { const range: RangeQuery = { format: 'strict_date_optional_time', @@ -61,10 +62,19 @@ export async function fetchHitsInInterval( .setField('size', maxCount) .setField('query', { query: { - constant_score: { - filter: { - range: { - [timeField]: range, + bool: { + must: { + constant_score: { + filter: { + range: { + [timeField]: range, + }, + }, + }, + }, + must_not: { + ids: { + values: [anchorId], }, }, }, From e52884cfa285ee0aeae6ba1ad7655efefddb67c3 Mon Sep 17 00:00:00 2001 From: Pete Hampton Date: Fri, 2 Oct 2020 10:28:37 +0100 Subject: [PATCH 30/50] [7.10][Telemetry] Display collected security event sample (#78963) * Add security example to usage data opt in panel. * Update translations. * Fix docs. * Fix broken type. Co-authored-by: Elastic Machine --- docs/developer/plugin-list.asciidoc | 2 +- .../telemetry_management_section/README.md | 2 +- ...t_in_security_example_flyout.test.tsx.snap | 134 ++++++++++ ...telemetry_management_section.test.tsx.snap | 35 ++- .../opt_in_security_example_flyout.test.tsx | 27 ++ .../opt_in_security_example_flyout.tsx | 235 ++++++++++++++++++ .../telemetry_management_section.test.tsx | 38 ++- .../telemetry_management_section.tsx | 37 ++- .../translations/translations/ja-JP.json | 1 - .../translations/translations/zh-CN.json | 1 - 10 files changed, 491 insertions(+), 21 deletions(-) create mode 100644 src/plugins/telemetry_management_section/public/components/__snapshots__/opt_in_security_example_flyout.test.tsx.snap create mode 100644 src/plugins/telemetry_management_section/public/components/opt_in_security_example_flyout.test.tsx create mode 100644 src/plugins/telemetry_management_section/public/components/opt_in_security_example_flyout.tsx diff --git a/docs/developer/plugin-list.asciidoc b/docs/developer/plugin-list.asciidoc index ed58e77427d47..bf11f87b96ce9 100644 --- a/docs/developer/plugin-list.asciidoc +++ b/docs/developer/plugin-list.asciidoc @@ -168,7 +168,7 @@ It also provides a stateful version of it on the start contract. |{kib-repo}blob/{branch}/src/plugins/telemetry_management_section/README.md[telemetryManagementSection] -|This plugin adds the Advanced Settings section for the Usage Data collection (aka Telemetry). +|This plugin adds the Advanced Settings section for the Usage and Security Data collection (aka Telemetry). |{kib-repo}blob/{branch}/src/plugins/tile_map[tileMap] diff --git a/src/plugins/telemetry_management_section/README.md b/src/plugins/telemetry_management_section/README.md index 0f795786720c9..c23a8591f6794 100644 --- a/src/plugins/telemetry_management_section/README.md +++ b/src/plugins/telemetry_management_section/README.md @@ -1,5 +1,5 @@ # Telemetry Management Section -This plugin adds the Advanced Settings section for the Usage Data collection (aka Telemetry). +This plugin adds the Advanced Settings section for the Usage and Security Data collection (aka Telemetry). The reason for having it separated from the `telemetry` plugin is to avoid circular dependencies. The plugin `advancedSettings` depends on the `home` app that depends on the `telemetry` plugin because of the telemetry banner in the welcome screen. diff --git a/src/plugins/telemetry_management_section/public/components/__snapshots__/opt_in_security_example_flyout.test.tsx.snap b/src/plugins/telemetry_management_section/public/components/__snapshots__/opt_in_security_example_flyout.test.tsx.snap new file mode 100644 index 0000000000000..0b9d426008ca4 --- /dev/null +++ b/src/plugins/telemetry_management_section/public/components/__snapshots__/opt_in_security_example_flyout.test.tsx.snap @@ -0,0 +1,134 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`security flyout renders as expected renders as expected 1`] = ` + + + + +

    + Endpoint security data +

    +
    + + + This is a representative sample of the endpoint security alert event that we collect. Endpoint security data is collected only when the Elastic Endpoint is enabled. It includes information about the endpoint configuration and detection events. + + +
    + + + { + "@timestamp": "2020-09-22T14:34:56.82202300Z", + "agent": { + "build": { + "original": "version: 7.9.1, compiled: Thu Aug 27 14:50:21 2020, branch: 7.9, commit: b594beb958817dee9b9d908191ed766d483df3ea" + }, + "id": "22dd8544-bcac-46cb-b970-5e681bb99e0b", + "type": "endpoint", + "version": "7.9.1" + }, + "Endpoint": { + "policy": { + "applied": { + "artifacts": { + "global": { + "identifiers": [ + { + "sha256": "6a546aade5563d3e8dffc1fe2d93d33edda8f9ca3e17ac3cc9ac707620cb9ecd", + "name": "endpointpe-v4-blocklist" + }, + { + "sha256": "04f9f87accc5d5aea433427bd1bd4ec6908f8528c78ceed26f70df7875a99385", + "name": "endpointpe-v4-exceptionlist" + }, + { + "sha256": "1471838597fcd79a54ea4a3ec9a9beee1a86feaedab6c98e61102559ced822a8", + "name": "endpointpe-v4-model" + }, + { + "sha256": "824859b0c6749cc31951d92a73bbdddfcfe9f38abfe432087934d4dab9766ce8", + "name": "global-exceptionlist-windows" + } + ], + "version": "1.0.0" + }, + "user": { + "identifiers": [ + { + "sha256": "d801aa1fb7ddcc330a5e3173372ea6af4a3d08ec58074478e85aa5603e926658", + "name": "endpoint-exceptionlist-windows-v1" + } + ], + "version": "1.0.0" + } + } + } + } + }, + "ecs": { + "version": "1.5.0" + }, + "elastic": { + "agent": { + "id": "b2e88aea-2671-402a-828a-957526bac315" + } + }, + "file": { + "path": "C:\\\\Windows\\\\Temp\\\\mimikatz.exe", + "size": 1263880, + "created": "2020-05-19T07:50:06.0Z", + "accessed": "2020-09-22T14:29:19.93531400Z", + "mtime": "2020-09-22T14:29:03.6040000Z", + "directory": "C:\\\\Windows\\\\Temp", + "hash": { + "sha1": "c9fb7f8a4c6b7b12b493a99a8dc6901d17867388", + "sha256": "cb1553a3c88817e4cc774a5a93f9158f6785bd3815447d04b6c3f4c2c4b21ed7", + "md5": "465d5d850f54d9cde767bda90743df30" + }, + "Ext": { + "code_signature": { + "trusted": true, + "subject_name": "Open Source Developer, Benjamin Delpy", + "exists": true, + "status": "trusted" + }, + "malware_classification": { + "identifier": "endpointpe-v4-model", + "score": 0.99956864118576, + "threshold": 0.71, + "version": "0.0.0" + } + } + }, + "host": { + "os": { + "Ext": { + "variant": "Windows 10 Enterprise Evaluation" + }, + "kernel": "2004 (10.0.19041.388)", + "name": "Windows", + "family": "windows", + "version": "2004 (10.0.19041.388)", + "platform": "windows", + "full": "Windows 10 Enterprise Evaluation 2004 (10.0.19041.388)" + } + }, + "event": { + "kind": "alert" + }, + "cluster_uuid": "kLbKvSMcRiiFAR0t8LebDA", + "cluster_name": "elasticsearch" +} + + +
    +
    +`; diff --git a/src/plugins/telemetry_management_section/public/components/__snapshots__/telemetry_management_section.test.tsx.snap b/src/plugins/telemetry_management_section/public/components/__snapshots__/telemetry_management_section.test.tsx.snap index bed1bbeabb044..7357598c8495f 100644 --- a/src/plugins/telemetry_management_section/public/components/__snapshots__/telemetry_management_section.test.tsx.snap +++ b/src/plugins/telemetry_management_section/public/components/__snapshots__/telemetry_management_section.test.tsx.snap @@ -80,15 +80,32 @@ exports[`TelemetryManagementSectionComponent renders as expected 1`] = ` />

    - - - + + + , + "endpointSecurityData": + + , + } + } + />

    , "displayName": "Provide usage statistics", diff --git a/src/plugins/telemetry_management_section/public/components/opt_in_security_example_flyout.test.tsx b/src/plugins/telemetry_management_section/public/components/opt_in_security_example_flyout.test.tsx new file mode 100644 index 0000000000000..c80d0daf5a695 --- /dev/null +++ b/src/plugins/telemetry_management_section/public/components/opt_in_security_example_flyout.test.tsx @@ -0,0 +1,27 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import { shallowWithIntl } from 'test_utils/enzyme_helpers'; +import { OptInSecurityExampleFlyout } from './opt_in_security_example_flyout'; + +describe('security flyout renders as expected', () => { + it('renders as expected', () => { + expect(shallowWithIntl()).toMatchSnapshot(); + }); +}); diff --git a/src/plugins/telemetry_management_section/public/components/opt_in_security_example_flyout.tsx b/src/plugins/telemetry_management_section/public/components/opt_in_security_example_flyout.tsx new file mode 100644 index 0000000000000..af0de5b268ddc --- /dev/null +++ b/src/plugins/telemetry_management_section/public/components/opt_in_security_example_flyout.tsx @@ -0,0 +1,235 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import * as React from 'react'; + +import { + EuiCallOut, + EuiCodeBlock, + EuiFlexGroup, + EuiFlexItem, + EuiFlyout, + EuiFlyoutHeader, + EuiFlyoutBody, + EuiLoadingSpinner, + EuiPortal, // EuiPortal is a temporary requirement to use EuiFlyout with "ownFocus" + EuiText, + EuiTextColor, + EuiTitle, +} from '@elastic/eui'; + +import { FormattedMessage } from '@kbn/i18n/react'; + +interface Props { + onClose: () => void; +} + +interface State { + isLoading: boolean; + hasPrivilegeToRead: boolean; +} + +/** + * React component for displaying the example data associated with the Telemetry opt-in banner. + */ +export class OptInSecurityExampleFlyout extends React.PureComponent { + public readonly state: State = { + isLoading: true, + hasPrivilegeToRead: false, + }; + + async componentDidMount() { + try { + this.setState({ + isLoading: false, + hasPrivilegeToRead: true, + }); + } catch (err) { + this.setState({ + isLoading: false, + hasPrivilegeToRead: err.status !== 403, + }); + } + } + + renderBody({ isLoading, hasPrivilegeToRead }: State) { + if (isLoading) { + return ( + + + + + + ); + } + + if (!hasPrivilegeToRead) { + return ( + + } + color="danger" + iconType="cross" + > + + + ); + } + + return ( + + {JSON.stringify(this.exampleSecurityPayload, null, 2)} + + ); + } + + render() { + return ( + + + + +

    Endpoint security data

    +
    + + + This is a representative sample of the endpoint security alert event that we + collect. Endpoint security data is collected only when the Elastic Endpoint is + enabled. It includes information about the endpoint configuration and detection + events. + + +
    + {this.renderBody(this.state)} +
    +
    + ); + } + + exampleSecurityPayload = { + '@timestamp': '2020-09-22T14:34:56.82202300Z', + agent: { + build: { + original: + 'version: 7.9.1, compiled: Thu Aug 27 14:50:21 2020, branch: 7.9, commit: b594beb958817dee9b9d908191ed766d483df3ea', + }, + id: '22dd8544-bcac-46cb-b970-5e681bb99e0b', + type: 'endpoint', + version: '7.9.1', + }, + Endpoint: { + policy: { + applied: { + artifacts: { + global: { + identifiers: [ + { + sha256: '6a546aade5563d3e8dffc1fe2d93d33edda8f9ca3e17ac3cc9ac707620cb9ecd', + name: 'endpointpe-v4-blocklist', + }, + { + sha256: '04f9f87accc5d5aea433427bd1bd4ec6908f8528c78ceed26f70df7875a99385', + name: 'endpointpe-v4-exceptionlist', + }, + { + sha256: '1471838597fcd79a54ea4a3ec9a9beee1a86feaedab6c98e61102559ced822a8', + name: 'endpointpe-v4-model', + }, + { + sha256: '824859b0c6749cc31951d92a73bbdddfcfe9f38abfe432087934d4dab9766ce8', + name: 'global-exceptionlist-windows', + }, + ], + version: '1.0.0', + }, + user: { + identifiers: [ + { + sha256: 'd801aa1fb7ddcc330a5e3173372ea6af4a3d08ec58074478e85aa5603e926658', + name: 'endpoint-exceptionlist-windows-v1', + }, + ], + version: '1.0.0', + }, + }, + }, + }, + }, + ecs: { + version: '1.5.0', + }, + elastic: { + agent: { + id: 'b2e88aea-2671-402a-828a-957526bac315', + }, + }, + file: { + path: 'C:\\Windows\\Temp\\mimikatz.exe', + size: 1263880, + created: '2020-05-19T07:50:06.0Z', + accessed: '2020-09-22T14:29:19.93531400Z', + mtime: '2020-09-22T14:29:03.6040000Z', + directory: 'C:\\Windows\\Temp', + hash: { + sha1: 'c9fb7f8a4c6b7b12b493a99a8dc6901d17867388', + sha256: 'cb1553a3c88817e4cc774a5a93f9158f6785bd3815447d04b6c3f4c2c4b21ed7', + md5: '465d5d850f54d9cde767bda90743df30', + }, + Ext: { + code_signature: { + trusted: true, + subject_name: 'Open Source Developer, Benjamin Delpy', + exists: true, + status: 'trusted', + }, + malware_classification: { + identifier: 'endpointpe-v4-model', + score: 0.99956864118576, + threshold: 0.71, + version: '0.0.0', + }, + }, + }, + host: { + os: { + Ext: { + variant: 'Windows 10 Enterprise Evaluation', + }, + kernel: '2004 (10.0.19041.388)', + name: 'Windows', + family: 'windows', + version: '2004 (10.0.19041.388)', + platform: 'windows', + full: 'Windows 10 Enterprise Evaluation 2004 (10.0.19041.388)', + }, + }, + event: { + kind: 'alert', + }, + cluster_uuid: 'kLbKvSMcRiiFAR0t8LebDA', + cluster_name: 'elasticsearch', + }; +} diff --git a/src/plugins/telemetry_management_section/public/components/telemetry_management_section.test.tsx b/src/plugins/telemetry_management_section/public/components/telemetry_management_section.test.tsx index 0e2855f055540..993295746ea5b 100644 --- a/src/plugins/telemetry_management_section/public/components/telemetry_management_section.test.tsx +++ b/src/plugins/telemetry_management_section/public/components/telemetry_management_section.test.tsx @@ -212,7 +212,7 @@ describe('TelemetryManagementSectionComponent', () => { /> ); try { - const toggleExampleComponent = component.find('p > EuiLink[onClick]'); + const toggleExampleComponent = component.find('FormattedMessage > EuiLink[onClick]').at(0); const updatedView = toggleExampleComponent.simulate('click'); updatedView.find('OptInExampleFlyout'); updatedView.simulate('close'); @@ -221,6 +221,42 @@ describe('TelemetryManagementSectionComponent', () => { } }); + it('shows the OptInSecurityExampleFlyout', () => { + const onQueryMatchChange = jest.fn(); + const telemetryService = new TelemetryService({ + config: { + enabled: true, + url: '', + banner: true, + allowChangingOptInStatus: true, + optIn: false, + optInStatusUrl: '', + sendUsageFrom: 'browser', + }, + reportOptInStatusChange: false, + notifications: coreStart.notifications, + http: coreSetup.http, + }); + + const component = mountWithIntl( + + ); + try { + const toggleExampleComponent = component.find('FormattedMessage > EuiLink[onClick]').at(1); + const updatedView = toggleExampleComponent.simulate('click'); + updatedView.find('OptInSecurityExampleFlyout'); + updatedView.simulate('close'); + } finally { + component.unmount(); + } + }); + it('toggles the OptIn button', async () => { const onQueryMatchChange = jest.fn(); const telemetryService = new TelemetryService({ diff --git a/src/plugins/telemetry_management_section/public/components/telemetry_management_section.tsx b/src/plugins/telemetry_management_section/public/components/telemetry_management_section.tsx index 9ae0a3d12fbb5..822d8b49661c1 100644 --- a/src/plugins/telemetry_management_section/public/components/telemetry_management_section.tsx +++ b/src/plugins/telemetry_management_section/public/components/telemetry_management_section.tsx @@ -34,6 +34,7 @@ import { i18n } from '@kbn/i18n'; import { TelemetryPluginSetup } from 'src/plugins/telemetry/public'; import { PRIVACY_STATEMENT_URL } from '../../../telemetry/common/constants'; import { OptInExampleFlyout } from './opt_in_example_flyout'; +import { OptInSecurityExampleFlyout } from './opt_in_security_example_flyout'; import { LazyField } from '../../../advanced_settings/public'; import { ToastsStart } from '../../../../core/public'; @@ -53,6 +54,7 @@ interface Props { interface State { processing: boolean; showExample: boolean; + showSecurityExample: boolean; queryMatches: boolean | null; enabled: boolean; } @@ -61,6 +63,7 @@ export class TelemetryManagementSection extends Component { state: State = { processing: false, showExample: false, + showSecurityExample: false, queryMatches: null, enabled: this.props.telemetryService.getIsOptedIn() || false, }; @@ -87,7 +90,7 @@ export class TelemetryManagementSection extends Component { render() { const { telemetryService } = this.props; - const { showExample, queryMatches, enabled, processing } = this.state; + const { showExample, showSecurityExample, queryMatches, enabled, processing } = this.state; if (!telemetryService.getCanChangeOptInStatus()) { return null; @@ -105,6 +108,7 @@ export class TelemetryManagementSection extends Component { onClose={this.toggleExample} /> )} + {showSecurityExample && } @@ -197,12 +201,25 @@ export class TelemetryManagementSection extends Component { />

    - - - + + + + ), + endpointSecurityData: ( + + + + ), + }} + />

    ); @@ -245,6 +262,12 @@ export class TelemetryManagementSection extends Component { showExample: !this.state.showExample, }); }; + + toggleSecurityExample = () => { + this.setState({ + showSecurityExample: !this.state.showSecurityExample, + }); + }; } // required for lazy loading diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index bd9a66b48f633..e344d18213ae5 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -2962,7 +2962,6 @@ "telemetry.provideUsageStatisticsAriaName": "使用統計を提供", "telemetry.provideUsageStatisticsTitle": "使用統計を提供", "telemetry.readOurUsageDataPrivacyStatementLinkText": "プライバシーポリシー", - "telemetry.seeExampleOfWhatWeCollectLinkText": "収集されるデータの例を見る", "telemetry.telemetryBannerDescription": "Elastic Stackの改善にご協力ください使用状況データの収集は現在無効です。使用状況データの収集を有効にすると、製品とサービスを管理して改善することができます。詳細については、{privacyStatementLink}をご覧ください。", "telemetry.telemetryConfigAndLinkDescription": "使用状況データの収集を有効にすると、製品とサービスを管理して改善することができます。詳細については、{privacyStatementLink}をご覧ください。", "telemetry.telemetryConfigDescription": "基本的な機能の利用状況に関する統計情報を提供して、Elastic Stack の改善にご協力ください。このデータは Elastic 社外と共有されません。", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 3ce9278234005..ab7b558afbbf2 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -2963,7 +2963,6 @@ "telemetry.provideUsageStatisticsAriaName": "提供使用情况统计", "telemetry.provideUsageStatisticsTitle": "提供使用情况统计", "telemetry.readOurUsageDataPrivacyStatementLinkText": "隐私声明", - "telemetry.seeExampleOfWhatWeCollectLinkText": "查看我们收集的内容示例", "telemetry.telemetryBannerDescription": "想帮助我们改进 Elastic Stack?数据使用情况收集当前已禁用。启用数据使用情况收集可帮助我们管理并改善产品和服务。有关详情,请参阅我们的{privacyStatementLink}。", "telemetry.telemetryConfigAndLinkDescription": "启用使用情况数据收集可帮助我们管理并改善产品和服务。有关更多详情,请参阅我们的{privacyStatementLink}。", "telemetry.telemetryConfigDescription": "通过提供基本功能的使用情况统计信息,来帮助我们改进 Elastic Stack。我们不会在 Elastic 之外共享此数据。", From 94ef651d7b03f0d31c1b704a66cdb9191e094d88 Mon Sep 17 00:00:00 2001 From: PavithraCP <31021423+PavithraCP@users.noreply.github.com> Date: Fri, 2 Oct 2020 07:16:46 -0400 Subject: [PATCH 31/50] [Lens]Do not enable histogram mode for multiple un-stacked bar series (#78525) --- .../xy_visualization/expression.test.tsx | 50 ++++++++++++++++++- .../public/xy_visualization/expression.tsx | 14 +++++- 2 files changed, 61 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/lens/public/xy_visualization/expression.test.tsx b/x-pack/plugins/lens/public/xy_visualization/expression.test.tsx index 3bd6cc73d6320..5fc89d831a961 100644 --- a/x-pack/plugins/lens/public/xy_visualization/expression.test.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/expression.test.tsx @@ -896,7 +896,12 @@ describe('xy_expression', () => { test('it applies histogram mode to the series for single series', () => { const { data, args } = sampleArgs(); - const firstLayer: LayerArgs = { ...args.layers[0], seriesType: 'bar', isHistogram: true }; + const firstLayer: LayerArgs = { + ...args.layers[0], + accessors: ['b'], + seriesType: 'bar', + isHistogram: true, + }; delete firstLayer.splitAccessor; const component = shallow( { /> ); expect(component.find(BarSeries).at(0).prop('enableHistogramMode')).toEqual(true); - expect(component.find(BarSeries).at(1).prop('enableHistogramMode')).toEqual(true); + }); + + test('it does not apply histogram mode to more than one bar series for unstacked bar chart', () => { + const { data, args } = sampleArgs(); + const firstLayer: LayerArgs = { ...args.layers[0], seriesType: 'bar', isHistogram: true }; + delete firstLayer.splitAccessor; + const component = shallow( + + ); + expect(component.find(BarSeries).at(0).prop('enableHistogramMode')).toEqual(false); + expect(component.find(BarSeries).at(1).prop('enableHistogramMode')).toEqual(false); + }); + + test('it applies histogram mode to more than one the series for unstacked line/area chart', () => { + const { data, args } = sampleArgs(); + const firstLayer: LayerArgs = { ...args.layers[0], seriesType: 'line', isHistogram: true }; + delete firstLayer.splitAccessor; + const secondLayer: LayerArgs = { ...args.layers[0], seriesType: 'line', isHistogram: true }; + delete secondLayer.splitAccessor; + const component = shallow( + + ); + expect(component.find(LineSeries).at(0).prop('enableHistogramMode')).toEqual(true); + expect(component.find(LineSeries).at(1).prop('enableHistogramMode')).toEqual(true); }); test('it applies histogram mode to the series for stacked series', () => { diff --git a/x-pack/plugins/lens/public/xy_visualization/expression.tsx b/x-pack/plugins/lens/public/xy_visualization/expression.tsx index f36525a9a0b14..a59739ec78f7f 100644 --- a/x-pack/plugins/lens/public/xy_visualization/expression.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/expression.tsx @@ -299,6 +299,13 @@ export function XYChart({ yRight: true, }; + const filteredBarLayers = filteredLayers.filter((layer) => layer.seriesType.includes('bar')); + + const chartHasMoreThanOneBarSeries = + filteredBarLayers.length > 1 || + filteredBarLayers.some((layer) => layer.accessors.length > 1) || + filteredBarLayers.some((layer) => layer.splitAccessor); + function calculateMinInterval() { // check all the tables to see if all of the rows have the same timestamp // that would mean that chart will draw a single bar @@ -599,7 +606,12 @@ export function XYChart({ groupId: yAxesConfiguration.find((axisConfiguration) => axisConfiguration.series.find((currentSeries) => currentSeries.accessor === accessor) )?.groupId, - enableHistogramMode: isHistogram && (seriesType.includes('stacked') || !splitAccessor), + enableHistogramMode: + isHistogram && + (seriesType.includes('stacked') || !splitAccessor) && + (seriesType.includes('stacked') || + !seriesType.includes('bar') || + !chartHasMoreThanOneBarSeries), stackMode: seriesType.includes('percentage') ? StackMode.Percentage : undefined, timeZone, areaSeriesStyle: { From 70dac72ad311d595b0f9f6bc871f718656296da6 Mon Sep 17 00:00:00 2001 From: Tim Roes Date: Fri, 2 Oct 2020 13:39:38 +0200 Subject: [PATCH 32/50] Move legacy plugins to appropriate teams (#79078) * Move legacy plugins to appropriate teams * More cleanup --- .github/CODEOWNERS | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index fc9c55e7868f4..d1cf0300b9e17 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -17,6 +17,7 @@ /src/plugins/input_control_vis/ @elastic/kibana-app /src/plugins/management/ @elastic/kibana-app /src/plugins/kibana_legacy/ @elastic/kibana-app +/src/plugins/timelion/ @elastic/kibana-app /src/plugins/vis_default_editor/ @elastic/kibana-app /src/plugins/vis_type_markdown/ @elastic/kibana-app /src/plugins/vis_type_metric/ @elastic/kibana-app @@ -30,32 +31,23 @@ /src/plugins/visualize/ @elastic/kibana-app /src/plugins/visualizations/ @elastic/kibana-app #CC# /src/legacy/core_plugins/kibana/public/local_application_service/ @elastic/kibana-app -#CC# /src/plugins/vis_type @elastic/kibana-app #CC# /src/legacy/core_plugins/kibana/ @elastic/kibana-app #CC# /src/legacy/core_plugins/kibana/common/utils @elastic/kibana-app #CC# /src/legacy/core_plugins/kibana/migrations @elastic/kibana-app #CC# /src/legacy/core_plugins/kibana/public @elastic/kibana-app #CC# /src/legacy/core_plugins/kibana/public/dashboard/ @elastic/kibana-app -#CC# /src/legacy/core_plugins/kibana/public/dev_tools/ @elastic/kibana-app #CC# /src/legacy/core_plugins/kibana/public/discover/ @elastic/kibana-app #CC# /src/legacy/core_plugins/kibana/public/local_application_service/ @elastic/kibana-app -#CC# /src/legacy/core_plugins/console_legacy @elastic/kibana-app #CC# /src/legacy/core_plugins/input_control_vis @elastic/kibana-app #CC# /src/legacy/core_plugins/timelion @elastic/kibana-app #CC# /src/legacy/core_plugins/vis_type_tagcloud @elastic/kibana-app #CC# /src/legacy/core_plugins/vis_type_vega @elastic/kibana-app #CC# /src/legacy/core_plugins/vis_type_vislib/ @elastic/kibana-app -#CC# /src/legacy/server/sample_data/ @elastic/kibana-app #CC# /src/legacy/server/url_shortening/ @elastic/kibana-app #CC# /src/legacy/ui/public/state_management @elastic/kibana-app -#CC# /src/plugins/charts/public/static/color_maps @elastic/kibana-app #CC# /src/plugins/index_pattern_management/public @elastic/kibana-app -#CC# /src/plugins/input_control_vis/ @elastic/kibana-app -#CC# /src/plugins/kibana_legacy/ @elastic/kibana-app -#CC# /src/plugins/timelion @elastic/kibana-app #CC# /x-pack/legacy/plugins/dashboard_mode/ @elastic/kibana-app #CC# /x-pack/plugins/dashboard_mode @elastic/kibana-app -#CC# /x-pack/plugins/lens/ @elastic/kibana-app # App Architecture /examples/bfetch_explorer/ @elastic/kibana-app-arch @@ -147,6 +139,7 @@ /src/plugins/home/server/services/ @elastic/kibana-core-ui /x-pack/plugins/global_search_bar/ @elastic/kibana-core-ui #CC# /src/legacy/core_plugins/newsfeed @elastic/kibana-core-ui +#CC# /src/legacy/server/sample_data/ @elastic/kibana-core-ui #CC# /src/plugins/newsfeed @elastic/kibana-core-ui #CC# /src/plugins/home/public @elastic/kibana-core-ui #CC# /src/plugins/home/server/services/ @elastic/kibana-core-ui @@ -351,6 +344,8 @@ x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json @elastic/kib /x-pack/plugins/ingest_pipelines/ @elastic/es-ui /packages/kbn-ace/ @elastic/es-ui /packages/kbn-monaco/ @elastic/es-ui +#CC# /src/legacy/core_plugins/kibana/public/dev_tools/ @elastic/es-ui +#CC# /src/legacy/core_plugins/console_legacy @elastic/es-ui #CC# /x-pack/legacy/plugins/rollup/ @elastic/es-ui #CC# /x-pack/legacy/server/lib/create_router/ @elastic/es-ui #CC# /x-pack/legacy/server/lib/check_license/ @elastic/es-ui From 09b0b6630abd6fe03c0be504a8e7a9ee5fc83e24 Mon Sep 17 00:00:00 2001 From: ymao1 Date: Fri, 2 Oct 2020 07:40:47 -0400 Subject: [PATCH 33/50] Rearranged PagerDuty action params so non-optional params are at the top (#79026) --- .../pagerduty/pagerduty_params.tsx | 47 ++++++++++--------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/pagerduty/pagerduty_params.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/pagerduty/pagerduty_params.tsx index 39800865ed761..32f16760dd461 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/pagerduty/pagerduty_params.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/pagerduty/pagerduty_params.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ import React, { Fragment } from 'react'; -import { EuiFlexGroup, EuiFlexItem, EuiFormRow, EuiSelect } from '@elastic/eui'; +import { EuiFlexGroup, EuiFlexItem, EuiFormRow, EuiSelect, EuiSpacer } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { ActionParamsProps } from '../../../../types'; import { PagerDutyActionParams } from '.././types'; @@ -143,6 +143,29 @@ const PagerDutyParamsFields: React.FunctionComponent
    + + 0 && summary !== undefined} + label={i18n.translate( + 'xpack.triggersActionsUI.components.builtinActionTypes.pagerDutyAction.summaryFieldLabel', + { + defaultMessage: 'Summary', + } + )} + > + + + + - 0 && summary !== undefined} - label={i18n.translate( - 'xpack.triggersActionsUI.components.builtinActionTypes.pagerDutyAction.summaryFieldLabel', - { - defaultMessage: 'Summary', - } - )} - > - - Date: Fri, 2 Oct 2020 13:52:03 +0200 Subject: [PATCH 34/50] improves eql test (#79014) Co-authored-by: Elastic Machine --- .../alerts_detection_rules_eql.spec.ts | 25 +++++++++++++++++++ .../security_solution/cypress/objects/rule.ts | 2 +- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/cypress/integration/alerts_detection_rules_eql.spec.ts b/x-pack/plugins/security_solution/cypress/integration/alerts_detection_rules_eql.spec.ts index e2ff51dd544a2..ca7832603f13d 100644 --- a/x-pack/plugins/security_solution/cypress/integration/alerts_detection_rules_eql.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/alerts_detection_rules_eql.spec.ts @@ -6,6 +6,14 @@ import { eqlRule, indexPatterns } from '../objects/rule'; +import { + ALERT_RULE_METHOD, + ALERT_RULE_NAME, + ALERT_RULE_RISK_SCORE, + ALERT_RULE_SEVERITY, + ALERT_RULE_VERSION, + NUMBER_OF_ALERTS, +} from '../screens/alerts'; import { CUSTOM_RULES_BTN, RISK_SCORE, @@ -59,9 +67,11 @@ import { fillDefineEqlRuleAndContinue, fillScheduleRuleAndContinue, selectEqlRuleType, + waitForTheRuleToBeExecuted, } from '../tasks/create_new_rule'; import { esArchiverLoad, esArchiverUnload } from '../tasks/es_archiver'; import { loginAndWaitForPageWithoutDateRange } from '../tasks/login'; +import { refreshPage } from '../tasks/security_header'; import { DETECTIONS_URL } from '../urls/navigation'; @@ -74,6 +84,7 @@ const expectedMitre = eqlRule.mitre }) .join(''); const expectedNumberOfRules = 1; +const expectedNumberOfAlerts = 7; describe('Detection rules, EQL', () => { before(() => { @@ -146,5 +157,19 @@ describe('Detection rules, EQL', () => { `${eqlRule.lookBack.interval}${eqlRule.lookBack.type}` ); }); + + refreshPage(); + waitForTheRuleToBeExecuted(); + + cy.get(NUMBER_OF_ALERTS) + .invoke('text') + .then((numberOfAlertsText) => { + cy.wrap(parseInt(numberOfAlertsText, 10)).should('eql', expectedNumberOfAlerts); + }); + cy.get(ALERT_RULE_NAME).first().should('have.text', eqlRule.name); + cy.get(ALERT_RULE_VERSION).first().should('have.text', '1'); + cy.get(ALERT_RULE_METHOD).first().should('have.text', 'eql'); + cy.get(ALERT_RULE_SEVERITY).first().should('have.text', eqlRule.severity.toLowerCase()); + cy.get(ALERT_RULE_RISK_SCORE).first().should('have.text', eqlRule.riskScore); }); }); diff --git a/x-pack/plugins/security_solution/cypress/objects/rule.ts b/x-pack/plugins/security_solution/cypress/objects/rule.ts index e84e2b7b1669f..f375eccd902c4 100644 --- a/x-pack/plugins/security_solution/cypress/objects/rule.ts +++ b/x-pack/plugins/security_solution/cypress/objects/rule.ts @@ -215,7 +215,7 @@ export const machineLearningRule: MachineLearningRule = { }; export const eqlRule: CustomRule = { - customQuery: 'process where process_name == "explorer.exe"', + customQuery: 'any where process.name == "which"', name: 'New EQL Rule', description: 'New EQL rule description.', severity: 'High', From ea6bec6c9bd6ef8912e8eed9d9e8ba77a3505789 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B8ren=20Louv-Jansen?= Date: Fri, 2 Oct 2020 14:33:33 +0200 Subject: [PATCH 35/50] [APM] Use `history.replace` to preserve back-button functionality (#78978) --- x-pack/plugins/apm/public/hooks/useTransactionDistribution.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/apm/public/hooks/useTransactionDistribution.ts b/x-pack/plugins/apm/public/hooks/useTransactionDistribution.ts index cd3e02d155602..a5096a314388c 100644 --- a/x-pack/plugins/apm/public/hooks/useTransactionDistribution.ts +++ b/x-pack/plugins/apm/public/hooks/useTransactionDistribution.ts @@ -75,7 +75,7 @@ export function useTransactionDistribution(urlParams: IUrlParams) { const preferredSample = maybe(bucketsSortedByCount[0]?.samples[0]); - history.push({ + history.replace({ ...history.location, search: fromQuery({ ...omit(toQuery(history.location.search), [ From b9a79836f8c15652da834be23db1b208180322da Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Fri, 2 Oct 2020 08:45:28 -0400 Subject: [PATCH 36/50] Grouped features for role management (#78152) * Grouped features for role management * address PR feedback Co-authored-by: Elastic Machine --- .../security/authorization/index.asciidoc | 38 +- .../roles/__fixtures__/kibana_features.ts | 5 +- .../feature_table/__fixtures__/index.ts | 68 ++- .../feature_table/change_all_privileges.tsx | 20 +- .../kibana/feature_table/feature_table.scss | 5 + .../feature_table/feature_table.test.tsx | 134 +++-- .../kibana/feature_table/feature_table.tsx | 487 ++++++++++-------- .../feature_table_cell.scss | 4 - .../feature_table_cell.test.tsx | 13 +- .../feature_table_cell/feature_table_cell.tsx | 7 +- .../privilege_summary/privilege_summary.tsx | 48 +- .../privilege_summary_table.tsx | 122 ++++- .../space_column_header.test.tsx | 5 +- .../privilege_summary/space_column_header.tsx | 12 +- .../privilege_space_form.test.tsx | 23 +- .../privilege_space_form.tsx | 123 ++--- .../privilege_space_table.tsx | 15 +- .../space_aware_privilege_section.tsx | 4 +- .../customize_space/customize_space.tsx | 2 +- .../enabled_features.test.tsx.snap | 2 - .../enabled_features/enabled_features.tsx | 2 - .../enabled_features/feature_table.scss | 2 +- .../__snapshots__/section_panel.test.tsx.snap | 11 - .../section_panel/section_panel.test.tsx | 23 +- .../section_panel/section_panel.tsx | 66 +-- .../translations/translations/ja-JP.json | 17 - .../translations/translations/zh-CN.json | 17 - .../functional/page_objects/security_page.ts | 5 +- 28 files changed, 630 insertions(+), 650 deletions(-) create mode 100644 x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table.scss delete mode 100644 x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table_cell/feature_table_cell.scss diff --git a/docs/user/security/authorization/index.asciidoc b/docs/user/security/authorization/index.asciidoc index 44ca96e4aece5..3af49753db664 100644 --- a/docs/user/security/authorization/index.asciidoc +++ b/docs/user/security/authorization/index.asciidoc @@ -2,11 +2,11 @@ [[xpack-security-authorization]] === Granting access to {kib} -The Elastic Stack comes with the `kibana_admin` {ref}/built-in-roles.html[built-in role], which you can use to grant access to all Kibana features in all spaces. To grant users access to a subset of spaces or features, you can create a custom role that grants the desired Kibana privileges. +The Elastic Stack comes with the `kibana_admin` {ref}/built-in-roles.html[built-in role], which you can use to grant access to all {kib} features in all spaces. To grant users access to a subset of spaces or features, you can create a custom role that grants the desired {kib} privileges. -When you assign a user multiple roles, the user receives a union of the roles’ privileges. Therefore, assigning the `kibana_admin` role in addition to a custom role that grants Kibana privileges is ineffective because `kibana_admin` has access to all the features in all spaces. +When you assign a user multiple roles, the user receives a union of the roles’ privileges. Therefore, assigning the `kibana_admin` role in addition to a custom role that grants {kib} privileges is ineffective because `kibana_admin` has access to all the features in all spaces. -NOTE: When running multiple tenants of Kibana by changing the `kibana.index` in your `kibana.yml`, you cannot use `kibana_admin` to grant access. You must create custom roles that authorize the user for that specific tenant. Although multi-tenant installations are supported, the recommended approach to securing access to Kibana segments is to grant users access to specific spaces. +NOTE: When running multiple tenants of {kib} by changing the `kibana.index` in your `kibana.yml`, you cannot use `kibana_admin` to grant access. You must create custom roles that authorize the user for that specific tenant. Although multi-tenant installations are supported, the recommended approach to securing access to {kib} segments is to grant users access to specific spaces. [role="xpack"] [[xpack-kibana-role-management]] @@ -17,26 +17,26 @@ To create a role that grants {kib} privileges, open the menu, go to *Stack Manag [[adding_kibana_privileges]] ==== Adding {kib} privileges -To assign {kib} privileges to the role, click **Add space privilege** in the Kibana section. +To assign {kib} privileges to the role, click **Add {kib} privilege** in the {kib} section. [role="screenshot"] -image::user/security/images/add-space-privileges.png[Add space privileges] +image::user/security/images/add-space-privileges.png[Add {kib} privileges] Open the **Spaces** selection control to specify whether to grant the role access to all spaces *** Global (all spaces)** or one or more individual spaces. If you select *** Global (all spaces)**, you can’t select individual spaces until you clear your selection. Use the **Privilege** menu to grant access to features. The default is **Custom**, which you can use to grant access to individual features. Otherwise, you can grant read and write access to all current and future features by selecting **All**, or grant read access to all current and future features by selecting **Read**. -When using the **Customize by feature** option, you can choose either **All**, **Read** or **None** for access to each feature. As new features are added to Kibana, roles that use the custom option do not automatically get access to the new features. You must manually update the roles. +When using the **Customize by feature** option, you can choose either **All**, **Read** or **None** for access to each feature. As new features are added to {kib}, roles that use the custom option do not automatically get access to the new features. You must manually update the roles. NOTE: *{stack-monitor-app}* relies on built-in roles to grant access. When a user is assigned the appropriate roles, the *{stack-monitor-app}* application is available; otherwise, it is not visible. -To apply your changes, click **Create space privilege**. The space privilege shows up under the Kibana privileges section of the role. +To apply your changes, click **Add {kib} privilege**. The privilege shows up under the {kib} privileges section of the role. [role="screenshot"] -image::user/security/images/create-space-privilege.png[Create space privilege] +image::user/security/images/create-space-privilege.png[Add {kib} privilege] ==== Feature availability @@ -64,9 +64,9 @@ Features are available to users when their roles grant access to the features, * ==== Assigning different privileges to different spaces -Using the same role, it’s possible to assign different privileges to different spaces. After you’ve added space privileges, click **Add space privilege**. If you’ve already added privileges for either *** Global (all spaces)** or an individual space, you will not be able to select these in the **Spaces** selection control. +Using the same role, it’s possible to assign different privileges to different spaces. After you’ve added privileges, click **Add {kib} privilege**. If you’ve already added privileges for either *** Global (all spaces)** or an individual space, you will not be able to select these in the **Spaces** selection control. -Additionally, if you’ve already assigned privileges at *** Global (all spaces)**, you are only able to assign additional privileges to individual spaces. Similar to the behavior of multiple roles granting the union of all privileges, space privileges are also a union. If you’ve already granted the user the **All** privilege at *** Global (all spaces)**, you’re not able to restrict the role to only the **Read** privilege at an individual space. +Additionally, if you’ve already assigned privileges at *** Global (all spaces)**, you are only able to assign additional privileges to individual spaces. Similar to the behavior of multiple roles granting the union of all privileges, {kib} privileges are also a union. If you’ve already granted the user the **All** privilege at *** Global (all spaces)**, you’re not able to restrict the role to only the **Read** privilege at an individual space. ==== Privilege summary @@ -78,39 +78,37 @@ image::user/security/images/view-privilege-summary.png[View privilege summary] ==== Example 1: Grant all access to Dashboard at an individual space -. Click **Add space privilege**. +. Click **Add {kib} privilege**. . For **Spaces**, select an individual space. . For **Privilege**, leave the default selection of **Custom**. . For the Dashboard feature, select **All** -. Click **Create space privilege**. +. Click **Add {kib} privilege**. [role="screenshot"] image::user/security/images/privilege-example-1.png[Privilege example 1] ==== Example 2: Grant all access to one space and read access to another -. Click **Add space privilege**. +. Click **Add {kib} privilege**. . For **Spaces**, select the first space. . For **Privilege**, select **All**. -. Click **Create space privilege**. -. Click **Add space privilege**. +. Click **Add {kib} privilege**. . For **Spaces**, select the second space. . For **Privilege**, select **Read**. -. Click **Create space privilege**. +. Click **Add {kib} privilege**. [role="screenshot"] image::user/security/images/privilege-example-2.png[Privilege example 2] ==== Example 3: Grant read access to all spaces and write access to an individual space -. Click **Add space privilege**. +. Click **Add {kib} privilege**. . For **Spaces**, select *** Global (all spaces)**. . For **Privilege**, select **Read**. -. Click **Create space privilege**. -. Click **Add space privilege**. +. Click **Add {kib} privilege**. . For **Spaces**, select the individual space. . For **Privilege**, select **All**. -. Click **Create space privilege**. +. Click **Add {kib} privilege**. [role="screenshot"] image::user/security/images/privilege-example-3.png[Privilege example 3] diff --git a/x-pack/plugins/security/public/management/roles/__fixtures__/kibana_features.ts b/x-pack/plugins/security/public/management/roles/__fixtures__/kibana_features.ts index 1bab51e70a494..c501ad82954a3 100644 --- a/x-pack/plugins/security/public/management/roles/__fixtures__/kibana_features.ts +++ b/x-pack/plugins/security/public/management/roles/__fixtures__/kibana_features.ts @@ -14,14 +14,15 @@ export const createFeature = ( excludeFromBaseAll?: boolean; excludeFromBaseRead?: boolean; privileges?: KibanaFeatureConfig['privileges']; + category?: KibanaFeatureConfig['category']; } ) => { - const { excludeFromBaseAll, excludeFromBaseRead, privileges, ...rest } = config; + const { excludeFromBaseAll, excludeFromBaseRead, privileges, category, ...rest } = config; return new KibanaFeature({ icon: 'discoverApp', navLinkId: 'discover', app: [], - category: { id: 'foo', label: 'foo' }, + category: category ?? { id: 'foo', label: 'foo' }, catalogue: [], privileges: privileges === null diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/__fixtures__/index.ts b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/__fixtures__/index.ts index 9df50b198bde0..7cfa50f6204fb 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/__fixtures__/index.ts +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/__fixtures__/index.ts @@ -6,30 +6,37 @@ import { ReactWrapper } from 'enzyme'; -import { - EuiTableRow, - EuiCheckbox, - EuiCheckboxProps, - EuiButtonGroup, - EuiButtonGroupProps, -} from '@elastic/eui'; +import { EuiCheckbox, EuiCheckboxProps, EuiButtonGroup, EuiButtonGroupProps } from '@elastic/eui'; import { findTestSubject } from 'test_utils/find_test_subject'; +import { EuiAccordion } from '@elastic/eui'; import { SubFeatureForm } from '../sub_feature_form'; export function getDisplayedFeaturePrivileges(wrapper: ReactWrapper) { - const allExpanderButtons = findTestSubject(wrapper, 'expandFeaturePrivilegeRow'); + const categoryExpander = findTestSubject(wrapper, 'featureCategoryButton_foo'); + categoryExpander.simulate('click'); + + const allExpanderButtons = findTestSubject(wrapper, 'featureTableCell'); allExpanderButtons.forEach((button) => button.simulate('click')); - // each expanded row renders its own `EuiTableRow`, so there are 2 rows - // for each feature: one for the primary feature privilege, and one for the sub privilege form - const rows = wrapper.find(EuiTableRow); + const featurePrivilegeControls = wrapper + .find(EuiAccordion) + .filter('[data-test-subj="featurePrivilegeControls"]'); + + return featurePrivilegeControls.reduce((acc, featureControls) => { + const buttonGroup = featureControls + .find(EuiButtonGroup) + .filter('[data-test-subj="primaryFeaturePrivilegeControl"]'); + const { name, idSelected } = buttonGroup.props(); + expect(name).toBeDefined(); + expect(idSelected).toBeDefined(); - return rows.reduce((acc, row) => { + const featureId = name!.substr(`featurePrivilege_`.length); + const primaryFeaturePrivilege = idSelected!.substr(`${featureId}_`.length); const subFeaturePrivileges = []; - const subFeatureForm = row.find(SubFeatureForm); + + const subFeatureForm = featureControls.find(SubFeatureForm); if (subFeatureForm.length > 0) { - const { featureId } = subFeatureForm.props(); const independentPrivileges = (subFeatureForm.find(EuiCheckbox) as ReactWrapper< EuiCheckboxProps >).reduce((acc2, checkbox) => { @@ -47,30 +54,15 @@ export function getDisplayedFeaturePrivileges(wrapper: ReactWrapper) { }, [] as string[]); subFeaturePrivileges.push(...independentPrivileges, ...mutuallyExclusivePrivileges); - - return { - ...acc, - [featureId]: { - ...acc[featureId], - subFeaturePrivileges, - }, - }; - } else { - const buttonGroup = row.find(EuiButtonGroup); - const { name, idSelected } = buttonGroup.props(); - expect(name).toBeDefined(); - expect(idSelected).toBeDefined(); - - const featureId = name!.substr(`featurePrivilege_`.length); - const primaryFeaturePrivilege = idSelected!.substr(`${featureId}_`.length); - - return { - ...acc, - [featureId]: { - ...acc[featureId], - primaryFeaturePrivilege, - }, - }; } + + return { + ...acc, + [featureId]: { + ...acc[featureId], + primaryFeaturePrivilege, + subFeaturePrivileges, + }, + }; }, {} as Record); } diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/change_all_privileges.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/change_all_privileges.tsx index 14375587c8497..426d9d7bf336b 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/change_all_privileges.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/change_all_privileges.tsx @@ -6,7 +6,14 @@ import './change_all_privileges.scss'; -import { EuiContextMenuItem, EuiContextMenuPanel, EuiLink, EuiPopover } from '@elastic/eui'; +import { + EuiContextMenuItem, + EuiContextMenuPanel, + EuiLink, + EuiPopover, + EuiIcon, + EuiText, +} from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import _ from 'lodash'; import React, { Component } from 'react'; @@ -34,10 +41,13 @@ export class ChangeAllPrivilegesControl extends Component { className={'secPrivilegeFeatureChangeAllLink'} data-test-subj="changeAllPrivilegesButton" > - + + {' '} + + ); diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table.scss b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table.scss new file mode 100644 index 0000000000000..e5c026d317034 --- /dev/null +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table.scss @@ -0,0 +1,5 @@ +.subFeaturePrivilegeExpandedRegion { + background-color: $euiColorLightestShade; + padding-left: $euiSizeXXL; + padding-top: $euiSizeS; +} \ No newline at end of file diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table.test.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table.test.tsx index 02d692bf9f507..002b13609005a 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table.test.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table.test.tsx @@ -13,7 +13,7 @@ import { createKibanaPrivileges } from '../../../../__fixtures__/kibana_privileg import { PrivilegeFormCalculator } from '../privilege_form_calculator'; import { getDisplayedFeaturePrivileges } from './__fixtures__'; import { findTestSubject } from 'test_utils/find_test_subject'; -import { FeatureTableExpandedRow } from './feature_table_expanded_row'; +import { EuiAccordion } from '@elastic/eui'; const createRole = (kibana: Role['kibana'] = []): Role => { return { @@ -86,18 +86,19 @@ describe('FeatureTable', () => { expect(displayedPrivileges).toEqual({ excluded_from_base: { primaryFeaturePrivilege: 'none', - ...(canCustomizeSubFeaturePrivileges ? { subFeaturePrivileges: [] } : {}), + subFeaturePrivileges: [], }, no_sub_features: { primaryFeaturePrivilege: 'none', + subFeaturePrivileges: [], }, with_excluded_sub_features: { primaryFeaturePrivilege: 'none', - ...(canCustomizeSubFeaturePrivileges ? { subFeaturePrivileges: [] } : {}), + subFeaturePrivileges: [], }, with_sub_features: { primaryFeaturePrivilege: 'none', - ...(canCustomizeSubFeaturePrivileges ? { subFeaturePrivileges: [] } : {}), + subFeaturePrivileges: [], }, }); }); @@ -125,14 +126,15 @@ describe('FeatureTable', () => { expect(displayedPrivileges).toEqual({ excluded_from_base: { primaryFeaturePrivilege: 'none', - ...(canCustomizeSubFeaturePrivileges ? { subFeaturePrivileges: [] } : {}), + subFeaturePrivileges: [], }, no_sub_features: { primaryFeaturePrivilege: 'all', + subFeaturePrivileges: [], }, with_excluded_sub_features: { primaryFeaturePrivilege: 'all', - ...(canCustomizeSubFeaturePrivileges ? { subFeaturePrivileges: [] } : {}), + subFeaturePrivileges: [], }, with_sub_features: { primaryFeaturePrivilege: 'all', @@ -144,7 +146,7 @@ describe('FeatureTable', () => { 'cool_all', ], } - : {}), + : { subFeaturePrivileges: [] }), }, }); }); @@ -175,14 +177,15 @@ describe('FeatureTable', () => { expect(displayedPrivileges).toEqual({ excluded_from_base: { primaryFeaturePrivilege: 'none', - ...(canCustomizeSubFeaturePrivileges ? { subFeaturePrivileges: [] } : {}), + subFeaturePrivileges: [], }, no_sub_features: { primaryFeaturePrivilege: 'none', + subFeaturePrivileges: [], }, with_excluded_sub_features: { primaryFeaturePrivilege: 'none', - ...(canCustomizeSubFeaturePrivileges ? { subFeaturePrivileges: [] } : {}), + subFeaturePrivileges: [], }, with_sub_features: { primaryFeaturePrivilege: 'all', @@ -194,7 +197,7 @@ describe('FeatureTable', () => { 'cool_all', ], } - : {}), + : { subFeaturePrivileges: [] }), }, }); }); @@ -279,6 +282,7 @@ describe('FeatureTable', () => { }, no_sub_features: { primaryFeaturePrivilege: 'none', + subFeaturePrivileges: [], }, with_excluded_sub_features: { primaryFeaturePrivilege: 'none', @@ -313,43 +317,18 @@ describe('FeatureTable', () => { }); kibanaFeatures.forEach((feature) => { - const rowExpander = findTestSubject(wrapper, `expandFeaturePrivilegeRow-${feature.id}`); + const { arrowDisplay } = wrapper + .find(EuiAccordion) + .filter(`#featurePrivilegeControls_${feature.id}`) + .props(); if (!feature.subFeatures || feature.subFeatures.length === 0) { - expect(rowExpander).toHaveLength(0); + expect(arrowDisplay).toEqual('none'); } else { - expect(rowExpander).toHaveLength(1); + expect(arrowDisplay).toEqual('left'); } }); }); - it('renders the when the row is expanded', () => { - const role = createRole([ - { - spaces: ['*'], - base: ['read'], - feature: {}, - }, - { - spaces: ['foo'], - base: [], - feature: {}, - }, - ]); - const { wrapper } = setup({ - role, - features: kibanaFeatures, - privilegeIndex: 1, - calculateDisplayedPrivileges: false, - canCustomizeSubFeaturePrivileges: true, - }); - - expect(wrapper.find(FeatureTableExpandedRow)).toHaveLength(0); - - findTestSubject(wrapper, 'expandFeaturePrivilegeRow').first().simulate('click'); - - expect(wrapper.find(FeatureTableExpandedRow)).toHaveLength(1); - }); - it('renders with sub-feature privileges granted when primary feature privilege is "all"', () => { const role = createRole([ { @@ -679,6 +658,7 @@ describe('FeatureTable', () => { }, no_sub_features: { primaryFeaturePrivilege: 'none', + subFeaturePrivileges: [], }, with_excluded_sub_features: { primaryFeaturePrivilege: 'none', @@ -716,15 +696,19 @@ describe('FeatureTable', () => { expect(displayedPrivileges).toEqual({ excluded_from_base: { primaryFeaturePrivilege: 'none', + subFeaturePrivileges: [], }, no_sub_features: { primaryFeaturePrivilege: 'none', + subFeaturePrivileges: [], }, with_excluded_sub_features: { primaryFeaturePrivilege: 'none', + subFeaturePrivileges: [], }, with_sub_features: { primaryFeaturePrivilege: 'none', + subFeaturePrivileges: [], }, }); }); @@ -750,15 +734,19 @@ describe('FeatureTable', () => { expect(displayedPrivileges).toEqual({ excluded_from_base: { primaryFeaturePrivilege: 'none', + subFeaturePrivileges: [], }, no_sub_features: { primaryFeaturePrivilege: 'none', + subFeaturePrivileges: [], }, with_excluded_sub_features: { primaryFeaturePrivilege: 'none', + subFeaturePrivileges: [], }, with_sub_features: { primaryFeaturePrivilege: 'none', + subFeaturePrivileges: [], }, }); }); @@ -843,6 +831,7 @@ describe('FeatureTable', () => { expect(displayedPrivileges).toEqual({ reserved_feature: { primaryFeaturePrivilege: 'none', + subFeaturePrivileges: [], }, }); }); @@ -873,16 +862,79 @@ describe('FeatureTable', () => { expect(displayedPrivileges).toEqual({ excluded_from_base: { primaryFeaturePrivilege: 'none', + subFeaturePrivileges: [], }, no_sub_features: { primaryFeaturePrivilege: 'none', + subFeaturePrivileges: [], }, with_excluded_sub_features: { primaryFeaturePrivilege: 'none', + subFeaturePrivileges: [], }, with_sub_features: { primaryFeaturePrivilege: 'none', + subFeaturePrivileges: [], }, }); }); + + it('renders features by category, indicating how many features are granted within', async () => { + const role = createRole([ + { + spaces: ['foo'], + base: [], + feature: { + feature_1: ['all'], + feature_3: ['all'], + feature_4: ['all'], + }, + }, + ]); + + const features = [ + createFeature({ + id: 'feature_1', + name: 'Feature1', + category: { id: 'foo', label: 'foo' }, + }), + createFeature({ + id: 'feature_2', + name: 'Feature2', + category: { id: 'foo', label: 'foo' }, + }), + createFeature({ + id: 'feature_3', + name: 'Feature3', + category: { id: 'bar', label: 'bar' }, + }), + createFeature({ + id: 'feature_4', + name: 'Feature4', + category: { id: 'bar', label: 'bar' }, + }), + ]; + + const { wrapper } = setup({ + role, + features, + privilegeIndex: 0, + calculateDisplayedPrivileges: false, + canCustomizeSubFeaturePrivileges: false, + }); + + const fooCategory = findTestSubject(wrapper, 'featureCategory_foo'); + const barCategory = findTestSubject(wrapper, 'featureCategory_bar'); + + expect(fooCategory).toHaveLength(1); + expect(barCategory).toHaveLength(1); + + expect(findTestSubject(fooCategory, 'categoryLabel').text()).toMatchInlineSnapshot( + `"1 / 2 features granted"` + ); + + expect(findTestSubject(barCategory, 'categoryLabel').text()).toMatchInlineSnapshot( + `"2 / 2 features granted"` + ); + }); }); diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table.tsx index 57e24f2838226..a07c2e1c14ac4 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table.tsx @@ -5,24 +5,31 @@ */ import { + EuiAccordionProps, EuiButtonGroup, EuiIconTip, - EuiInMemoryTable, EuiText, - EuiButtonIcon, EuiFlexGroup, EuiFlexItem, + EuiSpacer, + EuiCallOut, + EuiHorizontalRule, + EuiAccordion, + EuiIcon, + EuiTitle, } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; -import React, { Component } from 'react'; +import React, { Component, ReactElement } from 'react'; +import { AppCategory } from 'kibana/public'; import { Role } from '../../../../../../../common/model'; import { ChangeAllPrivilegesControl } from './change_all_privileges'; import { FeatureTableExpandedRow } from './feature_table_expanded_row'; import { NO_PRIVILEGE_VALUE } from '../constants'; import { PrivilegeFormCalculator } from '../privilege_form_calculator'; import { FeatureTableCell } from '../feature_table_cell'; -import { KibanaPrivileges, SecuredFeature, KibanaPrivilege } from '../../../../model'; +import { KibanaPrivileges, SecuredFeature } from '../../../../model'; +import './feature_table.scss'; interface Props { role: Role; @@ -35,250 +42,296 @@ interface Props { disabled?: boolean; } -interface State { - expandedFeatures: string[]; -} - -interface TableRow { - featureId: string; - feature: SecuredFeature; - inherited: KibanaPrivilege[]; - effective: KibanaPrivilege[]; - role: Role; -} - -export class FeatureTable extends Component { +export class FeatureTable extends Component { public static defaultProps = { privilegeIndex: -1, showLocks: true, }; + private featureCategories: Map = new Map(); + constructor(props: Props) { super(props); - this.state = { - expandedFeatures: [], - }; + + // features are static for the lifetime of the page, so this is safe to do here in a non-reactive manner + props.kibanaPrivileges + .getSecuredFeatures() + .filter((feature) => feature.privileges != null || feature.reserved != null) + .forEach((feature) => { + if (!this.featureCategories.has(feature.category.id)) { + this.featureCategories.set(feature.category.id, []); + } + this.featureCategories.get(feature.category.id)!.push(feature); + }); } public render() { - const { role, kibanaPrivileges } = this.props; + const basePrivileges = this.props.kibanaPrivileges.getBasePrivileges( + this.props.role.kibana[this.props.privilegeIndex] + ); - const featurePrivileges = kibanaPrivileges - .getSecuredFeatures() - .filter((feature) => feature.privileges != null || feature.reserved != null); + const accordions: Array<{ order: number; element: ReactElement }> = []; + this.featureCategories.forEach((featuresInCategory) => { + const { category } = featuresInCategory[0]; - const items: TableRow[] = featurePrivileges - .sort((feature1, feature2) => { - if (feature1.reserved && !feature2.reserved) { - return 1; - } + const featureCount = featuresInCategory.length; + const grantedCount = featuresInCategory.filter( + (feature) => + this.props.privilegeCalculator.getEffectivePrimaryFeaturePrivilege( + feature.id, + this.props.privilegeIndex + ) != null + ).length; + + const canExpandCategory = true; // featuresInCategory.length > 1; + + const buttonContent = ( + + {category.euiIconType ? ( + + + + ) : null} + + +

    {category.label}

    +
    +
    +
    + ); - if (feature2.reserved && !feature1.reserved) { - return -1; + const label: string = i18n.translate( + 'xpack.security.management.editRole.featureTable.featureAccordionSwitchLabel', + { + defaultMessage: + '{grantedCount} / {featureCount} {featureCount, plural, one {feature} other {features}} granted', + values: { + grantedCount, + featureCount, + }, } + ); + const extraAction = ( + + ); - return 0; - }) - .map((feature) => { - return { - featureId: feature.id, - feature, - inherited: [], - effective: [], - role, - }; + const helpText = this.getCategoryHelpText(category); + + const accordion = ( + +
    + + {helpText && ( + <> + + {helpText} + + + + )} + + {featuresInCategory.map((feature) => ( + + {this.renderPrivilegeControlsForFeature(feature)} + + ))} + +
    +
    + ); + + accordions.push({ + order: category.order ?? Number.MAX_SAFE_INTEGER, + element: accordion, }); + }); + + accordions.sort((a1, a2) => a1.order - a2.order); return ( - { - return { - ...acc, - [featureId]: ( - f.id === featureId)!} - privilegeIndex={this.props.privilegeIndex} - onChange={this.props.onChange} - privilegeCalculator={this.props.privilegeCalculator} - selectedFeaturePrivileges={ - this.props.role.kibana[this.props.privilegeIndex].feature[featureId] ?? [] - } - disabled={this.props.disabled} +
    + + + + + {i18n.translate( + 'xpack.security.management.editRole.featureTable.featureVisibilityTitle', + { + defaultMessage: 'Customize feature privileges', + } + )} + + + + {!this.props.disabled && ( + + - ), - }; - }, {})} - items={items} - /> + + )} + + + {accordions.flatMap((a, idx) => [ + a.element, + , + ])} +
    ); } - public onChange = (featureId: string) => (featurePrivilegeId: string) => { - const privilege = featurePrivilegeId.substr(`${featureId}_`.length); - if (privilege === NO_PRIVILEGE_VALUE) { - this.props.onChange(featureId, []); - } else { - this.props.onChange(featureId, [privilege]); + private renderPrivilegeControlsForFeature = (feature: SecuredFeature) => { + const renderFeatureMarkup = ( + buttonContent: EuiAccordionProps['buttonContent'], + extraAction: EuiAccordionProps['extraAction'], + warningIcon: JSX.Element + ) => { + const { canCustomizeSubFeaturePrivileges } = this.props; + const hasSubFeaturePrivileges = feature.getSubFeaturePrivileges().length > 0; + + return ( + + {warningIcon} + + +
    + +
    +
    +
    +
    + ); + }; + + const primaryFeaturePrivileges = feature.getPrimaryFeaturePrivileges(); + + if (feature.reserved && primaryFeaturePrivileges.length === 0) { + const buttonContent = ( + <> + {} + + ); + + const extraAction = ( + + {feature.reserved.description} + + ); + + return renderFeatureMarkup(buttonContent, extraAction, ); } - }; - private getColumns = () => { - const basePrivileges = this.props.kibanaPrivileges.getBasePrivileges( - this.props.role.kibana[this.props.privilegeIndex] + if (primaryFeaturePrivileges.length === 0) { + return null; + } + + const selectedPrivilegeId = this.props.privilegeCalculator.getDisplayedPrimaryFeaturePrivilegeId( + feature.id, + this.props.privilegeIndex ); - const columns = []; - - if (this.props.canCustomizeSubFeaturePrivileges) { - columns.push({ - width: '30px', - isExpander: true, - field: 'featureId', - name: '', - render: (featureId: string, record: TableRow) => { - const { feature } = record; - const hasSubFeaturePrivileges = feature.getSubFeaturePrivileges().length > 0; - if (!hasSubFeaturePrivileges) { - return null; - } - return ( - this.toggleExpandedFeature(featureId)} - data-test-subj={`expandFeaturePrivilegeRow expandFeaturePrivilegeRow-${featureId}`} - aria-label={this.state.expandedFeatures.includes(featureId) ? 'Collapse' : 'Expand'} - iconType={this.state.expandedFeatures.includes(featureId) ? 'arrowUp' : 'arrowDown'} - /> - ); - }, - }); - } + const options = primaryFeaturePrivileges.map((privilege) => { + return { + id: `${feature.id}_${privilege.id}`, + label: privilege.name, + isDisabled: this.props.disabled, + }; + }); - columns.push( - { - field: 'feature', - width: '200px', - name: i18n.translate( - 'xpack.security.management.editRole.featureTable.enabledRoleFeaturesFeatureColumnTitle', - { - defaultMessage: 'Feature', - } - ), - render: (feature: SecuredFeature) => { - return ; - }, - }, - { - field: 'privilege', - width: '200px', - name: ( - + options.push({ + id: `${feature.id}_${NO_PRIVILEGE_VALUE}`, + label: 'None', + isDisabled: this.props.disabled, + }); + + let warningIcon = ; + if ( + this.props.privilegeCalculator.hasCustomizedSubFeaturePrivileges( + feature.id, + this.props.privilegeIndex + ) + ) { + warningIcon = ( + - {!this.props.disabled && ( - - )} - - ), - mobileOptions: { - // Table isn't responsive, so skip rendering this for mobile. isn't free... - header: false, - }, - render: (roleEntry: Role, record: TableRow) => { - const { feature } = record; - - const primaryFeaturePrivileges = feature.getPrimaryFeaturePrivileges(); - - if (feature.reserved && primaryFeaturePrivileges.length === 0) { - return ( - - {feature.reserved.description} - - ); } + /> + ); + } - if (primaryFeaturePrivileges.length === 0) { - return null; - } + const { canCustomizeSubFeaturePrivileges } = this.props; + const hasSubFeaturePrivileges = feature.getSubFeaturePrivileges().length > 0; - const selectedPrivilegeId = this.props.privilegeCalculator.getDisplayedPrimaryFeaturePrivilegeId( - feature.id, - this.props.privilegeIndex - ); - - const options = primaryFeaturePrivileges.map((privilege) => { - return { - id: `${feature.id}_${privilege.id}`, - label: privilege.name, - isDisabled: this.props.disabled, - }; - }); - - options.push({ - id: `${feature.id}_${NO_PRIVILEGE_VALUE}`, - label: 'None', - isDisabled: this.props.disabled, - }); - - let warningIcon = ; - if ( - this.props.privilegeCalculator.hasCustomizedSubFeaturePrivileges( - feature.id, - this.props.privilegeIndex - ) - ) { - warningIcon = ( - - } - /> - ); - } + const showAccordionArrow = canCustomizeSubFeaturePrivileges && hasSubFeaturePrivileges; - return ( - - {warningIcon} - - - - - ); - }, - } + const buttonContent = ( + <> + {!showAccordionArrow && }{' '} + + ); - return columns; + + const extraAction = ( + + ); + + return renderFeatureMarkup(buttonContent, extraAction, warningIcon); }; - private toggleExpandedFeature = (featureId: string) => { - if (this.state.expandedFeatures.includes(featureId)) { - this.setState({ - expandedFeatures: this.state.expandedFeatures.filter((ef) => ef !== featureId), - }); + private onChange = (featureId: string) => (featurePrivilegeId: string) => { + const privilege = featurePrivilegeId.substr(`${featureId}_`.length); + if (privilege === NO_PRIVILEGE_VALUE) { + this.props.onChange(featureId, []); } else { - this.setState({ - expandedFeatures: [...this.state.expandedFeatures, featureId], - }); + this.props.onChange(featureId, [privilege]); } }; @@ -289,4 +342,16 @@ export class FeatureTable extends Component { this.props.onChangeAll([privilege]); } }; + + private getCategoryHelpText = (category: AppCategory) => { + if (category.id === 'management') { + return i18n.translate( + 'xpack.security.management.editRole.featureTable.managementCategoryHelpText', + { + defaultMessage: + 'Access to Stack Management is determined by both Elasticsearch and Kibana privileges, and cannot be explicitly disabled.', + } + ); + } + }; } diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table_cell/feature_table_cell.scss b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table_cell/feature_table_cell.scss deleted file mode 100644 index a7f24c96a2821..0000000000000 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table_cell/feature_table_cell.scss +++ /dev/null @@ -1,4 +0,0 @@ -.secPrivilegeFeatureIcon { - flex-shrink: 0; - margin-right: $euiSizeS; -} diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table_cell/feature_table_cell.test.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table_cell/feature_table_cell.test.tsx index 155e41baeba1e..1514677c82457 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table_cell/feature_table_cell.test.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table_cell/feature_table_cell.test.tsx @@ -9,10 +9,10 @@ import { createFeature } from '../../../../__fixtures__/kibana_features'; import { mountWithIntl } from 'test_utils/enzyme_helpers'; import { FeatureTableCell } from '.'; import { SecuredFeature } from '../../../../model'; -import { EuiIcon, EuiIconTip } from '@elastic/eui'; +import { EuiIconTip } from '@elastic/eui'; describe('FeatureTableCell', () => { - it('renders an icon and feature name', () => { + it('renders the feature name', () => { const feature = createFeature({ id: 'test-feature', name: 'Test Feature', @@ -23,13 +23,10 @@ describe('FeatureTableCell', () => { ); expect(wrapper.text()).toMatchInlineSnapshot(`"Test Feature "`); - expect(wrapper.find(EuiIcon).props()).toMatchObject({ - type: feature.icon, - }); expect(wrapper.find(EuiIconTip)).toHaveLength(0); }); - it('renders an icon and feature name with tooltip when configured', () => { + it('renders a feature name with tooltip when configured', () => { const feature = createFeature({ id: 'test-feature', name: 'Test Feature', @@ -41,9 +38,7 @@ describe('FeatureTableCell', () => { ); expect(wrapper.text()).toMatchInlineSnapshot(`"Test Feature "`); - expect(wrapper.find(EuiIcon).first().props()).toMatchObject({ - type: feature.icon, - }); + expect(wrapper.find(EuiIconTip).props().content).toMatchInlineSnapshot(`

    diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table_cell/feature_table_cell.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table_cell/feature_table_cell.tsx index 77445952f3d69..869be7f6a583a 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table_cell/feature_table_cell.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table_cell/feature_table_cell.tsx @@ -4,10 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -import './feature_table_cell.scss'; - import React from 'react'; -import { EuiText, EuiIconTip, EuiIcon, IconType } from '@elastic/eui'; +import { EuiText, EuiIconTip } from '@elastic/eui'; import { SecuredFeature } from '../../../../model'; interface Props { @@ -35,8 +33,7 @@ export const FeatureTableCell = ({ feature }: Props) => { } return ( - - + {feature.name} {tooltipElement} ); diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/privilege_summary.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/privilege_summary.tsx index e0889d91d759a..aa37b95ba3f2a 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/privilege_summary.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/privilege_summary.tsx @@ -6,16 +6,9 @@ import React, { useState, Fragment } from 'react'; import { FormattedMessage } from '@kbn/i18n/react'; -import { - EuiModal, - EuiButtonEmpty, - EuiOverlayMask, - EuiModalHeader, - EuiModalHeaderTitle, - EuiModalBody, - EuiModalFooter, - EuiButton, -} from '@elastic/eui'; +import { EuiButtonEmpty, EuiOverlayMask, EuiButton } from '@elastic/eui'; +import { EuiFlyout } from '@elastic/eui'; +import { EuiFlyoutHeader, EuiTitle, EuiFlyoutBody, EuiFlyoutFooter } from '@elastic/eui'; import { Space } from '../../../../../../../../spaces/common/model/space'; import { Role } from '../../../../../../../common/model'; import { PrivilegeSummaryTable } from './privilege_summary_table'; @@ -30,6 +23,9 @@ interface Props { export const PrivilegeSummary = (props: Props) => { const [isOpen, setIsOpen] = useState(false); + const numberOfPrivilegeDefinitions = props.role.kibana.length; + const flyoutSize = numberOfPrivilegeDefinitions > 5 ? 'l' : 'm'; + return ( setIsOpen(true)} data-test-subj="viewPrivilegeSummaryButton"> @@ -39,33 +35,35 @@ export const PrivilegeSummary = (props: Props) => { /> {isOpen && ( - - setIsOpen(false)} maxWidth={false}> - - - - - - + + setIsOpen(false)} size={flyoutSize}> + + +

    + +

    + + + - - + + setIsOpen(false)}> - - + + )} diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/privilege_summary_table.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/privilege_summary_table.tsx index 4b5169de3dfc3..8d24c0b220863 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/privilege_summary_table.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/privilege_summary_table.tsx @@ -4,14 +4,19 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { useState } from 'react'; +import React, { useMemo, useState, Fragment } from 'react'; import { FormattedMessage } from '@kbn/i18n/react'; import { + EuiFlexGroup, + EuiFlexItem, EuiInMemoryTable, EuiBasicTableColumn, EuiButtonIcon, EuiIcon, EuiIconTip, + EuiSpacer, + EuiAccordion, + EuiTitle, } from '@elastic/eui'; import { Space } from '../../../../../../../../spaces/common/model/space'; import { Role, RoleKibanaPrivilege } from '../../../../../../../common/model'; @@ -39,6 +44,22 @@ function getColumnKey(entry: RoleKibanaPrivilege) { export const PrivilegeSummaryTable = (props: Props) => { const [expandedFeatures, setExpandedFeatures] = useState([]); + const featureCategories = useMemo(() => { + const featureCategoryMap = new Map(); + + props.kibanaPrivileges + .getSecuredFeatures() + .filter((feature) => feature.privileges != null || feature.reserved != null) + .forEach((feature) => { + if (!featureCategoryMap.has(feature.category.id)) { + featureCategoryMap.set(feature.category.id, []); + } + featureCategoryMap.get(feature.category.id)!.push(feature); + }); + + return featureCategoryMap; + }, [props.kibanaPrivileges]); + const calculator = new PrivilegeSummaryCalculator(props.kibanaPrivileges, props.role); const toggleExpandedFeature = (featureId: string) => { @@ -140,35 +161,80 @@ export const PrivilegeSummaryTable = (props: Props) => { }; }, {} as Record); - const items = props.kibanaPrivileges.getSecuredFeatures().map((feature) => { - return { - feature, - featureId: feature.id, - ...privileges, - }; + const accordions: any[] = []; + + featureCategories.forEach((featuresInCategory) => { + const { category } = featuresInCategory[0]; + + const buttonContent = ( + + {category.euiIconType ? ( + + + + ) : null} + + +

    {category.label}

    +
    +
    +
    + ); + + const categoryItems = featuresInCategory.map((feature) => { + return { + feature, + featureId: feature.id, + ...privileges, + }; + }); + + accordions.push( + + { + return { + 'data-test-subj': `summaryTableRow-${record.featureId}`, + }; + }} + itemIdToExpandedRowMap={expandedFeatures.reduce((acc, featureId) => { + return { + ...acc, + [featureId]: ( + p[featureId])} + /> + ), + }; + }, {})} + /> + + ); }); return ( - { - return { - 'data-test-subj': `summaryTableRow-${record.featureId}`, - }; - }} - itemIdToExpandedRowMap={expandedFeatures.reduce((acc, featureId) => { - return { - ...acc, - [featureId]: ( - p[featureId])} - /> - ), - }; - }, {})} - /> + <> + {accordions.map((a, idx) => ( + + {a} + + + ))} + ); }; diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/space_column_header.test.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/space_column_header.test.tsx index b691056528498..3c9d1789fa5ab 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/space_column_header.test.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/space_column_header.test.tsx @@ -43,7 +43,7 @@ const spaces = [ ]; describe('SpaceColumnHeader', () => { - it('renders the Global privilege definition with a special label and popover control', () => { + it('renders the Global privilege definition with a special label', () => { const wrapper = mountWithIntl( { /> ); - expect(wrapper.find(SpacesPopoverList)).toHaveLength(1); // Snapshot includes space avatar (The first "G"), followed by the "Global" label, // followed by the (all spaces) text as part of the SpacesPopoverList - expect(wrapper.text()).toMatchInlineSnapshot(`"G Global(all spaces)"`); + expect(wrapper.text()).toMatchInlineSnapshot(`"G All Spaces"`); }); it('renders a placeholder space when the requested space no longer exists', () => { diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/space_column_header.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/space_column_header.tsx index 24ac0022b12af..a1641577dbb2f 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/space_column_header.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/space_column_header.tsx @@ -39,17 +39,7 @@ export const SpaceColumnHeader = (props: Props) => { -
    - s.id !== '*')} - buttonText={i18n.translate( - 'xpack.security.management.editRole.spacePrivilegeMatrix.showAllSpacesLink', - { - defaultMessage: '(all spaces)', - } - )} + defaultMessage="All Spaces" />
    )} diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_form.test.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_form.test.tsx index 32eed6c878016..e4dc0606ebf67 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_form.test.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_form.test.tsx @@ -11,11 +11,11 @@ import { mountWithIntl } from 'test_utils/enzyme_helpers'; import { PrivilegeSpaceForm } from './privilege_space_form'; import React from 'react'; import { Space } from '../../../../../../../../spaces/public'; -import { EuiSuperSelect } from '@elastic/eui'; import { FeatureTable } from '../feature_table'; import { getDisplayedFeaturePrivileges } from '../feature_table/__fixtures__'; import { findTestSubject } from 'test_utils/find_test_subject'; import { SpaceSelector } from './space_selector'; +import { EuiButtonGroup } from '@elastic/eui'; const createRole = (kibana: Role['kibana'] = []): Role => { return { @@ -59,7 +59,9 @@ describe('PrivilegeSpaceForm', () => { /> ); - expect(wrapper.find(EuiSuperSelect).props().valueOfSelected).toEqual(`basePrivilege_custom`); + expect( + wrapper.find(EuiButtonGroup).filter('[name="basePrivilegeButtonGroup"]').props().idSelected + ).toEqual(`basePrivilege_custom`); expect(wrapper.find(FeatureTable).props().disabled).toEqual(true); expect(getDisplayedFeaturePrivileges(wrapper)).toMatchInlineSnapshot(` Object { @@ -69,6 +71,7 @@ describe('PrivilegeSpaceForm', () => { }, "no_sub_features": Object { "primaryFeaturePrivilege": "none", + "subFeaturePrivileges": Array [], }, "with_excluded_sub_features": Object { "primaryFeaturePrivilege": "none", @@ -106,7 +109,9 @@ describe('PrivilegeSpaceForm', () => { /> ); - expect(wrapper.find(EuiSuperSelect).props().valueOfSelected).toEqual(`basePrivilege_all`); + expect( + wrapper.find(EuiButtonGroup).filter('[name="basePrivilegeButtonGroup"]').props().idSelected + ).toEqual(`basePrivilege_all`); expect(wrapper.find(FeatureTable).props().disabled).toEqual(true); expect(getDisplayedFeaturePrivileges(wrapper)).toMatchInlineSnapshot(` Object { @@ -116,6 +121,7 @@ describe('PrivilegeSpaceForm', () => { }, "no_sub_features": Object { "primaryFeaturePrivilege": "all", + "subFeaturePrivileges": Array [], }, "with_excluded_sub_features": Object { "primaryFeaturePrivilege": "all", @@ -159,7 +165,9 @@ describe('PrivilegeSpaceForm', () => { /> ); - expect(wrapper.find(EuiSuperSelect).props().valueOfSelected).toEqual(`basePrivilege_custom`); + expect( + wrapper.find(EuiButtonGroup).filter('[name="basePrivilegeButtonGroup"]').props().idSelected + ).toEqual(`basePrivilege_custom`); expect(wrapper.find(FeatureTable).props().disabled).toEqual(false); expect(getDisplayedFeaturePrivileges(wrapper)).toMatchInlineSnapshot(` Object { @@ -169,6 +177,7 @@ describe('PrivilegeSpaceForm', () => { }, "no_sub_features": Object { "primaryFeaturePrivilege": "none", + "subFeaturePrivileges": Array [], }, "with_excluded_sub_features": Object { "primaryFeaturePrivilege": "none", @@ -256,7 +265,10 @@ describe('PrivilegeSpaceForm', () => { /> ); - expect(wrapper.find(EuiSuperSelect).props().valueOfSelected).toEqual(`basePrivilege_custom`); + expect( + wrapper.find(EuiButtonGroup).filter('[name="basePrivilegeButtonGroup"]').props().idSelected + ).toEqual(`basePrivilege_custom`); + expect(wrapper.find(FeatureTable).props().disabled).toEqual(false); expect(getDisplayedFeaturePrivileges(wrapper)).toMatchInlineSnapshot(` Object { @@ -266,6 +278,7 @@ describe('PrivilegeSpaceForm', () => { }, "no_sub_features": Object { "primaryFeaturePrivilege": "none", + "subFeaturePrivileges": Array [], }, "with_excluded_sub_features": Object { "primaryFeaturePrivilege": "none", diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_form.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_form.tsx index 6c43f2f7ea734..28bbd55c7d544 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_form.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_form.tsx @@ -18,7 +18,6 @@ import { EuiFormRow, EuiOverlayMask, EuiSpacer, - EuiSuperSelect, EuiText, EuiTitle, EuiErrorBoundary, @@ -26,6 +25,7 @@ import { import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import React, { Component, Fragment } from 'react'; +import { EuiButtonGroup } from '@elastic/eui'; import { Space } from '../../../../../../../../spaces/public'; import { Role, copyRole } from '../../../../../../../common/model'; import { SpaceSelector } from './space_selector'; @@ -95,7 +95,7 @@ export class PrivilegeSpaceForm extends Component {

    @@ -164,6 +164,13 @@ export class PrivilegeSpaceForm extends Component { defaultMessage: 'Spaces', } )} + helpText={i18n.translate( + 'xpack.security.management.editRole.spacePrivilegeForm.spaceSelectorFormHelpText', + { + defaultMessage: + 'Select one or more Kibana spaces to which you wish to assign privileges.', + } + )} > { label={i18n.translate( 'xpack.security.management.editRole.spacePrivilegeForm.privilegeSelectorFormLabel', { - defaultMessage: 'Privilege', + defaultMessage: 'Privileges for all features', + } + )} + helpText={i18n.translate( + 'xpack.security.management.editRole.spacePrivilegeForm.privilegeSelectorFormHelpText', + { + defaultMessage: + 'Assign the privilege level you wish to grant to all present and future features across this space.', } )} > - - -
    - ), - dropdownDisplay: ( - - - - -

    - -

    -
    - ), + id: 'basePrivilege_all', + label: 'All', + ['data-test-subj']: 'basePrivilege_all', }, { - value: 'basePrivilege_read', - inputDisplay: ( - - - - ), - dropdownDisplay: ( - - - - -

    - -

    -
    - ), + id: 'basePrivilege_read', + label: 'Read', + ['data-test-subj']: 'basePrivilege_read', }, { - value: 'basePrivilege_all', - inputDisplay: ( - - - - ), - dropdownDisplay: ( - - - - -

    - -

    -
    - ), + id: 'basePrivilege_custom', + label: 'Customize', + ['data-test-subj']: 'basePrivilege_custom', }, ]} - hasDividers - valueOfSelected={this.getDisplayedBasePrivilege()} - disabled={!hasSelectedSpaces} + idSelected={this.getDisplayedBasePrivilege()} + isDisabled={!hasSelectedSpaces} + onChange={this.onSpaceBasePrivilegeChange} />
    - +

    {this.getFeatureListLabel(this.state.selectedBasePrivilege.length > 0)}

    @@ -338,7 +287,7 @@ export class PrivilegeSpaceForm extends Component { buttonText = ( ); } diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_table.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_table.tsx index 64b7fe3e2e3a9..6bb9840fd343c 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_table.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_table.tsx @@ -23,7 +23,6 @@ import { FormattedMessage } from '@kbn/i18n/react'; import React, { Component } from 'react'; import { Space, getSpaceColor } from '../../../../../../../../spaces/public'; import { FeaturesPrivileges, Role, copyRole } from '../../../../../../../common/model'; -import { SpacesPopoverList } from '../../../spaces_popover_list'; import { PrivilegeDisplay } from './privilege_display'; import { isGlobalPrivilegeDefinition } from '../../../privilege_utils'; import { PrivilegeFormCalculator } from '../privilege_form_calculator'; @@ -118,19 +117,7 @@ export class PrivilegeSpaceTable extends Component { const displayedSpaces = isExpanded ? spaces : spaces.slice(0, SPACES_DISPLAY_COUNT); let button = null; - if (record.isGlobal) { - button = ( - s.id !== '*')} - buttonText={i18n.translate( - 'xpack.security.management.editRole.spacePrivilegeTable.showAllSpacesLink', - { - defaultMessage: 'show spaces', - } - )} - /> - ); - } else if (spaces.length > displayedSpaces.length) { + if (spaces.length > displayedSpaces.length) { button = ( { name: i18n.translate( 'xpack.security.management.editRole.spaceAwarePrivilegeForm.globalSpacesName', { - defaultMessage: '* Global (all spaces)', + defaultMessage: '* All Spaces', } ), color: '#D3DAE6', @@ -198,7 +198,7 @@ export class SpaceAwarePrivilegeSection extends Component { > ); diff --git a/x-pack/plugins/spaces/public/management/edit_space/customize_space/customize_space.tsx b/x-pack/plugins/spaces/public/management/edit_space/customize_space/customize_space.tsx index 911a6b78a4944..95295b8e64732 100644 --- a/x-pack/plugins/spaces/public/management/edit_space/customize_space/customize_space.tsx +++ b/x-pack/plugins/spaces/public/management/edit_space/customize_space/customize_space.tsx @@ -58,7 +58,7 @@ export class CustomizeSpace extends Component { }; return ( - + diff --git a/x-pack/plugins/spaces/public/management/edit_space/enabled_features/__snapshots__/enabled_features.test.tsx.snap b/x-pack/plugins/spaces/public/management/edit_space/enabled_features/__snapshots__/enabled_features.test.tsx.snap index ee1eb7c5e9aba..063a34091c4e7 100644 --- a/x-pack/plugins/spaces/public/management/edit_space/enabled_features/__snapshots__/enabled_features.test.tsx.snap +++ b/x-pack/plugins/spaces/public/management/edit_space/enabled_features/__snapshots__/enabled_features.test.tsx.snap @@ -2,10 +2,8 @@ exports[`EnabledFeatures renders as expected 1`] = ` { return (
    - - - hide - -

    diff --git a/x-pack/plugins/spaces/public/management/edit_space/section_panel/section_panel.test.tsx b/x-pack/plugins/spaces/public/management/edit_space/section_panel/section_panel.test.tsx index 0b8085ff1ad16..576881398a63c 100644 --- a/x-pack/plugins/spaces/public/management/edit_space/section_panel/section_panel.test.tsx +++ b/x-pack/plugins/spaces/public/management/edit_space/section_panel/section_panel.test.tsx @@ -4,14 +4,13 @@ * you may not use this file except in compliance with the Elastic License. */ -import { EuiLink } from '@elastic/eui'; import React from 'react'; import { mountWithIntl, shallowWithIntl } from 'test_utils/enzyme_helpers'; import { SectionPanel } from './section_panel'; test('it renders without blowing up', () => { const wrapper = shallowWithIntl( - +

    child

    ); @@ -19,9 +18,9 @@ test('it renders without blowing up', () => { expect(wrapper).toMatchSnapshot(); }); -test('it renders children by default', () => { +test('it renders children', () => { const wrapper = mountWithIntl( - +

    child 1

    child 2

    @@ -30,19 +29,3 @@ test('it renders children by default', () => { expect(wrapper.find(SectionPanel)).toHaveLength(1); expect(wrapper.find('.child')).toHaveLength(2); }); - -test('it hides children when the "hide" link is clicked', () => { - const wrapper = mountWithIntl( - -

    child 1

    -

    child 2

    -
    - ); - - expect(wrapper.find(SectionPanel)).toHaveLength(1); - expect(wrapper.find('.child')).toHaveLength(2); - - wrapper.find(EuiLink).simulate('click'); - - expect(wrapper.find('.child')).toHaveLength(0); -}); diff --git a/x-pack/plugins/spaces/public/management/edit_space/section_panel/section_panel.tsx b/x-pack/plugins/spaces/public/management/edit_space/section_panel/section_panel.tsx index a6d25511acba6..492932aa95741 100644 --- a/x-pack/plugins/spaces/public/management/edit_space/section_panel/section_panel.tsx +++ b/x-pack/plugins/spaces/public/management/edit_space/section_panel/section_panel.tsx @@ -8,39 +8,20 @@ import { EuiFlexGroup, EuiFlexItem, EuiIcon, - EuiLink, EuiPanel, EuiSpacer, EuiTitle, IconType, } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; import React, { Component, Fragment, ReactNode } from 'react'; interface Props { iconType?: IconType; title: string | ReactNode; description: string; - collapsible: boolean; - initiallyCollapsed?: boolean; } -interface State { - collapsed: boolean; -} - -export class SectionPanel extends Component { - public state = { - collapsed: false, - }; - - constructor(props: Props) { - super(props); - this.state = { - collapsed: props.initiallyCollapsed || false, - }; - } - +export class SectionPanel extends Component { public render() { return ( @@ -51,30 +32,6 @@ export class SectionPanel extends Component { } public getTitle = () => { - const showLinkText = i18n.translate('xpack.spaces.management.collapsiblePanel.showLinkText', { - defaultMessage: 'show', - }); - - const hideLinkText = i18n.translate('xpack.spaces.management.collapsiblePanel.hideLinkText', { - defaultMessage: 'hide', - }); - - const showLinkDescription = i18n.translate( - 'xpack.spaces.management.collapsiblePanel.showLinkDescription', - { - defaultMessage: 'show {title}', - values: { title: this.props.description }, - } - ); - - const hideLinkDescription = i18n.translate( - 'xpack.spaces.management.collapsiblePanel.hideLinkDescription', - { - defaultMessage: 'hide {title}', - values: { title: this.props.description }, - } - ); - return ( @@ -93,26 +50,11 @@ export class SectionPanel extends Component { - {this.props.collapsible && ( - - - {this.state.collapsed ? showLinkText : hideLinkText} - - - )} ); }; public getForm = () => { - if (this.state.collapsed) { - return null; - } - return ( @@ -120,10 +62,4 @@ export class SectionPanel extends Component { ); }; - - public toggleCollapsed = () => { - this.setState({ - collapsed: !this.state.collapsed, - }); - }; } diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index e344d18213ae5..f144cbd3873f7 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -14302,8 +14302,6 @@ "xpack.security.management.editRole.elasticSearchPrivileges.manageRoleActionsDescription": "このロールがクラスターに対して実行できる操作を管理します。 ", "xpack.security.management.editRole.elasticSearchPrivileges.runAsPrivilegesTitle": "権限として実行", "xpack.security.management.editRole.featureTable.customizeSubFeaturePrivilegesSwitchLabel": "サブ機能権限をカスタマイズする", - "xpack.security.management.editRole.featureTable.enabledRoleFeaturesEnabledColumnTitle": "権限", - "xpack.security.management.editRole.featureTable.enabledRoleFeaturesFeatureColumnTitle": "機能", "xpack.security.management.editRole.featureTable.privilegeCustomizationTooltip": "機能でサブ機能の権限がカスタマイズされています。この行を展開すると詳細が表示されます。", "xpack.security.management.editRole.indexPrivilegeForm.deleteSpacePrivilegeAriaLabel": "インデックスの権限を削除", "xpack.security.management.editRole.indexPrivilegeForm.grantedDocumentsQueryFormRowLabel": "提供されたドキュメントのクエリ", @@ -14345,35 +14343,24 @@ "xpack.security.management.editRole.spaceAwarePrivilegeForm.howToViewAllAvailableSpacesDescription": "利用可能なすべてのスペースを表示する権限がありません。", "xpack.security.management.editRole.spaceAwarePrivilegeForm.insufficientPrivilegesDescription": "権限が不十分です", "xpack.security.management.editRole.spaceAwarePrivilegeForm.kibanaAdminTitle": "kibana_admin", - "xpack.security.management.editRole.spacePrivilegeForm.allPrivilegeDetails": "選択されたスペースの全機能への完全アクセスを許可します。", - "xpack.security.management.editRole.spacePrivilegeForm.allPrivilegeDisplay": "すべて", - "xpack.security.management.editRole.spacePrivilegeForm.allPrivilegeDropdownDisplay": "すべて", "xpack.security.management.editRole.spacePrivilegeForm.cancelButton": "キャンセル", "xpack.security.management.editRole.spacePrivilegeForm.customizeFeaturePrivilegeDescription": "機能ごとに権限のレベルを上げます。機能によってはスペースごとに非表示になっているか、グローバルスペース権限による影響を受けているものもあります。", "xpack.security.management.editRole.spacePrivilegeForm.customizeFeaturePrivileges": "機能ごとにカスタマイズ", - "xpack.security.management.editRole.spacePrivilegeForm.customPrivilegeDetails": "選択されたスペースの機能ごとにアクセスをカスタマイズします", - "xpack.security.management.editRole.spacePrivilegeForm.customPrivilegeDisplay": "カスタム", - "xpack.security.management.editRole.spacePrivilegeForm.customPrivilegeDropdownDisplay": "カスタム", "xpack.security.management.editRole.spacePrivilegeForm.featurePrivilegeSummaryDescription": "機能によってはスペースごとに非表示になっているか、グローバルスペース権限による影響を受けているものもあります。", "xpack.security.management.editRole.spacePrivilegeForm.globalPrivilegeNotice": "これらの権限はすべての現在および未来のスペースに適用されます。", "xpack.security.management.editRole.spacePrivilegeForm.globalPrivilegeWarning": "グローバル権限の作成は他のスペース権限に影響を与える可能性があります。", "xpack.security.management.editRole.spacePrivilegeForm.modalTitle": "スペース権限", "xpack.security.management.editRole.spacePrivilegeForm.privilegeSelectorFormLabel": "権限", - "xpack.security.management.editRole.spacePrivilegeForm.readPrivilegeDetails": "選択されたスペースの全機能への読み込み専用アクセスを許可します。", - "xpack.security.management.editRole.spacePrivilegeForm.readPrivilegeDisplay": "読み込み", - "xpack.security.management.editRole.spacePrivilegeForm.readPrivilegeDropdownDisplay": "読み込み", "xpack.security.management.editRole.spacePrivilegeForm.spaceSelectorFormLabel": "スペース", "xpack.security.management.editRole.spacePrivilegeForm.summaryOfFeaturePrivileges": "機能権限のサマリー", "xpack.security.management.editRole.spacePrivilegeForm.supersededWarning": "宣言された権限は、構成済みグローバル権限よりも許容度が低くなります。権限サマリーを表示すると有効な権限がわかります。", "xpack.security.management.editRole.spacePrivilegeForm.supersededWarningTitle": "グローバル権限に置き換え", "xpack.security.management.editRole.spacePrivilegeMatrix.globalSpaceName": "グローバル", - "xpack.security.management.editRole.spacePrivilegeMatrix.showAllSpacesLink": "(すべてのスペース)", "xpack.security.management.editRole.spacePrivilegeMatrix.showNMoreSpacesLink": "他 {count} 件", "xpack.security.management.editRole.spacePrivilegeSection.addSpacePrivilegeButton": "スペース権限を追加", "xpack.security.management.editRole.spacePrivilegeSection.noAccessToKibanaTitle": "このロールは Kibana へのアクセスを許可しません", "xpack.security.management.editRole.spacePrivilegeTable.deletePrivilegesLabel": "次のスペースの権限を削除: {spaceNames}", "xpack.security.management.editRole.spacePrivilegeTable.editPrivilegesLabel": "次のスペースの権限を編集: {spaceNames}", - "xpack.security.management.editRole.spacePrivilegeTable.showAllSpacesLink": "スペースを表示", "xpack.security.management.editRole.spacePrivilegeTable.showLessSpacesLink": "縮小表示", "xpack.security.management.editRole.spacePrivilegeTable.showNMoreSpacesLink": "他 {count} 件", "xpack.security.management.editRole.spacePrivilegeTable.supersededPrivilegeWarning": "権限は、構成されたグローバル権限に置き換わります。権限サマリーを表示すると有効な権限がわかります。", @@ -17360,10 +17347,6 @@ "xpack.spaces.management.advancedSettingsSubtitle.applyingSettingsOnPageToSpaceDescription": "このページの設定は、別途指定されていない限り {spaceName}’スペースに適用されます。’", "xpack.spaces.management.advancedSettingsTitle.settingsTitle": "設定", "xpack.spaces.management.breadcrumb": "スペース", - "xpack.spaces.management.collapsiblePanel.hideLinkDescription": "{title} を非表示", - "xpack.spaces.management.collapsiblePanel.hideLinkText": "非表示", - "xpack.spaces.management.collapsiblePanel.showLinkDescription": "{title} を表示", - "xpack.spaces.management.collapsiblePanel.showLinkText": "表示", "xpack.spaces.management.confirmAlterActiveSpaceModal.cancelButton": "キャンセル", "xpack.spaces.management.confirmAlterActiveSpaceModal.reloadWarningMessage": "このスペースで表示される機能を更新しました。保存後にページが更新されます。", "xpack.spaces.management.confirmAlterActiveSpaceModal.title": "スペースの更新の確認", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index ab7b558afbbf2..c4a599fa35e7f 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -14311,8 +14311,6 @@ "xpack.security.management.editRole.elasticSearchPrivileges.manageRoleActionsDescription": "管理此角色可以对您的集群执行的操作。 ", "xpack.security.management.editRole.elasticSearchPrivileges.runAsPrivilegesTitle": "运行身份权限", "xpack.security.management.editRole.featureTable.customizeSubFeaturePrivilegesSwitchLabel": "定制子功能权限", - "xpack.security.management.editRole.featureTable.enabledRoleFeaturesEnabledColumnTitle": "权限", - "xpack.security.management.editRole.featureTable.enabledRoleFeaturesFeatureColumnTitle": "功能", "xpack.security.management.editRole.featureTable.privilegeCustomizationTooltip": "功能已定制子功能权限。展开此行以了解更多信息。", "xpack.security.management.editRole.indexPrivilegeForm.deleteSpacePrivilegeAriaLabel": "删除索引权限", "xpack.security.management.editRole.indexPrivilegeForm.grantedDocumentsQueryFormRowLabel": "已授权文档查询", @@ -14354,35 +14352,24 @@ "xpack.security.management.editRole.spaceAwarePrivilegeForm.howToViewAllAvailableSpacesDescription": "您无权查看所有可用工作区。", "xpack.security.management.editRole.spaceAwarePrivilegeForm.insufficientPrivilegesDescription": "权限不足", "xpack.security.management.editRole.spaceAwarePrivilegeForm.kibanaAdminTitle": "kibana_admin", - "xpack.security.management.editRole.spacePrivilegeForm.allPrivilegeDetails": "授予对选定工作区所有功能的完全访问权限。", - "xpack.security.management.editRole.spacePrivilegeForm.allPrivilegeDisplay": "全部", - "xpack.security.management.editRole.spacePrivilegeForm.allPrivilegeDropdownDisplay": "全部", "xpack.security.management.editRole.spacePrivilegeForm.cancelButton": "取消", "xpack.security.management.editRole.spacePrivilegeForm.customizeFeaturePrivilegeDescription": "按功能提高权限级别。某些功能可能被工作区隐藏或受全局工作区权限影响。", "xpack.security.management.editRole.spacePrivilegeForm.customizeFeaturePrivileges": "按功能定制", - "xpack.security.management.editRole.spacePrivilegeForm.customPrivilegeDetails": "在选定工作区中按功能定制访问权限。", - "xpack.security.management.editRole.spacePrivilegeForm.customPrivilegeDisplay": "定制", - "xpack.security.management.editRole.spacePrivilegeForm.customPrivilegeDropdownDisplay": "定制", "xpack.security.management.editRole.spacePrivilegeForm.featurePrivilegeSummaryDescription": "某些功能可能被工作区隐藏或受全局工作区权限影响。", "xpack.security.management.editRole.spacePrivilegeForm.globalPrivilegeNotice": "这些权限将应用到所有当前和未来工作区。", "xpack.security.management.editRole.spacePrivilegeForm.globalPrivilegeWarning": "创建全局权限可能会影响您的其他工作区权限。", "xpack.security.management.editRole.spacePrivilegeForm.modalTitle": "工作区权限", "xpack.security.management.editRole.spacePrivilegeForm.privilegeSelectorFormLabel": "权限", - "xpack.security.management.editRole.spacePrivilegeForm.readPrivilegeDetails": "授予对选定工作区所有功能的只读访问权限。", - "xpack.security.management.editRole.spacePrivilegeForm.readPrivilegeDisplay": "读取", - "xpack.security.management.editRole.spacePrivilegeForm.readPrivilegeDropdownDisplay": "读取", "xpack.security.management.editRole.spacePrivilegeForm.spaceSelectorFormLabel": "工作区", "xpack.security.management.editRole.spacePrivilegeForm.summaryOfFeaturePrivileges": "功能权限的摘要", "xpack.security.management.editRole.spacePrivilegeForm.supersededWarning": "声明的权限相对配置的全局权限有较小的宽容度。查看权限摘要以查看有效的权限。", "xpack.security.management.editRole.spacePrivilegeForm.supersededWarningTitle": "已由全局权限取代", "xpack.security.management.editRole.spacePrivilegeMatrix.globalSpaceName": "全局", - "xpack.security.management.editRole.spacePrivilegeMatrix.showAllSpacesLink": "(所有工作区)", "xpack.security.management.editRole.spacePrivilegeMatrix.showNMoreSpacesLink": "另外 {count} 个", "xpack.security.management.editRole.spacePrivilegeSection.addSpacePrivilegeButton": "添加工作区权限", "xpack.security.management.editRole.spacePrivilegeSection.noAccessToKibanaTitle": "此角色未授予对 Kibana 的访问权限", "xpack.security.management.editRole.spacePrivilegeTable.deletePrivilegesLabel": "删除以下工作区的权限:{spaceNames}。", "xpack.security.management.editRole.spacePrivilegeTable.editPrivilegesLabel": "编辑以下工作区的权限:{spaceNames}。", - "xpack.security.management.editRole.spacePrivilegeTable.showAllSpacesLink": "显示工作区", "xpack.security.management.editRole.spacePrivilegeTable.showLessSpacesLink": "显示更少", "xpack.security.management.editRole.spacePrivilegeTable.showNMoreSpacesLink": "另外 {count} 个", "xpack.security.management.editRole.spacePrivilegeTable.supersededPrivilegeWarning": "权限已由配置的全局权限取代。查看权限摘要以查看有效的权限。", @@ -17370,10 +17357,6 @@ "xpack.spaces.management.advancedSettingsSubtitle.applyingSettingsOnPageToSpaceDescription": "除非已指定,否则此页面上的设置适用于 {spaceName} 空间。", "xpack.spaces.management.advancedSettingsTitle.settingsTitle": "设置", "xpack.spaces.management.breadcrumb": "工作区", - "xpack.spaces.management.collapsiblePanel.hideLinkDescription": "隐藏 {title}", - "xpack.spaces.management.collapsiblePanel.hideLinkText": "隐藏", - "xpack.spaces.management.collapsiblePanel.showLinkDescription": "显示 {title}", - "xpack.spaces.management.collapsiblePanel.showLinkText": "显示", "xpack.spaces.management.confirmAlterActiveSpaceModal.cancelButton": "取消", "xpack.spaces.management.confirmAlterActiveSpaceModal.reloadWarningMessage": "您已更新此工作区中的可见功能。保存后,您的页面将重新加载。", "xpack.spaces.management.confirmAlterActiveSpaceModal.title": "确认更新工作区", diff --git a/x-pack/test/functional/page_objects/security_page.ts b/x-pack/test/functional/page_objects/security_page.ts index 3ce8a0e681d69..77457ad94cf88 100644 --- a/x-pack/test/functional/page_objects/security_page.ts +++ b/x-pack/test/functional/page_objects/security_page.ts @@ -429,10 +429,7 @@ export function SecurityPageProvider({ getService, getPageObjects }: FtrProvider const globalSpaceOption = await find.byCssSelector(`#spaceOption_\\*`); await globalSpaceOption.click(); - await testSubjects.click('basePrivilegeComboBox'); - - const privilegeOption = await find.byCssSelector(`#basePrivilege_${privilegeName}`); - await privilegeOption.click(); + await testSubjects.click(`basePrivilege_${privilegeName}`); await testSubjects.click('createSpacePrivilegeButton'); } From 79eb9b7b7a47c4859020b0b84db911143fbffbb4 Mon Sep 17 00:00:00 2001 From: Paul Tavares <56442535+paul-tavares@users.noreply.github.com> Date: Fri, 2 Oct 2020 08:53:55 -0400 Subject: [PATCH 37/50] Use `process.executable` instead of `process.path` (#79216) --- .../common/endpoint/schema/trusted_apps.test.ts | 4 ++-- .../common/endpoint/schema/trusted_apps.ts | 2 +- .../common/endpoint/types/trusted_apps.ts | 2 +- .../components/condition_entry.tsx | 2 +- .../components/trusted_app_card/index.stories.tsx | 4 ++-- .../routes/trusted_apps/trusted_apps.test.ts | 14 +++++++------- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/x-pack/plugins/security_solution/common/endpoint/schema/trusted_apps.test.ts b/x-pack/plugins/security_solution/common/endpoint/schema/trusted_apps.test.ts index 13a3fb96e10f7..ef1d9a99b0aeb 100644 --- a/x-pack/plugins/security_solution/common/endpoint/schema/trusted_apps.test.ts +++ b/x-pack/plugins/security_solution/common/endpoint/schema/trusted_apps.test.ts @@ -76,7 +76,7 @@ describe('When invoking Trusted Apps Schema', () => { os: 'windows', entries: [ { - field: 'process.path.text', + field: 'process.executable.text', type: 'match', operator: 'included', value: 'c:/programs files/Anti-Virus', @@ -204,7 +204,7 @@ describe('When invoking Trusted Apps Schema', () => { field: 'process.hash.*', value: 'A4370C0CF81686C0B696FA6261c9d3e0d810ae704ab8301839dffd5d5112f476', }, - { field: 'process.path.text', value: '/tmp/dir1' }, + { field: 'process.executable.text', value: '/tmp/dir1' }, ].forEach((partialEntry) => { const bodyMsg3 = { ...getCreateTrustedAppItem(), diff --git a/x-pack/plugins/security_solution/common/endpoint/schema/trusted_apps.ts b/x-pack/plugins/security_solution/common/endpoint/schema/trusted_apps.ts index 912468b52adc0..25456115b3713 100644 --- a/x-pack/plugins/security_solution/common/endpoint/schema/trusted_apps.ts +++ b/x-pack/plugins/security_solution/common/endpoint/schema/trusted_apps.ts @@ -35,7 +35,7 @@ export const PostTrustedAppCreateRequestSchema = { schema.object({ field: schema.oneOf([ schema.literal('process.hash.*'), - schema.literal('process.path.text'), + schema.literal('process.executable.text'), ]), type: schema.literal('match'), operator: schema.literal('included'), diff --git a/x-pack/plugins/security_solution/common/endpoint/types/trusted_apps.ts b/x-pack/plugins/security_solution/common/endpoint/types/trusted_apps.ts index c0afe3b612d82..75e0347b10078 100644 --- a/x-pack/plugins/security_solution/common/endpoint/types/trusted_apps.ts +++ b/x-pack/plugins/security_solution/common/endpoint/types/trusted_apps.ts @@ -33,7 +33,7 @@ export interface PostTrustedAppCreateResponse { } export interface MacosLinuxConditionEntry { - field: 'process.hash.*' | 'process.path.text'; + field: 'process.hash.*' | 'process.executable.text'; type: 'match'; operator: 'included'; value: string; diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/logical_condition/components/condition_entry.tsx b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/logical_condition/components/condition_entry.tsx index 7f7eae18b0816..7d30e81898cf2 100644 --- a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/logical_condition/components/condition_entry.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/logical_condition/components/condition_entry.tsx @@ -83,7 +83,7 @@ export const ConditionEntry = memo( 'xpack.securitySolution.trustedapps.logicalConditionBuilder.entry.field.path', { defaultMessage: 'Path' } ), - value: 'process.path.text', + value: 'process.executable.text', }, ]; }, []); diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/trusted_app_card/index.stories.tsx b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/trusted_app_card/index.stories.tsx index 713e5e7095e12..4b64030a702c5 100644 --- a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/trusted_app_card/index.stories.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/trusted_app_card/index.stories.tsx @@ -30,7 +30,7 @@ storiesOf('TrustedApps|TrustedAppCard', module) trustedApp.created_at = '2020-09-17T14:52:33.899Z'; trustedApp.entries = [ { - field: 'process.path.text', + field: 'process.executable.text', operator: 'included', type: 'match', value: '/some/path/on/file/system', @@ -44,7 +44,7 @@ storiesOf('TrustedApps|TrustedAppCard', module) trustedApp.created_at = '2020-09-17T14:52:33.899Z'; trustedApp.entries = [ { - field: 'process.path.text', + field: 'process.executable.text', operator: 'included', type: 'match', value: '/some/path/on/file/system', diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/trusted_apps.test.ts b/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/trusted_apps.test.ts index 98c9b79f32d6b..9e9a35ea35318 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/trusted_apps.test.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/trusted_apps.test.ts @@ -240,7 +240,7 @@ describe('when invoking endpoint trusted apps route handlers', () => { os: 'windows', entries: [ { - field: 'process.path.text', + field: 'process.executable.text', type: 'match', operator: 'included', value: 'c:/programs files/Anti-Virus', @@ -293,7 +293,7 @@ describe('when invoking endpoint trusted apps route handlers', () => { description: 'this one is ok', entries: [ { - field: 'process.path.text', + field: 'process.executable.text', operator: 'included', type: 'match', value: 'c:/programs files/Anti-Virus', @@ -320,7 +320,7 @@ describe('when invoking endpoint trusted apps route handlers', () => { description: 'this one is ok', entries: [ { - field: 'process.path.text', + field: 'process.executable.text', operator: 'included', type: 'match', value: 'c:/programs files/Anti-Virus', @@ -357,7 +357,7 @@ describe('when invoking endpoint trusted apps route handlers', () => { it('should trim condition entry values', async () => { const newTrustedApp = createNewTrustedAppBody(); newTrustedApp.entries.push({ - field: 'process.path.text', + field: 'process.executable.text', value: '\n some value \r\n ', operator: 'included', type: 'match', @@ -366,13 +366,13 @@ describe('when invoking endpoint trusted apps route handlers', () => { await routeHandler(context, request, response); expect(exceptionsListClient.createExceptionListItem.mock.calls[0][0].entries).toEqual([ { - field: 'process.path.text', + field: 'process.executable.text', operator: 'included', type: 'match', value: 'c:/programs files/Anti-Virus', }, { - field: 'process.path.text', + field: 'process.executable.text', value: 'some value', operator: 'included', type: 'match', @@ -392,7 +392,7 @@ describe('when invoking endpoint trusted apps route handlers', () => { await routeHandler(context, request, response); expect(exceptionsListClient.createExceptionListItem.mock.calls[0][0].entries).toEqual([ { - field: 'process.path.text', + field: 'process.executable.text', operator: 'included', type: 'match', value: 'c:/programs files/Anti-Virus', From 0628cfecf4ef2d0bab6525702d5a98404cd37509 Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Fri, 2 Oct 2020 14:30:32 +0100 Subject: [PATCH 38/50] skip flaky suite (#79249) --- .../spaces_only/tests/alerting/execution_status.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/execution_status.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/execution_status.ts index ac63fe8faadc7..1c2e51637fb41 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/execution_status.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/execution_status.ts @@ -19,7 +19,8 @@ import { FtrProviderContext } from '../../../common/ftr_provider_context'; export default function executionStatusAlertTests({ getService }: FtrProviderContext) { const supertest = getService('supertest'); - describe('executionStatus', () => { + // FLAKY: https://github.com/elastic/kibana/issues/79249 + describe.skip('executionStatus', () => { const objectRemover = new ObjectRemover(supertest); after(async () => await objectRemover.removeAll()); From a7d9e2f481c0d15b8fe6d8cedef881a310c23be7 Mon Sep 17 00:00:00 2001 From: Ryan Keairns Date: Fri, 2 Oct 2020 08:39:37 -0500 Subject: [PATCH 39/50] Improved empty state for nav search (#79123) * Improved empty state for nav search * Updates tests to include required props * Update empty state text --- ...tration_product_no_search_results_dark.svg | 1 + ...ration_product_no_search_results_light.svg | 1 + .../public/components/search_bar.test.tsx | 21 +++++++- .../public/components/search_bar.tsx | 51 ++++++++++++------- .../global_search_bar/public/plugin.tsx | 20 ++++++-- 5 files changed, 72 insertions(+), 22 deletions(-) create mode 100644 x-pack/plugins/global_search_bar/public/assets/illustration_product_no_search_results_dark.svg create mode 100644 x-pack/plugins/global_search_bar/public/assets/illustration_product_no_search_results_light.svg diff --git a/x-pack/plugins/global_search_bar/public/assets/illustration_product_no_search_results_dark.svg b/x-pack/plugins/global_search_bar/public/assets/illustration_product_no_search_results_dark.svg new file mode 100644 index 0000000000000..3a87f06b7bcc8 --- /dev/null +++ b/x-pack/plugins/global_search_bar/public/assets/illustration_product_no_search_results_dark.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/x-pack/plugins/global_search_bar/public/assets/illustration_product_no_search_results_light.svg b/x-pack/plugins/global_search_bar/public/assets/illustration_product_no_search_results_light.svg new file mode 100644 index 0000000000000..ac5298be17cca --- /dev/null +++ b/x-pack/plugins/global_search_bar/public/assets/illustration_product_no_search_results_light.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/x-pack/plugins/global_search_bar/public/components/search_bar.test.tsx b/x-pack/plugins/global_search_bar/public/components/search_bar.test.tsx index 11fbc7931e620..6fad3335c5efc 100644 --- a/x-pack/plugins/global_search_bar/public/components/search_bar.test.tsx +++ b/x-pack/plugins/global_search_bar/public/components/search_bar.test.tsx @@ -8,6 +8,7 @@ import React from 'react'; import { wait } from '@testing-library/react'; import { of } from 'rxjs'; import { mountWithIntl } from 'test_utils/enzyme_helpers'; +import { httpServiceMock, uiSettingsServiceMock } from '../../../../../src/core/public/mocks'; import { GlobalSearchBatchedResults, GlobalSearchPluginStart, @@ -47,6 +48,10 @@ const getSearchProps: any = (component: any) => component.find('EuiFieldSearch') describe('SearchBar', () => { let searchService: GlobalSearchPluginStart; let findSpy: jest.SpyInstance; + const http = httpServiceMock.createSetupContract({ basePath: '/test' }); + const basePathUrl = http.basePath.prepend('/plugins/globalSearchBar/assets/'); + const uiSettings = uiSettingsServiceMock.createStartContract(); + const darkMode = uiSettings.get('theme:darkMode'); beforeEach(() => { searchService = globalSearchPluginMock.createStartContract(); @@ -66,7 +71,12 @@ describe('SearchBar', () => { .mockReturnValueOnce(of(createBatch('Discover', { id: 'My Dashboard', type: 'test' }))); const component = mountWithIntl( - + ); expect(findSpy).toHaveBeenCalledTimes(0); @@ -85,7 +95,14 @@ describe('SearchBar', () => { }); it('supports keyboard shortcuts', () => { - mountWithIntl(); + mountWithIntl( + + ); const searchEvent = new KeyboardEvent('keydown', { key: '/', diff --git a/x-pack/plugins/global_search_bar/public/components/search_bar.tsx b/x-pack/plugins/global_search_bar/public/components/search_bar.tsx index 0dde28db0436d..4ca0f8cf81b7b 100644 --- a/x-pack/plugins/global_search_bar/public/components/search_bar.tsx +++ b/x-pack/plugins/global_search_bar/public/components/search_bar.tsx @@ -12,6 +12,7 @@ import { EuiSelectableTemplateSitewideOption, EuiText, EuiIcon, + EuiImage, EuiHeaderSectionItemButton, EuiSelectableMessage, } from '@elastic/eui'; @@ -27,6 +28,8 @@ import { GlobalSearchPluginStart, GlobalSearchResult } from '../../../global_sea interface Props { globalSearch: GlobalSearchPluginStart['find']; navigateToUrl: ApplicationStart['navigateToUrl']; + basePathUrl: string; + darkMode: boolean; } const clearField = (field: HTMLInputElement) => { @@ -42,7 +45,7 @@ const clearField = (field: HTMLInputElement) => { const cleanMeta = (str: string) => (str.charAt(0).toUpperCase() + str.slice(1)).replace(/-/g, ' '); const blurEvent = new FocusEvent('blur'); -export function SearchBar({ globalSearch, navigateToUrl }: Props) { +export function SearchBar({ globalSearch, navigateToUrl, basePathUrl, darkMode }: Props) { const isMounted = useMountedState(); const [searchValue, setSearchValue] = useState(''); const [searchRef, setSearchRef] = useState(null); @@ -134,6 +137,34 @@ export function SearchBar({ globalSearch, navigateToUrl }: Props) { } }; + const emptyMessage = ( + + + +

    + +

    +
    +

    + +

    +
    + ); + useEvent('keydown', onKeyDown); return ( @@ -164,22 +195,8 @@ export function SearchBar({ globalSearch, navigateToUrl }: Props) { popoverProps={{ repositionOnScroll: true, }} - emptyMessage={ - -

    - -

    -

    - -

    -
    - } + emptyMessage={emptyMessage} + noMatchesMessage={emptyMessage} popoverFooter={ { public start(core: CoreStart, { globalSearch }: GlobalSearchBarPluginStartDeps) { core.chrome.navControls.registerCenter({ order: 1000, - mount: (target) => this.mount(target, globalSearch, core.application.navigateToUrl), + mount: (target) => + this.mount( + target, + globalSearch, + core.application.navigateToUrl, + core.http.basePath.prepend('/plugins/globalSearchBar/assets/'), + core.uiSettings.get('theme:darkMode') + ), }); return {}; } @@ -32,11 +39,18 @@ export class GlobalSearchBarPlugin implements Plugin<{}, {}> { private mount( targetDomElement: HTMLElement, globalSearch: GlobalSearchPluginStart, - navigateToUrl: ApplicationStart['navigateToUrl'] + navigateToUrl: ApplicationStart['navigateToUrl'], + basePathUrl: string, + darkMode: boolean ) { ReactDOM.render( - + , targetDomElement ); From 95bf8750cda2937afbc022163a1d28c0d1326e3e Mon Sep 17 00:00:00 2001 From: Bohdan Tsymbala Date: Fri, 2 Oct 2020 16:00:09 +0200 Subject: [PATCH 40/50] Refactored store code to group properties related to location so that would be easy to introduce a new view type parameter. (#79083) --- .../public/management/common/routing.test.ts | 22 +++---- .../public/management/common/routing.ts | 35 ++++++----- .../state/trusted_apps_list_page_state.ts | 12 ++-- .../trusted_apps/store/middleware.test.ts | 58 ++++++++++++------ .../pages/trusted_apps/store/middleware.ts | 12 ++-- .../pages/trusted_apps/store/reducer.test.ts | 14 ++--- .../pages/trusted_apps/store/reducer.ts | 33 ++++------ .../trusted_apps/store/selectors.test.ts | 58 +++++++----------- .../pages/trusted_apps/store/selectors.ts | 60 ++++++------------- .../pages/trusted_apps/test_utils/index.ts | 43 ++----------- .../trusted_apps/view/trusted_apps_list.tsx | 8 +-- .../trusted_apps/view/trusted_apps_page.tsx | 17 +++--- 12 files changed, 159 insertions(+), 213 deletions(-) diff --git a/x-pack/plugins/security_solution/public/management/common/routing.test.ts b/x-pack/plugins/security_solution/public/management/common/routing.test.ts index 7a36654dcffc3..7082ab0ce5c4f 100644 --- a/x-pack/plugins/security_solution/public/management/common/routing.test.ts +++ b/x-pack/plugins/security_solution/public/management/common/routing.test.ts @@ -4,57 +4,57 @@ * you may not use this file except in compliance with the Elastic License. */ -import { extractListPaginationParams, getTrustedAppsListPath } from './routing'; +import { extractTrustedAppsListPageLocation, getTrustedAppsListPath } from './routing'; import { MANAGEMENT_DEFAULT_PAGE, MANAGEMENT_DEFAULT_PAGE_SIZE } from './constants'; describe('routing', () => { describe('extractListPaginationParams()', () => { it('extracts default page index when not provided', () => { - expect(extractListPaginationParams({}).page_index).toBe(MANAGEMENT_DEFAULT_PAGE); + expect(extractTrustedAppsListPageLocation({}).page_index).toBe(MANAGEMENT_DEFAULT_PAGE); }); it('extracts default page index when too small value provided', () => { - expect(extractListPaginationParams({ page_index: '-1' }).page_index).toBe( + expect(extractTrustedAppsListPageLocation({ page_index: '-1' }).page_index).toBe( MANAGEMENT_DEFAULT_PAGE ); }); it('extracts default page index when not a number provided', () => { - expect(extractListPaginationParams({ page_index: 'a' }).page_index).toBe( + expect(extractTrustedAppsListPageLocation({ page_index: 'a' }).page_index).toBe( MANAGEMENT_DEFAULT_PAGE ); }); it('extracts only last page index when multiple values provided', () => { - expect(extractListPaginationParams({ page_index: ['1', '2'] }).page_index).toBe(2); + expect(extractTrustedAppsListPageLocation({ page_index: ['1', '2'] }).page_index).toBe(2); }); it('extracts proper page index when single valid value provided', () => { - expect(extractListPaginationParams({ page_index: '2' }).page_index).toBe(2); + expect(extractTrustedAppsListPageLocation({ page_index: '2' }).page_index).toBe(2); }); it('extracts default page size when not provided', () => { - expect(extractListPaginationParams({}).page_size).toBe(MANAGEMENT_DEFAULT_PAGE_SIZE); + expect(extractTrustedAppsListPageLocation({}).page_size).toBe(MANAGEMENT_DEFAULT_PAGE_SIZE); }); it('extracts default page size when invalid option provided', () => { - expect(extractListPaginationParams({ page_size: '25' }).page_size).toBe( + expect(extractTrustedAppsListPageLocation({ page_size: '25' }).page_size).toBe( MANAGEMENT_DEFAULT_PAGE_SIZE ); }); it('extracts default page size when not a number provided', () => { - expect(extractListPaginationParams({ page_size: 'a' }).page_size).toBe( + expect(extractTrustedAppsListPageLocation({ page_size: 'a' }).page_size).toBe( MANAGEMENT_DEFAULT_PAGE_SIZE ); }); it('extracts only last page size when multiple values provided', () => { - expect(extractListPaginationParams({ page_size: ['10', '20'] }).page_size).toBe(20); + expect(extractTrustedAppsListPageLocation({ page_size: ['10', '20'] }).page_size).toBe(20); }); it('extracts proper page size when single valid value provided', () => { - expect(extractListPaginationParams({ page_size: '20' }).page_size).toBe(20); + expect(extractTrustedAppsListPageLocation({ page_size: '20' }).page_size).toBe(20); }); }); diff --git a/x-pack/plugins/security_solution/public/management/common/routing.ts b/x-pack/plugins/security_solution/public/management/common/routing.ts index cb4ed9b098fce..9acf4a1613c0b 100644 --- a/x-pack/plugins/security_solution/public/management/common/routing.ts +++ b/x-pack/plugins/security_solution/public/management/common/routing.ts @@ -21,7 +21,7 @@ import { import { AdministrationSubTab } from '../types'; import { appendSearch } from '../../common/components/link_to/helpers'; import { EndpointIndexUIQueryParams } from '../pages/endpoint_hosts/types'; -import { TrustedAppsUrlParams } from '../pages/trusted_apps/types'; +import { TrustedAppsListPageLocation } from '../pages/trusted_apps/state'; // Taken from: https://github.com/microsoft/TypeScript/issues/12936#issuecomment-559034150 type ExactKeys = Exclude extends never ? T1 : never; @@ -94,18 +94,18 @@ const isDefaultOrMissing = (value: T | undefined, defaultValue: T) => { return value === undefined || value === defaultValue; }; -const normalizeListPaginationParams = ( - params?: Partial -): Partial => { - if (params) { +const normalizeTrustedAppsPageLocation = ( + location?: Partial +): Partial => { + if (location) { return { - ...(!isDefaultOrMissing(params.page_index, MANAGEMENT_DEFAULT_PAGE) - ? { page_index: params.page_index } + ...(!isDefaultOrMissing(location.page_index, MANAGEMENT_DEFAULT_PAGE) + ? { page_index: location.page_index } : {}), - ...(!isDefaultOrMissing(params.page_size, MANAGEMENT_DEFAULT_PAGE_SIZE) - ? { page_size: params.page_size } + ...(!isDefaultOrMissing(location.page_size, MANAGEMENT_DEFAULT_PAGE_SIZE) + ? { page_size: location.page_size } : {}), - ...(!isDefaultOrMissing(params.show, undefined) ? { show: params.show } : {}), + ...(!isDefaultOrMissing(location.show, undefined) ? { show: location.show } : {}), }; } else { return {}; @@ -135,17 +135,22 @@ const extractPageSize = (query: querystring.ParsedUrlQuery): number => { return MANAGEMENT_PAGE_SIZE_OPTIONS.includes(pageSize) ? pageSize : MANAGEMENT_DEFAULT_PAGE_SIZE; }; -export const extractListPaginationParams = ( - query: querystring.ParsedUrlQuery -): TrustedAppsUrlParams => ({ +export const extractListPaginationParams = (query: querystring.ParsedUrlQuery) => ({ page_index: extractPageIndex(query), page_size: extractPageSize(query), }); -export const getTrustedAppsListPath = (params?: Partial): string => { +export const extractTrustedAppsListPageLocation = ( + query: querystring.ParsedUrlQuery +): TrustedAppsListPageLocation => ({ + ...extractListPaginationParams(query), + show: extractFirstParamValue(query, 'show') === 'create' ? 'create' : undefined, +}); + +export const getTrustedAppsListPath = (params?: Partial): string => { const path = generatePath(MANAGEMENT_ROUTING_TRUSTED_APPS_PATH, { tabName: AdministrationSubTab.trustedApps, }); - return `${path}${appendSearch(querystring.stringify(normalizeListPaginationParams(params)))}`; + return `${path}${appendSearch(querystring.stringify(normalizeTrustedAppsPageLocation(params)))}`; }; diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/state/trusted_apps_list_page_state.ts b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/state/trusted_apps_list_page_state.ts index 4c38ac0c4239a..a98ec03a006f5 100644 --- a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/state/trusted_apps_list_page_state.ts +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/state/trusted_apps_list_page_state.ts @@ -7,7 +7,6 @@ import { ServerApiError } from '../../../../common/types'; import { NewTrustedApp, TrustedApp } from '../../../../../common/endpoint/types/trusted_apps'; import { AsyncResourceState } from '.'; -import { TrustedAppsUrlParams } from '../types'; export interface PaginationInfo { index: number; @@ -39,12 +38,16 @@ export interface TrustedAppCreateFailure { data: ServerApiError; } +export interface TrustedAppsListPageLocation { + page_index: number; + page_size: number; + show?: 'create'; +} + export interface TrustedAppsListPageState { listView: { - currentListResourceState: AsyncResourceState; - currentPaginationInfo: PaginationInfo; + listResourceState: AsyncResourceState; freshDataTimestamp: number; - show: TrustedAppsUrlParams['show'] | undefined; }; deletionDialog: { entry?: TrustedApp; @@ -56,5 +59,6 @@ export interface TrustedAppsListPageState { | TrustedAppCreatePending | TrustedAppCreateSuccess | TrustedAppCreateFailure; + location: TrustedAppsListPageLocation; active: boolean; } diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/store/middleware.test.ts b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/store/middleware.test.ts index 19c2d3a62781f..2143b5135c575 100644 --- a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/store/middleware.test.ts +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/store/middleware.test.ts @@ -9,13 +9,12 @@ import { applyMiddleware, createStore } from 'redux'; import { createSpyMiddleware } from '../../../../common/store/test_utils'; import { - createFailedListViewWithPagination, createListLoadedResourceState, createLoadedListViewWithPagination, - createLoadingListViewWithPagination, createSampleTrustedApp, createSampleTrustedApps, createServerApiError, + createUninitialisedResourceState, createUserChangedUrlAction, } from '../test_utils'; @@ -76,6 +75,7 @@ describe('middleware', () => { describe('refreshing list resource state', () => { it('refreshes the list when location changes and data gets outdated', async () => { const pagination = { index: 2, size: 50 }; + const location = { page_index: 2, page_size: 50, show: undefined }; const service = createTrustedAppsServiceMock(); const { store, spyMiddleware } = createStoreSetup(service); @@ -87,21 +87,30 @@ describe('middleware', () => { expect(store.getState()).toStrictEqual({ ...initialState, - listView: createLoadingListViewWithPagination(initialNow, pagination), + listView: { + listResourceState: { + type: 'LoadingResourceState', + previousState: createUninitialisedResourceState(), + }, + freshDataTimestamp: initialNow, + }, active: true, + location, }); await spyMiddleware.waitForAction('trustedAppsListResourceStateChanged'); expect(store.getState()).toStrictEqual({ ...initialState, - listView: createLoadedListViewWithPagination(initialNow, pagination, pagination, 500), + listView: createLoadedListViewWithPagination(initialNow, pagination, 500), active: true, + location, }); }); it('does not refresh the list when location changes and data does not get outdated', async () => { const pagination = { index: 2, size: 50 }; + const location = { page_index: 2, page_size: 50, show: undefined }; const service = createTrustedAppsServiceMock(); const { store, spyMiddleware } = createStoreSetup(service); @@ -118,14 +127,16 @@ describe('middleware', () => { expect(service.getTrustedAppsList).toBeCalledTimes(1); expect(store.getState()).toStrictEqual({ ...initialState, - listView: createLoadedListViewWithPagination(initialNow, pagination, pagination, 500), + listView: createLoadedListViewWithPagination(initialNow, pagination, 500), active: true, + location, }); }); it('refreshes the list when data gets outdated with and outdate action', async () => { const newNow = 222222; const pagination = { index: 0, size: 10 }; + const location = { page_index: 0, page_size: 10, show: undefined }; const service = createTrustedAppsServiceMock(); const { store, spyMiddleware } = createStoreSetup(service); @@ -143,20 +154,24 @@ describe('middleware', () => { expect(store.getState()).toStrictEqual({ ...initialState, - listView: createLoadingListViewWithPagination( - newNow, - pagination, - createListLoadedResourceState(pagination, 500, initialNow) - ), + listView: { + listResourceState: { + type: 'LoadingResourceState', + previousState: createListLoadedResourceState(pagination, 500, initialNow), + }, + freshDataTimestamp: newNow, + }, active: true, + location, }); await spyMiddleware.waitForAction('trustedAppsListResourceStateChanged'); expect(store.getState()).toStrictEqual({ ...initialState, - listView: createLoadedListViewWithPagination(newNow, pagination, pagination, 500), + listView: createLoadedListViewWithPagination(newNow, pagination, 500), active: true, + location, }); }); @@ -172,12 +187,16 @@ describe('middleware', () => { expect(store.getState()).toStrictEqual({ ...initialState, - listView: createFailedListViewWithPagination( - initialNow, - { index: 2, size: 50 }, - createServerApiError('Internal Server Error') - ), + listView: { + listResourceState: { + type: 'FailedResourceState', + error: createServerApiError('Internal Server Error'), + lastLoadedState: undefined, + }, + freshDataTimestamp: initialNow, + }, active: true, + location: { page_index: 2, page_size: 50, show: undefined }, }); const infiniteLoopTest = async () => { @@ -193,10 +212,11 @@ describe('middleware', () => { const entry = createSampleTrustedApp(3); const notFoundError = createServerApiError('Not Found'); const pagination = { index: 0, size: 10 }; + const location = { page_index: 0, page_size: 10, show: undefined }; const getTrustedAppsListResponse = createGetTrustedListAppsResponse(pagination, 500); - const listView = createLoadedListViewWithPagination(initialNow, pagination, pagination, 500); - const listViewNew = createLoadedListViewWithPagination(newNow, pagination, pagination, 500); - const testStartState = { ...initialState, listView, active: true }; + const listView = createLoadedListViewWithPagination(initialNow, pagination, 500); + const listViewNew = createLoadedListViewWithPagination(newNow, pagination, 500); + const testStartState = { ...initialState, listView, active: true, location }; it('does not submit when entry is undefined', async () => { const service = createTrustedAppsServiceMock(); diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/store/middleware.ts b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/store/middleware.ts index dd96c8d807048..9fa456dc5ffe2 100644 --- a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/store/middleware.ts +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/store/middleware.ts @@ -29,12 +29,12 @@ import { } from './action'; import { - getCurrentListResourceState, + getListResourceState, getDeletionDialogEntry, getDeletionSubmissionResourceState, getLastLoadedListResourceState, - getListCurrentPageIndex, - getListCurrentPageSize, + getCurrentLocationPageIndex, + getCurrentLocationPageSize, getTrustedAppCreateData, isCreatePending, needsRefreshOfListData, @@ -56,15 +56,15 @@ const refreshListIfNeeded = async ( createTrustedAppsListResourceStateChangedAction({ type: 'LoadingResourceState', // need to think on how to avoid the casting - previousState: getCurrentListResourceState(store.getState()) as Immutable< + previousState: getListResourceState(store.getState()) as Immutable< StaleResourceState >, }) ); try { - const pageIndex = getListCurrentPageIndex(store.getState()); - const pageSize = getListCurrentPageSize(store.getState()); + const pageIndex = getCurrentLocationPageIndex(store.getState()); + const pageSize = getCurrentLocationPageSize(store.getState()); const response = await trustedAppsService.getTrustedAppsList({ page: pageIndex + 1, per_page: pageSize, diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/store/reducer.test.ts b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/store/reducer.test.ts index 228f0932edd28..94fcdb39bb169 100644 --- a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/store/reducer.test.ts +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/store/reducer.test.ts @@ -32,17 +32,14 @@ describe('reducer', () => { expect(result).toStrictEqual({ ...initialState, - listView: { ...initialState.listView, currentPaginationInfo: { index: 5, size: 50 } }, + location: { page_index: 5, page_size: 50, show: undefined }, active: true, }); }); it('extracts default pagination parameters when none provided', () => { const result = trustedAppsPageReducer( - { - ...initialState, - listView: { ...initialState.listView, currentPaginationInfo: { index: 5, size: 50 } }, - }, + { ...initialState, location: { page_index: 5, page_size: 50 } }, createUserChangedUrlAction('/trusted_apps', '?page_index=b&page_size=60') ); @@ -51,10 +48,7 @@ describe('reducer', () => { it('extracts default pagination parameters when invalid provided', () => { const result = trustedAppsPageReducer( - { - ...initialState, - listView: { ...initialState.listView, currentPaginationInfo: { index: 5, size: 50 } }, - }, + { ...initialState, location: { page_index: 5, page_size: 50 } }, createUserChangedUrlAction('/trusted_apps') ); @@ -85,7 +79,7 @@ describe('reducer', () => { expect(result).toStrictEqual({ ...initialState, - listView: { ...initialState.listView, currentListResourceState: listResourceState }, + listView: { ...initialState.listView, listResourceState }, }); }); }); diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/store/reducer.ts b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/store/reducer.ts index ec210254bf76f..f4056f02a4140 100644 --- a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/store/reducer.ts +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/store/reducer.ts @@ -11,7 +11,8 @@ import { ImmutableReducer } from '../../../../common/store'; import { AppLocation, Immutable } from '../../../../../common/endpoint/types'; import { UserChangedUrl } from '../../../../common/store/routing/action'; import { AppAction } from '../../../../common/store/actions'; -import { extractFirstParamValue, extractListPaginationParams } from '../../../common/routing'; +import { extractTrustedAppsListPageLocation } from '../../../common/routing'; + import { MANAGEMENT_ROUTING_TRUSTED_APPS_PATH, MANAGEMENT_DEFAULT_PAGE, @@ -29,6 +30,7 @@ import { ServerReturnedCreateTrustedAppSuccess, UserClickedSaveNewTrustedAppButton, } from './action'; + import { TrustedAppsListPageState } from '../state'; type StateReducer = ImmutableReducer; @@ -64,7 +66,7 @@ const trustedAppsListResourceStateChanged: CaseReducer = (state, action) => { if (isTrustedAppsPageLocation(action.payload)) { const parsedUrlsParams = parse(action.payload.search.slice(1)); - const paginationParams = extractListPaginationParams(parsedUrlsParams); - const show = - extractFirstParamValue(parsedUrlsParams, 'show') === 'create' ? 'create' : undefined; + const location = extractTrustedAppsListPageLocation(parsedUrlsParams); return { ...state, - listView: { - ...state.listView, - currentPaginationInfo: { - index: paginationParams.page_index, - size: paginationParams.page_size, - }, - show, - }, - createView: show ? state.createView : undefined, + createView: location.show ? state.createView : undefined, active: true, + location, }; } else { return initialTrustedAppsPageState(); @@ -150,16 +143,16 @@ const initialDeletionDialogState = (): TrustedAppsListPageState['deletionDialog' export const initialTrustedAppsPageState = (): TrustedAppsListPageState => ({ listView: { - currentListResourceState: { type: 'UninitialisedResourceState' }, - currentPaginationInfo: { - index: MANAGEMENT_DEFAULT_PAGE, - size: MANAGEMENT_DEFAULT_PAGE_SIZE, - }, + listResourceState: { type: 'UninitialisedResourceState' }, freshDataTimestamp: Date.now(), - show: undefined, }, deletionDialog: initialDeletionDialogState(), createView: undefined, + location: { + page_index: MANAGEMENT_DEFAULT_PAGE, + page_size: MANAGEMENT_DEFAULT_PAGE_SIZE, + show: undefined, + }, active: false, }); diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/store/selectors.test.ts b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/store/selectors.test.ts index 0be4d0b05acc4..01fe3e5bf202e 100644 --- a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/store/selectors.test.ts +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/store/selectors.test.ts @@ -7,10 +7,10 @@ import { AsyncResourceState, TrustedAppsListPageState } from '../state'; import { initialTrustedAppsPageState } from './reducer'; import { - getCurrentListResourceState, + getListResourceState, getLastLoadedListResourceState, - getListCurrentPageIndex, - getListCurrentPageSize, + getCurrentLocationPageIndex, + getCurrentLocationPageSize, getListErrorMessage, getListItems, getListTotalItemsCount, @@ -25,7 +25,6 @@ import { } from './selectors'; import { - createDefaultListView, createDefaultPaginationInfo, createListComplexLoadingResourceState, createListFailedResourceState, @@ -85,16 +84,17 @@ describe('selectors', () => { it('returns false when current loaded data is up to date', () => { const listView = createLoadedListViewWithPagination(initialNow); + const location = { page_index: 0, page_size: 10 }; - expect(needsRefreshOfListData({ ...initialState, listView, active: true })).toBe(false); + expect(needsRefreshOfListData({ ...initialState, listView, active: true, location })).toBe( + false + ); }); }); - describe('getCurrentListResourceState()', () => { + describe('getListResourceState()', () => { it('returns current list resource state', () => { - const state = { ...initialState, listView: createDefaultListView(initialNow) }; - - expect(getCurrentListResourceState(state)).toStrictEqual(createUninitialisedResourceState()); + expect(getListResourceState(initialState)).toStrictEqual(createUninitialisedResourceState()); }); }); @@ -103,14 +103,12 @@ describe('selectors', () => { const state = { ...initialState, listView: { - currentListResourceState: createListComplexLoadingResourceState( + listResourceState: createListComplexLoadingResourceState( createDefaultPaginationInfo(), 200, initialNow ), - currentPaginationInfo: createDefaultPaginationInfo(), freshDataTimestamp: initialNow, - show: undefined, }, }; @@ -122,23 +120,19 @@ describe('selectors', () => { describe('getListItems()', () => { it('returns empty list when no valid data loaded', () => { - const state = { ...initialState, listView: createDefaultListView(initialNow) }; - - expect(getListItems(state)).toStrictEqual([]); + expect(getListItems(initialState)).toStrictEqual([]); }); it('returns last loaded list items', () => { const state = { ...initialState, listView: { - currentListResourceState: createListComplexLoadingResourceState( + listResourceState: createListComplexLoadingResourceState( createDefaultPaginationInfo(), 200, initialNow ), - currentPaginationInfo: createDefaultPaginationInfo(), freshDataTimestamp: initialNow, - show: undefined, }, }; @@ -150,23 +144,19 @@ describe('selectors', () => { describe('getListTotalItemsCount()', () => { it('returns 0 when no valid data loaded', () => { - const state = { ...initialState, listView: createDefaultListView(initialNow) }; - - expect(getListTotalItemsCount(state)).toBe(0); + expect(getListTotalItemsCount(initialState)).toBe(0); }); it('returns last loaded total items count', () => { const state = { ...initialState, listView: { - currentListResourceState: createListComplexLoadingResourceState( + listResourceState: createListComplexLoadingResourceState( createDefaultPaginationInfo(), 200, initialNow ), - currentPaginationInfo: createDefaultPaginationInfo(), freshDataTimestamp: initialNow, - show: undefined, }, }; @@ -176,17 +166,17 @@ describe('selectors', () => { describe('getListCurrentPageIndex()', () => { it('returns page index', () => { - const state = { ...initialState, listView: createDefaultListView(initialNow) }; + const state = { ...initialState, location: { page_index: 3, page_size: 10 } }; - expect(getListCurrentPageIndex(state)).toBe(0); + expect(getCurrentLocationPageIndex(state)).toBe(3); }); }); describe('getListCurrentPageSize()', () => { it('returns page size', () => { - const state = { ...initialState, listView: createDefaultListView(initialNow) }; + const state = { ...initialState, location: { page_index: 0, page_size: 20 } }; - expect(getListCurrentPageSize(state)).toBe(20); + expect(getCurrentLocationPageSize(state)).toBe(20); }); }); @@ -195,14 +185,12 @@ describe('selectors', () => { const state = { ...initialState, listView: { - currentListResourceState: createListComplexLoadingResourceState( + listResourceState: createListComplexLoadingResourceState( createDefaultPaginationInfo(), 200, initialNow ), - currentPaginationInfo: createDefaultPaginationInfo(), freshDataTimestamp: initialNow, - show: undefined, }, }; @@ -213,10 +201,8 @@ describe('selectors', () => { const state = { ...initialState, listView: { - currentListResourceState: createListFailedResourceState('Internal Server Error'), - currentPaginationInfo: createDefaultPaginationInfo(), + listResourceState: createListFailedResourceState('Internal Server Error'), freshDataTimestamp: initialNow, - show: undefined, }, }; @@ -233,14 +219,12 @@ describe('selectors', () => { const state = { ...initialState, listView: { - currentListResourceState: createListComplexLoadingResourceState( + listResourceState: createListComplexLoadingResourceState( createDefaultPaginationInfo(), 200, initialNow ), - currentPaginationInfo: createDefaultPaginationInfo(), freshDataTimestamp: initialNow, - show: undefined, }, }; diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/store/selectors.ts b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/store/selectors.ts index 6239b425efe2f..62ffa364e4a6c 100644 --- a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/store/selectors.ts +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/store/selectors.ts @@ -4,7 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -import { createSelector } from 'reselect'; import { ServerApiError } from '../../../../common/types'; import { Immutable, NewTrustedApp, TrustedApp } from '../../../../../common/endpoint/types'; @@ -17,97 +16,76 @@ import { isLoadingResourceState, isOutdatedResourceState, LoadedResourceState, - PaginationInfo, TrustedAppCreateFailure, TrustedAppsListData, + TrustedAppsListPageLocation, TrustedAppsListPageState, } from '../state'; -import { TrustedAppsUrlParams } from '../types'; import { isTrustedAppCreateFailureState, isTrustedAppCreatePendingState, isTrustedAppCreateSuccessState, } from '../state/type_guards'; -const pageInfosEqual = (pageInfo1: PaginationInfo, pageInfo2: PaginationInfo): boolean => - pageInfo1.index === pageInfo2.index && pageInfo1.size === pageInfo2.size; - export const needsRefreshOfListData = (state: Immutable): boolean => { - const currentPageInfo = state.listView.currentPaginationInfo; - const currentPage = state.listView.currentListResourceState; const freshDataTimestamp = state.listView.freshDataTimestamp; + const currentPage = state.listView.listResourceState; + const location = state.location; return ( state.active && isOutdatedResourceState(currentPage, (data) => { return ( - pageInfosEqual(currentPageInfo, data.paginationInfo) && data.timestamp >= freshDataTimestamp + data.paginationInfo.index === location.page_index && + data.paginationInfo.size === location.page_size && + data.timestamp >= freshDataTimestamp ); }) ); }; -export const getCurrentListResourceState = ( +export const getListResourceState = ( state: Immutable ): Immutable> | undefined => { - return state.listView.currentListResourceState; + return state.listView.listResourceState; }; export const getLastLoadedListResourceState = ( state: Immutable ): Immutable> | undefined => { - return getLastLoadedResourceState(state.listView.currentListResourceState); + return getLastLoadedResourceState(state.listView.listResourceState); }; export const getListItems = ( state: Immutable ): Immutable => { - return getLastLoadedResourceState(state.listView.currentListResourceState)?.data.items || []; + return getLastLoadedResourceState(state.listView.listResourceState)?.data.items || []; }; -export const getListCurrentPageIndex = (state: Immutable): number => { - return state.listView.currentPaginationInfo.index; +export const getCurrentLocationPageIndex = (state: Immutable): number => { + return state.location.page_index; }; -export const getListCurrentPageSize = (state: Immutable): number => { - return state.listView.currentPaginationInfo.size; +export const getCurrentLocationPageSize = (state: Immutable): number => { + return state.location.page_size; }; export const getListTotalItemsCount = (state: Immutable): number => { - return ( - getLastLoadedResourceState(state.listView.currentListResourceState)?.data.totalItemsCount || 0 - ); -}; - -export const getListCurrentShowValue: ( - state: Immutable -) => TrustedAppsListPageState['listView']['show'] = (state) => { - return state.listView.show; + return getLastLoadedResourceState(state.listView.listResourceState)?.data.totalItemsCount || 0; }; -export const getListUrlSearchParams: ( +export const getCurrentLocation = ( state: Immutable -) => TrustedAppsUrlParams = createSelector( - getListCurrentPageIndex, - getListCurrentPageSize, - getListCurrentShowValue, - (pageIndex, pageSize, showValue) => { - return { - page_index: pageIndex, - page_size: pageSize, - show: showValue, - }; - } -); +): TrustedAppsListPageLocation => state.location; export const getListErrorMessage = ( state: Immutable ): string | undefined => { - return getCurrentResourceError(state.listView.currentListResourceState)?.message; + return getCurrentResourceError(state.listView.listResourceState)?.message; }; export const isListLoading = (state: Immutable): boolean => { - return isLoadingResourceState(state.listView.currentListResourceState); + return isLoadingResourceState(state.listView.listResourceState); }; export const isDeletionDialogOpen = (state: Immutable): boolean => { diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/test_utils/index.ts b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/test_utils/index.ts index 020a87f526e52..c23b6ceae7b07 100644 --- a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/test_utils/index.ts +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/test_utils/index.ts @@ -5,11 +5,12 @@ */ import { combineReducers, createStore } from 'redux'; -import { ServerApiError } from '../../../../common/types'; import { TrustedApp } from '../../../../../common/endpoint/types'; import { RoutingAction } from '../../../../common/store/routing'; import { + MANAGEMENT_DEFAULT_PAGE, + MANAGEMENT_DEFAULT_PAGE_SIZE, MANAGEMENT_STORE_GLOBAL_NAMESPACE, MANAGEMENT_STORE_TRUSTED_APPS_NAMESPACE, } from '../../../common/constants'; @@ -105,54 +106,22 @@ export const createListComplexLoadingResourceState = ( ) ); -export const createDefaultPaginationInfo = () => ({ index: 0, size: 20 }); - -export const createDefaultListView = ( - freshDataTimestamp: number -): TrustedAppsListPageState['listView'] => ({ - currentListResourceState: createUninitialisedResourceState(), - currentPaginationInfo: createDefaultPaginationInfo(), - freshDataTimestamp, - show: undefined, -}); - -export const createLoadingListViewWithPagination = ( - freshDataTimestamp: number, - currentPaginationInfo: PaginationInfo, - previousState: StaleResourceState = createUninitialisedResourceState() -): TrustedAppsListPageState['listView'] => ({ - currentListResourceState: { type: 'LoadingResourceState', previousState }, - currentPaginationInfo, - freshDataTimestamp, - show: undefined, +export const createDefaultPaginationInfo = () => ({ + index: MANAGEMENT_DEFAULT_PAGE, + size: MANAGEMENT_DEFAULT_PAGE_SIZE, }); export const createLoadedListViewWithPagination = ( freshDataTimestamp: number, paginationInfo: PaginationInfo = createDefaultPaginationInfo(), - currentPaginationInfo: PaginationInfo = createDefaultPaginationInfo(), totalItemsCount: number = 200 ): TrustedAppsListPageState['listView'] => ({ - currentListResourceState: createListLoadedResourceState( + listResourceState: createListLoadedResourceState( paginationInfo, totalItemsCount, freshDataTimestamp ), - currentPaginationInfo, - freshDataTimestamp, - show: undefined, -}); - -export const createFailedListViewWithPagination = ( - freshDataTimestamp: number, - currentPaginationInfo: PaginationInfo, - error: ServerApiError, - lastLoadedState?: LoadedResourceState -): TrustedAppsListPageState['listView'] => ({ - currentListResourceState: { type: 'FailedResourceState', error, lastLoadedState }, - currentPaginationInfo, freshDataTimestamp, - show: undefined, }); export const createUserChangedUrlAction = (path: string, search: string = ''): RoutingAction => { diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/trusted_apps_list.tsx b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/trusted_apps_list.tsx index d0c1fb477ea46..ae1f314842aab 100644 --- a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/trusted_apps_list.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/trusted_apps_list.tsx @@ -23,8 +23,8 @@ import { MANAGEMENT_PAGE_SIZE_OPTIONS } from '../../../common/constants'; import { getTrustedAppsListPath } from '../../../common/routing'; import { - getListCurrentPageIndex, - getListCurrentPageSize, + getCurrentLocationPageIndex, + getCurrentLocationPageSize, getListErrorMessage, getListItems, getListTotalItemsCount, @@ -149,8 +149,8 @@ const getColumnDefinitions = (context: TrustedAppsListContext): ColumnsList => { export const TrustedAppsList = memo(() => { const [detailsMap, setDetailsMap] = useState({}); - const pageIndex = useTrustedAppsSelector(getListCurrentPageIndex); - const pageSize = useTrustedAppsSelector(getListCurrentPageSize); + const pageIndex = useTrustedAppsSelector(getCurrentLocationPageIndex); + const pageSize = useTrustedAppsSelector(getCurrentLocationPageSize); const totalItemCount = useTrustedAppsSelector(getListTotalItemsCount); const listItems = useTrustedAppsSelector(getListItems); const dispatch = useDispatch(); 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 878818d9b77fe..d63cda5b513dc 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 @@ -15,27 +15,26 @@ import { TrustedAppsNotifications } from './trusted_apps_notifications'; import { CreateTrustedAppFlyout } from './components/create_trusted_app_flyout'; import { getTrustedAppsListPath } from '../../../common/routing'; import { useTrustedAppsSelector } from './hooks'; -import { getListCurrentShowValue, getListUrlSearchParams } from '../store/selectors'; +import { getCurrentLocation } from '../store/selectors'; import { TrustedAppsListPageRouteState } from '../../../../../common/endpoint/types'; import { useNavigateToAppEventHandler } from '../../../../common/hooks/endpoint/use_navigate_to_app_event_handler'; export const TrustedAppsPage = memo(() => { const history = useHistory(); const { state: routeState } = useLocation(); - const urlParams = useTrustedAppsSelector(getListUrlSearchParams); - const showAddFlout = useTrustedAppsSelector(getListCurrentShowValue) === 'create'; + const location = useTrustedAppsSelector(getCurrentLocation); const handleAddButtonClick = useCallback(() => { history.push( getTrustedAppsListPath({ - ...urlParams, + ...location, show: 'create', }) ); - }, [history, urlParams]); + }, [history, location]); const handleAddFlyoutClose = useCallback(() => { - const { show, ...paginationParamsOnly } = urlParams; + const { show, ...paginationParamsOnly } = location; history.push(getTrustedAppsListPath(paginationParamsOnly)); - }, [history, urlParams]); + }, [history, location]); const backButton = useMemo(() => { if (routeState && routeState.onBackButtonNavigateTo) { @@ -50,7 +49,7 @@ export const TrustedAppsPage = memo(() => { @@ -82,7 +81,7 @@ export const TrustedAppsPage = memo(() => { > - {showAddFlout && ( + {location.show === 'create' && ( Date: Fri, 2 Oct 2020 10:10:38 -0400 Subject: [PATCH 41/50] [Security Solution][Detections] Enrich shell signals with fields common to all building blocks (#79130) * Enrich shell signals with fields common to all building blocks * PR comments + additional unit test --- .../signals/build_bulk_body.test.ts | 448 +++++++++++++++++- .../signals/build_bulk_body.ts | 53 +++ 2 files changed, 498 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/build_bulk_body.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/build_bulk_body.test.ts index 2f7dd22c0c78e..75a7de8cd2c44 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/build_bulk_body.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/build_bulk_body.test.ts @@ -11,8 +11,15 @@ import { sampleIdGuid, sampleDocWithAncestors, sampleRuleSO, + sampleDocNoSortIdNoVersion, } from './__mocks__/es_results'; -import { buildBulkBody, buildSignalFromSequence, buildSignalFromEvent } from './build_bulk_body'; +import { + buildBulkBody, + buildSignalFromSequence, + buildSignalFromEvent, + objectPairIntersection, + objectArrayIntersection, +} from './build_bulk_body'; import { SignalHit } from './types'; import { getListArrayMock } from '../../../../common/detection_engine/schemas/types/lists.mock'; @@ -438,13 +445,20 @@ describe('buildBulkBody', () => { describe('buildSignalFromSequence', () => { test('builds a basic signal from a sequence of building blocks', () => { - const blocks = [sampleDocWithAncestors().hits.hits[0], sampleDocWithAncestors().hits.hits[0]]; + const block1 = sampleDocWithAncestors().hits.hits[0]; + block1._source.new_key = 'new_key_value'; + block1._source.new_key2 = 'new_key2_value'; + const block2 = sampleDocWithAncestors().hits.hits[0]; + block2._source.new_key = 'new_key_value'; + const blocks = [block1, block2]; const ruleSO = sampleRuleSO(); const signal = buildSignalFromSequence(blocks, ruleSO); // Timestamp will potentially always be different so remove it for the test // @ts-expect-error delete signal['@timestamp']; - const expected: Omit = { + const expected: Omit & { someKey: string; new_key: string } = { + someKey: 'someValue', + new_key: 'new_key_value', event: { kind: 'signal', }, @@ -539,6 +553,96 @@ describe('buildSignalFromSequence', () => { }; expect(signal).toEqual(expected); }); + + test('builds a basic signal if there is no overlap between source events', () => { + const block1 = sampleDocNoSortIdNoVersion(); + const block2 = sampleDocNoSortIdNoVersion(); + block2._source['@timestamp'] = '2021-05-20T22:28:46+0000'; + block2._source.someKey = 'someOtherValue'; + const ruleSO = sampleRuleSO(); + const signal = buildSignalFromSequence([block1, block2], ruleSO); + // Timestamp will potentially always be different so remove it for the test + // @ts-expect-error + delete signal['@timestamp']; + const expected: Omit = { + event: { + kind: 'signal', + }, + signal: { + parents: [ + { + id: sampleIdGuid, + type: 'event', + index: 'myFakeSignalIndex', + depth: 0, + }, + { + id: sampleIdGuid, + type: 'event', + index: 'myFakeSignalIndex', + depth: 0, + }, + ], + ancestors: [ + { + id: sampleIdGuid, + type: 'event', + index: 'myFakeSignalIndex', + depth: 0, + }, + { + id: sampleIdGuid, + type: 'event', + index: 'myFakeSignalIndex', + depth: 0, + }, + ], + status: 'open', + rule: { + actions: [], + author: ['Elastic'], + building_block_type: 'default', + id: '04128c15-0d1b-4716-a4c5-46997ac7f3bd', + rule_id: 'rule-1', + false_positives: [], + max_signals: 10000, + risk_score: 50, + risk_score_mapping: [], + output_index: '.siem-signals', + description: 'Detecting root and admin users', + from: 'now-6m', + immutable: false, + index: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'], + interval: '5m', + language: 'kuery', + license: 'Elastic License', + name: 'rule-name', + query: 'user.name: root or user.name: admin', + references: ['http://google.com'], + severity: 'high', + severity_mapping: [], + tags: ['some fake tag 1', 'some fake tag 2'], + threat: [], + type: 'query', + to: 'now', + note: '', + enabled: true, + created_by: 'sample user', + updated_by: 'sample user', + version: 1, + updated_at: ruleSO.updated_at ?? '', + created_at: ruleSO.attributes.createdAt, + throttle: 'no_actions', + exceptions_list: getListArrayMock(), + }, + depth: 1, + group: { + id: '269c1f5754bff92fb8040283b687258e99b03e8b2ab1262cc20c82442e5de5ea', + }, + }, + }; + expect(signal).toEqual(expected); + }); }); describe('buildSignalFromEvent', () => { @@ -632,3 +736,341 @@ describe('buildSignalFromEvent', () => { expect(signal).toEqual(expected); }); }); + +describe('recursive intersection between objects', () => { + test('should treat numbers and strings as unequal', () => { + const a = { + field1: 1, + field2: 1, + }; + const b = { + field1: 1, + field2: '1', + }; + const intersection = objectPairIntersection(a, b); + const expected = { + field1: 1, + }; + expect(intersection).toEqual(expected); + }); + + test('should strip unequal numbers and strings', () => { + const a = { + field1: 1, + field2: 1, + field3: 'abcd', + field4: 'abcd', + }; + const b = { + field1: 1, + field2: 100, + field3: 'abcd', + field4: 'wxyz', + }; + const intersection = objectPairIntersection(a, b); + const expected = { + field1: 1, + field3: 'abcd', + }; + expect(intersection).toEqual(expected); + }); + + test('should handle null values', () => { + const a = { + field1: 1, + field2: '1', + field3: null, + }; + const b = { + field1: null, + field2: null, + field3: null, + }; + const intersection = objectPairIntersection(a, b); + const expected = { + field3: null, + }; + expect(intersection).toEqual(expected); + }); + + test('should handle explicit undefined values and return undefined if left with only undefined fields', () => { + const a = { + field1: 1, + field2: '1', + field3: undefined, + }; + const b = { + field1: undefined, + field2: undefined, + field3: undefined, + }; + const intersection = objectPairIntersection(a, b); + const expected = undefined; + expect(intersection).toEqual(expected); + }); + + test('should strip arrays out regardless of whether they are equal', () => { + const a = { + array_field1: [1, 2], + array_field2: [1, 2], + }; + const b = { + array_field1: [1, 2], + array_field2: [3, 4], + }; + const intersection = objectPairIntersection(a, b); + const expected = undefined; + expect(intersection).toEqual(expected); + }); + + test('should strip fields that are not in both objects', () => { + const a = { + field1: 1, + }; + const b = { + field2: 1, + }; + const intersection = objectPairIntersection(a, b); + const expected = undefined; + expect(intersection).toEqual(expected); + }); + + test('should work on objects within objects', () => { + const a = { + container_field: { + field1: 1, + field2: 1, + field3: 10, + field5: 1, + field6: null, + array_field: [1, 2], + nested_container_field: { + field1: 1, + field2: 1, + }, + nested_container_field2: { + field1: undefined, + }, + }, + container_field_without_intersection: { + sub_field1: 1, + }, + }; + const b = { + container_field: { + field1: 1, + field2: 2, + field4: 10, + field5: '1', + field6: null, + array_field: [1, 2], + nested_container_field: { + field1: 1, + field2: 2, + }, + nested_container_field2: { + field1: undefined, + }, + }, + container_field_without_intersection: { + sub_field2: 1, + }, + }; + const intersection = objectPairIntersection(a, b); + const expected = { + container_field: { + field1: 1, + field6: null, + nested_container_field: { + field1: 1, + }, + }, + }; + expect(intersection).toEqual(expected); + }); + + test('should work on objects with a variety of fields', () => { + const a = { + field1: 1, + field2: 1, + field3: 10, + field5: 1, + field6: null, + array_field: [1, 2], + container_field: { + sub_field1: 1, + sub_field2: 1, + sub_field3: 10, + }, + container_field_without_intersection: { + sub_field1: 1, + }, + }; + const b = { + field1: 1, + field2: 2, + field4: 10, + field5: '1', + field6: null, + array_field: [1, 2], + container_field: { + sub_field1: 1, + sub_field2: 2, + sub_field4: 10, + }, + container_field_without_intersection: { + sub_field2: 1, + }, + }; + const intersection = objectPairIntersection(a, b); + const expected = { + field1: 1, + field6: null, + container_field: { + sub_field1: 1, + }, + }; + expect(intersection).toEqual(expected); + }); +}); + +describe('objectArrayIntersection', () => { + test('should return undefined if the array is empty', () => { + const intersection = objectArrayIntersection([]); + const expected = undefined; + expect(intersection).toEqual(expected); + }); + test('should return the initial object if there is only 1', () => { + const a = { + field1: 1, + field2: 1, + field3: 10, + field5: 1, + field6: null, + array_field: [1, 2], + container_field: { + sub_field1: 1, + sub_field2: 1, + sub_field3: 10, + }, + container_field_without_intersection: { + sub_field1: 1, + }, + }; + const intersection = objectArrayIntersection([a]); + const expected = { + field1: 1, + field2: 1, + field3: 10, + field5: 1, + field6: null, + array_field: [1, 2], + container_field: { + sub_field1: 1, + sub_field2: 1, + sub_field3: 10, + }, + container_field_without_intersection: { + sub_field1: 1, + }, + }; + expect(intersection).toEqual(expected); + }); + test('should work with exactly 2 objects', () => { + const a = { + field1: 1, + field2: 1, + field3: 10, + field5: 1, + field6: null, + array_field: [1, 2], + container_field: { + sub_field1: 1, + sub_field2: 1, + sub_field3: 10, + }, + container_field_without_intersection: { + sub_field1: 1, + }, + }; + const b = { + field1: 1, + field2: 2, + field4: 10, + field5: '1', + field6: null, + array_field: [1, 2], + container_field: { + sub_field1: 1, + sub_field2: 2, + sub_field4: 10, + }, + container_field_without_intersection: { + sub_field2: 1, + }, + }; + const intersection = objectArrayIntersection([a, b]); + const expected = { + field1: 1, + field6: null, + container_field: { + sub_field1: 1, + }, + }; + expect(intersection).toEqual(expected); + }); + + test('should work with 3 or more objects', () => { + const a = { + field1: 1, + field2: 1, + field3: 10, + field5: 1, + field6: null, + array_field: [1, 2], + container_field: { + sub_field1: 1, + sub_field2: 1, + sub_field3: 10, + }, + container_field_without_intersection: { + sub_field1: 1, + }, + }; + const b = { + field1: 1, + field2: 2, + field4: 10, + field5: '1', + field6: null, + array_field: [1, 2], + container_field: { + sub_field1: 1, + sub_field2: 2, + sub_field4: 10, + }, + container_field_without_intersection: { + sub_field2: 1, + }, + }; + const c = { + field1: 1, + field2: 2, + field4: 10, + field5: '1', + array_field: [1, 2], + container_field: { + sub_field2: 2, + sub_field4: 10, + }, + container_field_without_intersection: { + sub_field2: 1, + }, + }; + const intersection = objectArrayIntersection([a, b, c]); + const expected = { + field1: 1, + }; + expect(intersection).toEqual(expected); + }); +}); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/build_bulk_body.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/build_bulk_body.ts index f8632a85c77e9..8e9571fe8a445 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/build_bulk_body.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/build_bulk_body.ts @@ -129,7 +129,9 @@ export const buildSignalFromSequence = ( ): SignalHit => { const rule = buildRuleWithoutOverrides(ruleSO); const signal: Signal = buildSignal(events, rule); + const mergedEvents = objectArrayIntersection(events.map((event) => event._source)); return { + ...mergedEvents, '@timestamp': new Date().toISOString(), event: { kind: 'signal', @@ -167,3 +169,54 @@ export const buildSignalFromEvent = ( }; return signalHit; }; + +export const objectArrayIntersection = (objects: object[]) => { + if (objects.length === 0) { + return undefined; + } else if (objects.length === 1) { + return objects[0]; + } else { + return objects + .slice(1) + .reduce( + (acc: object | undefined, obj): object | undefined => objectPairIntersection(acc, obj), + objects[0] + ); + } +}; + +export const objectPairIntersection = (a: object | undefined, b: object | undefined) => { + if (a === undefined || b === undefined) { + return undefined; + } + const intersection: Record = {}; + Object.entries(a).forEach(([key, aVal]) => { + if (key in b) { + const bVal = (b as Record)[key]; + if ( + typeof aVal === 'object' && + !(aVal instanceof Array) && + aVal !== null && + typeof bVal === 'object' && + !(bVal instanceof Array) && + bVal !== null + ) { + intersection[key] = objectPairIntersection(aVal, bVal); + } else if (aVal === bVal) { + intersection[key] = aVal; + } + } + }); + // Count up the number of entries that are NOT undefined in the intersection + // If there are no keys OR all entries are undefined, return undefined + if ( + Object.values(intersection).reduce( + (acc: number, value) => (value !== undefined ? acc + 1 : acc), + 0 + ) === 0 + ) { + return undefined; + } else { + return intersection; + } +}; From f398b492002dd33c0fc4f764be7a1e6d0d81c6f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Fern=C3=A1ndez=20Haro?= Date: Fri, 2 Oct 2020 16:03:42 +0100 Subject: [PATCH 42/50] [Usage Collection] [schema] `actions` (#78832) --- x-pack/.telemetryrc.json | 1 - .../server/usage/actions_usage_collector.ts | 23 +++++- .../schema/xpack_plugins.json | 78 +++++++++++++++++++ 3 files changed, 100 insertions(+), 2 deletions(-) diff --git a/x-pack/.telemetryrc.json b/x-pack/.telemetryrc.json index c7430666c538f..db50727c599a9 100644 --- a/x-pack/.telemetryrc.json +++ b/x-pack/.telemetryrc.json @@ -2,7 +2,6 @@ "output": "plugins/telemetry_collection_xpack/schema/xpack_plugins.json", "root": "plugins/", "exclude": [ - "plugins/actions/server/usage/actions_usage_collector.ts", "plugins/alerts/server/usage/alerts_usage_collector.ts", "plugins/apm/server/lib/apm_telemetry/index.ts" ] diff --git a/x-pack/plugins/actions/server/usage/actions_usage_collector.ts b/x-pack/plugins/actions/server/usage/actions_usage_collector.ts index aa546e08ea1ba..fac57b6282c44 100644 --- a/x-pack/plugins/actions/server/usage/actions_usage_collector.ts +++ b/x-pack/plugins/actions/server/usage/actions_usage_collector.ts @@ -4,11 +4,26 @@ * you may not use this file except in compliance with the Elastic License. */ -import { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; +import { MakeSchemaFrom, UsageCollectionSetup } from 'src/plugins/usage_collection/server'; import { get } from 'lodash'; import { TaskManagerStartContract } from '../../../task_manager/server'; import { ActionsUsage } from './types'; +const byTypeSchema: MakeSchemaFrom['count_by_type'] = { + // TODO: Find out an automated way to populate the keys or reformat these into an array (and change the Remote Telemetry indexer accordingly) + DYNAMIC_KEY: { type: 'long' }, + // Known actions: + __email: { type: 'long' }, + __index: { type: 'long' }, + __pagerduty: { type: 'long' }, + '__server-log': { type: 'long' }, + __slack: { type: 'long' }, + __webhook: { type: 'long' }, + __servicenow: { type: 'long' }, + __jira: { type: 'long' }, + __resilient: { type: 'long' }, +}; + export function createActionsUsageCollector( usageCollection: UsageCollectionSetup, taskManager: TaskManagerStartContract @@ -16,6 +31,12 @@ export function createActionsUsageCollector( return usageCollection.makeUsageCollector({ type: 'actions', isReady: () => true, + schema: { + count_total: { type: 'long' }, + count_active_total: { type: 'long' }, + count_by_type: byTypeSchema, + count_active_by_type: byTypeSchema, + }, fetch: async () => { try { const doc = await getLatestTaskState(await taskManager); 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 b08585066f100..bdafbfd8ec967 100644 --- a/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json +++ b/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json @@ -1,5 +1,83 @@ { "properties": { + "actions": { + "properties": { + "count_total": { + "type": "long" + }, + "count_active_total": { + "type": "long" + }, + "count_by_type": { + "properties": { + "DYNAMIC_KEY": { + "type": "long" + }, + "__email": { + "type": "long" + }, + "__index": { + "type": "long" + }, + "__pagerduty": { + "type": "long" + }, + "__server-log": { + "type": "long" + }, + "__slack": { + "type": "long" + }, + "__webhook": { + "type": "long" + }, + "__servicenow": { + "type": "long" + }, + "__jira": { + "type": "long" + }, + "__resilient": { + "type": "long" + } + } + }, + "count_active_by_type": { + "properties": { + "DYNAMIC_KEY": { + "type": "long" + }, + "__email": { + "type": "long" + }, + "__index": { + "type": "long" + }, + "__pagerduty": { + "type": "long" + }, + "__server-log": { + "type": "long" + }, + "__slack": { + "type": "long" + }, + "__webhook": { + "type": "long" + }, + "__servicenow": { + "type": "long" + }, + "__jira": { + "type": "long" + }, + "__resilient": { + "type": "long" + } + } + } + } + }, "canvas": { "properties": { "workpads": { From fccfad24cb7856f0a871381524e3e404dedfa839 Mon Sep 17 00:00:00 2001 From: Marta Bondyra Date: Fri, 2 Oct 2020 17:18:20 +0200 Subject: [PATCH 43/50] [Lens] remove test warnings about improper HTML structure (#79251) * [Lens] remove test warnings about improper HTML structure --- .../workspace_panel/workspace_panel.tsx | 32 ++++++++----------- 1 file changed, 13 insertions(+), 19 deletions(-) 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 2a5798ac6a70c..3993b4ffc02b0 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 @@ -208,27 +208,22 @@ export function InnerWorkspacePanel({ >

    - {expression === null ? ( - - ) : ( - - )} + {expression === null + ? i18n.translate('xpack.lens.editorFrame.emptyWorkspace', { + defaultMessage: 'Drop some fields here to start', + }) + : i18n.translate('xpack.lens.editorFrame.emptyWorkspaceSimple', { + defaultMessage: 'Drop field here', + })}

    {expression === null && ( <>

    - + {i18n.translate('xpack.lens.editorFrame.emptyWorkspaceHeading', { + defaultMessage: 'Lens is a new tool for creating visualization', + })}

    @@ -237,10 +232,9 @@ export function InnerWorkspacePanel({ target="_blank" external > - + {i18n.translate('xpack.lens.editorFrame.goToForums', { + defaultMessage: 'Make requests and give feedback', + })}

    From 6364c14ffd99fc86cf257beaea81e56e04a41c68 Mon Sep 17 00:00:00 2001 From: Devon Thomson Date: Fri, 2 Oct 2020 12:31:08 -0400 Subject: [PATCH 44/50] Panel Description Tooltip Design Change (#79213) * wrapped Embeddable Panel title in EuiTooltip and centered description icon --- .../public/lib/panel/_embeddable_panel.scss | 5 ++ .../lib/panel/panel_header/panel_header.tsx | 55 ++++++++++--------- 2 files changed, 33 insertions(+), 27 deletions(-) diff --git a/src/plugins/embeddable/public/lib/panel/_embeddable_panel.scss b/src/plugins/embeddable/public/lib/panel/_embeddable_panel.scss index 36a7fee14cce1..cdc0f9f0e0451 100644 --- a/src/plugins/embeddable/public/lib/panel/_embeddable_panel.scss +++ b/src/plugins/embeddable/public/lib/panel/_embeddable_panel.scss @@ -54,9 +54,14 @@ .embPanel__titleInner { overflow: hidden; display: flex; + align-items: center; padding-right: $euiSizeS; } + .embPanel__titleTooltipAnchor { + max-width: 100%; + } + .embPanel__titleText { @include euiTextTruncate; } diff --git a/src/plugins/embeddable/public/lib/panel/panel_header/panel_header.tsx b/src/plugins/embeddable/public/lib/panel/panel_header/panel_header.tsx index c538b98949a43..ea6a6a78c2b67 100644 --- a/src/plugins/embeddable/public/lib/panel/panel_header/panel_header.tsx +++ b/src/plugins/embeddable/public/lib/panel/panel_header/panel_header.tsx @@ -99,16 +99,6 @@ function renderNotifications( }); } -function renderTooltip(description: string) { - return ( - description !== '' && ( - - - - ) - ); -} - type EmbeddableWithDescription = IEmbeddable & { getDescription: () => string }; function getViewDescription(embeddable: IEmbeddable | EmbeddableWithDescription) { @@ -134,9 +124,10 @@ export function PanelHeader({ embeddable, headerId, }: PanelHeaderProps) { - const viewDescription = getViewDescription(embeddable); - const showTitle = !hidePanelTitle && (!isViewMode || title || viewDescription !== ''); - const showPanelBar = !isViewMode || badges.length > 0 || notifications.length > 0 || showTitle; + const description = getViewDescription(embeddable); + const showTitle = !hidePanelTitle && (!isViewMode || title); + const showPanelBar = + !isViewMode || badges.length > 0 || notifications.length > 0 || showTitle || description; const classes = classNames('embPanel__header', { // eslint-disable-next-line @typescript-eslint/naming-convention 'embPanel__header--floater': !showPanelBar, @@ -174,26 +165,36 @@ export function PanelHeader({ ); } + const renderTitle = () => { + const titleComponent = showTitle ? ( + + {title || placeholderTitle} + + ) : undefined; + return description ? ( + + + {titleComponent} + + + ) : ( + titleComponent + ); + }; + return (

    - {showTitle ? ( - - - {getAriaLabel()} - {renderTooltip(viewDescription)} - - ) : ( - {getAriaLabel()} - )} + {getAriaLabel()} + {renderTitle()} {renderBadges(badges, embeddable)}

    {renderNotifications(notifications, embeddable)} From d67962453224404647e4859ba6c4f996e64f2e48 Mon Sep 17 00:00:00 2001 From: Marco Liberati Date: Fri, 2 Oct 2020 18:41:40 +0200 Subject: [PATCH 45/50] [Lens] Fix open custom ranges saved issue (#78915) Co-authored-by: Elastic Machine --- .../definitions/ranges/advanced_editor.tsx | 4 +- .../definitions/ranges/ranges.test.tsx | 42 ++++++++++++++++++- .../operations/definitions/ranges/ranges.tsx | 19 ++++++--- 3 files changed, 57 insertions(+), 8 deletions(-) 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 a6756df403ba7..16b861ae034fa 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 @@ -132,11 +132,11 @@ export const RangePopover = ({ { const newRange = { ...tempRange, - to: target.value !== '' ? Number(target.value) : -Infinity, + to: target.value !== '' ? Number(target.value) : Infinity, }; setTempRange(newRange); saveRangeAndReset(newRange); 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 2409406afcdbc..fb6cf6df8573f 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 @@ -485,7 +485,7 @@ describe('ranges', () => { /> ); - // This series of act clojures are made to make it work properly the update flush + // This series of act closures are made to make it work properly the update flush act(() => { instance.find(RangePopover).find(EuiLink).prop('onClick')!({} as ReactMouseEvent); }); @@ -550,6 +550,46 @@ describe('ranges', () => { expect(instance.find(RangePopover)).toHaveLength(1); }); }); + + it('should handle correctly open ranges when saved', () => { + const setStateSpy = jest.fn(); + + // Add an extra open range: + (state.layers.first.columns.col1 as RangeIndexPatternColumn).params.ranges.push({ + from: null, + to: null, + label: '', + }); + + const instance = mount( + + ); + + act(() => { + instance.find(RangePopover).last().find(EuiLink).prop('onClick')!({} as ReactMouseEvent); + }); + + act(() => { + // need another wrapping for this in order to work + instance.update(); + + // Check UI values for open ranges + expect( + instance.find(RangePopover).last().find(EuiFieldNumber).first().prop('value') + ).toBe(''); + + expect(instance.find(RangePopover).last().find(EuiFieldNumber).last().prop('value')).toBe( + '' + ); + }); + }); }); }); }); diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/ranges.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/ranges.tsx index a59780ef59939..a8304456262eb 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/ranges.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/ranges.tsx @@ -16,7 +16,13 @@ import { updateColumnParam, changeColumn } from '../../../state_helpers'; import { MODES, AUTO_BARS, DEFAULT_INTERVAL, MIN_HISTOGRAM_BARS, SLICES } from './constants'; type RangeType = Omit; -export type RangeTypeLens = RangeType & { label: string }; +// Try to cover all possible serialized states for ranges +export type RangeTypeLens = (RangeType | { from: Range['from'] | null; to: Range['to'] | null }) & { + label: string; +}; + +// This is a subset of RangeTypeLens which has both from and to defined +type FullRangeTypeLens = Extract>; export type MODES_TYPES = typeof MODES[keyof typeof MODES]; @@ -35,10 +41,13 @@ export type UpdateParamsFnType = ( value: RangeColumnParams[K] ) => void; -export const isValidNumber = (value: number | '') => - value !== '' && !isNaN(value) && isFinite(value); -export const isRangeWithin = (range: RangeTypeLens): boolean => range.from <= range.to; -const isFullRange = ({ from, to }: RangeType) => isValidNumber(from) && isValidNumber(to); +// on initialization values can be null (from the Infinity serialization), so handle it correctly +// or they will be casted to 0 by the editor ( see #78867 ) +export const isValidNumber = (value: number | '' | null): value is number => + value != null && value !== '' && !isNaN(value) && isFinite(value); +export const isRangeWithin = (range: RangeType): boolean => range.from <= range.to; +const isFullRange = (range: RangeTypeLens): range is FullRangeTypeLens => + isValidNumber(range.from) && isValidNumber(range.to); export const isValidRange = (range: RangeTypeLens): boolean => { if (isFullRange(range)) { return isRangeWithin(range); From 7afb8b4d7b2813e6235bcb164bbebc4c30f1d43d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Fern=C3=A1ndez=20Haro?= Date: Fri, 2 Oct 2020 17:45:47 +0100 Subject: [PATCH 46/50] [Usage Collection] [schema] `alerts` (#78933) --- x-pack/.telemetryrc.json | 1 - .../server/usage/alerts_usage_collector.ts | 57 +++++- .../schema/xpack_plugins.json | 192 ++++++++++++++++++ 3 files changed, 248 insertions(+), 2 deletions(-) diff --git a/x-pack/.telemetryrc.json b/x-pack/.telemetryrc.json index db50727c599a9..706decfc93e9c 100644 --- a/x-pack/.telemetryrc.json +++ b/x-pack/.telemetryrc.json @@ -2,7 +2,6 @@ "output": "plugins/telemetry_collection_xpack/schema/xpack_plugins.json", "root": "plugins/", "exclude": [ - "plugins/alerts/server/usage/alerts_usage_collector.ts", "plugins/apm/server/lib/apm_telemetry/index.ts" ] } diff --git a/x-pack/plugins/alerts/server/usage/alerts_usage_collector.ts b/x-pack/plugins/alerts/server/usage/alerts_usage_collector.ts index 64d3ad54a2318..de82dd31877af 100644 --- a/x-pack/plugins/alerts/server/usage/alerts_usage_collector.ts +++ b/x-pack/plugins/alerts/server/usage/alerts_usage_collector.ts @@ -4,11 +4,44 @@ * you may not use this file except in compliance with the Elastic License. */ -import { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; +import { MakeSchemaFrom, UsageCollectionSetup } from 'src/plugins/usage_collection/server'; import { get } from 'lodash'; import { TaskManagerStartContract } from '../../../task_manager/server'; import { AlertsUsage } from './types'; +const byTypeSchema: MakeSchemaFrom['count_by_type'] = { + // TODO: Find out an automated way to populate the keys or reformat these into an array (and change the Remote Telemetry indexer accordingly) + DYNAMIC_KEY: { type: 'long' }, + // Known alerts (searching the use of the alerts API `registerType`: + // Built-in + '__index-threshold': { type: 'long' }, + // APM + apm__error_rate: { type: 'long' }, // eslint-disable-line @typescript-eslint/naming-convention + apm__transaction_error_rate: { type: 'long' }, // eslint-disable-line @typescript-eslint/naming-convention + apm__transaction_duration: { type: 'long' }, // eslint-disable-line @typescript-eslint/naming-convention + apm__transaction_duration_anomaly: { type: 'long' }, // eslint-disable-line @typescript-eslint/naming-convention + // Infra + metrics__alert__threshold: { type: 'long' }, // eslint-disable-line @typescript-eslint/naming-convention + metrics__alert__inventory__threshold: { type: 'long' }, // eslint-disable-line @typescript-eslint/naming-convention + logs__alert__document__count: { type: 'long' }, // eslint-disable-line @typescript-eslint/naming-convention + // Monitoring + monitoring_alert_cluster_health: { type: 'long' }, + monitoring_alert_cpu_usage: { type: 'long' }, + monitoring_alert_disk_usage: { type: 'long' }, + monitoring_alert_elasticsearch_version_mismatch: { type: 'long' }, + monitoring_alert_kibana_version_mismatch: { type: 'long' }, + monitoring_alert_license_expiration: { type: 'long' }, + monitoring_alert_logstash_version_mismatch: { type: 'long' }, + monitoring_alert_nodes_changed: { type: 'long' }, + // Security Solution + siem__signals: { type: 'long' }, // eslint-disable-line @typescript-eslint/naming-convention + siem__notifications: { type: 'long' }, // eslint-disable-line @typescript-eslint/naming-convention + // Uptime + xpack__uptime__alerts__monitorStatus: { type: 'long' }, // eslint-disable-line @typescript-eslint/naming-convention + xpack__uptime__alerts__tls: { type: 'long' }, // eslint-disable-line @typescript-eslint/naming-convention + xpack__uptime__alerts__durationAnomaly: { type: 'long' }, // eslint-disable-line @typescript-eslint/naming-convention +}; + export function createAlertsUsageCollector( usageCollection: UsageCollectionSetup, taskManager: TaskManagerStartContract @@ -50,6 +83,28 @@ export function createAlertsUsageCollector( }; } }, + schema: { + count_total: { type: 'long' }, + count_active_total: { type: 'long' }, + count_disabled_total: { type: 'long' }, + throttle_time: { + min: { type: 'long' }, + avg: { type: 'float' }, + max: { type: 'long' }, + }, + schedule_time: { + min: { type: 'long' }, + avg: { type: 'float' }, + max: { type: 'long' }, + }, + connectors_per_alert: { + min: { type: 'long' }, + avg: { type: 'float' }, + max: { type: 'long' }, + }, + count_active_by_type: byTypeSchema, + count_by_type: byTypeSchema, + }, }); } 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 bdafbfd8ec967..98230f143d3d6 100644 --- a/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json +++ b/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json @@ -78,6 +78,198 @@ } } }, + "alerts": { + "properties": { + "count_total": { + "type": "long" + }, + "count_active_total": { + "type": "long" + }, + "count_disabled_total": { + "type": "long" + }, + "throttle_time": { + "properties": { + "min": { + "type": "long" + }, + "avg": { + "type": "float" + }, + "max": { + "type": "long" + } + } + }, + "schedule_time": { + "properties": { + "min": { + "type": "long" + }, + "avg": { + "type": "float" + }, + "max": { + "type": "long" + } + } + }, + "connectors_per_alert": { + "properties": { + "min": { + "type": "long" + }, + "avg": { + "type": "float" + }, + "max": { + "type": "long" + } + } + }, + "count_active_by_type": { + "properties": { + "DYNAMIC_KEY": { + "type": "long" + }, + "__index-threshold": { + "type": "long" + }, + "apm__error_rate": { + "type": "long" + }, + "apm__transaction_error_rate": { + "type": "long" + }, + "apm__transaction_duration": { + "type": "long" + }, + "apm__transaction_duration_anomaly": { + "type": "long" + }, + "metrics__alert__threshold": { + "type": "long" + }, + "metrics__alert__inventory__threshold": { + "type": "long" + }, + "logs__alert__document__count": { + "type": "long" + }, + "monitoring_alert_cluster_health": { + "type": "long" + }, + "monitoring_alert_cpu_usage": { + "type": "long" + }, + "monitoring_alert_disk_usage": { + "type": "long" + }, + "monitoring_alert_elasticsearch_version_mismatch": { + "type": "long" + }, + "monitoring_alert_kibana_version_mismatch": { + "type": "long" + }, + "monitoring_alert_license_expiration": { + "type": "long" + }, + "monitoring_alert_logstash_version_mismatch": { + "type": "long" + }, + "monitoring_alert_nodes_changed": { + "type": "long" + }, + "siem__signals": { + "type": "long" + }, + "siem__notifications": { + "type": "long" + }, + "xpack__uptime__alerts__monitorStatus": { + "type": "long" + }, + "xpack__uptime__alerts__tls": { + "type": "long" + }, + "xpack__uptime__alerts__durationAnomaly": { + "type": "long" + } + } + }, + "count_by_type": { + "properties": { + "DYNAMIC_KEY": { + "type": "long" + }, + "__index-threshold": { + "type": "long" + }, + "apm__error_rate": { + "type": "long" + }, + "apm__transaction_error_rate": { + "type": "long" + }, + "apm__transaction_duration": { + "type": "long" + }, + "apm__transaction_duration_anomaly": { + "type": "long" + }, + "metrics__alert__threshold": { + "type": "long" + }, + "metrics__alert__inventory__threshold": { + "type": "long" + }, + "logs__alert__document__count": { + "type": "long" + }, + "monitoring_alert_cluster_health": { + "type": "long" + }, + "monitoring_alert_cpu_usage": { + "type": "long" + }, + "monitoring_alert_disk_usage": { + "type": "long" + }, + "monitoring_alert_elasticsearch_version_mismatch": { + "type": "long" + }, + "monitoring_alert_kibana_version_mismatch": { + "type": "long" + }, + "monitoring_alert_license_expiration": { + "type": "long" + }, + "monitoring_alert_logstash_version_mismatch": { + "type": "long" + }, + "monitoring_alert_nodes_changed": { + "type": "long" + }, + "siem__signals": { + "type": "long" + }, + "siem__notifications": { + "type": "long" + }, + "xpack__uptime__alerts__monitorStatus": { + "type": "long" + }, + "xpack__uptime__alerts__tls": { + "type": "long" + }, + "xpack__uptime__alerts__durationAnomaly": { + "type": "long" + } + } + } + } + }, "canvas": { "properties": { "workpads": { From d9915fdee08e179a11c494b852faa72ead77f33b Mon Sep 17 00:00:00 2001 From: Ryan Keairns Date: Fri, 2 Oct 2020 11:47:20 -0500 Subject: [PATCH 47/50] Re-style and re-order top menu buttons (#79206) * Re-style and re-order top menu buttons * Update snapshot due to removed fill prop * Fix link order for Maps --- .../application/top_nav/get_top_nav_config.ts | 12 +- .../top_nav_menu_item.test.tsx.snap | 1 - .../public/top_nav_menu/_index.scss | 4 + .../public/top_nav_menu/top_nav_menu_item.tsx | 2 +- .../application/utils/get_top_nav_config.tsx | 185 +++++++++--------- .../lens/public/app_plugin/lens_top_nav.tsx | 36 ++-- .../routes/maps_app/top_nav_config.tsx | 125 ++++++------ 7 files changed, 187 insertions(+), 178 deletions(-) diff --git a/src/plugins/dashboard/public/application/top_nav/get_top_nav_config.ts b/src/plugins/dashboard/public/application/top_nav/get_top_nav_config.ts index dbdadeb4e4e7c..77c4a2235d471 100644 --- a/src/plugins/dashboard/public/application/top_nav/get_top_nav_config.ts +++ b/src/plugins/dashboard/public/application/top_nav/get_top_nav_config.ts @@ -48,12 +48,12 @@ export function getTopNavConfig( ]; case ViewMode.EDIT: return [ - getCreateNewConfig(actions[TopNavIds.VISUALIZE]), - getSaveConfig(actions[TopNavIds.SAVE]), - getViewConfig(actions[TopNavIds.EXIT_EDIT_MODE]), - getAddConfig(actions[TopNavIds.ADD_EXISTING]), getOptionsConfig(actions[TopNavIds.OPTIONS]), getShareConfig(actions[TopNavIds.SHARE]), + getAddConfig(actions[TopNavIds.ADD_EXISTING]), + getViewConfig(actions[TopNavIds.EXIT_EDIT_MODE]), + getSaveConfig(actions[TopNavIds.SAVE]), + getCreateNewConfig(actions[TopNavIds.VISUALIZE]), ]; default: return []; @@ -79,7 +79,9 @@ function getFullScreenConfig(action: NavAction) { */ function getEditConfig(action: NavAction) { return { + emphasize: true, id: 'edit', + iconType: 'pencil', label: i18n.translate('dashboard.topNave.editButtonAriaLabel', { defaultMessage: 'edit', }), @@ -168,7 +170,7 @@ function getAddConfig(action: NavAction) { function getCreateNewConfig(action: NavAction) { return { emphasize: true, - iconType: 'plusInCircle', + iconType: 'plusInCircleFilled', id: 'addNew', label: i18n.translate('dashboard.topNave.addNewButtonAriaLabel', { defaultMessage: 'Create new', diff --git a/src/plugins/navigation/public/top_nav_menu/__snapshots__/top_nav_menu_item.test.tsx.snap b/src/plugins/navigation/public/top_nav_menu/__snapshots__/top_nav_menu_item.test.tsx.snap index 570699aa0c0e2..155377e5ea335 100644 --- a/src/plugins/navigation/public/top_nav_menu/__snapshots__/top_nav_menu_item.test.tsx.snap +++ b/src/plugins/navigation/public/top_nav_menu/__snapshots__/top_nav_menu_item.test.tsx.snap @@ -2,7 +2,6 @@ exports[`TopNavMenu Should render emphasized item which should be clickable 1`] = ` * > * { // TEMP fix to adjust spacing between EuiHeaderList__list items margin: 0 $euiSizeXS; diff --git a/src/plugins/navigation/public/top_nav_menu/top_nav_menu_item.tsx b/src/plugins/navigation/public/top_nav_menu/top_nav_menu_item.tsx index 96a205b737273..e503ebb839f48 100644 --- a/src/plugins/navigation/public/top_nav_menu/top_nav_menu_item.tsx +++ b/src/plugins/navigation/public/top_nav_menu/top_nav_menu_item.tsx @@ -48,7 +48,7 @@ export function TopNavMenuItem(props: TopNavMenuData) { }; const btn = props.emphasize ? ( - + {upperFirst(props.label || props.id!)} ) : ( diff --git a/src/plugins/visualize/public/application/utils/get_top_nav_config.tsx b/src/plugins/visualize/public/application/utils/get_top_nav_config.tsx index 12720f3f22e7c..cb68a647cb81d 100644 --- a/src/plugins/visualize/public/application/utils/get_top_nav_config.tsx +++ b/src/plugins/visualize/public/application/utils/get_top_nav_config.tsx @@ -175,54 +175,61 @@ export const getTopNavConfig = ( }; const topNavMenu: TopNavMenuData[] = [ - ...(originatingApp && ((savedVis && savedVis.id) || embeddableId) - ? [ - { - id: 'saveAndReturn', - label: i18n.translate('visualize.topNavMenu.saveAndReturnVisualizationButtonLabel', { - defaultMessage: 'Save and return', - }), - emphasize: true, - iconType: 'check', - description: i18n.translate( - 'visualize.topNavMenu.saveAndReturnVisualizationButtonAriaLabel', - { - defaultMessage: 'Finish editing visualization and return to the last app', - } - ), - testId: 'visualizesaveAndReturnButton', - disableButton: hasUnappliedChanges, - tooltip() { - if (hasUnappliedChanges) { - return i18n.translate( - 'visualize.topNavMenu.saveAndReturnVisualizationDisabledButtonTooltip', - { - defaultMessage: 'Apply or Discard your changes before finishing', - } - ); - } - }, - run: async () => { - const saveOptions = { - confirmOverwrite: false, - returnToOrigin: true, - }; - if ( - originatingApp === 'dashboards' && - dashboard.dashboardFeatureFlagConfig.allowByValueEmbeddables && - !savedVis - ) { - return createVisReference(); - } - return doSave(saveOptions); + { + id: 'inspector', + label: i18n.translate('visualize.topNavMenu.openInspectorButtonLabel', { + defaultMessage: 'inspect', + }), + description: i18n.translate('visualize.topNavMenu.openInspectorButtonAriaLabel', { + defaultMessage: 'Open Inspector for visualization', + }), + testId: 'openInspectorButton', + disableButton() { + return !embeddableHandler.hasInspector || !embeddableHandler.hasInspector(); + }, + run: openInspector, + tooltip() { + if (!embeddableHandler.hasInspector || !embeddableHandler.hasInspector()) { + return i18n.translate('visualize.topNavMenu.openInspectorDisabledButtonTooltip', { + defaultMessage: `This visualization doesn't support any inspectors.`, + }); + } + }, + }, + { + id: 'share', + label: i18n.translate('visualize.topNavMenu.shareVisualizationButtonLabel', { + defaultMessage: 'share', + }), + description: i18n.translate('visualize.topNavMenu.shareVisualizationButtonAriaLabel', { + defaultMessage: 'Share Visualization', + }), + testId: 'shareTopNavButton', + run: (anchorElement) => { + if (share && !embeddableId) { + // TODO: support sharing in by-value mode + share.toggleShareContextMenu({ + anchorElement, + allowEmbed: true, + allowShortUrl: visualizeCapabilities.createShortUrl, + shareableUrl: unhashUrl(window.location.href), + objectId: savedVis?.id, + objectType: 'visualization', + sharingData: { + title: savedVis?.title, }, - }, - ] - : []), + isDirty: hasUnappliedChanges || hasUnsavedChanges, + }); + } + }, + // disable the Share button if no action specified + disableButton: !share || !!embeddableId, + }, ...(visualizeCapabilities.save && !embeddableId ? [ { id: 'save', + iconType: savedVis?.id && originatingApp ? undefined : 'save', label: savedVis?.id && originatingApp ? i18n.translate('visualize.topNavMenu.saveVisualizationAsButtonLabel', { @@ -303,56 +310,50 @@ export const getTopNavConfig = ( }, ] : []), - { - id: 'share', - label: i18n.translate('visualize.topNavMenu.shareVisualizationButtonLabel', { - defaultMessage: 'share', - }), - description: i18n.translate('visualize.topNavMenu.shareVisualizationButtonAriaLabel', { - defaultMessage: 'Share Visualization', - }), - testId: 'shareTopNavButton', - run: (anchorElement) => { - if (share && !embeddableId) { - // TODO: support sharing in by-value mode - share.toggleShareContextMenu({ - anchorElement, - allowEmbed: true, - allowShortUrl: visualizeCapabilities.createShortUrl, - shareableUrl: unhashUrl(window.location.href), - objectId: savedVis?.id, - objectType: 'visualization', - sharingData: { - title: savedVis?.title, + ...(originatingApp && ((savedVis && savedVis.id) || embeddableId) + ? [ + { + id: 'saveAndReturn', + label: i18n.translate('visualize.topNavMenu.saveAndReturnVisualizationButtonLabel', { + defaultMessage: 'Save and return', + }), + emphasize: true, + iconType: 'checkInCircleFilled', + description: i18n.translate( + 'visualize.topNavMenu.saveAndReturnVisualizationButtonAriaLabel', + { + defaultMessage: 'Finish editing visualization and return to the last app', + } + ), + testId: 'visualizesaveAndReturnButton', + disableButton: hasUnappliedChanges, + tooltip() { + if (hasUnappliedChanges) { + return i18n.translate( + 'visualize.topNavMenu.saveAndReturnVisualizationDisabledButtonTooltip', + { + defaultMessage: 'Apply or Discard your changes before finishing', + } + ); + } }, - isDirty: hasUnappliedChanges || hasUnsavedChanges, - }); - } - }, - // disable the Share button if no action specified - disableButton: !share || !!embeddableId, - }, - { - id: 'inspector', - label: i18n.translate('visualize.topNavMenu.openInspectorButtonLabel', { - defaultMessage: 'inspect', - }), - description: i18n.translate('visualize.topNavMenu.openInspectorButtonAriaLabel', { - defaultMessage: 'Open Inspector for visualization', - }), - testId: 'openInspectorButton', - disableButton() { - return !embeddableHandler.hasInspector || !embeddableHandler.hasInspector(); - }, - run: openInspector, - tooltip() { - if (!embeddableHandler.hasInspector || !embeddableHandler.hasInspector()) { - return i18n.translate('visualize.topNavMenu.openInspectorDisabledButtonTooltip', { - defaultMessage: `This visualization doesn't support any inspectors.`, - }); - } - }, - }, + run: async () => { + const saveOptions = { + confirmOverwrite: false, + returnToOrigin: true, + }; + if ( + originatingApp === 'dashboards' && + dashboard.dashboardFeatureFlagConfig.allowByValueEmbeddables && + !savedVis + ) { + return createVisReference(); + } + return doSave(saveOptions); + }, + }, + ] + : []), ]; return topNavMenu; 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 f6234d063d8cd..9162af52052ee 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 @@ -30,24 +30,22 @@ export function getLensTopNavConfig(options: { defaultMessage: 'Save', }); - if (showSaveAndReturn) { + if (showCancel) { topNavMenu.push({ - label: i18n.translate('xpack.lens.app.saveAndReturn', { - defaultMessage: 'Save and return', + label: i18n.translate('xpack.lens.app.cancel', { + defaultMessage: 'cancel', }), - emphasize: true, - iconType: 'check', - run: actions.saveAndReturn, - testId: 'lnsApp_saveAndReturnButton', - disableButton: !savingPermitted, - description: i18n.translate('xpack.lens.app.saveAndReturnButtonAriaLabel', { - defaultMessage: 'Save the current lens visualization and return to the last app', + run: actions.cancel, + testId: 'lnsApp_cancelButton', + description: i18n.translate('xpack.lens.app.cancelButtonAriaLabel', { + defaultMessage: 'Return to the last app without saving changes', }), }); } topNavMenu.push({ label: saveButtonLabel, + iconType: !showSaveAndReturn ? 'save' : undefined, emphasize: !showSaveAndReturn, run: actions.showSaveModal, testId: 'lnsApp_saveButton', @@ -57,17 +55,21 @@ export function getLensTopNavConfig(options: { disableButton: !savingPermitted, }); - if (showCancel) { + if (showSaveAndReturn) { topNavMenu.push({ - label: i18n.translate('xpack.lens.app.cancel', { - defaultMessage: 'cancel', + label: i18n.translate('xpack.lens.app.saveAndReturn', { + defaultMessage: 'Save and return', }), - run: actions.cancel, - testId: 'lnsApp_cancelButton', - description: i18n.translate('xpack.lens.app.cancelButtonAriaLabel', { - defaultMessage: 'Return to the last app without saving changes', + emphasize: true, + iconType: 'checkInCircleFilled', + run: actions.saveAndReturn, + testId: 'lnsApp_saveAndReturnButton', + disableButton: !savingPermitted, + description: i18n.translate('xpack.lens.app.saveAndReturnButtonAriaLabel', { + defaultMessage: 'Save the current lens visualization and return to the last app', }), }); } + return topNavMenu; } diff --git a/x-pack/plugins/maps/public/routing/routes/maps_app/top_nav_config.tsx b/x-pack/plugins/maps/public/routing/routes/maps_app/top_nav_config.tsx index 8a0eb8db4d7aa..917abebfb6b25 100644 --- a/x-pack/plugins/maps/public/routing/routes/maps_app/top_nav_config.tsx +++ b/x-pack/plugins/maps/public/routing/routes/maps_app/top_nav_config.tsx @@ -123,31 +123,56 @@ export function getTopNavConfig({ return { id: savedObjectId }; } - if (hasSaveAndReturnConfig) { - topNavConfigs.push({ - id: 'saveAndReturn', - label: i18n.translate('xpack.maps.topNav.saveAndReturnButtonLabel', { - defaultMessage: 'Save and return', + topNavConfigs.push( + { + id: 'mapSettings', + label: i18n.translate('xpack.maps.topNav.openSettingsButtonLabel', { + defaultMessage: `Map settings`, }), - emphasize: true, - iconType: 'check', - run: () => { - onSave({ - newTitle: savedMap.title ? savedMap.title : '', - newDescription: savedMap.description ? savedMap.description : '', - newCopyOnSave: false, - isTitleDuplicateConfirmed: false, - returnToOrigin: true, - onTitleDuplicate: () => {}, - }); + description: i18n.translate('xpack.maps.topNav.openSettingsDescription', { + defaultMessage: `Open map settings`, + }), + testId: 'openSettingsButton', + disableButton() { + return isOpenSettingsDisabled; }, - testId: 'mapSaveAndReturnButton', - }); - } + run() { + openMapSettings(); + }, + }, + { + id: 'inspect', + label: i18n.translate('xpack.maps.topNav.openInspectorButtonLabel', { + defaultMessage: `inspect`, + }), + description: i18n.translate('xpack.maps.topNav.openInspectorDescription', { + defaultMessage: `Open Inspector`, + }), + testId: 'openInspectorButton', + run() { + getInspector().open(inspectorAdapters, {}); + }, + }, + { + id: 'full-screen', + label: i18n.translate('xpack.maps.topNav.fullScreenButtonLabel', { + defaultMessage: `full screen`, + }), + description: i18n.translate('xpack.maps.topNav.fullScreenDescription', { + defaultMessage: `full screen`, + }), + testId: 'mapsFullScreenMode', + run() { + getCoreChrome().setIsVisible(false); + enableFullScreen(); + }, + } + ); if (hasWritePermissions) { topNavConfigs.push({ id: 'save', + iconType: hasSaveAndReturnConfig ? undefined : 'save', label: hasSaveAndReturnConfig ? i18n.translate('xpack.maps.topNav.saveAsButtonLabel', { defaultMessage: 'Save as', @@ -192,51 +217,27 @@ export function getTopNavConfig({ }); } - topNavConfigs.push( - { - id: 'mapSettings', - label: i18n.translate('xpack.maps.topNav.openSettingsButtonLabel', { - defaultMessage: `Map settings`, - }), - description: i18n.translate('xpack.maps.topNav.openSettingsDescription', { - defaultMessage: `Open map settings`, - }), - testId: 'openSettingsButton', - disableButton() { - return isOpenSettingsDisabled; - }, - run() { - openMapSettings(); - }, - }, - { - id: 'inspect', - label: i18n.translate('xpack.maps.topNav.openInspectorButtonLabel', { - defaultMessage: `inspect`, - }), - description: i18n.translate('xpack.maps.topNav.openInspectorDescription', { - defaultMessage: `Open Inspector`, - }), - testId: 'openInspectorButton', - run() { - getInspector().open(inspectorAdapters, {}); - }, - }, - { - id: 'full-screen', - label: i18n.translate('xpack.maps.topNav.fullScreenButtonLabel', { - defaultMessage: `full screen`, - }), - description: i18n.translate('xpack.maps.topNav.fullScreenDescription', { - defaultMessage: `full screen`, + if (hasSaveAndReturnConfig) { + topNavConfigs.push({ + id: 'saveAndReturn', + label: i18n.translate('xpack.maps.topNav.saveAndReturnButtonLabel', { + defaultMessage: 'Save and return', }), - testId: 'mapsFullScreenMode', - run() { - getCoreChrome().setIsVisible(false); - enableFullScreen(); + emphasize: true, + iconType: 'checkInCircleFilled', + run: () => { + onSave({ + newTitle: savedMap.title ? savedMap.title : '', + newDescription: savedMap.description ? savedMap.description : '', + newCopyOnSave: false, + isTitleDuplicateConfirmed: false, + returnToOrigin: true, + onTitleDuplicate: () => {}, + }); }, - } - ); + testId: 'mapSaveAndReturnButton', + }); + } return topNavConfigs; } From bb4ad196ea25858234176248030814144a087f0b Mon Sep 17 00:00:00 2001 From: Spencer Date: Fri, 2 Oct 2020 09:50:49 -0700 Subject: [PATCH 48/50] normalize paths before printing them into the generated plugin list (#79232) Co-authored-by: spalger --- docs/developer/plugin-list.asciidoc | 12 ++++++------ .../src/plugin_list/discover_plugins.ts | 2 +- .../src/plugin_list/generate_plugin_list.ts | 10 ++++++---- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/docs/developer/plugin-list.asciidoc b/docs/developer/plugin-list.asciidoc index bf11f87b96ce9..67b7aa8e6a011 100644 --- a/docs/developer/plugin-list.asciidoc +++ b/docs/developer/plugin-list.asciidoc @@ -16,7 +16,7 @@ NOTE: [discrete] === src/plugins -[%header,cols=2*] +[%header,cols=2*] |=== |Name |Description @@ -259,7 +259,7 @@ which will load the visualization's editor. [discrete] === x-pack/plugins -[%header,cols=2*] +[%header,cols=2*] |=== |Name |Description @@ -515,6 +515,10 @@ As a developer you can reuse and extend built-in alerts and actions UI functiona in their infrastructure. +|{kib-repo}blob/{branch}/x-pack/plugins/drilldowns/url_drilldown/README.md[urlDrilldown] +|NOTE: This plugin contains implementation of URL drilldown. For drilldowns infrastructure code refer to ui_actions_enhanced plugin. + + |{kib-repo}blob/{branch}/x-pack/plugins/watcher/README.md[watcher] |This plugins adopts some conventions in addition to or in place of conventions in Kibana (at the time of the plugin's creation): @@ -523,10 +527,6 @@ in their infrastructure. |Contains HTTP endpoints and UiSettings that are slated for removal. -|{kib-repo}blob/{branch}/x-pack/plugins/drilldowns/url_drilldown/README.md[urlDrilldown] -|NOTE: This plugin contains implementation of URL drilldown. For drilldowns infrastructure code refer to ui_actions_enhanced plugin. - - |=== include::{kibana-root}/src/plugins/dashboard/README.asciidoc[leveloffset=+1] diff --git a/packages/kbn-dev-utils/src/plugin_list/discover_plugins.ts b/packages/kbn-dev-utils/src/plugin_list/discover_plugins.ts index 5d92ddb600aa9..e8f6735205b19 100644 --- a/packages/kbn-dev-utils/src/plugin_list/discover_plugins.ts +++ b/packages/kbn-dev-utils/src/plugin_list/discover_plugins.ts @@ -29,7 +29,7 @@ import { extractAsciidocInfo } from './extract_asciidoc_info'; export interface Plugin { id: string; - relativeDir?: string; + relativeDir: string; relativeReadmePath?: string; readmeSnippet?: string; readmeAsciidocAnchor?: string; diff --git a/packages/kbn-dev-utils/src/plugin_list/generate_plugin_list.ts b/packages/kbn-dev-utils/src/plugin_list/generate_plugin_list.ts index e1a1323553113..680c220adb18c 100644 --- a/packages/kbn-dev-utils/src/plugin_list/generate_plugin_list.ts +++ b/packages/kbn-dev-utils/src/plugin_list/generate_plugin_list.ts @@ -24,9 +24,11 @@ import { REPO_ROOT } from '@kbn/utils'; import { Plugins } from './discover_plugins'; +const sortPlugins = (plugins: Plugins) => plugins.sort((a, b) => a.id.localeCompare(b.id)); + function* printPlugins(plugins: Plugins, includes: string[]) { - for (const plugin of plugins) { - const path = plugin.relativeReadmePath || plugin.relativeDir; + for (const plugin of sortPlugins(plugins)) { + const path = normalizePath(plugin.relativeReadmePath || plugin.relativeDir); yield ''; if (plugin.readmeAsciidocAnchor) { @@ -67,7 +69,7 @@ NOTE: [discrete] === src/plugins -[%header,cols=2*] +[%header,cols=2*] |=== |Name |Description @@ -79,7 +81,7 @@ ${Array.from(printPlugins(ossPlugins, includes)).join('\n')} [discrete] === x-pack/plugins -[%header,cols=2*] +[%header,cols=2*] |=== |Name |Description From 2899e83df8b849f5fb2a898944c6aada69dff12f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Fern=C3=A1ndez=20G=C3=B3mez?= Date: Fri, 2 Oct 2020 18:57:50 +0200 Subject: [PATCH 49/50] [Logs UI] Remove legacy singletons (#77743) Removes the `npStart` legacy singleton used during the migration to the new platform. The singleton was used in API calls to access the `http.fetch` service. To remove the singleton we have injected `fetch` as a dependency in all functions. --- .../common/components/get_alert_preview.ts | 4 +- .../logs/log_analysis/api/ml_cleanup.ts | 56 ++++++------- .../api/ml_get_jobs_summary_api.ts | 26 +++--- .../logs/log_analysis/api/ml_get_module.ts | 16 ++-- .../log_analysis/api/ml_setup_module_api.ts | 52 +++++++----- .../log_analysis/api/validate_datasets.ts | 19 +++-- .../logs/log_analysis/api/validate_indices.ts | 26 +++--- .../log_analysis_capabilities.tsx | 15 ++-- .../log_analysis/log_analysis_cleanup.tsx | 21 ++--- .../logs/log_analysis/log_analysis_module.tsx | 28 +++++-- .../log_analysis_module_definition.tsx | 4 +- .../log_analysis/log_analysis_module_types.ts | 24 ++++-- .../log_analysis/log_analysis_setup_state.ts | 8 +- .../log_entry_categories/module_descriptor.ts | 80 ++++++++++++------- .../log_entry_rate/module_descriptor.ts | 72 ++++++++++------- .../logs/log_entries/api/fetch_log_entries.ts | 13 ++- .../log_entries/api/fetch_log_entries_item.ts | 19 ++--- .../containers/logs/log_entries/index.ts | 6 +- .../public/containers/logs/log_flyout.tsx | 4 +- .../api/fetch_log_entries_highlights.ts | 19 ++--- .../api/fetch_log_summary_highlights.ts | 18 ++--- .../log_highlights/log_entry_highlights.tsx | 23 +++--- .../log_highlights/log_summary_highlights.ts | 21 +++-- .../api/fetch_log_source_configuration.ts | 7 +- .../log_source/api/fetch_log_source_status.ts | 4 +- .../api/patch_log_source_configuration.ts | 4 +- .../containers/logs/log_source/log_source.ts | 10 +-- .../containers/logs/log_stream/index.ts | 19 +++-- .../logs/log_summary/api/fetch_log_summary.ts | 19 ++--- .../logs/log_summary/log_summary.test.tsx | 24 ++++-- .../logs/log_summary/log_summary.tsx | 19 +++-- .../public/containers/ml/api/ml_cleanup.ts | 57 ++++++------- .../ml/api/ml_get_jobs_summary_api.ts | 26 +++--- .../public/containers/ml/api/ml_get_module.ts | 16 ++-- .../containers/ml/api/ml_setup_module_api.ts | 52 +++++++----- .../containers/ml/infra_ml_capabilities.tsx | 5 +- .../public/containers/ml/infra_ml_cleanup.tsx | 20 +++-- .../public/containers/ml/infra_ml_module.tsx | 31 ++++--- .../ml/infra_ml_module_definition.tsx | 4 +- .../containers/ml/infra_ml_module_types.ts | 37 ++++++--- .../metrics_hosts/module_descriptor.ts | 53 ++++++------ .../modules/metrics_k8s/module_descriptor.ts | 53 ++++++------ .../plugins/infra/public/legacy_singletons.ts | 14 ---- .../pages/link_to/link_to_logs.test.tsx | 1 - .../get_log_entry_category_datasets.ts | 27 ++++--- .../get_log_entry_category_examples.ts | 31 +++---- .../get_top_log_entry_categories.ts | 30 +++---- .../use_log_entry_categories_results.ts | 20 +++-- .../use_log_entry_category_examples.tsx | 16 ++-- .../service_calls/get_log_entry_anomalies.ts | 23 +++--- .../get_log_entry_anomalies_datasets.ts | 16 ++-- .../service_calls/get_log_entry_examples.ts | 33 ++++---- .../service_calls/get_log_entry_rate.ts | 31 ++++--- .../use_log_entry_anomalies_results.ts | 25 ++++-- .../log_entry_rate/use_log_entry_examples.ts | 17 ++-- .../use_log_entry_rate_results.ts | 15 ++-- .../hooks/use_metrics_hosts_anomalies.ts | 43 ++++++---- .../hooks/use_metrics_k8s_anomalies.ts | 45 +++++++---- x-pack/plugins/infra/public/plugin.ts | 5 +- 59 files changed, 798 insertions(+), 628 deletions(-) delete mode 100644 x-pack/plugins/infra/public/legacy_singletons.ts diff --git a/x-pack/plugins/infra/public/alerting/common/components/get_alert_preview.ts b/x-pack/plugins/infra/public/alerting/common/components/get_alert_preview.ts index 207d8a722a8c6..ea50ea6f11f3a 100644 --- a/x-pack/plugins/infra/public/alerting/common/components/get_alert_preview.ts +++ b/x-pack/plugins/infra/public/alerting/common/components/get_alert_preview.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { HttpSetup } from 'src/core/public'; +import type { HttpHandler } from 'src/core/public'; import { INFRA_ALERT_PREVIEW_PATH, METRIC_THRESHOLD_ALERT_TYPE_ID, @@ -22,7 +22,7 @@ export async function getAlertPreview({ params, alertType, }: { - fetch: HttpSetup['fetch']; + fetch: HttpHandler; params: AlertPreviewRequestParams; alertType: PreviewableAlertTypes; }): Promise { diff --git a/x-pack/plugins/infra/public/containers/logs/log_analysis/api/ml_cleanup.ts b/x-pack/plugins/infra/public/containers/logs/log_analysis/api/ml_cleanup.ts index 6fa2ac175ace6..4fdd6bdd282ba 100644 --- a/x-pack/plugins/infra/public/containers/logs/log_analysis/api/ml_cleanup.ts +++ b/x-pack/plugins/infra/public/containers/logs/log_analysis/api/ml_cleanup.ts @@ -5,21 +5,25 @@ */ import * as rt from 'io-ts'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { fold } from 'fp-ts/lib/Either'; -import { identity } from 'fp-ts/lib/function'; -import { npStart } from '../../../../legacy_singletons'; +import type { HttpHandler } from 'src/core/public'; import { getDatafeedId, getJobId } from '../../../../../common/log_analysis'; -import { throwErrors, createPlainError } from '../../../../../common/runtime_types'; +import { decodeOrThrow } from '../../../../../common/runtime_types'; + +interface DeleteJobsRequestArgs { + spaceId: string; + sourceId: string; + jobTypes: JobType[]; +} export const callDeleteJobs = async ( - spaceId: string, - sourceId: string, - jobTypes: JobType[] + requestArgs: DeleteJobsRequestArgs, + fetch: HttpHandler ) => { + const { spaceId, sourceId, jobTypes } = requestArgs; + // NOTE: Deleting the jobs via this API will delete the datafeeds at the same time - const deleteJobsResponse = await npStart.http.fetch('/api/ml/jobs/delete_jobs', { + const deleteJobsResponse = await fetch('/api/ml/jobs/delete_jobs', { method: 'POST', body: JSON.stringify( deleteJobsRequestPayloadRT.encode({ @@ -28,28 +32,29 @@ export const callDeleteJobs = async ( ), }); - return pipe( - deleteJobsResponsePayloadRT.decode(deleteJobsResponse), - fold(throwErrors(createPlainError), identity) - ); + return decodeOrThrow(deleteJobsResponsePayloadRT)(deleteJobsResponse); }; -export const callGetJobDeletionTasks = async () => { - const jobDeletionTasksResponse = await npStart.http.fetch('/api/ml/jobs/deleting_jobs_tasks'); +export const callGetJobDeletionTasks = async (fetch: HttpHandler) => { + const jobDeletionTasksResponse = await fetch('/api/ml/jobs/deleting_jobs_tasks'); - return pipe( - getJobDeletionTasksResponsePayloadRT.decode(jobDeletionTasksResponse), - fold(throwErrors(createPlainError), identity) - ); + return decodeOrThrow(getJobDeletionTasksResponsePayloadRT)(jobDeletionTasksResponse); }; +interface StopDatafeedsRequestArgs { + spaceId: string; + sourceId: string; + jobTypes: JobType[]; +} + export const callStopDatafeeds = async ( - spaceId: string, - sourceId: string, - jobTypes: JobType[] + requestArgs: StopDatafeedsRequestArgs, + fetch: HttpHandler ) => { + const { spaceId, sourceId, jobTypes } = requestArgs; + // Stop datafeed due to https://github.com/elastic/kibana/issues/44652 - const stopDatafeedResponse = await npStart.http.fetch('/api/ml/jobs/stop_datafeeds', { + const stopDatafeedResponse = await fetch('/api/ml/jobs/stop_datafeeds', { method: 'POST', body: JSON.stringify( stopDatafeedsRequestPayloadRT.encode({ @@ -58,10 +63,7 @@ export const callStopDatafeeds = async ( ), }); - return pipe( - stopDatafeedsResponsePayloadRT.decode(stopDatafeedResponse), - fold(throwErrors(createPlainError), identity) - ); + return decodeOrThrow(stopDatafeedsResponsePayloadRT)(stopDatafeedResponse); }; export const deleteJobsRequestPayloadRT = rt.type({ diff --git a/x-pack/plugins/infra/public/containers/logs/log_analysis/api/ml_get_jobs_summary_api.ts b/x-pack/plugins/infra/public/containers/logs/log_analysis/api/ml_get_jobs_summary_api.ts index 7441c0ab7d34c..7cb477dbe5b37 100644 --- a/x-pack/plugins/infra/public/containers/logs/log_analysis/api/ml_get_jobs_summary_api.ts +++ b/x-pack/plugins/infra/public/containers/logs/log_analysis/api/ml_get_jobs_summary_api.ts @@ -4,21 +4,24 @@ * you may not use this file except in compliance with the Elastic License. */ -import { fold } from 'fp-ts/lib/Either'; -import { identity } from 'fp-ts/lib/function'; -import { pipe } from 'fp-ts/lib/pipeable'; import * as rt from 'io-ts'; -import { npStart } from '../../../../legacy_singletons'; +import type { HttpHandler } from 'src/core/public'; import { getJobId, jobCustomSettingsRT } from '../../../../../common/log_analysis'; -import { createPlainError, throwErrors } from '../../../../../common/runtime_types'; +import { decodeOrThrow } from '../../../../../common/runtime_types'; + +interface RequestArgs { + spaceId: string; + sourceId: string; + jobTypes: JobType[]; +} export const callJobsSummaryAPI = async ( - spaceId: string, - sourceId: string, - jobTypes: JobType[] + requestArgs: RequestArgs, + fetch: HttpHandler ) => { - const response = await npStart.http.fetch('/api/ml/jobs/jobs_summary', { + const { spaceId, sourceId, jobTypes } = requestArgs; + const response = await fetch('/api/ml/jobs/jobs_summary', { method: 'POST', body: JSON.stringify( fetchJobStatusRequestPayloadRT.encode({ @@ -26,10 +29,7 @@ export const callJobsSummaryAPI = async ( }) ), }); - return pipe( - fetchJobStatusResponsePayloadRT.decode(response), - fold(throwErrors(createPlainError), identity) - ); + return decodeOrThrow(fetchJobStatusResponsePayloadRT)(response); }; export const fetchJobStatusRequestPayloadRT = rt.type({ diff --git a/x-pack/plugins/infra/public/containers/logs/log_analysis/api/ml_get_module.ts b/x-pack/plugins/infra/public/containers/logs/log_analysis/api/ml_get_module.ts index b6b40d6dc651f..2bf18d4e52c79 100644 --- a/x-pack/plugins/infra/public/containers/logs/log_analysis/api/ml_get_module.ts +++ b/x-pack/plugins/infra/public/containers/logs/log_analysis/api/ml_get_module.ts @@ -4,24 +4,18 @@ * you may not use this file except in compliance with the Elastic License. */ -import { fold } from 'fp-ts/lib/Either'; -import { identity } from 'fp-ts/lib/function'; -import { pipe } from 'fp-ts/lib/pipeable'; import * as rt from 'io-ts'; -import { npStart } from '../../../../legacy_singletons'; +import type { HttpHandler } from 'src/core/public'; import { jobCustomSettingsRT } from '../../../../../common/log_analysis'; -import { createPlainError, throwErrors } from '../../../../../common/runtime_types'; +import { decodeOrThrow } from '../../../../../common/runtime_types'; -export const callGetMlModuleAPI = async (moduleId: string) => { - const response = await npStart.http.fetch(`/api/ml/modules/get_module/${moduleId}`, { +export const callGetMlModuleAPI = async (moduleId: string, fetch: HttpHandler) => { + const response = await fetch(`/api/ml/modules/get_module/${moduleId}`, { method: 'GET', }); - return pipe( - getMlModuleResponsePayloadRT.decode(response), - fold(throwErrors(createPlainError), identity) - ); + return decodeOrThrow(getMlModuleResponsePayloadRT)(response); }; const jobDefinitionRT = rt.type({ diff --git a/x-pack/plugins/infra/public/containers/logs/log_analysis/api/ml_setup_module_api.ts b/x-pack/plugins/infra/public/containers/logs/log_analysis/api/ml_setup_module_api.ts index 7c8d63374924c..1f203ef9618b8 100644 --- a/x-pack/plugins/infra/public/containers/logs/log_analysis/api/ml_setup_module_api.ts +++ b/x-pack/plugins/infra/public/containers/logs/log_analysis/api/ml_setup_module_api.ts @@ -4,27 +4,38 @@ * you may not use this file except in compliance with the Elastic License. */ -import { fold } from 'fp-ts/lib/Either'; -import { identity } from 'fp-ts/lib/function'; -import { pipe } from 'fp-ts/lib/pipeable'; import * as rt from 'io-ts'; -import { npStart } from '../../../../legacy_singletons'; +import type { HttpHandler } from 'src/core/public'; import { getJobIdPrefix, jobCustomSettingsRT } from '../../../../../common/log_analysis'; -import { createPlainError, throwErrors } from '../../../../../common/runtime_types'; - -export const callSetupMlModuleAPI = async ( - moduleId: string, - start: number | undefined, - end: number | undefined, - spaceId: string, - sourceId: string, - indexPattern: string, - jobOverrides: SetupMlModuleJobOverrides[] = [], - datafeedOverrides: SetupMlModuleDatafeedOverrides[] = [], - query?: object -) => { - const response = await npStart.http.fetch(`/api/ml/modules/setup/${moduleId}`, { +import { decodeOrThrow } from '../../../../../common/runtime_types'; + +interface RequestArgs { + moduleId: string; + start?: number; + end?: number; + spaceId: string; + sourceId: string; + indexPattern: string; + jobOverrides?: SetupMlModuleJobOverrides[]; + datafeedOverrides?: SetupMlModuleDatafeedOverrides[]; + query?: object; +} + +export const callSetupMlModuleAPI = async (requestArgs: RequestArgs, fetch: HttpHandler) => { + const { + moduleId, + start, + end, + spaceId, + sourceId, + indexPattern, + jobOverrides = [], + datafeedOverrides = [], + query, + } = requestArgs; + + const response = await fetch(`/api/ml/modules/setup/${moduleId}`, { method: 'POST', body: JSON.stringify( setupMlModuleRequestPayloadRT.encode({ @@ -40,10 +51,7 @@ export const callSetupMlModuleAPI = async ( ), }); - return pipe( - setupMlModuleResponsePayloadRT.decode(response), - fold(throwErrors(createPlainError), identity) - ); + return decodeOrThrow(setupMlModuleResponsePayloadRT)(response); }; const setupMlModuleTimeParamsRT = rt.partial({ diff --git a/x-pack/plugins/infra/public/containers/logs/log_analysis/api/validate_datasets.ts b/x-pack/plugins/infra/public/containers/logs/log_analysis/api/validate_datasets.ts index 6c9d5e439d359..ec08d3ac107e5 100644 --- a/x-pack/plugins/infra/public/containers/logs/log_analysis/api/validate_datasets.ts +++ b/x-pack/plugins/infra/public/containers/logs/log_analysis/api/validate_datasets.ts @@ -4,21 +4,24 @@ * you may not use this file except in compliance with the Elastic License. */ +import type { HttpHandler } from 'src/core/public'; import { LOG_ANALYSIS_VALIDATE_DATASETS_PATH, validateLogEntryDatasetsRequestPayloadRT, validateLogEntryDatasetsResponsePayloadRT, } from '../../../../../common/http_api'; import { decodeOrThrow } from '../../../../../common/runtime_types'; -import { npStart } from '../../../../legacy_singletons'; -export const callValidateDatasetsAPI = async ( - indices: string[], - timestampField: string, - startTime: number, - endTime: number -) => { - const response = await npStart.http.fetch(LOG_ANALYSIS_VALIDATE_DATASETS_PATH, { +interface RequestArgs { + indices: string[]; + timestampField: string; + startTime: number; + endTime: number; +} + +export const callValidateDatasetsAPI = async (requestArgs: RequestArgs, fetch: HttpHandler) => { + const { indices, timestampField, startTime, endTime } = requestArgs; + const response = await fetch(LOG_ANALYSIS_VALIDATE_DATASETS_PATH, { method: 'POST', body: JSON.stringify( validateLogEntryDatasetsRequestPayloadRT.encode({ diff --git a/x-pack/plugins/infra/public/containers/logs/log_analysis/api/validate_indices.ts b/x-pack/plugins/infra/public/containers/logs/log_analysis/api/validate_indices.ts index bbef7d201045f..465d09a744b19 100644 --- a/x-pack/plugins/infra/public/containers/logs/log_analysis/api/validate_indices.ts +++ b/x-pack/plugins/infra/public/containers/logs/log_analysis/api/validate_indices.ts @@ -4,10 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -import { fold } from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { identity } from 'fp-ts/lib/function'; -import { npStart } from '../../../../legacy_singletons'; +import type { HttpHandler } from 'src/core/public'; + import { LOG_ANALYSIS_VALIDATE_INDICES_PATH, ValidationIndicesFieldSpecification, @@ -15,19 +13,19 @@ import { validationIndicesResponsePayloadRT, } from '../../../../../common/http_api'; -import { throwErrors, createPlainError } from '../../../../../common/runtime_types'; +import { decodeOrThrow } from '../../../../../common/runtime_types'; + +interface RequestArgs { + indices: string[]; + fields: ValidationIndicesFieldSpecification[]; +} -export const callValidateIndicesAPI = async ( - indices: string[], - fields: ValidationIndicesFieldSpecification[] -) => { - const response = await npStart.http.fetch(LOG_ANALYSIS_VALIDATE_INDICES_PATH, { +export const callValidateIndicesAPI = async (requestArgs: RequestArgs, fetch: HttpHandler) => { + const { indices, fields } = requestArgs; + const response = await fetch(LOG_ANALYSIS_VALIDATE_INDICES_PATH, { method: 'POST', body: JSON.stringify(validationIndicesRequestPayloadRT.encode({ data: { indices, fields } })), }); - return pipe( - validationIndicesResponsePayloadRT.decode(response), - fold(throwErrors(createPlainError), identity) - ); + return decodeOrThrow(validationIndicesResponsePayloadRT)(response); }; diff --git a/x-pack/plugins/infra/public/containers/logs/log_analysis/log_analysis_capabilities.tsx b/x-pack/plugins/infra/public/containers/logs/log_analysis/log_analysis_capabilities.tsx index 9116900ec2196..74b316f78259f 100644 --- a/x-pack/plugins/infra/public/containers/logs/log_analysis/log_analysis_capabilities.tsx +++ b/x-pack/plugins/infra/public/containers/logs/log_analysis/log_analysis_capabilities.tsx @@ -6,18 +6,16 @@ import createContainer from 'constate'; import { useMemo, useState, useEffect } from 'react'; -import { fold } from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { identity } from 'fp-ts/lib/function'; import { useTrackedPromise } from '../../../utils/use_tracked_promise'; -import { npStart } from '../../../legacy_singletons'; import { getMlCapabilitiesResponsePayloadRT, GetMlCapabilitiesResponsePayload, } from './api/ml_api_types'; -import { throwErrors, createPlainError } from '../../../../common/runtime_types'; +import { decodeOrThrow } from '../../../../common/runtime_types'; +import { useKibanaContextForPlugin } from '../../../hooks/use_kibana'; export const useLogAnalysisCapabilities = () => { + const { services } = useKibanaContextForPlugin(); const [mlCapabilities, setMlCapabilities] = useState( initialMlCapabilities ); @@ -26,12 +24,9 @@ export const useLogAnalysisCapabilities = () => { { cancelPreviousOn: 'resolution', createPromise: async () => { - const rawResponse = await npStart.http.fetch('/api/ml/ml_capabilities'); + const rawResponse = await services.http.fetch('/api/ml/ml_capabilities'); - return pipe( - getMlCapabilitiesResponsePayloadRT.decode(rawResponse), - fold(throwErrors(createPlainError), identity) - ); + return decodeOrThrow(getMlCapabilitiesResponsePayloadRT)(rawResponse); }, onResolve: (response) => { setMlCapabilities(response); diff --git a/x-pack/plugins/infra/public/containers/logs/log_analysis/log_analysis_cleanup.tsx b/x-pack/plugins/infra/public/containers/logs/log_analysis/log_analysis_cleanup.tsx index 522616f83d0cb..ec5e879131aa1 100644 --- a/x-pack/plugins/infra/public/containers/logs/log_analysis/log_analysis_cleanup.tsx +++ b/x-pack/plugins/infra/public/containers/logs/log_analysis/log_analysis_cleanup.tsx @@ -3,17 +3,18 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ - +import type { HttpHandler } from 'src/core/public'; import { getJobId } from '../../../../common/log_analysis'; import { callDeleteJobs, callGetJobDeletionTasks, callStopDatafeeds } from './api/ml_cleanup'; export const cleanUpJobsAndDatafeeds = async ( spaceId: string, sourceId: string, - jobTypes: JobType[] + jobTypes: JobType[], + fetch: HttpHandler ) => { try { - await callStopDatafeeds(spaceId, sourceId, jobTypes); + await callStopDatafeeds({ spaceId, sourceId, jobTypes }, fetch); } catch (err) { // Proceed only if datafeed has been deleted or didn't exist in the first place if (err?.res?.status !== 404) { @@ -21,27 +22,29 @@ export const cleanUpJobsAndDatafeeds = async ( } } - return await deleteJobs(spaceId, sourceId, jobTypes); + return await deleteJobs(spaceId, sourceId, jobTypes, fetch); }; const deleteJobs = async ( spaceId: string, sourceId: string, - jobTypes: JobType[] + jobTypes: JobType[], + fetch: HttpHandler ) => { - const deleteJobsResponse = await callDeleteJobs(spaceId, sourceId, jobTypes); - await waitUntilJobsAreDeleted(spaceId, sourceId, jobTypes); + const deleteJobsResponse = await callDeleteJobs({ spaceId, sourceId, jobTypes }, fetch); + await waitUntilJobsAreDeleted(spaceId, sourceId, jobTypes, fetch); return deleteJobsResponse; }; const waitUntilJobsAreDeleted = async ( spaceId: string, sourceId: string, - jobTypes: JobType[] + jobTypes: JobType[], + fetch: HttpHandler ) => { const moduleJobIds = jobTypes.map((jobType) => getJobId(spaceId, sourceId, jobType)); while (true) { - const { jobIds: jobIdsBeingDeleted } = await callGetJobDeletionTasks(); + const { jobIds: jobIdsBeingDeleted } = await callGetJobDeletionTasks(fetch); const needToWait = jobIdsBeingDeleted.some((jobId) => moduleJobIds.includes(jobId)); if (needToWait) { diff --git a/x-pack/plugins/infra/public/containers/logs/log_analysis/log_analysis_module.tsx b/x-pack/plugins/infra/public/containers/logs/log_analysis/log_analysis_module.tsx index 79768302a7310..27ef0039ae49f 100644 --- a/x-pack/plugins/infra/public/containers/logs/log_analysis/log_analysis_module.tsx +++ b/x-pack/plugins/infra/public/containers/logs/log_analysis/log_analysis_module.tsx @@ -6,6 +6,7 @@ import { useCallback, useMemo } from 'react'; import { DatasetFilter } from '../../../../common/log_analysis'; +import { useKibanaContextForPlugin } from '../../../hooks/use_kibana'; import { useTrackedPromise } from '../../../utils/use_tracked_promise'; import { useModuleStatus } from './log_analysis_module_status'; import { ModuleDescriptor, ModuleSourceConfiguration } from './log_analysis_module_types'; @@ -17,6 +18,7 @@ export const useLogAnalysisModule = ({ sourceConfiguration: ModuleSourceConfiguration; moduleDescriptor: ModuleDescriptor; }) => { + const { services } = useKibanaContextForPlugin(); const { spaceId, sourceId, timestampField } = sourceConfiguration; const [moduleStatus, dispatchModuleStatus] = useModuleStatus(moduleDescriptor.jobTypes); @@ -25,7 +27,7 @@ export const useLogAnalysisModule = ({ cancelPreviousOn: 'resolution', createPromise: async () => { dispatchModuleStatus({ type: 'fetchingJobStatuses' }); - return await moduleDescriptor.getJobSummary(spaceId, sourceId); + return await moduleDescriptor.getJobSummary(spaceId, sourceId, services.http.fetch); }, onResolve: (jobResponse) => { dispatchModuleStatus({ @@ -52,13 +54,23 @@ export const useLogAnalysisModule = ({ datasetFilter: DatasetFilter ) => { dispatchModuleStatus({ type: 'startedSetup' }); - const setupResult = await moduleDescriptor.setUpModule(start, end, datasetFilter, { - indices: selectedIndices, - sourceId, + const setupResult = await moduleDescriptor.setUpModule( + start, + end, + datasetFilter, + { + indices: selectedIndices, + sourceId, + spaceId, + timestampField, + }, + services.http.fetch + ); + const jobSummaries = await moduleDescriptor.getJobSummary( spaceId, - timestampField, - }); - const jobSummaries = await moduleDescriptor.getJobSummary(spaceId, sourceId); + sourceId, + services.http.fetch + ); return { setupResult, jobSummaries }; }, onResolve: ({ setupResult: { datafeeds, jobs }, jobSummaries }) => { @@ -82,7 +94,7 @@ export const useLogAnalysisModule = ({ { cancelPreviousOn: 'resolution', createPromise: async () => { - return await moduleDescriptor.cleanUpModule(spaceId, sourceId); + return await moduleDescriptor.cleanUpModule(spaceId, sourceId, services.http.fetch); }, }, [spaceId, sourceId] diff --git a/x-pack/plugins/infra/public/containers/logs/log_analysis/log_analysis_module_definition.tsx b/x-pack/plugins/infra/public/containers/logs/log_analysis/log_analysis_module_definition.tsx index 1f643d0e5eb34..7a5c1d354dc34 100644 --- a/x-pack/plugins/infra/public/containers/logs/log_analysis/log_analysis_module_definition.tsx +++ b/x-pack/plugins/infra/public/containers/logs/log_analysis/log_analysis_module_definition.tsx @@ -6,6 +6,7 @@ import { useCallback, useMemo, useState } from 'react'; import { getJobId } from '../../../../common/log_analysis'; +import { useKibanaContextForPlugin } from '../../../hooks/use_kibana'; import { useTrackedPromise } from '../../../utils/use_tracked_promise'; import { JobSummary } from './api/ml_get_jobs_summary_api'; import { GetMlModuleResponsePayload, JobDefinition } from './api/ml_get_module'; @@ -18,6 +19,7 @@ export const useLogAnalysisModuleDefinition = ({ sourceConfiguration: ModuleSourceConfiguration; moduleDescriptor: ModuleDescriptor; }) => { + const { services } = useKibanaContextForPlugin(); const [moduleDefinition, setModuleDefinition] = useState< GetMlModuleResponsePayload | undefined >(); @@ -40,7 +42,7 @@ export const useLogAnalysisModuleDefinition = ({ { cancelPreviousOn: 'resolution', createPromise: async () => { - return await moduleDescriptor.getModuleDefinition(); + return await moduleDescriptor.getModuleDefinition(services.http.fetch); }, onResolve: (response) => { setModuleDefinition(response); diff --git a/x-pack/plugins/infra/public/containers/logs/log_analysis/log_analysis_module_types.ts b/x-pack/plugins/infra/public/containers/logs/log_analysis/log_analysis_module_types.ts index ba355ad195b11..c42704860b032 100644 --- a/x-pack/plugins/infra/public/containers/logs/log_analysis/log_analysis_module_types.ts +++ b/x-pack/plugins/infra/public/containers/logs/log_analysis/log_analysis_module_types.ts @@ -4,6 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ +import type { HttpHandler } from 'src/core/public'; import { ValidateLogEntryDatasetsResponsePayload, ValidationIndicesResponsePayload, @@ -23,24 +24,35 @@ export interface ModuleDescriptor { jobTypes: JobType[]; bucketSpan: number; getJobIds: (spaceId: string, sourceId: string) => Record; - getJobSummary: (spaceId: string, sourceId: string) => Promise; - getModuleDefinition: () => Promise; + getJobSummary: ( + spaceId: string, + sourceId: string, + fetch: HttpHandler + ) => Promise; + getModuleDefinition: (fetch: HttpHandler) => Promise; setUpModule: ( start: number | undefined, end: number | undefined, datasetFilter: DatasetFilter, - sourceConfiguration: ModuleSourceConfiguration + sourceConfiguration: ModuleSourceConfiguration, + fetch: HttpHandler ) => Promise; - cleanUpModule: (spaceId: string, sourceId: string) => Promise; + cleanUpModule: ( + spaceId: string, + sourceId: string, + fetch: HttpHandler + ) => Promise; validateSetupIndices: ( indices: string[], - timestampField: string + timestampField: string, + fetch: HttpHandler ) => Promise; validateSetupDatasets: ( indices: string[], timestampField: string, startTime: number, - endTime: number + endTime: number, + fetch: HttpHandler ) => Promise; } diff --git a/x-pack/plugins/infra/public/containers/logs/log_analysis/log_analysis_setup_state.ts b/x-pack/plugins/infra/public/containers/logs/log_analysis/log_analysis_setup_state.ts index e6fe8f4e92cc4..750a7104a3a98 100644 --- a/x-pack/plugins/infra/public/containers/logs/log_analysis/log_analysis_setup_state.ts +++ b/x-pack/plugins/infra/public/containers/logs/log_analysis/log_analysis_setup_state.ts @@ -18,6 +18,7 @@ import { ValidationIndicesError, ValidationUIError, } from '../../../components/logging/log_analysis_setup/initial_configuration_step'; +import { useKibanaContextForPlugin } from '../../../hooks/use_kibana'; import { useTrackedPromise } from '../../../utils/use_tracked_promise'; import { ModuleDescriptor, ModuleSourceConfiguration } from './log_analysis_module_types'; @@ -43,6 +44,7 @@ export const useAnalysisSetupState = ({ setUpModule, sourceConfiguration, }: AnalysisSetupStateArguments) => { + const { services } = useKibanaContextForPlugin(); const [startTime, setStartTime] = useState(Date.now() - fourWeeksInMs); const [endTime, setEndTime] = useState(undefined); @@ -158,7 +160,8 @@ export const useAnalysisSetupState = ({ createPromise: async () => { return await validateSetupIndices( sourceConfiguration.indices, - sourceConfiguration.timestampField + sourceConfiguration.timestampField, + services.http.fetch ); }, onResolve: ({ data: { errors } }) => { @@ -183,7 +186,8 @@ export const useAnalysisSetupState = ({ validIndexNames, sourceConfiguration.timestampField, startTime ?? 0, - endTime ?? Date.now() + endTime ?? Date.now(), + services.http.fetch ); }, onResolve: ({ data: { datasets } }) => { diff --git a/x-pack/plugins/infra/public/containers/logs/log_analysis/modules/log_entry_categories/module_descriptor.ts b/x-pack/plugins/infra/public/containers/logs/log_analysis/modules/log_entry_categories/module_descriptor.ts index 9682b3e74db3b..46b28e091cc5c 100644 --- a/x-pack/plugins/infra/public/containers/logs/log_analysis/modules/log_entry_categories/module_descriptor.ts +++ b/x-pack/plugins/infra/public/containers/logs/log_analysis/modules/log_entry_categories/module_descriptor.ts @@ -5,6 +5,7 @@ */ import { i18n } from '@kbn/i18n'; +import type { HttpHandler } from 'src/core/public'; import { bucketSpan, categoriesMessageField, @@ -42,22 +43,26 @@ const getJobIds = (spaceId: string, sourceId: string) => {} as Record ); -const getJobSummary = async (spaceId: string, sourceId: string) => { - const response = await callJobsSummaryAPI(spaceId, sourceId, logEntryCategoriesJobTypes); +const getJobSummary = async (spaceId: string, sourceId: string, fetch: HttpHandler) => { + const response = await callJobsSummaryAPI( + { spaceId, sourceId, jobTypes: logEntryCategoriesJobTypes }, + fetch + ); const jobIds = Object.values(getJobIds(spaceId, sourceId)); return response.filter((jobSummary) => jobIds.includes(jobSummary.id)); }; -const getModuleDefinition = async () => { - return await callGetMlModuleAPI(moduleId); +const getModuleDefinition = async (fetch: HttpHandler) => { + return await callGetMlModuleAPI(moduleId, fetch); }; const setUpModule = async ( start: number | undefined, end: number | undefined, datasetFilter: DatasetFilter, - { spaceId, sourceId, indices, timestampField }: ModuleSourceConfiguration + { spaceId, sourceId, indices, timestampField }: ModuleSourceConfiguration, + fetch: HttpHandler ) => { const indexNamePattern = indices.join(','); const jobOverrides = [ @@ -101,46 +106,59 @@ const setUpModule = async ( }; return callSetupMlModuleAPI( - moduleId, - start, - end, - spaceId, - sourceId, - indexNamePattern, - jobOverrides, - [], - query + { + moduleId, + start, + end, + spaceId, + sourceId, + indexPattern: indexNamePattern, + jobOverrides, + query, + }, + fetch ); }; -const cleanUpModule = async (spaceId: string, sourceId: string) => { - return await cleanUpJobsAndDatafeeds(spaceId, sourceId, logEntryCategoriesJobTypes); +const cleanUpModule = async (spaceId: string, sourceId: string, fetch: HttpHandler) => { + return await cleanUpJobsAndDatafeeds(spaceId, sourceId, logEntryCategoriesJobTypes, fetch); }; -const validateSetupIndices = async (indices: string[], timestampField: string) => { - return await callValidateIndicesAPI(indices, [ - { - name: timestampField, - validTypes: ['date'], - }, - { - name: partitionField, - validTypes: ['keyword'], - }, +const validateSetupIndices = async ( + indices: string[], + timestampField: string, + fetch: HttpHandler +) => { + return await callValidateIndicesAPI( { - name: categoriesMessageField, - validTypes: ['text'], + indices, + fields: [ + { + name: timestampField, + validTypes: ['date'], + }, + { + name: partitionField, + validTypes: ['keyword'], + }, + { + name: categoriesMessageField, + validTypes: ['text'], + }, + ], }, - ]); + fetch + ); }; const validateSetupDatasets = async ( indices: string[], timestampField: string, startTime: number, - endTime: number + endTime: number, + fetch: HttpHandler ) => { - return await callValidateDatasetsAPI(indices, timestampField, startTime, endTime); + return await callValidateDatasetsAPI({ indices, timestampField, startTime, endTime }, fetch); }; export const logEntryCategoriesModule: ModuleDescriptor = { diff --git a/x-pack/plugins/infra/public/containers/logs/log_analysis/modules/log_entry_rate/module_descriptor.ts b/x-pack/plugins/infra/public/containers/logs/log_analysis/modules/log_entry_rate/module_descriptor.ts index 001174a2b7558..b97ec55105f5d 100644 --- a/x-pack/plugins/infra/public/containers/logs/log_analysis/modules/log_entry_rate/module_descriptor.ts +++ b/x-pack/plugins/infra/public/containers/logs/log_analysis/modules/log_entry_rate/module_descriptor.ts @@ -5,6 +5,7 @@ */ import { i18n } from '@kbn/i18n'; +import type { HttpHandler } from 'src/core/public'; import { bucketSpan, DatasetFilter, @@ -41,22 +42,26 @@ const getJobIds = (spaceId: string, sourceId: string) => {} as Record ); -const getJobSummary = async (spaceId: string, sourceId: string) => { - const response = await callJobsSummaryAPI(spaceId, sourceId, logEntryRateJobTypes); +const getJobSummary = async (spaceId: string, sourceId: string, fetch: HttpHandler) => { + const response = await callJobsSummaryAPI( + { spaceId, sourceId, jobTypes: logEntryRateJobTypes }, + fetch + ); const jobIds = Object.values(getJobIds(spaceId, sourceId)); return response.filter((jobSummary) => jobIds.includes(jobSummary.id)); }; -const getModuleDefinition = async () => { - return await callGetMlModuleAPI(moduleId); +const getModuleDefinition = async (fetch: HttpHandler) => { + return await callGetMlModuleAPI(moduleId, fetch); }; const setUpModule = async ( start: number | undefined, end: number | undefined, datasetFilter: DatasetFilter, - { spaceId, sourceId, indices, timestampField }: ModuleSourceConfiguration + { spaceId, sourceId, indices, timestampField }: ModuleSourceConfiguration, + fetch: HttpHandler ) => { const indexNamePattern = indices.join(','); const jobOverrides = [ @@ -93,42 +98,55 @@ const setUpModule = async ( : undefined; return callSetupMlModuleAPI( - moduleId, - start, - end, - spaceId, - sourceId, - indexNamePattern, - jobOverrides, - [], - query + { + moduleId, + start, + end, + spaceId, + sourceId, + indexPattern: indexNamePattern, + jobOverrides, + query, + }, + fetch ); }; -const cleanUpModule = async (spaceId: string, sourceId: string) => { - return await cleanUpJobsAndDatafeeds(spaceId, sourceId, logEntryRateJobTypes); +const cleanUpModule = async (spaceId: string, sourceId: string, fetch: HttpHandler) => { + return await cleanUpJobsAndDatafeeds(spaceId, sourceId, logEntryRateJobTypes, fetch); }; -const validateSetupIndices = async (indices: string[], timestampField: string) => { - return await callValidateIndicesAPI(indices, [ - { - name: timestampField, - validTypes: ['date'], - }, +const validateSetupIndices = async ( + indices: string[], + timestampField: string, + fetch: HttpHandler +) => { + return await callValidateIndicesAPI( { - name: partitionField, - validTypes: ['keyword'], + indices, + fields: [ + { + name: timestampField, + validTypes: ['date'], + }, + { + name: partitionField, + validTypes: ['keyword'], + }, + ], }, - ]); + fetch + ); }; const validateSetupDatasets = async ( indices: string[], timestampField: string, startTime: number, - endTime: number + endTime: number, + fetch: HttpHandler ) => { - return await callValidateDatasetsAPI(indices, timestampField, startTime, endTime); + return await callValidateDatasetsAPI({ indices, timestampField, startTime, endTime }, fetch); }; export const logEntryRateModule: ModuleDescriptor = { diff --git a/x-pack/plugins/infra/public/containers/logs/log_entries/api/fetch_log_entries.ts b/x-pack/plugins/infra/public/containers/logs/log_entries/api/fetch_log_entries.ts index 2a19a82892427..3bbd86cb0ef75 100644 --- a/x-pack/plugins/infra/public/containers/logs/log_entries/api/fetch_log_entries.ts +++ b/x-pack/plugins/infra/public/containers/logs/log_entries/api/fetch_log_entries.ts @@ -4,12 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import { fold } from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { identity } from 'fp-ts/lib/function'; -import { npStart } from '../../../../legacy_singletons'; +import type { HttpHandler } from 'src/core/public'; -import { throwErrors, createPlainError } from '../../../../../common/runtime_types'; +import { decodeOrThrow } from '../../../../../common/runtime_types'; import { LOG_ENTRIES_PATH, @@ -18,11 +15,11 @@ import { logEntriesResponseRT, } from '../../../../../common/http_api'; -export const fetchLogEntries = async (requestArgs: LogEntriesRequest) => { - const response = await npStart.http.fetch(LOG_ENTRIES_PATH, { +export const fetchLogEntries = async (requestArgs: LogEntriesRequest, fetch: HttpHandler) => { + const response = await fetch(LOG_ENTRIES_PATH, { method: 'POST', body: JSON.stringify(logEntriesRequestRT.encode(requestArgs)), }); - return pipe(logEntriesResponseRT.decode(response), fold(throwErrors(createPlainError), identity)); + return decodeOrThrow(logEntriesResponseRT)(response); }; diff --git a/x-pack/plugins/infra/public/containers/logs/log_entries/api/fetch_log_entries_item.ts b/x-pack/plugins/infra/public/containers/logs/log_entries/api/fetch_log_entries_item.ts index 5fde01e458e36..d459fba6cf957 100644 --- a/x-pack/plugins/infra/public/containers/logs/log_entries/api/fetch_log_entries_item.ts +++ b/x-pack/plugins/infra/public/containers/logs/log_entries/api/fetch_log_entries_item.ts @@ -4,12 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import { fold } from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { identity } from 'fp-ts/lib/function'; -import { npStart } from '../../../../legacy_singletons'; +import type { HttpHandler } from 'src/core/public'; -import { throwErrors, createPlainError } from '../../../../../common/runtime_types'; +import { decodeOrThrow } from '../../../../../common/runtime_types'; import { LOG_ENTRIES_ITEM_PATH, @@ -18,14 +15,14 @@ import { logEntriesItemResponseRT, } from '../../../../../common/http_api'; -export const fetchLogEntriesItem = async (requestArgs: LogEntriesItemRequest) => { - const response = await npStart.http.fetch(LOG_ENTRIES_ITEM_PATH, { +export const fetchLogEntriesItem = async ( + requestArgs: LogEntriesItemRequest, + fetch: HttpHandler +) => { + const response = await fetch(LOG_ENTRIES_ITEM_PATH, { method: 'POST', body: JSON.stringify(logEntriesItemRequestRT.encode(requestArgs)), }); - return pipe( - logEntriesItemResponseRT.decode(response), - fold(throwErrors(createPlainError), identity) - ); + return decodeOrThrow(logEntriesItemResponseRT)(response); }; diff --git a/x-pack/plugins/infra/public/containers/logs/log_entries/index.ts b/x-pack/plugins/infra/public/containers/logs/log_entries/index.ts index d5b2a0aaa61c0..4c8c610794b2e 100644 --- a/x-pack/plugins/infra/public/containers/logs/log_entries/index.ts +++ b/x-pack/plugins/infra/public/containers/logs/log_entries/index.ts @@ -14,6 +14,7 @@ import { LogEntriesBaseRequest, } from '../../../../common/http_api'; import { fetchLogEntries } from './api/fetch_log_entries'; +import { useKibanaContextForPlugin } from '../../../hooks/use_kibana'; const DESIRED_BUFFER_PAGES = 2; const LIVE_STREAM_INTERVAL = 5000; @@ -144,6 +145,7 @@ const useFetchEntriesEffect = ( dispatch: Dispatch, props: LogEntriesProps ) => { + const { services } = useKibanaContextForPlugin(); const [prevParams, cachePrevParams] = useState(); const [startedStreaming, setStartedStreaming] = useState(false); @@ -172,7 +174,7 @@ const useFetchEntriesEffect = ( before: 'last', }; - const { data: payload } = await fetchLogEntries(fetchArgs); + const { data: payload } = await fetchLogEntries(fetchArgs, services.http.fetch); dispatch({ type: Action.ReceiveNewEntries, payload }); // Move position to the bottom if it's the first load. @@ -228,7 +230,7 @@ const useFetchEntriesEffect = ( after: state.bottomCursor, }; - const { data: payload } = await fetchLogEntries(fetchArgs); + const { data: payload } = await fetchLogEntries(fetchArgs, services.http.fetch); dispatch({ type: getEntriesBefore ? Action.ReceiveEntriesBefore : Action.ReceiveEntriesAfter, diff --git a/x-pack/plugins/infra/public/containers/logs/log_flyout.tsx b/x-pack/plugins/infra/public/containers/logs/log_flyout.tsx index 0489892e58f2a..9ed2f5ad175c7 100644 --- a/x-pack/plugins/infra/public/containers/logs/log_flyout.tsx +++ b/x-pack/plugins/infra/public/containers/logs/log_flyout.tsx @@ -9,6 +9,7 @@ import { isString } from 'lodash'; import React, { useContext, useEffect, useMemo, useState } from 'react'; import { LogEntriesItem } from '../../../common/http_api'; +import { useKibanaContextForPlugin } from '../../hooks/use_kibana'; import { UrlStateContainer } from '../../utils/url_state'; import { useTrackedPromise } from '../../utils/use_tracked_promise'; import { fetchLogEntriesItem } from './log_entries/api/fetch_log_entries_item'; @@ -26,6 +27,7 @@ export interface FlyoutOptionsUrlState { } export const useLogFlyout = () => { + const { services } = useKibanaContextForPlugin(); const { sourceId } = useLogSourceContext(); const [flyoutVisible, setFlyoutVisibility] = useState(false); const [flyoutId, setFlyoutId] = useState(null); @@ -39,7 +41,7 @@ export const useLogFlyout = () => { if (!flyoutId) { return; } - return await fetchLogEntriesItem({ sourceId, id: flyoutId }); + return await fetchLogEntriesItem({ sourceId, id: flyoutId }, services.http.fetch); }, onResolve: (response) => { if (response) { diff --git a/x-pack/plugins/infra/public/containers/logs/log_highlights/api/fetch_log_entries_highlights.ts b/x-pack/plugins/infra/public/containers/logs/log_highlights/api/fetch_log_entries_highlights.ts index 030a9d180c7b5..25865a30467f5 100644 --- a/x-pack/plugins/infra/public/containers/logs/log_highlights/api/fetch_log_entries_highlights.ts +++ b/x-pack/plugins/infra/public/containers/logs/log_highlights/api/fetch_log_entries_highlights.ts @@ -4,12 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import { fold } from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { identity } from 'fp-ts/lib/function'; -import { npStart } from '../../../../legacy_singletons'; +import type { HttpHandler } from 'src/core/public'; -import { throwErrors, createPlainError } from '../../../../../common/runtime_types'; +import { decodeOrThrow } from '../../../../../common/runtime_types'; import { LOG_ENTRIES_HIGHLIGHTS_PATH, @@ -18,14 +15,14 @@ import { logEntriesHighlightsResponseRT, } from '../../../../../common/http_api'; -export const fetchLogEntriesHighlights = async (requestArgs: LogEntriesHighlightsRequest) => { - const response = await npStart.http.fetch(LOG_ENTRIES_HIGHLIGHTS_PATH, { +export const fetchLogEntriesHighlights = async ( + requestArgs: LogEntriesHighlightsRequest, + fetch: HttpHandler +) => { + const response = await fetch(LOG_ENTRIES_HIGHLIGHTS_PATH, { method: 'POST', body: JSON.stringify(logEntriesHighlightsRequestRT.encode(requestArgs)), }); - return pipe( - logEntriesHighlightsResponseRT.decode(response), - fold(throwErrors(createPlainError), identity) - ); + return decodeOrThrow(logEntriesHighlightsResponseRT)(response); }; diff --git a/x-pack/plugins/infra/public/containers/logs/log_highlights/api/fetch_log_summary_highlights.ts b/x-pack/plugins/infra/public/containers/logs/log_highlights/api/fetch_log_summary_highlights.ts index bda8f535549c7..1cf95bc08a521 100644 --- a/x-pack/plugins/infra/public/containers/logs/log_highlights/api/fetch_log_summary_highlights.ts +++ b/x-pack/plugins/infra/public/containers/logs/log_highlights/api/fetch_log_summary_highlights.ts @@ -3,11 +3,9 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import { fold } from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { identity } from 'fp-ts/lib/function'; -import { npStart } from '../../../../legacy_singletons'; -import { throwErrors, createPlainError } from '../../../../../common/runtime_types'; + +import type { HttpHandler } from 'src/core/public'; +import { decodeOrThrow } from '../../../../../common/runtime_types'; import { LOG_ENTRIES_SUMMARY_HIGHLIGHTS_PATH, @@ -17,15 +15,13 @@ import { } from '../../../../../common/http_api'; export const fetchLogSummaryHighlights = async ( - requestArgs: LogEntriesSummaryHighlightsRequest + requestArgs: LogEntriesSummaryHighlightsRequest, + fetch: HttpHandler ) => { - const response = await npStart.http.fetch(LOG_ENTRIES_SUMMARY_HIGHLIGHTS_PATH, { + const response = await fetch(LOG_ENTRIES_SUMMARY_HIGHLIGHTS_PATH, { method: 'POST', body: JSON.stringify(logEntriesSummaryHighlightsRequestRT.encode(requestArgs)), }); - return pipe( - logEntriesSummaryHighlightsResponseRT.decode(response), - fold(throwErrors(createPlainError), identity) - ); + return decodeOrThrow(logEntriesSummaryHighlightsResponseRT)(response); }; diff --git a/x-pack/plugins/infra/public/containers/logs/log_highlights/log_entry_highlights.tsx b/x-pack/plugins/infra/public/containers/logs/log_highlights/log_entry_highlights.tsx index dbeb8c71c11eb..b4edebe8f8207 100644 --- a/x-pack/plugins/infra/public/containers/logs/log_highlights/log_entry_highlights.tsx +++ b/x-pack/plugins/infra/public/containers/logs/log_highlights/log_entry_highlights.tsx @@ -10,6 +10,7 @@ import { TimeKey } from '../../../../common/time'; import { useTrackedPromise } from '../../../utils/use_tracked_promise'; import { fetchLogEntriesHighlights } from './api/fetch_log_entries_highlights'; import { LogEntry, LogEntriesHighlightsResponse } from '../../../../common/http_api'; +import { useKibanaContextForPlugin } from '../../../hooks/use_kibana'; export const useLogEntryHighlights = ( sourceId: string, @@ -21,6 +22,7 @@ export const useLogEntryHighlights = ( filterQuery: string | null, highlightTerms: string[] ) => { + const { services } = useKibanaContextForPlugin(); const [logEntryHighlights, setLogEntryHighlights] = useState< LogEntriesHighlightsResponse['data'] >([]); @@ -32,15 +34,18 @@ export const useLogEntryHighlights = ( throw new Error('Skipping request: Insufficient parameters'); } - return await fetchLogEntriesHighlights({ - sourceId, - startTimestamp, - endTimestamp, - center: centerPoint, - size, - query: filterQuery || undefined, - highlightTerms, - }); + return await fetchLogEntriesHighlights( + { + sourceId, + startTimestamp, + endTimestamp, + center: centerPoint, + size, + query: filterQuery || undefined, + highlightTerms, + }, + services.http.fetch + ); }, onResolve: (response) => { setLogEntryHighlights(response.data); diff --git a/x-pack/plugins/infra/public/containers/logs/log_highlights/log_summary_highlights.ts b/x-pack/plugins/infra/public/containers/logs/log_highlights/log_summary_highlights.ts index 6d982ee004ccc..14366891dbf59 100644 --- a/x-pack/plugins/infra/public/containers/logs/log_highlights/log_summary_highlights.ts +++ b/x-pack/plugins/infra/public/containers/logs/log_highlights/log_summary_highlights.ts @@ -11,6 +11,7 @@ import { useTrackedPromise } from '../../../utils/use_tracked_promise'; import { fetchLogSummaryHighlights } from './api/fetch_log_summary_highlights'; import { LogEntriesSummaryHighlightsResponse } from '../../../../common/http_api'; import { useBucketSize } from '../log_summary/bucket_size'; +import { useKibanaContextForPlugin } from '../../../hooks/use_kibana'; export const useLogSummaryHighlights = ( sourceId: string, @@ -20,6 +21,7 @@ export const useLogSummaryHighlights = ( filterQuery: string | null, highlightTerms: string[] ) => { + const { services } = useKibanaContextForPlugin(); const [logSummaryHighlights, setLogSummaryHighlights] = useState< LogEntriesSummaryHighlightsResponse['data'] >([]); @@ -34,14 +36,17 @@ export const useLogSummaryHighlights = ( throw new Error('Skipping request: Insufficient parameters'); } - return await fetchLogSummaryHighlights({ - sourceId, - startTimestamp, - endTimestamp, - bucketSize, - query: filterQuery, - highlightTerms, - }); + return await fetchLogSummaryHighlights( + { + sourceId, + startTimestamp, + endTimestamp, + bucketSize, + query: filterQuery, + highlightTerms, + }, + services.http.fetch + ); }, onResolve: (response) => { setLogSummaryHighlights(response.data); diff --git a/x-pack/plugins/infra/public/containers/logs/log_source/api/fetch_log_source_configuration.ts b/x-pack/plugins/infra/public/containers/logs/log_source/api/fetch_log_source_configuration.ts index e847302a6d367..c9ced069473a3 100644 --- a/x-pack/plugins/infra/public/containers/logs/log_source/api/fetch_log_source_configuration.ts +++ b/x-pack/plugins/infra/public/containers/logs/log_source/api/fetch_log_source_configuration.ts @@ -4,17 +4,14 @@ * you may not use this file except in compliance with the Elastic License. */ -import { HttpSetup } from 'src/core/public'; +import type { HttpHandler } from 'src/core/public'; import { getLogSourceConfigurationPath, getLogSourceConfigurationSuccessResponsePayloadRT, } from '../../../../../common/http_api/log_sources'; import { decodeOrThrow } from '../../../../../common/runtime_types'; -export const callFetchLogSourceConfigurationAPI = async ( - sourceId: string, - fetch: HttpSetup['fetch'] -) => { +export const callFetchLogSourceConfigurationAPI = async (sourceId: string, fetch: HttpHandler) => { const response = await fetch(getLogSourceConfigurationPath(sourceId), { method: 'GET', }); diff --git a/x-pack/plugins/infra/public/containers/logs/log_source/api/fetch_log_source_status.ts b/x-pack/plugins/infra/public/containers/logs/log_source/api/fetch_log_source_status.ts index 20e67a0a59c9f..5bc409115e595 100644 --- a/x-pack/plugins/infra/public/containers/logs/log_source/api/fetch_log_source_status.ts +++ b/x-pack/plugins/infra/public/containers/logs/log_source/api/fetch_log_source_status.ts @@ -4,14 +4,14 @@ * you may not use this file except in compliance with the Elastic License. */ -import { HttpSetup } from 'src/core/public'; +import type { HttpHandler } from 'src/core/public'; import { getLogSourceStatusPath, getLogSourceStatusSuccessResponsePayloadRT, } from '../../../../../common/http_api/log_sources'; import { decodeOrThrow } from '../../../../../common/runtime_types'; -export const callFetchLogSourceStatusAPI = async (sourceId: string, fetch: HttpSetup['fetch']) => { +export const callFetchLogSourceStatusAPI = async (sourceId: string, fetch: HttpHandler) => { const response = await fetch(getLogSourceStatusPath(sourceId), { method: 'GET', }); diff --git a/x-pack/plugins/infra/public/containers/logs/log_source/api/patch_log_source_configuration.ts b/x-pack/plugins/infra/public/containers/logs/log_source/api/patch_log_source_configuration.ts index 4361e4bef827f..33212c5d3b0f2 100644 --- a/x-pack/plugins/infra/public/containers/logs/log_source/api/patch_log_source_configuration.ts +++ b/x-pack/plugins/infra/public/containers/logs/log_source/api/patch_log_source_configuration.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { HttpSetup } from 'src/core/public'; +import type { HttpHandler } from 'src/core/public'; import { getLogSourceConfigurationPath, patchLogSourceConfigurationSuccessResponsePayloadRT, @@ -16,7 +16,7 @@ import { decodeOrThrow } from '../../../../../common/runtime_types'; export const callPatchLogSourceConfigurationAPI = async ( sourceId: string, patchedProperties: LogSourceConfigurationPropertiesPatch, - fetch: HttpSetup['fetch'] + fetch: HttpHandler ) => { const response = await fetch(getLogSourceConfigurationPath(sourceId), { method: 'PATCH', diff --git a/x-pack/plugins/infra/public/containers/logs/log_source/log_source.ts b/x-pack/plugins/infra/public/containers/logs/log_source/log_source.ts index 51b32a4c4eacf..e2dd4c523c03f 100644 --- a/x-pack/plugins/infra/public/containers/logs/log_source/log_source.ts +++ b/x-pack/plugins/infra/public/containers/logs/log_source/log_source.ts @@ -7,7 +7,7 @@ import createContainer from 'constate'; import { useCallback, useMemo, useState } from 'react'; import { useMountedState } from 'react-use'; -import { HttpSetup } from 'src/core/public'; +import type { HttpHandler } from 'src/core/public'; import { LogSourceConfiguration, LogSourceConfigurationProperties, @@ -26,13 +26,7 @@ export { LogSourceStatus, }; -export const useLogSource = ({ - sourceId, - fetch, -}: { - sourceId: string; - fetch: HttpSetup['fetch']; -}) => { +export const useLogSource = ({ sourceId, fetch }: { sourceId: string; fetch: HttpHandler }) => { const getIsMounted = useMountedState(); const [sourceConfiguration, setSourceConfiguration] = useState< LogSourceConfiguration | undefined diff --git a/x-pack/plugins/infra/public/containers/logs/log_stream/index.ts b/x-pack/plugins/infra/public/containers/logs/log_stream/index.ts index b414408512db2..4a6da6063e960 100644 --- a/x-pack/plugins/infra/public/containers/logs/log_stream/index.ts +++ b/x-pack/plugins/infra/public/containers/logs/log_stream/index.ts @@ -9,6 +9,7 @@ import { esKuery } from '../../../../../../../src/plugins/data/public'; import { fetchLogEntries } from '../log_entries/api/fetch_log_entries'; import { useTrackedPromise } from '../../../utils/use_tracked_promise'; import { LogEntry, LogEntriesCursor } from '../../../../common/http_api'; +import { useKibanaContextForPlugin } from '../../../hooks/use_kibana'; interface LogStreamProps { sourceId: string; @@ -31,6 +32,7 @@ export function useLogStream({ query, center, }: LogStreamProps): LogStreamState { + const { services } = useKibanaContextForPlugin(); const [entries, setEntries] = useState([]); const parsedQuery = useMemo(() => { @@ -47,13 +49,16 @@ export function useLogStream({ setEntries([]); const fetchPosition = center ? { center } : { before: 'last' }; - return fetchLogEntries({ - sourceId, - startTimestamp, - endTimestamp, - query: parsedQuery, - ...fetchPosition, - }); + return fetchLogEntries( + { + sourceId, + startTimestamp, + endTimestamp, + query: parsedQuery, + ...fetchPosition, + }, + services.http.fetch + ); }, onResolve: ({ data }) => { setEntries(data.entries); diff --git a/x-pack/plugins/infra/public/containers/logs/log_summary/api/fetch_log_summary.ts b/x-pack/plugins/infra/public/containers/logs/log_summary/api/fetch_log_summary.ts index f74f0dc0e3117..2be6538e21ebe 100644 --- a/x-pack/plugins/infra/public/containers/logs/log_summary/api/fetch_log_summary.ts +++ b/x-pack/plugins/infra/public/containers/logs/log_summary/api/fetch_log_summary.ts @@ -4,11 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -import { fold } from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { identity } from 'fp-ts/lib/function'; -import { npStart } from '../../../../legacy_singletons'; -import { throwErrors, createPlainError } from '../../../../../common/runtime_types'; +import type { HttpHandler } from 'src/core/public'; +import { decodeOrThrow } from '../../../../../common/runtime_types'; import { LOG_ENTRIES_SUMMARY_PATH, @@ -17,14 +14,14 @@ import { logEntriesSummaryResponseRT, } from '../../../../../common/http_api'; -export const fetchLogSummary = async (requestArgs: LogEntriesSummaryRequest) => { - const response = await npStart.http.fetch(LOG_ENTRIES_SUMMARY_PATH, { +export const fetchLogSummary = async ( + requestArgs: LogEntriesSummaryRequest, + fetch: HttpHandler +) => { + const response = await fetch(LOG_ENTRIES_SUMMARY_PATH, { method: 'POST', body: JSON.stringify(logEntriesSummaryRequestRT.encode(requestArgs)), }); - return pipe( - logEntriesSummaryResponseRT.decode(response), - fold(throwErrors(createPlainError), identity) - ); + return decodeOrThrow(logEntriesSummaryResponseRT)(response); }; diff --git a/x-pack/plugins/infra/public/containers/logs/log_summary/log_summary.test.tsx b/x-pack/plugins/infra/public/containers/logs/log_summary/log_summary.test.tsx index 73d0e5efdf06b..652ea8c71dc44 100644 --- a/x-pack/plugins/infra/public/containers/logs/log_summary/log_summary.test.tsx +++ b/x-pack/plugins/infra/public/containers/logs/log_summary/log_summary.test.tsx @@ -5,6 +5,8 @@ */ import { renderHook } from '@testing-library/react-hooks'; +// We are using this inside a `jest.mock` call. Jest requires dynamic dependencies to be prefixed with `mock` +import { coreMock as mockCoreMock } from 'src/core/public/mocks'; import { useLogSummary } from './log_summary'; @@ -16,6 +18,10 @@ import { datemathToEpochMillis } from '../../../utils/datemath'; jest.mock('./api/fetch_log_summary', () => ({ fetchLogSummary: jest.fn() })); const fetchLogSummaryMock = fetchLogSummary as jest.MockedFunction; +jest.mock('../../../hooks/use_kibana', () => ({ + useKibanaContextForPlugin: () => ({ services: mockCoreMock.createStart() }), +})); + describe('useLogSummary hook', () => { beforeEach(() => { fetchLogSummaryMock.mockClear(); @@ -53,7 +59,8 @@ describe('useLogSummary hook', () => { expect(fetchLogSummaryMock).toHaveBeenLastCalledWith( expect.objectContaining({ sourceId: 'INITIAL_SOURCE_ID', - }) + }), + expect.anything() ); expect(result.current.buckets).toEqual(firstMockResponse.data.buckets); @@ -64,7 +71,8 @@ describe('useLogSummary hook', () => { expect(fetchLogSummaryMock).toHaveBeenLastCalledWith( expect.objectContaining({ sourceId: 'CHANGED_SOURCE_ID', - }) + }), + expect.anything() ); expect(result.current.buckets).toEqual(secondMockResponse.data.buckets); }); @@ -96,7 +104,8 @@ describe('useLogSummary hook', () => { expect(fetchLogSummaryMock).toHaveBeenLastCalledWith( expect.objectContaining({ query: 'INITIAL_FILTER_QUERY', - }) + }), + expect.anything() ); expect(result.current.buckets).toEqual(firstMockResponse.data.buckets); @@ -107,7 +116,8 @@ describe('useLogSummary hook', () => { expect(fetchLogSummaryMock).toHaveBeenLastCalledWith( expect.objectContaining({ query: 'CHANGED_FILTER_QUERY', - }) + }), + expect.anything() ); expect(result.current.buckets).toEqual(secondMockResponse.data.buckets); }); @@ -132,7 +142,8 @@ describe('useLogSummary hook', () => { expect.objectContaining({ startTimestamp: firstRange.startTimestamp, endTimestamp: firstRange.endTimestamp, - }) + }), + expect.anything() ); const secondRange = createMockDateRange('now-20s', 'now'); @@ -145,7 +156,8 @@ describe('useLogSummary hook', () => { expect.objectContaining({ startTimestamp: secondRange.startTimestamp, endTimestamp: secondRange.endTimestamp, - }) + }), + expect.anything() ); }); }); diff --git a/x-pack/plugins/infra/public/containers/logs/log_summary/log_summary.tsx b/x-pack/plugins/infra/public/containers/logs/log_summary/log_summary.tsx index b83be77656863..be0d87f5d267d 100644 --- a/x-pack/plugins/infra/public/containers/logs/log_summary/log_summary.tsx +++ b/x-pack/plugins/infra/public/containers/logs/log_summary/log_summary.tsx @@ -10,6 +10,7 @@ import { useCancellableEffect } from '../../../utils/cancellable_effect'; import { fetchLogSummary } from './api/fetch_log_summary'; import { LogEntriesSummaryResponse } from '../../../../common/http_api'; import { useBucketSize } from './bucket_size'; +import { useKibanaContextForPlugin } from '../../../hooks/use_kibana'; export type LogSummaryBuckets = LogEntriesSummaryResponse['data']['buckets']; @@ -19,6 +20,7 @@ export const useLogSummary = ( endTimestamp: number | null, filterQuery: string | null ) => { + const { services } = useKibanaContextForPlugin(); const [logSummaryBuckets, setLogSummaryBuckets] = useState([]); const bucketSize = useBucketSize(startTimestamp, endTimestamp); @@ -28,13 +30,16 @@ export const useLogSummary = ( return; } - fetchLogSummary({ - sourceId, - startTimestamp, - endTimestamp, - bucketSize, - query: filterQuery, - }).then((response) => { + fetchLogSummary( + { + sourceId, + startTimestamp, + endTimestamp, + bucketSize, + query: filterQuery, + }, + services.http.fetch + ).then((response) => { if (!getIsCancelled()) { setLogSummaryBuckets(response.data.buckets); } diff --git a/x-pack/plugins/infra/public/containers/ml/api/ml_cleanup.ts b/x-pack/plugins/infra/public/containers/ml/api/ml_cleanup.ts index 23fa338e74f14..fa7d8f14c6a9a 100644 --- a/x-pack/plugins/infra/public/containers/ml/api/ml_cleanup.ts +++ b/x-pack/plugins/infra/public/containers/ml/api/ml_cleanup.ts @@ -5,21 +5,24 @@ */ import * as rt from 'io-ts'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { fold } from 'fp-ts/lib/Either'; -import { identity } from 'fp-ts/lib/function'; -import { npStart } from '../../../legacy_singletons'; - +import type { HttpHandler } from 'src/core/public'; import { getDatafeedId, getJobId } from '../../../../common/infra_ml'; -import { throwErrors, createPlainError } from '../../../../common/runtime_types'; +import { decodeOrThrow } from '../../../../common/runtime_types'; + +interface DeleteJobsRequestArgs { + spaceId: string; + sourceId: string; + jobTypes: JobType[]; +} export const callDeleteJobs = async ( - spaceId: string, - sourceId: string, - jobTypes: JobType[] + requestArgs: DeleteJobsRequestArgs, + fetch: HttpHandler ) => { + const { spaceId, sourceId, jobTypes } = requestArgs; + // NOTE: Deleting the jobs via this API will delete the datafeeds at the same time - const deleteJobsResponse = await npStart.http.fetch('/api/ml/jobs/delete_jobs', { + const deleteJobsResponse = await fetch('/api/ml/jobs/delete_jobs', { method: 'POST', body: JSON.stringify( deleteJobsRequestPayloadRT.encode({ @@ -28,28 +31,29 @@ export const callDeleteJobs = async ( ), }); - return pipe( - deleteJobsResponsePayloadRT.decode(deleteJobsResponse), - fold(throwErrors(createPlainError), identity) - ); + return decodeOrThrow(deleteJobsResponsePayloadRT)(deleteJobsResponse); }; -export const callGetJobDeletionTasks = async () => { - const jobDeletionTasksResponse = await npStart.http.fetch('/api/ml/jobs/deleting_jobs_tasks'); +export const callGetJobDeletionTasks = async (fetch: HttpHandler) => { + const jobDeletionTasksResponse = await fetch('/api/ml/jobs/deleting_jobs_tasks'); - return pipe( - getJobDeletionTasksResponsePayloadRT.decode(jobDeletionTasksResponse), - fold(throwErrors(createPlainError), identity) - ); + return decodeOrThrow(getJobDeletionTasksResponsePayloadRT)(jobDeletionTasksResponse); }; +interface StopDatafeedsRequestArgs { + spaceId: string; + sourceId: string; + jobTypes: JobType[]; +} + export const callStopDatafeeds = async ( - spaceId: string, - sourceId: string, - jobTypes: JobType[] + requestArgs: StopDatafeedsRequestArgs, + fetch: HttpHandler ) => { + const { spaceId, sourceId, jobTypes } = requestArgs; + // Stop datafeed due to https://github.com/elastic/kibana/issues/44652 - const stopDatafeedResponse = await npStart.http.fetch('/api/ml/jobs/stop_datafeeds', { + const stopDatafeedResponse = await fetch('/api/ml/jobs/stop_datafeeds', { method: 'POST', body: JSON.stringify( stopDatafeedsRequestPayloadRT.encode({ @@ -58,10 +62,7 @@ export const callStopDatafeeds = async ( ), }); - return pipe( - stopDatafeedsResponsePayloadRT.decode(stopDatafeedResponse), - fold(throwErrors(createPlainError), identity) - ); + return decodeOrThrow(stopDatafeedsResponsePayloadRT)(stopDatafeedResponse); }; export const deleteJobsRequestPayloadRT = rt.type({ diff --git a/x-pack/plugins/infra/public/containers/ml/api/ml_get_jobs_summary_api.ts b/x-pack/plugins/infra/public/containers/ml/api/ml_get_jobs_summary_api.ts index 3fddb63f69791..84b5df3d172c7 100644 --- a/x-pack/plugins/infra/public/containers/ml/api/ml_get_jobs_summary_api.ts +++ b/x-pack/plugins/infra/public/containers/ml/api/ml_get_jobs_summary_api.ts @@ -4,21 +4,24 @@ * you may not use this file except in compliance with the Elastic License. */ -import { fold } from 'fp-ts/lib/Either'; -import { identity } from 'fp-ts/lib/function'; -import { pipe } from 'fp-ts/lib/pipeable'; import * as rt from 'io-ts'; -import { npStart } from '../../../legacy_singletons'; +import type { HttpHandler } from 'src/core/public'; import { getJobId, jobCustomSettingsRT } from '../../../../common/infra_ml'; -import { createPlainError, throwErrors } from '../../../../common/runtime_types'; +import { decodeOrThrow } from '../../../../common/runtime_types'; + +interface RequestArgs { + spaceId: string; + sourceId: string; + jobTypes: JobType[]; +} export const callJobsSummaryAPI = async ( - spaceId: string, - sourceId: string, - jobTypes: JobType[] + requestArgs: RequestArgs, + fetch: HttpHandler ) => { - const response = await npStart.http.fetch('/api/ml/jobs/jobs_summary', { + const { spaceId, sourceId, jobTypes } = requestArgs; + const response = await fetch('/api/ml/jobs/jobs_summary', { method: 'POST', body: JSON.stringify( fetchJobStatusRequestPayloadRT.encode({ @@ -26,10 +29,7 @@ export const callJobsSummaryAPI = async ( }) ), }); - return pipe( - fetchJobStatusResponsePayloadRT.decode(response), - fold(throwErrors(createPlainError), identity) - ); + return decodeOrThrow(fetchJobStatusResponsePayloadRT)(response); }; export const fetchJobStatusRequestPayloadRT = rt.type({ diff --git a/x-pack/plugins/infra/public/containers/ml/api/ml_get_module.ts b/x-pack/plugins/infra/public/containers/ml/api/ml_get_module.ts index d492522c120a1..75ce335fbe49c 100644 --- a/x-pack/plugins/infra/public/containers/ml/api/ml_get_module.ts +++ b/x-pack/plugins/infra/public/containers/ml/api/ml_get_module.ts @@ -4,24 +4,18 @@ * you may not use this file except in compliance with the Elastic License. */ -import { fold } from 'fp-ts/lib/Either'; -import { identity } from 'fp-ts/lib/function'; -import { pipe } from 'fp-ts/lib/pipeable'; import * as rt from 'io-ts'; -import { npStart } from '../../../legacy_singletons'; +import type { HttpHandler } from 'src/core/public'; import { jobCustomSettingsRT } from '../../../../common/log_analysis'; -import { createPlainError, throwErrors } from '../../../../common/runtime_types'; +import { decodeOrThrow } from '../../../../common/runtime_types'; -export const callGetMlModuleAPI = async (moduleId: string) => { - const response = await npStart.http.fetch(`/api/ml/modules/get_module/${moduleId}`, { +export const callGetMlModuleAPI = async (moduleId: string, fetch: HttpHandler) => { + const response = await fetch(`/api/ml/modules/get_module/${moduleId}`, { method: 'GET', }); - return pipe( - getMlModuleResponsePayloadRT.decode(response), - fold(throwErrors(createPlainError), identity) - ); + return decodeOrThrow(getMlModuleResponsePayloadRT)(response); }; const jobDefinitionRT = rt.type({ diff --git a/x-pack/plugins/infra/public/containers/ml/api/ml_setup_module_api.ts b/x-pack/plugins/infra/public/containers/ml/api/ml_setup_module_api.ts index 06b0e075387b0..36dced1bd2680 100644 --- a/x-pack/plugins/infra/public/containers/ml/api/ml_setup_module_api.ts +++ b/x-pack/plugins/infra/public/containers/ml/api/ml_setup_module_api.ts @@ -4,27 +4,38 @@ * you may not use this file except in compliance with the Elastic License. */ -import { fold } from 'fp-ts/lib/Either'; -import { identity } from 'fp-ts/lib/function'; -import { pipe } from 'fp-ts/lib/pipeable'; import * as rt from 'io-ts'; -import { npStart } from '../../../legacy_singletons'; +import type { HttpHandler } from 'src/core/public'; import { getJobIdPrefix, jobCustomSettingsRT } from '../../../../common/infra_ml'; -import { createPlainError, throwErrors } from '../../../../common/runtime_types'; - -export const callSetupMlModuleAPI = async ( - moduleId: string, - start: number | undefined, - end: number | undefined, - spaceId: string, - sourceId: string, - indexPattern: string, - jobOverrides: SetupMlModuleJobOverrides[] = [], - datafeedOverrides: SetupMlModuleDatafeedOverrides[] = [], - query?: object -) => { - const response = await npStart.http.fetch(`/api/ml/modules/setup/${moduleId}`, { +import { decodeOrThrow } from '../../../../common/runtime_types'; + +interface RequestArgs { + moduleId: string; + start?: number; + end?: number; + spaceId: string; + sourceId: string; + indexPattern: string; + jobOverrides?: SetupMlModuleJobOverrides[]; + datafeedOverrides?: SetupMlModuleDatafeedOverrides[]; + query?: object; +} + +export const callSetupMlModuleAPI = async (requestArgs: RequestArgs, fetch: HttpHandler) => { + const { + moduleId, + start, + end, + spaceId, + sourceId, + indexPattern, + jobOverrides = [], + datafeedOverrides = [], + query, + } = requestArgs; + + const response = await fetch(`/api/ml/modules/setup/${moduleId}`, { method: 'POST', body: JSON.stringify( setupMlModuleRequestPayloadRT.encode({ @@ -40,10 +51,7 @@ export const callSetupMlModuleAPI = async ( ), }); - return pipe( - setupMlModuleResponsePayloadRT.decode(response), - fold(throwErrors(createPlainError), identity) - ); + return decodeOrThrow(setupMlModuleResponsePayloadRT)(response); }; const setupMlModuleTimeParamsRT = rt.partial({ diff --git a/x-pack/plugins/infra/public/containers/ml/infra_ml_capabilities.tsx b/x-pack/plugins/infra/public/containers/ml/infra_ml_capabilities.tsx index f4c90a459af6a..bc488a51e2aff 100644 --- a/x-pack/plugins/infra/public/containers/ml/infra_ml_capabilities.tsx +++ b/x-pack/plugins/infra/public/containers/ml/infra_ml_capabilities.tsx @@ -10,14 +10,15 @@ import { fold } from 'fp-ts/lib/Either'; import { pipe } from 'fp-ts/lib/pipeable'; import { identity } from 'fp-ts/lib/function'; import { useTrackedPromise } from '../../utils/use_tracked_promise'; -import { npStart } from '../../legacy_singletons'; import { getMlCapabilitiesResponsePayloadRT, GetMlCapabilitiesResponsePayload, } from './api/ml_api_types'; import { throwErrors, createPlainError } from '../../../common/runtime_types'; +import { useKibanaContextForPlugin } from '../../hooks/use_kibana'; export const useInfraMLCapabilities = () => { + const { services } = useKibanaContextForPlugin(); const [mlCapabilities, setMlCapabilities] = useState( initialMlCapabilities ); @@ -26,7 +27,7 @@ export const useInfraMLCapabilities = () => { { cancelPreviousOn: 'resolution', createPromise: async () => { - const rawResponse = await npStart.http.fetch('/api/ml/ml_capabilities'); + const rawResponse = await services.http.fetch('/api/ml/ml_capabilities'); return pipe( getMlCapabilitiesResponsePayloadRT.decode(rawResponse), diff --git a/x-pack/plugins/infra/public/containers/ml/infra_ml_cleanup.tsx b/x-pack/plugins/infra/public/containers/ml/infra_ml_cleanup.tsx index 736982c8043b1..871e61ecfe507 100644 --- a/x-pack/plugins/infra/public/containers/ml/infra_ml_cleanup.tsx +++ b/x-pack/plugins/infra/public/containers/ml/infra_ml_cleanup.tsx @@ -4,16 +4,18 @@ * you may not use this file except in compliance with the Elastic License. */ +import { HttpHandler } from 'src/core/public'; import { getJobId } from '../../../common/infra_ml'; import { callDeleteJobs, callGetJobDeletionTasks, callStopDatafeeds } from './api/ml_cleanup'; export const cleanUpJobsAndDatafeeds = async ( spaceId: string, sourceId: string, - jobTypes: JobType[] + jobTypes: JobType[], + fetch: HttpHandler ) => { try { - await callStopDatafeeds(spaceId, sourceId, jobTypes); + await callStopDatafeeds({ spaceId, sourceId, jobTypes }, fetch); } catch (err) { // Proceed only if datafeed has been deleted or didn't exist in the first place if (err?.res?.status !== 404) { @@ -21,27 +23,29 @@ export const cleanUpJobsAndDatafeeds = async ( } } - return await deleteJobs(spaceId, sourceId, jobTypes); + return await deleteJobs(spaceId, sourceId, jobTypes, fetch); }; const deleteJobs = async ( spaceId: string, sourceId: string, - jobTypes: JobType[] + jobTypes: JobType[], + fetch: HttpHandler ) => { - const deleteJobsResponse = await callDeleteJobs(spaceId, sourceId, jobTypes); - await waitUntilJobsAreDeleted(spaceId, sourceId, jobTypes); + const deleteJobsResponse = await callDeleteJobs({ spaceId, sourceId, jobTypes }, fetch); + await waitUntilJobsAreDeleted(spaceId, sourceId, jobTypes, fetch); return deleteJobsResponse; }; const waitUntilJobsAreDeleted = async ( spaceId: string, sourceId: string, - jobTypes: JobType[] + jobTypes: JobType[], + fetch: HttpHandler ) => { const moduleJobIds = jobTypes.map((jobType) => getJobId(spaceId, sourceId, jobType)); while (true) { - const { jobIds: jobIdsBeingDeleted } = await callGetJobDeletionTasks(); + const { jobIds: jobIdsBeingDeleted } = await callGetJobDeletionTasks(fetch); const needToWait = jobIdsBeingDeleted.some((jobId) => moduleJobIds.includes(jobId)); if (needToWait) { diff --git a/x-pack/plugins/infra/public/containers/ml/infra_ml_module.tsx b/x-pack/plugins/infra/public/containers/ml/infra_ml_module.tsx index 349541d108f5e..5408084a5246e 100644 --- a/x-pack/plugins/infra/public/containers/ml/infra_ml_module.tsx +++ b/x-pack/plugins/infra/public/containers/ml/infra_ml_module.tsx @@ -6,6 +6,7 @@ import { useCallback, useMemo } from 'react'; import { DatasetFilter } from '../../../common/infra_ml'; +import { useKibanaContextForPlugin } from '../../hooks/use_kibana'; import { useTrackedPromise } from '../../utils/use_tracked_promise'; import { useModuleStatus } from './infra_ml_module_status'; import { ModuleDescriptor, ModuleSourceConfiguration } from './infra_ml_module_types'; @@ -17,6 +18,7 @@ export const useInfraMLModule = ({ sourceConfiguration: ModuleSourceConfiguration; moduleDescriptor: ModuleDescriptor; }) => { + const { services } = useKibanaContextForPlugin(); const { spaceId, sourceId, timestampField } = sourceConfiguration; const [moduleStatus, dispatchModuleStatus] = useModuleStatus(moduleDescriptor.jobTypes); @@ -25,7 +27,7 @@ export const useInfraMLModule = ({ cancelPreviousOn: 'resolution', createPromise: async () => { dispatchModuleStatus({ type: 'fetchingJobStatuses' }); - return await moduleDescriptor.getJobSummary(spaceId, sourceId); + return await moduleDescriptor.getJobSummary(spaceId, sourceId, services.http.fetch); }, onResolve: (jobResponse) => { dispatchModuleStatus({ @@ -54,18 +56,25 @@ export const useInfraMLModule = ({ ) => { dispatchModuleStatus({ type: 'startedSetup' }); const setupResult = await moduleDescriptor.setUpModule( - start, - end, - datasetFilter, { - indices: selectedIndices, - sourceId, - spaceId, - timestampField, + start, + end, + datasetFilter, + moduleSourceConfiguration: { + indices: selectedIndices, + sourceId, + spaceId, + timestampField, + }, + partitionField, }, - partitionField + services.http.fetch + ); + const jobSummaries = await moduleDescriptor.getJobSummary( + spaceId, + sourceId, + services.http.fetch ); - const jobSummaries = await moduleDescriptor.getJobSummary(spaceId, sourceId); return { setupResult, jobSummaries }; }, onResolve: ({ setupResult: { datafeeds, jobs }, jobSummaries }) => { @@ -89,7 +98,7 @@ export const useInfraMLModule = ({ { cancelPreviousOn: 'resolution', createPromise: async () => { - return await moduleDescriptor.cleanUpModule(spaceId, sourceId); + return await moduleDescriptor.cleanUpModule(spaceId, sourceId, services.http.fetch); }, }, [spaceId, sourceId] diff --git a/x-pack/plugins/infra/public/containers/ml/infra_ml_module_definition.tsx b/x-pack/plugins/infra/public/containers/ml/infra_ml_module_definition.tsx index 3c7ffcfd4a4e2..a747a2853d1f7 100644 --- a/x-pack/plugins/infra/public/containers/ml/infra_ml_module_definition.tsx +++ b/x-pack/plugins/infra/public/containers/ml/infra_ml_module_definition.tsx @@ -6,6 +6,7 @@ import { useCallback, useMemo, useState } from 'react'; import { getJobId } from '../../../common/log_analysis'; +import { useKibanaContextForPlugin } from '../../hooks/use_kibana'; import { useTrackedPromise } from '../../utils/use_tracked_promise'; import { JobSummary } from './api/ml_get_jobs_summary_api'; import { GetMlModuleResponsePayload, JobDefinition } from './api/ml_get_module'; @@ -18,6 +19,7 @@ export const useInfraMLModuleDefinition = ({ sourceConfiguration: ModuleSourceConfiguration; moduleDescriptor: ModuleDescriptor; }) => { + const { services } = useKibanaContextForPlugin(); const [moduleDefinition, setModuleDefinition] = useState< GetMlModuleResponsePayload | undefined >(); @@ -40,7 +42,7 @@ export const useInfraMLModuleDefinition = ({ { cancelPreviousOn: 'resolution', createPromise: async () => { - return await moduleDescriptor.getModuleDefinition(); + return await moduleDescriptor.getModuleDefinition(services.http.fetch); }, onResolve: (response) => { setModuleDefinition(response); diff --git a/x-pack/plugins/infra/public/containers/ml/infra_ml_module_types.ts b/x-pack/plugins/infra/public/containers/ml/infra_ml_module_types.ts index e36f38add641a..976a64e8034bc 100644 --- a/x-pack/plugins/infra/public/containers/ml/infra_ml_module_types.ts +++ b/x-pack/plugins/infra/public/containers/ml/infra_ml_module_types.ts @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ - +import { HttpHandler } from 'src/core/public'; import { ValidateLogEntryDatasetsResponsePayload, ValidationIndicesResponsePayload, @@ -16,6 +16,14 @@ import { SetupMlModuleResponsePayload } from './api/ml_setup_module_api'; export { JobModelSizeStats, JobSummary } from './api/ml_get_jobs_summary_api'; +export interface SetUpModuleArgs { + start?: number | undefined; + end?: number | undefined; + datasetFilter?: DatasetFilter; + moduleSourceConfiguration: ModuleSourceConfiguration; + partitionField?: string; +} + export interface ModuleDescriptor { moduleId: string; moduleName: string; @@ -23,25 +31,32 @@ export interface ModuleDescriptor { jobTypes: JobType[]; bucketSpan: number; getJobIds: (spaceId: string, sourceId: string) => Record; - getJobSummary: (spaceId: string, sourceId: string) => Promise; - getModuleDefinition: () => Promise; + getJobSummary: ( + spaceId: string, + sourceId: string, + fetch: HttpHandler + ) => Promise; + getModuleDefinition: (fetch: HttpHandler) => Promise; setUpModule: ( - start: number | undefined, - end: number | undefined, - datasetFilter: DatasetFilter, - sourceConfiguration: ModuleSourceConfiguration, - partitionField?: string + setUpModuleArgs: SetUpModuleArgs, + fetch: HttpHandler ) => Promise; - cleanUpModule: (spaceId: string, sourceId: string) => Promise; + cleanUpModule: ( + spaceId: string, + sourceId: string, + fetch: HttpHandler + ) => Promise; validateSetupIndices?: ( indices: string[], - timestampField: string + timestampField: string, + fetch: HttpHandler ) => Promise; validateSetupDatasets?: ( indices: string[], timestampField: string, startTime: number, - endTime: number + endTime: number, + fetch: HttpHandler ) => Promise; } diff --git a/x-pack/plugins/infra/public/containers/ml/modules/metrics_hosts/module_descriptor.ts b/x-pack/plugins/infra/public/containers/ml/modules/metrics_hosts/module_descriptor.ts index 7ea87c3d21322..47230cbed977f 100644 --- a/x-pack/plugins/infra/public/containers/ml/modules/metrics_hosts/module_descriptor.ts +++ b/x-pack/plugins/infra/public/containers/ml/modules/metrics_hosts/module_descriptor.ts @@ -5,7 +5,8 @@ */ import { i18n } from '@kbn/i18n'; -import { ModuleDescriptor, ModuleSourceConfiguration } from '../../infra_ml_module_types'; +import { HttpHandler } from 'src/core/public'; +import { ModuleDescriptor, SetUpModuleArgs } from '../../infra_ml_module_types'; import { cleanUpJobsAndDatafeeds } from '../../infra_ml_cleanup'; import { callJobsSummaryAPI } from '../../api/ml_get_jobs_summary_api'; import { callGetMlModuleAPI } from '../../api/ml_get_module'; @@ -14,7 +15,6 @@ import { metricsHostsJobTypes, getJobId, MetricsHostsJobType, - DatasetFilter, bucketSpan, } from '../../../../../common/infra_ml'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths @@ -48,24 +48,28 @@ const getJobIds = (spaceId: string, sourceId: string) => {} as Record ); -const getJobSummary = async (spaceId: string, sourceId: string) => { - const response = await callJobsSummaryAPI(spaceId, sourceId, metricsHostsJobTypes); +const getJobSummary = async (spaceId: string, sourceId: string, fetch: HttpHandler) => { + const response = await callJobsSummaryAPI( + { spaceId, sourceId, jobTypes: metricsHostsJobTypes }, + fetch + ); const jobIds = Object.values(getJobIds(spaceId, sourceId)); return response.filter((jobSummary) => jobIds.includes(jobSummary.id)); }; -const getModuleDefinition = async () => { - return await callGetMlModuleAPI(moduleId); +const getModuleDefinition = async (fetch: HttpHandler) => { + return await callGetMlModuleAPI(moduleId, fetch); }; -const setUpModule = async ( - start: number | undefined, - end: number | undefined, - datasetFilter: DatasetFilter, - { spaceId, sourceId, indices, timestampField }: ModuleSourceConfiguration, - partitionField?: string -) => { +const setUpModule = async (setUpModuleArgs: SetUpModuleArgs, fetch: HttpHandler) => { + const { + start, + end, + moduleSourceConfiguration: { spaceId, sourceId, indices, timestampField }, + partitionField, + } = setUpModuleArgs; + const indexNamePattern = indices.join(','); const jobIds: JobType[] = ['hosts_memory_usage', 'hosts_network_in', 'hosts_network_out']; @@ -128,14 +132,17 @@ const setUpModule = async ( }); return callSetupMlModuleAPI( - moduleId, - start, - end, - spaceId, - sourceId, - indexNamePattern, - jobOverrides, - datafeedOverrides + { + moduleId, + start, + end, + spaceId, + sourceId, + indexPattern: indexNamePattern, + jobOverrides, + datafeedOverrides, + }, + fetch ); }; @@ -159,8 +166,8 @@ const getDefaultJobConfigs = (jobId: JobType): { datafeed: any; job: any } => { } }; -const cleanUpModule = async (spaceId: string, sourceId: string) => { - return await cleanUpJobsAndDatafeeds(spaceId, sourceId, metricsHostsJobTypes); +const cleanUpModule = async (spaceId: string, sourceId: string, fetch: HttpHandler) => { + return await cleanUpJobsAndDatafeeds(spaceId, sourceId, metricsHostsJobTypes, fetch); }; export const metricHostsModule: ModuleDescriptor = { diff --git a/x-pack/plugins/infra/public/containers/ml/modules/metrics_k8s/module_descriptor.ts b/x-pack/plugins/infra/public/containers/ml/modules/metrics_k8s/module_descriptor.ts index eaf7489c84eb4..488803dc113b0 100644 --- a/x-pack/plugins/infra/public/containers/ml/modules/metrics_k8s/module_descriptor.ts +++ b/x-pack/plugins/infra/public/containers/ml/modules/metrics_k8s/module_descriptor.ts @@ -5,7 +5,8 @@ */ import { i18n } from '@kbn/i18n'; -import { ModuleDescriptor, ModuleSourceConfiguration } from '../../infra_ml_module_types'; +import { HttpHandler } from 'src/core/public'; +import { ModuleDescriptor, SetUpModuleArgs } from '../../infra_ml_module_types'; import { cleanUpJobsAndDatafeeds } from '../../infra_ml_cleanup'; import { callJobsSummaryAPI } from '../../api/ml_get_jobs_summary_api'; import { callGetMlModuleAPI } from '../../api/ml_get_module'; @@ -14,7 +15,6 @@ import { metricsK8SJobTypes, getJobId, MetricK8sJobType, - DatasetFilter, bucketSpan, } from '../../../../../common/infra_ml'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths @@ -49,24 +49,28 @@ const getJobIds = (spaceId: string, sourceId: string) => {} as Record ); -const getJobSummary = async (spaceId: string, sourceId: string) => { - const response = await callJobsSummaryAPI(spaceId, sourceId, metricsK8SJobTypes); +const getJobSummary = async (spaceId: string, sourceId: string, fetch: HttpHandler) => { + const response = await callJobsSummaryAPI( + { spaceId, sourceId, jobTypes: metricsK8SJobTypes }, + fetch + ); const jobIds = Object.values(getJobIds(spaceId, sourceId)); return response.filter((jobSummary) => jobIds.includes(jobSummary.id)); }; -const getModuleDefinition = async () => { - return await callGetMlModuleAPI(moduleId); +const getModuleDefinition = async (fetch: HttpHandler) => { + return await callGetMlModuleAPI(moduleId, fetch); }; -const setUpModule = async ( - start: number | undefined, - end: number | undefined, - datasetFilter: DatasetFilter, - { spaceId, sourceId, indices, timestampField }: ModuleSourceConfiguration, - partitionField?: string -) => { +const setUpModule = async (setUpModuleArgs: SetUpModuleArgs, fetch: HttpHandler) => { + const { + start, + end, + moduleSourceConfiguration: { spaceId, sourceId, indices, timestampField }, + partitionField, + } = setUpModuleArgs; + const indexNamePattern = indices.join(','); const jobIds: JobType[] = ['k8s_memory_usage', 'k8s_network_in', 'k8s_network_out']; const jobOverrides = jobIds.map((id) => { @@ -133,14 +137,17 @@ const setUpModule = async ( }); return callSetupMlModuleAPI( - moduleId, - start, - end, - spaceId, - sourceId, - indexNamePattern, - jobOverrides, - datafeedOverrides + { + moduleId, + start, + end, + spaceId, + sourceId, + indexPattern: indexNamePattern, + jobOverrides, + datafeedOverrides, + }, + fetch ); }; @@ -164,8 +171,8 @@ const getDefaultJobConfigs = (jobId: JobType): { datafeed: any; job: any } => { } }; -const cleanUpModule = async (spaceId: string, sourceId: string) => { - return await cleanUpJobsAndDatafeeds(spaceId, sourceId, metricsK8SJobTypes); +const cleanUpModule = async (spaceId: string, sourceId: string, fetch: HttpHandler) => { + return await cleanUpJobsAndDatafeeds(spaceId, sourceId, metricsK8SJobTypes, fetch); }; export const metricHostsModule: ModuleDescriptor = { diff --git a/x-pack/plugins/infra/public/legacy_singletons.ts b/x-pack/plugins/infra/public/legacy_singletons.ts deleted file mode 100644 index f57047f21c281..0000000000000 --- a/x-pack/plugins/infra/public/legacy_singletons.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; - * you may not use this file except in compliance with the Elastic License. - */ -import { CoreStart } from 'kibana/public'; - -let npStart: CoreStart; - -export function registerStartSingleton(start: CoreStart) { - npStart = start; -} - -export { npStart }; diff --git a/x-pack/plugins/infra/public/pages/link_to/link_to_logs.test.tsx b/x-pack/plugins/infra/public/pages/link_to/link_to_logs.test.tsx index 945b299674aaa..4f83e37d7e029 100644 --- a/x-pack/plugins/infra/public/pages/link_to/link_to_logs.test.tsx +++ b/x-pack/plugins/infra/public/pages/link_to/link_to_logs.test.tsx @@ -14,7 +14,6 @@ import { createMemoryHistory } from 'history'; import React from 'react'; import { Route, Router, Switch } from 'react-router-dom'; import { httpServiceMock } from 'src/core/public/mocks'; -// import { HttpSetup } from 'src/core/public'; import { KibanaContextProvider } from 'src/plugins/kibana_react/public'; import { useLogSource } from '../../containers/logs/log_source'; import { diff --git a/x-pack/plugins/infra/public/pages/logs/log_entry_categories/service_calls/get_log_entry_category_datasets.ts b/x-pack/plugins/infra/public/pages/logs/log_entry_categories/service_calls/get_log_entry_category_datasets.ts index a8cd7854efb6b..5f34d45635b60 100644 --- a/x-pack/plugins/infra/public/pages/logs/log_entry_categories/service_calls/get_log_entry_category_datasets.ts +++ b/x-pack/plugins/infra/public/pages/logs/log_entry_categories/service_calls/get_log_entry_category_datasets.ts @@ -4,24 +4,28 @@ * you may not use this file except in compliance with the Elastic License. */ -import { fold } from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { identity } from 'fp-ts/lib/function'; -import { npStart } from '../../../../legacy_singletons'; +import type { HttpHandler } from 'src/core/public'; import { getLogEntryCategoryDatasetsRequestPayloadRT, getLogEntryCategoryDatasetsSuccessReponsePayloadRT, LOG_ANALYSIS_GET_LOG_ENTRY_CATEGORY_DATASETS_PATH, } from '../../../../../common/http_api/log_analysis'; -import { createPlainError, throwErrors } from '../../../../../common/runtime_types'; +import { decodeOrThrow } from '../../../../../common/runtime_types'; + +interface RequestArgs { + sourceId: string; + startTime: number; + endTime: number; +} export const callGetLogEntryCategoryDatasetsAPI = async ( - sourceId: string, - startTime: number, - endTime: number + requestArgs: RequestArgs, + fetch: HttpHandler ) => { - const response = await npStart.http.fetch(LOG_ANALYSIS_GET_LOG_ENTRY_CATEGORY_DATASETS_PATH, { + const { sourceId, startTime, endTime } = requestArgs; + + const response = await fetch(LOG_ANALYSIS_GET_LOG_ENTRY_CATEGORY_DATASETS_PATH, { method: 'POST', body: JSON.stringify( getLogEntryCategoryDatasetsRequestPayloadRT.encode({ @@ -36,8 +40,5 @@ export const callGetLogEntryCategoryDatasetsAPI = async ( ), }); - return pipe( - getLogEntryCategoryDatasetsSuccessReponsePayloadRT.decode(response), - fold(throwErrors(createPlainError), identity) - ); + return decodeOrThrow(getLogEntryCategoryDatasetsSuccessReponsePayloadRT)(response); }; diff --git a/x-pack/plugins/infra/public/pages/logs/log_entry_categories/service_calls/get_log_entry_category_examples.ts b/x-pack/plugins/infra/public/pages/logs/log_entry_categories/service_calls/get_log_entry_category_examples.ts index a10d077a2dd4f..c4b756ebf5d58 100644 --- a/x-pack/plugins/infra/public/pages/logs/log_entry_categories/service_calls/get_log_entry_category_examples.ts +++ b/x-pack/plugins/infra/public/pages/logs/log_entry_categories/service_calls/get_log_entry_category_examples.ts @@ -4,26 +4,30 @@ * you may not use this file except in compliance with the Elastic License. */ -import { fold } from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { identity } from 'fp-ts/lib/function'; -import { npStart } from '../../../../legacy_singletons'; +import type { HttpHandler } from 'src/core/public'; import { getLogEntryCategoryExamplesRequestPayloadRT, getLogEntryCategoryExamplesSuccessReponsePayloadRT, LOG_ANALYSIS_GET_LOG_ENTRY_CATEGORY_EXAMPLES_PATH, } from '../../../../../common/http_api/log_analysis'; -import { createPlainError, throwErrors } from '../../../../../common/runtime_types'; +import { decodeOrThrow } from '../../../../../common/runtime_types'; + +interface RequestArgs { + sourceId: string; + startTime: number; + endTime: number; + categoryId: number; + exampleCount: number; +} export const callGetLogEntryCategoryExamplesAPI = async ( - sourceId: string, - startTime: number, - endTime: number, - categoryId: number, - exampleCount: number + requestArgs: RequestArgs, + fetch: HttpHandler ) => { - const response = await npStart.http.fetch(LOG_ANALYSIS_GET_LOG_ENTRY_CATEGORY_EXAMPLES_PATH, { + const { sourceId, startTime, endTime, categoryId, exampleCount } = requestArgs; + + const response = await fetch(LOG_ANALYSIS_GET_LOG_ENTRY_CATEGORY_EXAMPLES_PATH, { method: 'POST', body: JSON.stringify( getLogEntryCategoryExamplesRequestPayloadRT.encode({ @@ -40,8 +44,5 @@ export const callGetLogEntryCategoryExamplesAPI = async ( ), }); - return pipe( - getLogEntryCategoryExamplesSuccessReponsePayloadRT.decode(response), - fold(throwErrors(createPlainError), identity) - ); + return decodeOrThrow(getLogEntryCategoryExamplesSuccessReponsePayloadRT)(response); }; diff --git a/x-pack/plugins/infra/public/pages/logs/log_entry_categories/service_calls/get_top_log_entry_categories.ts b/x-pack/plugins/infra/public/pages/logs/log_entry_categories/service_calls/get_top_log_entry_categories.ts index 2ebcff4fd3ca5..fd53803796339 100644 --- a/x-pack/plugins/infra/public/pages/logs/log_entry_categories/service_calls/get_top_log_entry_categories.ts +++ b/x-pack/plugins/infra/public/pages/logs/log_entry_categories/service_calls/get_top_log_entry_categories.ts @@ -4,28 +4,31 @@ * you may not use this file except in compliance with the Elastic License. */ -import { fold } from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { identity } from 'fp-ts/lib/function'; -import { npStart } from '../../../../legacy_singletons'; +import type { HttpHandler } from 'src/core/public'; import { getLogEntryCategoriesRequestPayloadRT, getLogEntryCategoriesSuccessReponsePayloadRT, LOG_ANALYSIS_GET_LOG_ENTRY_CATEGORIES_PATH, } from '../../../../../common/http_api/log_analysis'; -import { createPlainError, throwErrors } from '../../../../../common/runtime_types'; +import { decodeOrThrow } from '../../../../../common/runtime_types'; + +interface RequestArgs { + sourceId: string; + startTime: number; + endTime: number; + categoryCount: number; + datasets?: string[]; +} export const callGetTopLogEntryCategoriesAPI = async ( - sourceId: string, - startTime: number, - endTime: number, - categoryCount: number, - datasets?: string[] + requestArgs: RequestArgs, + fetch: HttpHandler ) => { + const { sourceId, startTime, endTime, categoryCount, datasets } = requestArgs; const intervalDuration = endTime - startTime; - const response = await npStart.http.fetch(LOG_ANALYSIS_GET_LOG_ENTRY_CATEGORIES_PATH, { + const response = await fetch(LOG_ANALYSIS_GET_LOG_ENTRY_CATEGORIES_PATH, { method: 'POST', body: JSON.stringify( getLogEntryCategoriesRequestPayloadRT.encode({ @@ -60,8 +63,5 @@ export const callGetTopLogEntryCategoriesAPI = async ( ), }); - return pipe( - getLogEntryCategoriesSuccessReponsePayloadRT.decode(response), - fold(throwErrors(createPlainError), identity) - ); + return decodeOrThrow(getLogEntryCategoriesSuccessReponsePayloadRT)(response); }; diff --git a/x-pack/plugins/infra/public/pages/logs/log_entry_categories/use_log_entry_categories_results.ts b/x-pack/plugins/infra/public/pages/logs/log_entry_categories/use_log_entry_categories_results.ts index 123b188046b85..0a12c433db60a 100644 --- a/x-pack/plugins/infra/public/pages/logs/log_entry_categories/use_log_entry_categories_results.ts +++ b/x-pack/plugins/infra/public/pages/logs/log_entry_categories/use_log_entry_categories_results.ts @@ -13,6 +13,7 @@ import { import { useTrackedPromise, CanceledPromiseError } from '../../../utils/use_tracked_promise'; import { callGetTopLogEntryCategoriesAPI } from './service_calls/get_top_log_entry_categories'; import { callGetLogEntryCategoryDatasetsAPI } from './service_calls/get_log_entry_category_datasets'; +import { useKibanaContextForPlugin } from '../../../hooks/use_kibana'; type TopLogEntryCategories = GetLogEntryCategoriesSuccessResponsePayload['data']['categories']; type LogEntryCategoryDatasets = GetLogEntryCategoryDatasetsSuccessResponsePayload['data']['datasets']; @@ -34,6 +35,7 @@ export const useLogEntryCategoriesResults = ({ sourceId: string; startTime: number; }) => { + const { services } = useKibanaContextForPlugin(); const [topLogEntryCategories, setTopLogEntryCategories] = useState([]); const [logEntryCategoryDatasets, setLogEntryCategoryDatasets] = useState< LogEntryCategoryDatasets @@ -44,11 +46,14 @@ export const useLogEntryCategoriesResults = ({ cancelPreviousOn: 'creation', createPromise: async () => { return await callGetTopLogEntryCategoriesAPI( - sourceId, - startTime, - endTime, - categoriesCount, - filteredDatasets + { + sourceId, + startTime, + endTime, + categoryCount: categoriesCount, + datasets: filteredDatasets, + }, + services.http.fetch ); }, onResolve: ({ data: { categories } }) => { @@ -71,7 +76,10 @@ export const useLogEntryCategoriesResults = ({ { cancelPreviousOn: 'creation', createPromise: async () => { - return await callGetLogEntryCategoryDatasetsAPI(sourceId, startTime, endTime); + return await callGetLogEntryCategoryDatasetsAPI( + { sourceId, startTime, endTime }, + services.http.fetch + ); }, onResolve: ({ data: { datasets } }) => { setLogEntryCategoryDatasets(datasets); diff --git a/x-pack/plugins/infra/public/pages/logs/log_entry_categories/use_log_entry_category_examples.tsx b/x-pack/plugins/infra/public/pages/logs/log_entry_categories/use_log_entry_category_examples.tsx index cdf3b642a8012..84b9f045288cc 100644 --- a/x-pack/plugins/infra/public/pages/logs/log_entry_categories/use_log_entry_category_examples.tsx +++ b/x-pack/plugins/infra/public/pages/logs/log_entry_categories/use_log_entry_category_examples.tsx @@ -7,6 +7,7 @@ import { useMemo, useState } from 'react'; import { LogEntryCategoryExample } from '../../../../common/http_api'; +import { useKibanaContextForPlugin } from '../../../hooks/use_kibana'; import { useTrackedPromise } from '../../../utils/use_tracked_promise'; import { callGetLogEntryCategoryExamplesAPI } from './service_calls/get_log_entry_category_examples'; @@ -23,6 +24,8 @@ export const useLogEntryCategoryExamples = ({ sourceId: string; startTime: number; }) => { + const { services } = useKibanaContextForPlugin(); + const [logEntryCategoryExamples, setLogEntryCategoryExamples] = useState< LogEntryCategoryExample[] >([]); @@ -32,11 +35,14 @@ export const useLogEntryCategoryExamples = ({ cancelPreviousOn: 'creation', createPromise: async () => { return await callGetLogEntryCategoryExamplesAPI( - sourceId, - startTime, - endTime, - categoryId, - exampleCount + { + sourceId, + startTime, + endTime, + categoryId, + exampleCount, + }, + services.http.fetch ); }, onResolve: ({ data: { examples } }) => { diff --git a/x-pack/plugins/infra/public/pages/logs/log_entry_rate/service_calls/get_log_entry_anomalies.ts b/x-pack/plugins/infra/public/pages/logs/log_entry_rate/service_calls/get_log_entry_anomalies.ts index 21696df566ed9..7f90604bfefdd 100644 --- a/x-pack/plugins/infra/public/pages/logs/log_entry_rate/service_calls/get_log_entry_anomalies.ts +++ b/x-pack/plugins/infra/public/pages/logs/log_entry_rate/service_calls/get_log_entry_anomalies.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { npStart } from '../../../../legacy_singletons'; +import type { HttpHandler } from 'src/core/public'; import { getLogEntryAnomaliesRequestPayloadRT, getLogEntryAnomaliesSuccessReponsePayloadRT, @@ -13,15 +13,18 @@ import { import { decodeOrThrow } from '../../../../../common/runtime_types'; import { Sort, Pagination } from '../../../../../common/http_api/log_analysis'; -export const callGetLogEntryAnomaliesAPI = async ( - sourceId: string, - startTime: number, - endTime: number, - sort: Sort, - pagination: Pagination, - datasets?: string[] -) => { - const response = await npStart.http.fetch(LOG_ANALYSIS_GET_LOG_ENTRY_ANOMALIES_PATH, { +interface RequestArgs { + sourceId: string; + startTime: number; + endTime: number; + sort: Sort; + pagination: Pagination; + datasets?: string[]; +} + +export const callGetLogEntryAnomaliesAPI = async (requestArgs: RequestArgs, fetch: HttpHandler) => { + const { sourceId, startTime, endTime, sort, pagination, datasets } = requestArgs; + const response = await fetch(LOG_ANALYSIS_GET_LOG_ENTRY_ANOMALIES_PATH, { method: 'POST', body: JSON.stringify( getLogEntryAnomaliesRequestPayloadRT.encode({ diff --git a/x-pack/plugins/infra/public/pages/logs/log_entry_rate/service_calls/get_log_entry_anomalies_datasets.ts b/x-pack/plugins/infra/public/pages/logs/log_entry_rate/service_calls/get_log_entry_anomalies_datasets.ts index 24be5a646d103..c62bec691590c 100644 --- a/x-pack/plugins/infra/public/pages/logs/log_entry_rate/service_calls/get_log_entry_anomalies_datasets.ts +++ b/x-pack/plugins/infra/public/pages/logs/log_entry_rate/service_calls/get_log_entry_anomalies_datasets.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { npStart } from '../../../../legacy_singletons'; +import type { HttpHandler } from 'src/core/public'; import { decodeOrThrow } from '../../../../../common/runtime_types'; import { getLogEntryAnomaliesDatasetsRequestPayloadRT, @@ -12,12 +12,18 @@ import { LOG_ANALYSIS_GET_LOG_ENTRY_ANOMALIES_DATASETS_PATH, } from '../../../../../common/http_api/log_analysis'; +interface RequestArgs { + sourceId: string; + startTime: number; + endTime: number; +} + export const callGetLogEntryAnomaliesDatasetsAPI = async ( - sourceId: string, - startTime: number, - endTime: number + requestArgs: RequestArgs, + fetch: HttpHandler ) => { - const response = await npStart.http.fetch(LOG_ANALYSIS_GET_LOG_ENTRY_ANOMALIES_DATASETS_PATH, { + const { sourceId, startTime, endTime } = requestArgs; + const response = await fetch(LOG_ANALYSIS_GET_LOG_ENTRY_ANOMALIES_DATASETS_PATH, { method: 'POST', body: JSON.stringify( getLogEntryAnomaliesDatasetsRequestPayloadRT.encode({ diff --git a/x-pack/plugins/infra/public/pages/logs/log_entry_rate/service_calls/get_log_entry_examples.ts b/x-pack/plugins/infra/public/pages/logs/log_entry_rate/service_calls/get_log_entry_examples.ts index a125b53f9e635..ab724a2f435b2 100644 --- a/x-pack/plugins/infra/public/pages/logs/log_entry_rate/service_calls/get_log_entry_examples.ts +++ b/x-pack/plugins/infra/public/pages/logs/log_entry_rate/service_calls/get_log_entry_examples.ts @@ -4,27 +4,27 @@ * you may not use this file except in compliance with the Elastic License. */ -import { fold } from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { identity } from 'fp-ts/lib/function'; -import { npStart } from '../../../../legacy_singletons'; +import type { HttpHandler } from 'src/core/public'; import { getLogEntryExamplesRequestPayloadRT, getLogEntryExamplesSuccessReponsePayloadRT, LOG_ANALYSIS_GET_LOG_ENTRY_RATE_EXAMPLES_PATH, } from '../../../../../common/http_api/log_analysis'; -import { createPlainError, throwErrors } from '../../../../../common/runtime_types'; +import { decodeOrThrow } from '../../../../../common/runtime_types'; -export const callGetLogEntryExamplesAPI = async ( - sourceId: string, - startTime: number, - endTime: number, - dataset: string, - exampleCount: number, - categoryId?: string -) => { - const response = await npStart.http.fetch(LOG_ANALYSIS_GET_LOG_ENTRY_RATE_EXAMPLES_PATH, { +interface RequestArgs { + sourceId: string; + startTime: number; + endTime: number; + dataset: string; + exampleCount: number; + categoryId?: string; +} + +export const callGetLogEntryExamplesAPI = async (requestArgs: RequestArgs, fetch: HttpHandler) => { + const { sourceId, startTime, endTime, dataset, exampleCount, categoryId } = requestArgs; + const response = await fetch(LOG_ANALYSIS_GET_LOG_ENTRY_RATE_EXAMPLES_PATH, { method: 'POST', body: JSON.stringify( getLogEntryExamplesRequestPayloadRT.encode({ @@ -42,8 +42,5 @@ export const callGetLogEntryExamplesAPI = async ( ), }); - return pipe( - getLogEntryExamplesSuccessReponsePayloadRT.decode(response), - fold(throwErrors(createPlainError), identity) - ); + return decodeOrThrow(getLogEntryExamplesSuccessReponsePayloadRT)(response); }; diff --git a/x-pack/plugins/infra/public/pages/logs/log_entry_rate/service_calls/get_log_entry_rate.ts b/x-pack/plugins/infra/public/pages/logs/log_entry_rate/service_calls/get_log_entry_rate.ts index 77111d279309d..c9189bd803955 100644 --- a/x-pack/plugins/infra/public/pages/logs/log_entry_rate/service_calls/get_log_entry_rate.ts +++ b/x-pack/plugins/infra/public/pages/logs/log_entry_rate/service_calls/get_log_entry_rate.ts @@ -4,25 +4,25 @@ * you may not use this file except in compliance with the Elastic License. */ -import { fold } from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { identity } from 'fp-ts/lib/function'; -import { npStart } from '../../../../legacy_singletons'; +import type { HttpHandler } from 'src/core/public'; import { getLogEntryRateRequestPayloadRT, getLogEntryRateSuccessReponsePayloadRT, LOG_ANALYSIS_GET_LOG_ENTRY_RATE_PATH, } from '../../../../../common/http_api/log_analysis'; -import { createPlainError, throwErrors } from '../../../../../common/runtime_types'; +import { decodeOrThrow } from '../../../../../common/runtime_types'; -export const callGetLogEntryRateAPI = async ( - sourceId: string, - startTime: number, - endTime: number, - bucketDuration: number, - datasets?: string[] -) => { - const response = await npStart.http.fetch(LOG_ANALYSIS_GET_LOG_ENTRY_RATE_PATH, { +interface RequestArgs { + sourceId: string; + startTime: number; + endTime: number; + bucketDuration: number; + datasets?: string[]; +} + +export const callGetLogEntryRateAPI = async (requestArgs: RequestArgs, fetch: HttpHandler) => { + const { sourceId, startTime, endTime, bucketDuration, datasets } = requestArgs; + const response = await fetch(LOG_ANALYSIS_GET_LOG_ENTRY_RATE_PATH, { method: 'POST', body: JSON.stringify( getLogEntryRateRequestPayloadRT.encode({ @@ -38,8 +38,5 @@ export const callGetLogEntryRateAPI = async ( }) ), }); - return pipe( - getLogEntryRateSuccessReponsePayloadRT.decode(response), - fold(throwErrors(createPlainError), identity) - ); + return decodeOrThrow(getLogEntryRateSuccessReponsePayloadRT)(response); }; diff --git a/x-pack/plugins/infra/public/pages/logs/log_entry_rate/use_log_entry_anomalies_results.ts b/x-pack/plugins/infra/public/pages/logs/log_entry_rate/use_log_entry_anomalies_results.ts index 52632e54390a9..37c99272f0872 100644 --- a/x-pack/plugins/infra/public/pages/logs/log_entry_rate/use_log_entry_anomalies_results.ts +++ b/x-pack/plugins/infra/public/pages/logs/log_entry_rate/use_log_entry_anomalies_results.ts @@ -16,6 +16,7 @@ import { GetLogEntryAnomaliesDatasetsSuccessResponsePayload, LogEntryAnomaly, } from '../../../../common/http_api/log_analysis'; +import { useKibanaContextForPlugin } from '../../../hooks/use_kibana'; export type SortOptions = Sort; export type PaginationOptions = Pick; @@ -161,6 +162,8 @@ export const useLogEntryAnomaliesResults = ({ }; }; + const { services } = useKibanaContextForPlugin(); + const [reducerState, dispatch] = useReducer(stateReducer, STATE_DEFAULTS, initStateReducer); const [logEntryAnomalies, setLogEntryAnomalies] = useState([]); @@ -177,15 +180,18 @@ export const useLogEntryAnomaliesResults = ({ filteredDatasets: queryFilteredDatasets, } = reducerState; return await callGetLogEntryAnomaliesAPI( - sourceId, - queryStartTime, - queryEndTime, - sortOptions, { - ...paginationOptions, - cursor: paginationCursor, + sourceId, + startTime: queryStartTime, + endTime: queryEndTime, + sort: sortOptions, + pagination: { + ...paginationOptions, + cursor: paginationCursor, + }, + datasets: queryFilteredDatasets, }, - queryFilteredDatasets + services.http.fetch ); }, onResolve: ({ data: { anomalies, paginationCursors: requestCursors, hasMoreEntries } }) => { @@ -286,7 +292,10 @@ export const useLogEntryAnomaliesResults = ({ { cancelPreviousOn: 'creation', createPromise: async () => { - return await callGetLogEntryAnomaliesDatasetsAPI(sourceId, startTime, endTime); + return await callGetLogEntryAnomaliesDatasetsAPI( + { sourceId, startTime, endTime }, + services.http.fetch + ); }, onResolve: ({ data: { datasets } }) => { setLogEntryAnomaliesDatasets(datasets); diff --git a/x-pack/plugins/infra/public/pages/logs/log_entry_rate/use_log_entry_examples.ts b/x-pack/plugins/infra/public/pages/logs/log_entry_rate/use_log_entry_examples.ts index fae5bd200a415..e809ab9cd5a6f 100644 --- a/x-pack/plugins/infra/public/pages/logs/log_entry_rate/use_log_entry_examples.ts +++ b/x-pack/plugins/infra/public/pages/logs/log_entry_rate/use_log_entry_examples.ts @@ -7,6 +7,7 @@ import { useMemo, useState } from 'react'; import { LogEntryExample } from '../../../../common/http_api'; +import { useKibanaContextForPlugin } from '../../../hooks/use_kibana'; import { useTrackedPromise } from '../../../utils/use_tracked_promise'; import { callGetLogEntryExamplesAPI } from './service_calls/get_log_entry_examples'; @@ -25,6 +26,7 @@ export const useLogEntryExamples = ({ startTime: number; categoryId?: string; }) => { + const { services } = useKibanaContextForPlugin(); const [logEntryExamples, setLogEntryExamples] = useState([]); const [getLogEntryExamplesRequest, getLogEntryExamples] = useTrackedPromise( @@ -32,12 +34,15 @@ export const useLogEntryExamples = ({ cancelPreviousOn: 'creation', createPromise: async () => { return await callGetLogEntryExamplesAPI( - sourceId, - startTime, - endTime, - dataset, - exampleCount, - categoryId + { + sourceId, + startTime, + endTime, + dataset, + exampleCount, + categoryId, + }, + services.http.fetch ); }, onResolve: ({ data: { examples } }) => { diff --git a/x-pack/plugins/infra/public/pages/logs/log_entry_rate/use_log_entry_rate_results.ts b/x-pack/plugins/infra/public/pages/logs/log_entry_rate/use_log_entry_rate_results.ts index a52dab58cb018..aef94afa505f1 100644 --- a/x-pack/plugins/infra/public/pages/logs/log_entry_rate/use_log_entry_rate_results.ts +++ b/x-pack/plugins/infra/public/pages/logs/log_entry_rate/use_log_entry_rate_results.ts @@ -12,6 +12,7 @@ import { LogEntryRatePartition, LogEntryRateAnomaly, } from '../../../../common/http_api/log_analysis'; +import { useKibanaContextForPlugin } from '../../../hooks/use_kibana'; import { useTrackedPromise } from '../../../utils/use_tracked_promise'; import { callGetLogEntryRateAPI } from './service_calls/get_log_entry_rate'; @@ -49,6 +50,7 @@ export const useLogEntryRateResults = ({ bucketDuration: number; filteredDatasets?: string[]; }) => { + const { services } = useKibanaContextForPlugin(); const [logEntryRate, setLogEntryRate] = useState(null); const [getLogEntryRateRequest, getLogEntryRate] = useTrackedPromise( @@ -56,11 +58,14 @@ export const useLogEntryRateResults = ({ cancelPreviousOn: 'resolution', createPromise: async () => { return await callGetLogEntryRateAPI( - sourceId, - startTime, - endTime, - bucketDuration, - filteredDatasets + { + sourceId, + startTime, + endTime, + bucketDuration, + datasets: filteredDatasets, + }, + services.http.fetch ); }, onResolve: ({ data }) => { diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/hooks/use_metrics_hosts_anomalies.ts b/x-pack/plugins/infra/public/pages/metrics/inventory_view/hooks/use_metrics_hosts_anomalies.ts index f33e3ea16b389..02170f41a32ca 100644 --- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/hooks/use_metrics_hosts_anomalies.ts +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/hooks/use_metrics_hosts_anomalies.ts @@ -5,6 +5,7 @@ */ import { useMemo, useState, useCallback, useEffect, useReducer } from 'react'; +import { HttpHandler } from 'src/core/public'; import { INFA_ML_GET_METRICS_HOSTS_ANOMALIES_PATH, Metric, @@ -16,8 +17,8 @@ import { getMetricsHostsAnomaliesSuccessReponsePayloadRT, } from '../../../../../common/http_api/infra_ml'; import { useTrackedPromise } from '../../../../utils/use_tracked_promise'; -import { npStart } from '../../../../legacy_singletons'; import { decodeOrThrow } from '../../../../../common/runtime_types'; +import { useKibanaContextForPlugin } from '../../../../hooks/use_kibana'; export type SortOptions = Sort; export type PaginationOptions = Pick; @@ -149,6 +150,7 @@ export const useMetricsHostsAnomaliesResults = ({ onGetMetricsHostsAnomaliesDatasetsError?: (error: Error) => void; filteredDatasets?: string[]; }) => { + const { services } = useKibanaContextForPlugin(); const initStateReducer = (stateDefaults: ReducerStateDefaults): ReducerState => { return { ...stateDefaults, @@ -177,15 +179,18 @@ export const useMetricsHostsAnomaliesResults = ({ paginationCursor, } = reducerState; return await callGetMetricHostsAnomaliesAPI( - sourceId, - queryStartTime, - queryEndTime, - metric, - sortOptions, { - ...paginationOptions, - cursor: paginationCursor, - } + sourceId, + startTime: queryStartTime, + endTime: queryEndTime, + metric, + sort: sortOptions, + pagination: { + ...paginationOptions, + cursor: paginationCursor, + }, + }, + services.http.fetch ); }, onResolve: ({ data: { anomalies, paginationCursors: requestCursors, hasMoreEntries } }) => { @@ -288,15 +293,21 @@ export const useMetricsHostsAnomaliesResults = ({ }; }; +interface RequestArgs { + sourceId: string; + startTime: number; + endTime: number; + metric: Metric; + sort: Sort; + pagination: Pagination; +} + export const callGetMetricHostsAnomaliesAPI = async ( - sourceId: string, - startTime: number, - endTime: number, - metric: Metric, - sort: Sort, - pagination: Pagination + requestArgs: RequestArgs, + fetch: HttpHandler ) => { - const response = await npStart.http.fetch(INFA_ML_GET_METRICS_HOSTS_ANOMALIES_PATH, { + const { sourceId, startTime, endTime, metric, sort, pagination } = requestArgs; + const response = await fetch(INFA_ML_GET_METRICS_HOSTS_ANOMALIES_PATH, { method: 'POST', body: JSON.stringify( getMetricsHostsAnomaliesRequestPayloadRT.encode({ diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/hooks/use_metrics_k8s_anomalies.ts b/x-pack/plugins/infra/public/pages/metrics/inventory_view/hooks/use_metrics_k8s_anomalies.ts index 89e70c4c5c4c7..951951b9b6106 100644 --- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/hooks/use_metrics_k8s_anomalies.ts +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/hooks/use_metrics_k8s_anomalies.ts @@ -5,6 +5,7 @@ */ import { useMemo, useState, useCallback, useEffect, useReducer } from 'react'; +import { HttpHandler } from 'src/core/public'; import { Sort, Pagination, @@ -16,8 +17,8 @@ import { Metric, } from '../../../../../common/http_api/infra_ml'; import { useTrackedPromise } from '../../../../utils/use_tracked_promise'; -import { npStart } from '../../../../legacy_singletons'; import { decodeOrThrow } from '../../../../../common/runtime_types'; +import { useKibanaContextForPlugin } from '../../../../hooks/use_kibana'; export type SortOptions = Sort; export type PaginationOptions = Pick; @@ -149,6 +150,7 @@ export const useMetricsK8sAnomaliesResults = ({ onGetMetricsHostsAnomaliesDatasetsError?: (error: Error) => void; filteredDatasets?: string[]; }) => { + const { services } = useKibanaContextForPlugin(); const initStateReducer = (stateDefaults: ReducerStateDefaults): ReducerState => { return { ...stateDefaults, @@ -178,16 +180,19 @@ export const useMetricsK8sAnomaliesResults = ({ filteredDatasets: queryFilteredDatasets, } = reducerState; return await callGetMetricsK8sAnomaliesAPI( - sourceId, - queryStartTime, - queryEndTime, - metric, - sortOptions, { - ...paginationOptions, - cursor: paginationCursor, + sourceId, + startTime: queryStartTime, + endTime: queryEndTime, + metric, + sort: sortOptions, + pagination: { + ...paginationOptions, + cursor: paginationCursor, + }, + datasets: queryFilteredDatasets, }, - queryFilteredDatasets + services.http.fetch ); }, onResolve: ({ data: { anomalies, paginationCursors: requestCursors, hasMoreEntries } }) => { @@ -290,16 +295,22 @@ export const useMetricsK8sAnomaliesResults = ({ }; }; +interface RequestArgs { + sourceId: string; + startTime: number; + endTime: number; + metric: Metric; + sort: Sort; + pagination: Pagination; + datasets?: string[]; +} + export const callGetMetricsK8sAnomaliesAPI = async ( - sourceId: string, - startTime: number, - endTime: number, - metric: Metric, - sort: Sort, - pagination: Pagination, - datasets?: string[] + requestArgs: RequestArgs, + fetch: HttpHandler ) => { - const response = await npStart.http.fetch(INFA_ML_GET_METRICS_K8S_ANOMALIES_PATH, { + const { sourceId, startTime, endTime, metric, sort, pagination, datasets } = requestArgs; + const response = await fetch(INFA_ML_GET_METRICS_K8S_ANOMALIES_PATH, { method: 'POST', body: JSON.stringify( getMetricsK8sAnomaliesRequestPayloadRT.encode({ diff --git a/x-pack/plugins/infra/public/plugin.ts b/x-pack/plugins/infra/public/plugin.ts index 3c6b1a14cfd47..0e49ca93010fd 100644 --- a/x-pack/plugins/infra/public/plugin.ts +++ b/x-pack/plugins/infra/public/plugin.ts @@ -9,7 +9,6 @@ import { DEFAULT_APP_CATEGORIES } from '../../../../src/core/public'; import { createMetricThresholdAlertType } from './alerting/metric_threshold'; import { createInventoryMetricAlertType } from './alerting/inventory'; import { getAlertType as getLogsAlertType } from './alerting/log_threshold'; -import { registerStartSingleton } from './legacy_singletons'; import { registerFeatures } from './register_feature'; import { InfraClientSetupDeps, @@ -98,9 +97,7 @@ export class Plugin implements InfraClientPluginClass { }); } - start(core: InfraClientCoreStart, _plugins: InfraClientStartDeps) { - registerStartSingleton(core); - } + start(_core: InfraClientCoreStart, _plugins: InfraClientStartDeps) {} stop() {} } From e9fd3902c5a503083fa629e787d7deff1fc7a3bd Mon Sep 17 00:00:00 2001 From: Nick Partridge Date: Fri, 2 Oct 2020 12:48:40 -0500 Subject: [PATCH 50/50] upgrade @elastic/charts to v23.0.0 (#79226) Co-authored-by: Elastic Machine --- package.json | 2 +- packages/kbn-ui-shared-deps/package.json | 2 +- .../lens/public/xy_visualization/expression.test.tsx | 2 +- yarn.lock | 8 ++++---- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index ff98d7f85dcef..5089e6e1a140d 100644 --- a/package.json +++ b/package.json @@ -230,7 +230,7 @@ "@babel/parser": "^7.11.2", "@babel/types": "^7.11.0", "@elastic/apm-rum": "^5.6.1", - "@elastic/charts": "21.1.2", + "@elastic/charts": "23.0.0", "@elastic/ems-client": "7.10.0", "@elastic/eslint-config-kibana": "0.15.0", "@elastic/eslint-plugin-eui": "0.0.2", diff --git a/packages/kbn-ui-shared-deps/package.json b/packages/kbn-ui-shared-deps/package.json index 278e8efd2d29e..e5f1a06e5bffa 100644 --- a/packages/kbn-ui-shared-deps/package.json +++ b/packages/kbn-ui-shared-deps/package.json @@ -9,7 +9,7 @@ "kbn:watch": "node scripts/build --dev --watch" }, "dependencies": { - "@elastic/charts": "21.1.2", + "@elastic/charts": "23.0.0", "@elastic/eui": "29.0.0", "@elastic/numeral": "^2.5.0", "@kbn/i18n": "1.0.0", diff --git a/x-pack/plugins/lens/public/xy_visualization/expression.test.tsx b/x-pack/plugins/lens/public/xy_visualization/expression.test.tsx index 5fc89d831a961..405491ddc372a 100644 --- a/x-pack/plugins/lens/public/xy_visualization/expression.test.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/expression.test.tsx @@ -751,7 +751,7 @@ describe('xy_expression', () => { }); test('onElementClick returns correct context data', () => { - const geometry: GeometryValue = { x: 5, y: 1, accessor: 'y1', mark: null }; + const geometry: GeometryValue = { x: 5, y: 1, accessor: 'y1', mark: null, datum: {} }; const series = { key: 'spec{d}yAccessor{d}splitAccessors{b-2}', specId: 'd', diff --git a/yarn.lock b/yarn.lock index 2d72b6d6c3bb6..971a94bfe56c3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1218,10 +1218,10 @@ dependencies: "@elastic/apm-rum-core" "^5.7.0" -"@elastic/charts@21.1.2": - version "21.1.2" - resolved "https://registry.yarnpkg.com/@elastic/charts/-/charts-21.1.2.tgz#da7e9c1025bf730a738b6ac6d7024d97dd2b5aa2" - integrity sha512-Uri+Xolgii7/mRSarfXTfA6X2JC76ILIxTPO8RlYdI44gzprJfUO7Aw5s8vVQke3x6Cu39a+9B0s6TY4GAaApQ== +"@elastic/charts@23.0.0": + version "23.0.0" + resolved "https://registry.yarnpkg.com/@elastic/charts/-/charts-23.0.0.tgz#6152f5ef0e31b2d7d7a5c95a2f7baba0f4296c18" + integrity sha512-FUZ72mzkIVYubtZMPA1bT7rrua1X2ZnsdzO+qRwR81QLfUYM6ht3WLaffVAUT1y6eXmnXFs+d88U7jlsontN6w== dependencies: "@popperjs/core" "^2.4.0" chroma-js "^2.1.0"

    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 delta 141962 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 Faeoz-^Tc-np@l{rI`dzuB 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 delta 37775 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 From 8406e04a427983ee6d6e93300fc96a5f3a6e0c45 Mon Sep 17 00:00:00 2001 From: Shahzad Date: Thu, 1 Oct 2020 22:49:31 +0200 Subject: [PATCH 15/50] Fix long tasks query (#79099) --- .../__snapshots__/queries.test.ts.snap | 50 +++++--- .../lib/rum_client/get_long_task_metrics.ts | 121 ++++++------------ .../projections/rum_page_load_transactions.ts | 28 ---- .../plugins/apm/server/routes/rum_client.ts | 3 +- .../trial/tests/csm/long_task_metrics.ts | 6 +- 5 files changed, 77 insertions(+), 131 deletions(-) diff --git a/x-pack/plugins/apm/server/lib/rum_client/__snapshots__/queries.test.ts.snap b/x-pack/plugins/apm/server/lib/rum_client/__snapshots__/queries.test.ts.snap index 1c724efac37b2..dcafe09221164 100644 --- a/x-pack/plugins/apm/server/lib/rum_client/__snapshots__/queries.test.ts.snap +++ b/x-pack/plugins/apm/server/lib/rum_client/__snapshots__/queries.test.ts.snap @@ -167,27 +167,42 @@ exports[`rum client dashboard queries fetches long task metrics 1`] = ` Object { "apm": Object { "events": Array [ - "span", + "transaction", ], }, "body": Object { "aggs": Object { - "transIds": Object { - "aggs": Object { - "longestLongTask": Object { - "max": Object { - "field": "span.duration.us", - }, + "longTaskCount": Object { + "percentiles": Object { + "field": "transaction.experience.longtask.count", + "hdr": Object { + "number_of_significant_value_digits": 3, }, - "sumLongTask": Object { - "sum": Object { - "field": "span.duration.us", - }, + "percents": Array [ + 50, + ], + }, + }, + "longTaskMax": Object { + "percentiles": Object { + "field": "transaction.experience.longtask.max", + "hdr": Object { + "number_of_significant_value_digits": 3, }, + "percents": Array [ + 50, + ], }, - "terms": Object { - "field": "transaction.id", - "size": 1000, + }, + "longTaskSum": Object { + "percentiles": Object { + "field": "transaction.experience.longtask.sum", + "hdr": Object { + "number_of_significant_value_digits": 3, + }, + "percents": Array [ + 50, + ], }, }, }, @@ -205,7 +220,12 @@ Object { }, Object { "term": Object { - "span.type": "longtask", + "transaction.type": "page-load", + }, + }, + Object { + "exists": Object { + "field": "transaction.marks.navigationTiming.fetchStart", }, }, Object { diff --git a/x-pack/plugins/apm/server/lib/rum_client/get_long_task_metrics.ts b/x-pack/plugins/apm/server/lib/rum_client/get_long_task_metrics.ts index bd4bdb9ca3536..c2c86ae05d57c 100644 --- a/x-pack/plugins/apm/server/lib/rum_client/get_long_task_metrics.ts +++ b/x-pack/plugins/apm/server/lib/rum_client/get_long_task_metrics.ts @@ -4,51 +4,60 @@ * you may not use this file except in compliance with the Elastic License. */ -import { - getRumLongTasksProjection, - getRumPageLoadTransactionsProjection, -} from '../../projections/rum_page_load_transactions'; +import { getRumPageLoadTransactionsProjection } from '../../projections/rum_page_load_transactions'; import { mergeProjection } from '../../projections/util/merge_projection'; import { Setup, SetupTimeRange, SetupUIFilters, } from '../helpers/setup_request'; -import { - SPAN_DURATION, - TRANSACTION_ID, -} from '../../../common/elasticsearch_fieldnames'; + +const LONG_TASK_SUM_FIELD = 'transaction.experience.longtask.sum'; +const LONG_TASK_COUNT_FIELD = 'transaction.experience.longtask.count'; +const LONG_TASK_MAX_FIELD = 'transaction.experience.longtask.max'; export async function getLongTaskMetrics({ setup, urlQuery, + percentile = 50, }: { setup: Setup & SetupTimeRange & SetupUIFilters; urlQuery?: string; + percentile?: number; }) { - const projection = getRumLongTasksProjection({ + const projection = getRumPageLoadTransactionsProjection({ setup, + urlQuery, }); const params = mergeProjection(projection, { body: { size: 0, aggs: { - transIds: { - terms: { - field: 'transaction.id', - size: 1000, + longTaskSum: { + percentiles: { + field: LONG_TASK_SUM_FIELD, + percents: [percentile], + hdr: { + number_of_significant_value_digits: 3, + }, }, - aggs: { - sumLongTask: { - sum: { - field: SPAN_DURATION, - }, + }, + longTaskCount: { + percentiles: { + field: LONG_TASK_COUNT_FIELD, + percents: [percentile], + hdr: { + number_of_significant_value_digits: 3, }, - longestLongTask: { - max: { - field: SPAN_DURATION, - }, + }, + }, + longTaskMax: { + percentiles: { + field: LONG_TASK_MAX_FIELD, + percents: [percentile], + hdr: { + number_of_significant_value_digits: 3, }, }, }, @@ -59,71 +68,15 @@ export async function getLongTaskMetrics({ const { apmEventClient } = setup; const response = await apmEventClient.search(params); - const { transIds } = response.aggregations ?? {}; - const validTransactions: string[] = await filterPageLoadTransactions({ - setup, - urlQuery, - transactionIds: (transIds?.buckets ?? []).map( - (bucket) => bucket.key as string - ), - }); - let noOfLongTasks = 0; - let sumOfLongTasks = 0; - let longestLongTask = 0; + const pkey = percentile.toFixed(1); - (transIds?.buckets ?? []).forEach((bucket) => { - if (validTransactions.includes(bucket.key as string)) { - noOfLongTasks += bucket.doc_count; - sumOfLongTasks += bucket.sumLongTask.value ?? 0; - if ((bucket.longestLongTask.value ?? 0) > longestLongTask) { - longestLongTask = bucket.longestLongTask.value!; - } - } - }); + const { longTaskSum, longTaskCount, longTaskMax } = + response.aggregations ?? {}; return { - noOfLongTasks, - sumOfLongTasks, - longestLongTask, + noOfLongTasks: longTaskCount?.values[pkey] ?? 0, + sumOfLongTasks: longTaskSum?.values[pkey] ?? 0, + longestLongTask: longTaskMax?.values[pkey] ?? 0, }; } - -async function filterPageLoadTransactions({ - setup, - urlQuery, - transactionIds, -}: { - setup: Setup & SetupTimeRange & SetupUIFilters; - urlQuery?: string; - transactionIds: string[]; -}) { - const projection = getRumPageLoadTransactionsProjection({ - setup, - urlQuery, - }); - - const params = mergeProjection(projection, { - body: { - size: transactionIds.length, - query: { - bool: { - must: [ - { - terms: { - [TRANSACTION_ID]: transactionIds, - }, - }, - ], - filter: [...projection.body.query.bool.filter], - }, - }, - _source: [TRANSACTION_ID], - }, - }); - - const { apmEventClient } = setup; - - const response = await apmEventClient.search(params); - return response.hits.hits.map((hit) => (hit._source as any).transaction.id)!; -} diff --git a/x-pack/plugins/apm/server/projections/rum_page_load_transactions.ts b/x-pack/plugins/apm/server/projections/rum_page_load_transactions.ts index a8505337e8aec..c27314923f6bd 100644 --- a/x-pack/plugins/apm/server/projections/rum_page_load_transactions.ts +++ b/x-pack/plugins/apm/server/projections/rum_page_load_transactions.ts @@ -10,7 +10,6 @@ import { SetupUIFilters, } from '../../server/lib/helpers/setup_request'; import { - SPAN_TYPE, AGENT_NAME, TRANSACTION_TYPE, SERVICE_LANGUAGE_NAME, @@ -66,33 +65,6 @@ export function getRumPageLoadTransactionsProjection({ }; } -export function getRumLongTasksProjection({ - setup, -}: { - setup: Setup & SetupTimeRange & SetupUIFilters; -}) { - const { start, end, uiFiltersES } = setup; - - const bool = { - filter: [ - { range: rangeFilter(start, end) }, - { term: { [SPAN_TYPE]: 'longtask' } }, - ...uiFiltersES, - ], - }; - - return { - apm: { - events: [ProcessorEvent.span], - }, - body: { - query: { - bool, - }, - }, - }; -} - export function getRumErrorsProjection({ setup, }: { diff --git a/x-pack/plugins/apm/server/routes/rum_client.ts b/x-pack/plugins/apm/server/routes/rum_client.ts index 2bdfaa1421eea..8dee8b759df26 100644 --- a/x-pack/plugins/apm/server/routes/rum_client.ts +++ b/x-pack/plugins/apm/server/routes/rum_client.ts @@ -177,12 +177,13 @@ export const rumLongTaskMetrics = createRoute(() => ({ const setup = await setupRequest(context, request); const { - query: { urlQuery }, + query: { urlQuery, percentile }, } = context.params; return getLongTaskMetrics({ setup, urlQuery, + percentile: percentile ? Number(percentile) : undefined, }); }, })); diff --git a/x-pack/test/apm_api_integration/trial/tests/csm/long_task_metrics.ts b/x-pack/test/apm_api_integration/trial/tests/csm/long_task_metrics.ts index 425268264612f..518c4ef8a81a7 100644 --- a/x-pack/test/apm_api_integration/trial/tests/csm/long_task_metrics.ts +++ b/x-pack/test/apm_api_integration/trial/tests/csm/long_task_metrics.ts @@ -47,9 +47,9 @@ export default function rumServicesApiTests({ getService }: FtrProviderContext) expectSnapshot(response.body).toMatchInline(` Object { - "longestLongTask": 109000, - "noOfLongTasks": 2, - "sumOfLongTasks": 168000, + "longestLongTask": 0, + "noOfLongTasks": 0, + "sumOfLongTasks": 0, } `); }); From 63ff0606df1d35978049ff9aa25f04c46be895f8 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Thu, 1 Oct 2020 13:57:28 -0700 Subject: [PATCH 16/50] Extended Email action configuration with hasAuth property to identify if the connector require user credentials. Improved UX for Email connector (#78235) * Extended Email action configuration with hasAuth property to identify if the connector require user credentials. Improved UX for Email connector * Fixed failing tests and comments * Fixed type check and reverted logic of Add user and password switch button * Fixed due to the latest design requirenments * Fixed due to review comments --- .../server/builtin_action_types/email.test.ts | 7 + .../server/builtin_action_types/email.ts | 2 + .../lib/send_email.test.ts | 35 +++- .../builtin_action_types/lib/send_email.ts | 5 +- .../server/saved_objects/migrations.test.ts | 30 ++++ .../server/saved_objects/migrations.ts | 91 +++++++--- .../builtin_action_types/email/email.test.tsx | 5 + .../builtin_action_types/email/email.tsx | 20 +++ .../email/email_connector.test.tsx | 32 ++++ .../email/email_connector.tsx | 161 ++++++++++++------ .../components/builtin_action_types/types.ts | 1 + .../action_connector_form.tsx | 52 +++--- .../actions/builtin_action_types/email.ts | 3 + 13 files changed, 345 insertions(+), 99 deletions(-) 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 7147483998d98..132510ea0ce84 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 @@ -55,6 +55,7 @@ describe('config validation', () => { const config: Record = { service: 'gmail', from: 'bob@example.com', + hasAuth: true, }; expect(validateConfig(actionType, config)).toEqual({ ...config, @@ -66,6 +67,7 @@ describe('config validation', () => { delete config.service; config.host = 'elastic.co'; config.port = 8080; + config.hasAuth = true; expect(validateConfig(actionType, config)).toEqual({ ...config, service: null, @@ -233,6 +235,7 @@ describe('execute()', () => { port: 42, secure: true, from: 'bob@example.com', + hasAuth: true, }; const secrets: ActionTypeSecretsType = { user: 'bob', @@ -269,6 +272,7 @@ describe('execute()', () => { "message": "a message to you", "subject": "the subject", }, + "hasAuth": true, "proxySettings": undefined, "routing": Object { "bcc": Array [ @@ -298,6 +302,7 @@ describe('execute()', () => { port: 42, secure: true, from: 'bob@example.com', + hasAuth: false, }; const secrets: ActionTypeSecretsType = { user: null, @@ -327,6 +332,7 @@ describe('execute()', () => { "message": "a message to you", "subject": "the subject", }, + "hasAuth": false, "proxySettings": undefined, "routing": Object { "bcc": Array [ @@ -356,6 +362,7 @@ describe('execute()', () => { port: 42, secure: true, from: 'bob@example.com', + hasAuth: false, }; const secrets: ActionTypeSecretsType = { user: null, diff --git a/x-pack/plugins/actions/server/builtin_action_types/email.ts b/x-pack/plugins/actions/server/builtin_action_types/email.ts index 6fd2d694b06f7..be2664887d943 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/email.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/email.ts @@ -36,6 +36,7 @@ const ConfigSchemaProps = { port: schema.nullable(portSchema()), secure: schema.nullable(schema.boolean()), from: schema.string(), + hasAuth: schema.boolean({ defaultValue: true }), }; const ConfigSchema = schema.object(ConfigSchemaProps); @@ -185,6 +186,7 @@ async function executor( message: params.message, }, proxySettings: execOptions.proxySettings, + hasAuth: config.hasAuth, }; let result; 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 b6c4a4ea882e5..a1c4041628bd5 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 @@ -64,7 +64,7 @@ describe('send_email module', () => { }); test('handles unauthenticated email using not secure host/port', async () => { - const sendEmailOptions = getSendEmailOptions( + const sendEmailOptions = getSendEmailOptionsNoAuth( { transport: { host: 'example.com', @@ -76,12 +76,7 @@ describe('send_email module', () => { proxyRejectUnauthorizedCertificates: false, } ); - // @ts-expect-error - delete sendEmailOptions.transport.service; - // @ts-expect-error - delete sendEmailOptions.transport.user; - // @ts-expect-error - delete sendEmailOptions.transport.password; + const result = await sendEmail(mockLogger, sendEmailOptions); expect(result).toBe(sendMailMockResult); expect(createTransportMock.mock.calls[0]).toMatchInlineSnapshot(` @@ -248,5 +243,31 @@ function getSendEmailOptions( password: 'changeme', }, proxySettings, + hasAuth: true, + }; +} + +function getSendEmailOptionsNoAuth( + { content = {}, routing = {}, transport = {} } = {}, + proxySettings?: ProxySettings +) { + return { + content: { + ...content, + message: 'a message', + subject: 'a subject', + }, + routing: { + ...routing, + from: 'fred@example.com', + to: ['jim@example.com'], + cc: ['bob@example.com', 'robert@example.com'], + bcc: [], + }, + transport: { + ...transport, + }, + proxySettings, + hasAuth: false, }; } 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 dead8fee63d4f..f3cdf82bfe8cd 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 @@ -20,6 +20,7 @@ export interface SendEmailOptions { content: Content; proxySettings?: ProxySettings; rejectUnauthorized?: boolean; + hasAuth: boolean; } // config validation ensures either service is set or host/port are set @@ -46,14 +47,14 @@ export interface Content { // send an email export async function sendEmail(logger: Logger, options: SendEmailOptions): Promise { - const { transport, routing, content, proxySettings, rejectUnauthorized } = options; + const { transport, routing, content, proxySettings, rejectUnauthorized, hasAuth } = options; const { service, host, port, secure, user, password } = transport; const { from, to, cc, bcc } = routing; const { subject, message } = content; const transportConfig: Record = {}; - if (user != null && password != null) { + if (hasAuth && user != null && password != null) { transportConfig.auth = { user, pass: password, diff --git a/x-pack/plugins/actions/server/saved_objects/migrations.test.ts b/x-pack/plugins/actions/server/saved_objects/migrations.test.ts index d577f0c8bbc6c..1fa5889e77cb0 100644 --- a/x-pack/plugins/actions/server/saved_objects/migrations.test.ts +++ b/x-pack/plugins/actions/server/saved_objects/migrations.test.ts @@ -21,6 +21,20 @@ describe('7.10.0', () => { ); }); + test('add hasAuth config property for .email actions', () => { + const migration710 = getMigrations(encryptedSavedObjectsSetup)['7.10.0']; + const action = getMockDataForEmail({}); + expect(migration710(action, context)).toMatchObject({ + ...action, + attributes: { + ...action.attributes, + config: { + hasAuth: true, + }, + }, + }); + }); + test('rename cases configuration object', () => { const migration710 = getMigrations(encryptedSavedObjectsSetup)['7.10.0']; const action = getMockData({}); @@ -36,6 +50,22 @@ describe('7.10.0', () => { }); }); +function getMockDataForEmail( + overwrites: Record = {} +): SavedObjectUnsanitizedDoc { + return { + attributes: { + name: 'abc', + actionTypeId: '.email', + config: {}, + secrets: { user: 'test', password: '123' }, + ...overwrites, + }, + id: uuid.v4(), + type: 'action', + }; +} + function getMockData( overwrites: Record = {} ): SavedObjectUnsanitizedDoc { diff --git a/x-pack/plugins/actions/server/saved_objects/migrations.ts b/x-pack/plugins/actions/server/saved_objects/migrations.ts index 0006d88c44149..993beef8d9b2b 100644 --- a/x-pack/plugins/actions/server/saved_objects/migrations.ts +++ b/x-pack/plugins/actions/server/saved_objects/migrations.ts @@ -3,40 +3,87 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ - import { SavedObjectMigrationMap, SavedObjectUnsanitizedDoc, SavedObjectMigrationFn, + SavedObjectMigrationContext, } from '../../../../../src/core/server'; import { RawAction } from '../types'; import { EncryptedSavedObjectsPluginSetup } from '../../../encrypted_saved_objects/server'; +type ActionMigration = ( + doc: SavedObjectUnsanitizedDoc +) => SavedObjectUnsanitizedDoc; + export function getMigrations( encryptedSavedObjects: EncryptedSavedObjectsPluginSetup ): SavedObjectMigrationMap { - return { '7.10.0': renameCasesConfigurationObject(encryptedSavedObjects) }; + const migrationActions = encryptedSavedObjects.createMigration( + (doc): doc is SavedObjectUnsanitizedDoc => + !!doc.attributes.config?.casesConfiguration || doc.attributes.actionTypeId === '.email', + pipeMigrations(renameCasesConfigurationObject, addHasAuthConfigurationObject) + ); + + return { + '7.10.0': executeMigrationWithErrorHandling(migrationActions, '7.10.0'), + }; } -const renameCasesConfigurationObject = ( - encryptedSavedObjects: EncryptedSavedObjectsPluginSetup -): SavedObjectMigrationFn => { - return encryptedSavedObjects.createMigration( - (doc): doc is SavedObjectUnsanitizedDoc => - !!doc.attributes.config?.casesConfiguration, - (doc: SavedObjectUnsanitizedDoc): SavedObjectUnsanitizedDoc => { - const { casesConfiguration, ...restConfiguration } = doc.attributes.config; - - return { - ...doc, - attributes: { - ...doc.attributes, - config: { - ...restConfiguration, - incidentConfiguration: casesConfiguration, - }, - }, - }; +function executeMigrationWithErrorHandling( + migrationFunc: SavedObjectMigrationFn, + version: string +) { + return (doc: SavedObjectUnsanitizedDoc, context: SavedObjectMigrationContext) => { + try { + return migrationFunc(doc, context); + } catch (ex) { + context.log.error( + `encryptedSavedObject ${version} migration failed for action ${doc.id} with error: ${ex.message}`, + { actionDocument: doc } + ); } - ); + return doc; + }; +} + +function renameCasesConfigurationObject( + doc: SavedObjectUnsanitizedDoc +): SavedObjectUnsanitizedDoc { + if (!doc.attributes.config?.casesConfiguration) { + return doc; + } + const { casesConfiguration, ...restConfiguration } = doc.attributes.config; + + return { + ...doc, + attributes: { + ...doc.attributes, + config: { + ...restConfiguration, + incidentConfiguration: casesConfiguration, + }, + }, + }; +} + +const addHasAuthConfigurationObject = ( + doc: SavedObjectUnsanitizedDoc +): SavedObjectUnsanitizedDoc => { + const hasAuth = !!doc.attributes.secrets.user || !!doc.attributes.secrets.password; + return { + ...doc, + attributes: { + ...doc.attributes, + config: { + ...doc.attributes.config, + hasAuth, + }, + }, + }; }; + +function pipeMigrations(...migrations: ActionMigration[]): ActionMigration { + return (doc: SavedObjectUnsanitizedDoc) => + migrations.reduce((migratedDoc, nextMigration) => nextMigration(migratedDoc), doc); +} diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/email/email.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/email/email.test.tsx index e823e848f52c2..ae698f2304e4e 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/email/email.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/email/email.test.tsx @@ -43,6 +43,7 @@ describe('connector validation', () => { port: 2323, host: 'localhost', test: 'test', + hasAuth: true, }, } as EmailActionConnector; @@ -72,6 +73,7 @@ describe('connector validation', () => { port: 2323, host: 'localhost', test: 'test', + hasAuth: false, }, } as EmailActionConnector; @@ -96,6 +98,7 @@ describe('connector validation', () => { name: 'email', config: { from: 'test@test.com', + hasAuth: true, }, } as EmailActionConnector; @@ -124,6 +127,7 @@ describe('connector validation', () => { port: 2323, host: 'localhost', test: 'test', + hasAuth: true, }, } as EmailActionConnector; @@ -152,6 +156,7 @@ describe('connector validation', () => { port: 2323, host: 'localhost', test: 'test', + hasAuth: true, }, } as EmailActionConnector; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/email/email.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/email/email.tsx index 3e8e71991a594..b75d809f6a327 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/email/email.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/email/email.tsx @@ -75,6 +75,26 @@ export function getActionType(): ActionTypeModel { name: 'email', config: { from: 'test@test.com', + hasAuth: true, }, } as EmailActionConnector; const wrapper = mountWithIntl( @@ -42,4 +43,35 @@ describe('EmailActionConnectorFields renders', () => { expect(wrapper.find('[data-test-subj="emailUserInput"]').length > 0).toBeTruthy(); expect(wrapper.find('[data-test-subj="emailPasswordInput"]').length > 0).toBeTruthy(); }); + + test('secret connector fields is not rendered when hasAuth false', () => { + const actionConnector = { + secrets: {}, + id: 'test', + actionTypeId: '.email', + name: 'email', + config: { + from: 'test@test.com', + hasAuth: false, + }, + } as EmailActionConnector; + const wrapper = mountWithIntl( + {}} + editActionSecrets={() => {}} + docLinks={{ ELASTIC_WEBSITE_URL: '', DOC_LINK_VERSION: '' } as DocLinksStart} + readOnly={false} + /> + ); + expect(wrapper.find('[data-test-subj="emailFromInput"]').length > 0).toBeTruthy(); + expect(wrapper.find('[data-test-subj="emailFromInput"]').first().prop('value')).toBe( + 'test@test.com' + ); + expect(wrapper.find('[data-test-subj="emailHostInput"]').length > 0).toBeTruthy(); + expect(wrapper.find('[data-test-subj="emailPortInput"]').length > 0).toBeTruthy(); + expect(wrapper.find('[data-test-subj="emailUserInput"]').length > 0).toBeFalsy(); + expect(wrapper.find('[data-test-subj="emailPasswordInput"]').length > 0).toBeFalsy(); + }); }); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/email/email_connector.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/email/email_connector.tsx index 4ef9c2e0d4d2e..1e92e9fc2519c 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/email/email_connector.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/email/email_connector.tsx @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import React, { Fragment } from 'react'; +import React, { Fragment, useEffect } from 'react'; import { EuiFieldText, EuiFlexItem, @@ -12,6 +12,9 @@ import { EuiFieldPassword, EuiSwitch, EuiFormRow, + EuiTitle, + EuiSpacer, + EuiCallOut, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; @@ -22,8 +25,14 @@ import { EmailActionConnector } from '../types'; export const EmailActionConnectorFields: React.FunctionComponent> = ({ action, editActionConfig, editActionSecrets, errors, readOnly, docLinks }) => { - const { from, host, port, secure } = action.config; + const { from, host, port, secure, hasAuth } = action.config; const { user, password } = action.secrets; + useEffect(() => { + if (!action.id) { + editActionConfig('hasAuth', true); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); return ( @@ -160,60 +169,116 @@ export const EmailActionConnectorFields: React.FunctionComponent - + - 0} + + +