From 8532b996c4924ae10723d42b37a02d7f92422cdc Mon Sep 17 00:00:00 2001 From: Sander Philipse <94373878+sphilipse@users.noreply.github.com> Date: Mon, 21 Aug 2023 10:37:59 +0200 Subject: [PATCH 01/19] [Search] Disable crawler on overview without ent-search (#164227) ## Summary This disables the crawler if Enterprise Search is not available on the new overview page. --- .../product_selector/ingestion_selector.tsx | 120 ++++++++++-------- 1 file changed, 67 insertions(+), 53 deletions(-) diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_overview/components/product_selector/ingestion_selector.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_overview/components/product_selector/ingestion_selector.tsx index 8758506edd9b6..abb569361e7c3 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_overview/components/product_selector/ingestion_selector.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_overview/components/product_selector/ingestion_selector.tsx @@ -9,6 +9,8 @@ import React from 'react'; import { generatePath } from 'react-router-dom'; +import { useValues } from 'kea'; + import { EuiButton, EuiCard, EuiFlexGroup, EuiFlexItem, EuiIcon } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; @@ -27,13 +29,18 @@ import { NEW_INDEX_METHOD_PATH, NEW_INDEX_SELECT_CONNECTOR_PATH, } from '../../../enterprise_search_content/routes'; -import { EuiLinkTo } from '../../../shared/react_router_helpers'; +import { HttpLogic } from '../../../shared/http/http_logic'; +import { KibanaLogic } from '../../../shared/kibana'; +import { EuiButtonTo, EuiLinkTo } from '../../../shared/react_router_helpers'; const START_LABEL = i18n.translate('xpack.enterpriseSearch.ingestSelector.startButton', { defaultMessage: 'Start', }); export const IngestionSelector: React.FC = () => { + const { config, productFeatures } = useValues(KibanaLogic); + const { errorConnectingMessage } = useValues(HttpLogic); + const crawlerDisabled = Boolean(errorConnectingMessage || !config.host); return ( @@ -61,60 +68,67 @@ export const IngestionSelector: React.FC = () => { } /> - - } - textAlign="left" - title={i18n.translate('xpack.enterpriseSearch.ingestSelector.method.connectors', { - defaultMessage: 'Connectors', - })} - description={i18n.translate( - 'xpack.enterpriseSearch.ingestSelector.method.connectors.description', - { - defaultMessage: - 'Extract, transform, index and sync data from a third-party data source.', + {productFeatures.hasConnectors && ( + + } + textAlign="left" + title={i18n.translate('xpack.enterpriseSearch.ingestSelector.method.connectors', { + defaultMessage: 'Connectors', + })} + description={i18n.translate( + 'xpack.enterpriseSearch.ingestSelector.method.connectors.description', + { + defaultMessage: + 'Extract, transform, index and sync data from a third-party data source.', + } + )} + footer={ + + {START_LABEL} + } - )} - footer={ - - {START_LABEL} - - } - /> - - - } - textAlign="left" - title={i18n.translate('xpack.enterpriseSearch.ingestSelector.method.crawler', { - defaultMessage: 'Web Crawler', - })} - description={i18n.translate( - 'xpack.enterpriseSearch.ingestSelector.method.crawler.description', - { - defaultMessage: - 'Discover, extract, and index searchable content from websites and knowledge bases.', + /> + + )} + {productFeatures.hasWebCrawler && ( + + } + textAlign="left" + title={i18n.translate('xpack.enterpriseSearch.ingestSelector.method.crawler', { + defaultMessage: 'Web Crawler', + })} + description={i18n.translate( + 'xpack.enterpriseSearch.ingestSelector.method.crawler.description', + { + defaultMessage: + 'Discover, extract, and index searchable content from websites and knowledge bases.', + } + )} + footer={ + + {START_LABEL} + } - )} - footer={ - - {START_LABEL} - - } - /> - + /> + + )} ); }; From 81a151ef712b76838480f6216f4ad667e7570cb6 Mon Sep 17 00:00:00 2001 From: Or Ouziel Date: Mon, 21 Aug 2023 12:23:15 +0300 Subject: [PATCH 02/19] [Cloud Security] Only clean up AWS creds (#164154) --- x-pack/plugins/cloud_security_posture/common/utils/helpers.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/cloud_security_posture/common/utils/helpers.ts b/x-pack/plugins/cloud_security_posture/common/utils/helpers.ts index 8a5fd5fa0112d..f50a5ef47bb59 100644 --- a/x-pack/plugins/cloud_security_posture/common/utils/helpers.ts +++ b/x-pack/plugins/cloud_security_posture/common/utils/helpers.ts @@ -104,7 +104,7 @@ export const getStatusForIndexName = (indexName: string, status?: BaseCspSetupSt export const cleanupCredentials = (packagePolicy: NewPackagePolicy | UpdatePackagePolicy) => { const enabledInput = packagePolicy.inputs.find((i) => i.enabled); const credentialType: AwsCredentialsType | undefined = - enabledInput?.streams?.[0].vars?.['aws.credentials.type'].value; + enabledInput?.streams?.[0].vars?.['aws.credentials.type']?.value; if (credentialType) { const credsToKeep = AWS_CREDENTIALS_TYPE_TO_FIELDS_MAP[credentialType]; From bc988f22c6ddb300dbc411976959c5650abe86cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20S=C3=A1nchez?= Date: Mon, 21 Aug 2023 11:30:06 +0200 Subject: [PATCH 03/19] [Security Solution] [Endpoint] Generate empty endpoint user artifacts depending on the PLI (#163602) ## Summary Generates empty array when the PLI don't meet the requirement. It end up having empty fleet artifacts for those cannot be generated. It also adds new test cases --------- Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../manifest_manager/manifest_manager.mock.ts | 13 +- .../manifest_manager/manifest_manager.test.ts | 266 ++++++++++++++++++ .../manifest_manager/manifest_manager.ts | 23 +- .../security_solution/server/plugin.ts | 1 + 4 files changed, 295 insertions(+), 8 deletions(-) diff --git a/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.mock.ts b/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.mock.ts index cb947b5221dbb..4ddb81bfacd49 100644 --- a/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.mock.ts +++ b/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.mock.ts @@ -27,6 +27,9 @@ import { createEndpointArtifactClientMock, getManifestClientMock } from '../mock import type { ManifestManagerContext } from './manifest_manager'; import { ManifestManager } from './manifest_manager'; import { parseExperimentalConfigValue } from '../../../../../common/experimental_features'; +import { createAppFeaturesMock } from '../../../../lib/app_features/mocks'; +import type { AppFeatureKeys } from '../../../../../common/types/app_features'; +import type { AppFeatures } from '../../../../lib/app_features/app_features'; export const createExceptionListResponse = (data: ExceptionListItemSchema[], total?: number) => ({ data, @@ -68,24 +71,28 @@ export interface ManifestManagerMockOptions { exceptionListClient: ExceptionListClient; packagePolicyService: jest.Mocked; savedObjectsClient: ReturnType; + appFeatures: AppFeatures; } export const buildManifestManagerMockOptions = ( - opts: Partial + opts: Partial, + customAppFeatures?: AppFeatureKeys ): ManifestManagerMockOptions => { const savedObjectMock = savedObjectsClientMock.create(); return { exceptionListClient: listMock.getExceptionListClient(savedObjectMock), packagePolicyService: createPackagePolicyServiceMock(), savedObjectsClient: savedObjectMock, + appFeatures: createAppFeaturesMock(customAppFeatures), ...opts, }; }; export const buildManifestManagerContextMock = ( - opts: Partial + opts: Partial, + customAppFeatures?: AppFeatureKeys ): ManifestManagerContext => { - const fullOpts = buildManifestManagerMockOptions(opts); + const fullOpts = buildManifestManagerMockOptions(opts, customAppFeatures); return { ...fullOpts, diff --git a/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.test.ts b/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.test.ts index 6a498d142a383..1fba98d891bb9 100644 --- a/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.test.ts +++ b/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.test.ts @@ -43,6 +43,7 @@ import type { EndpointArtifactClientInterface } from '../artifact_client'; import { InvalidInternalManifestError } from '../errors'; import { EndpointError } from '../../../../../common/endpoint/errors'; import type { Artifact } from '@kbn/fleet-plugin/server'; +import { AppFeatureSecurityKey } from '../../../../../common/types/app_features'; const getArtifactObject = (artifact: InternalArtifactSchema) => JSON.parse(Buffer.from(artifact.body!, 'base64').toString()); @@ -599,6 +600,271 @@ describe('ManifestManager', () => { }); }); + describe('buildNewManifest when using app features', () => { + const SUPPORTED_ARTIFACT_NAMES = [ + ARTIFACT_NAME_EXCEPTIONS_MACOS, + ARTIFACT_NAME_EXCEPTIONS_WINDOWS, + ARTIFACT_NAME_EXCEPTIONS_LINUX, + ARTIFACT_NAME_TRUSTED_APPS_MACOS, + ARTIFACT_NAME_TRUSTED_APPS_WINDOWS, + ARTIFACT_NAME_TRUSTED_APPS_LINUX, + ARTIFACT_NAME_EVENT_FILTERS_MACOS, + ARTIFACT_NAME_EVENT_FILTERS_WINDOWS, + ARTIFACT_NAME_EVENT_FILTERS_LINUX, + ARTIFACT_NAME_HOST_ISOLATION_EXCEPTIONS_MACOS, + ARTIFACT_NAME_HOST_ISOLATION_EXCEPTIONS_WINDOWS, + ARTIFACT_NAME_HOST_ISOLATION_EXCEPTIONS_LINUX, + ARTIFACT_NAME_BLOCKLISTS_MACOS, + ARTIFACT_NAME_BLOCKLISTS_WINDOWS, + ARTIFACT_NAME_BLOCKLISTS_LINUX, + ]; + + const getArtifactIds = (artifacts: InternalArtifactSchema[]) => [ + ...new Set(artifacts.map((artifact) => artifact.identifier)).values(), + ]; + + const mockPolicyListIdsResponse = (items: string[]) => + jest.fn().mockResolvedValue({ + items, + page: 1, + per_page: 100, + total: items.length, + }); + + test('when it has endpoint artifact management app feature it should not generate host isolation exceptions', async () => { + const exceptionListItem = getExceptionListItemSchemaMock({ os_types: ['macos'] }); + const trustedAppListItem = getExceptionListItemSchemaMock({ + os_types: ['linux'], + tags: ['policy:all'], + }); + const eventFiltersListItem = getExceptionListItemSchemaMock({ + os_types: ['windows'], + tags: ['policy:all'], + }); + const hostIsolationExceptionsItem = getExceptionListItemSchemaMock({ + os_types: ['linux'], + tags: ['policy:all'], + }); + const blocklistsListItem = getExceptionListItemSchemaMock({ + os_types: ['macos'], + tags: ['policy:all'], + }); + const context = buildManifestManagerContextMock({}, [ + AppFeatureSecurityKey.endpointArtifactManagement, + ]); + const manifestManager = new ManifestManager(context); + + context.exceptionListClient.findExceptionListItem = mockFindExceptionListItemResponses({ + [ENDPOINT_LIST_ID]: { macos: [exceptionListItem] }, + [ENDPOINT_TRUSTED_APPS_LIST_ID]: { linux: [trustedAppListItem] }, + [ENDPOINT_EVENT_FILTERS_LIST_ID]: { linux: [eventFiltersListItem] }, + [ENDPOINT_HOST_ISOLATION_EXCEPTIONS_LIST_ID]: { linux: [hostIsolationExceptionsItem] }, + [ENDPOINT_BLOCKLISTS_LIST_ID]: { linux: [blocklistsListItem] }, + }); + context.savedObjectsClient.create = jest + .fn() + .mockImplementation((_type: string, object: InternalManifestSchema) => ({ + attributes: object, + })); + context.packagePolicyService.listIds = mockPolicyListIdsResponse([TEST_POLICY_ID_1]); + + const manifest = await manifestManager.buildNewManifest(); + + expect(manifest?.getSchemaVersion()).toStrictEqual('v1'); + expect(manifest?.getSemanticVersion()).toStrictEqual('1.0.0'); + expect(manifest?.getSavedObjectVersion()).toBeUndefined(); + + const artifacts = manifest.getAllArtifacts(); + + expect(artifacts.length).toBe(15); + expect(getArtifactIds(artifacts)).toStrictEqual(SUPPORTED_ARTIFACT_NAMES); + + expect(getArtifactObject(artifacts[0])).toStrictEqual({ + entries: translateToEndpointExceptions([exceptionListItem], 'v1'), + }); + expect(getArtifactObject(artifacts[1])).toStrictEqual({ entries: [] }); + expect(getArtifactObject(artifacts[2])).toStrictEqual({ entries: [] }); + expect(getArtifactObject(artifacts[3])).toStrictEqual({ entries: [] }); + expect(getArtifactObject(artifacts[4])).toStrictEqual({ entries: [] }); + expect(getArtifactObject(artifacts[5])).toStrictEqual({ + entries: translateToEndpointExceptions([trustedAppListItem], 'v1'), + }); + expect(getArtifactObject(artifacts[6])).toStrictEqual({ entries: [] }); + expect(getArtifactObject(artifacts[7])).toStrictEqual({ entries: [] }); + expect(getArtifactObject(artifacts[8])).toStrictEqual({ + entries: translateToEndpointExceptions([eventFiltersListItem], 'v1'), + }); + expect(getArtifactObject(artifacts[9])).toStrictEqual({ entries: [] }); + expect(getArtifactObject(artifacts[10])).toStrictEqual({ entries: [] }); + expect(getArtifactObject(artifacts[11])).toStrictEqual({ entries: [] }); + expect(getArtifactObject(artifacts[12])).toStrictEqual({ entries: [] }); + expect(getArtifactObject(artifacts[13])).toStrictEqual({ entries: [] }); + expect(getArtifactObject(artifacts[14])).toStrictEqual({ + entries: translateToEndpointExceptions([blocklistsListItem], 'v1'), + }); + + for (const artifact of artifacts) { + expect(manifest.isDefaultArtifact(artifact)).toBe(true); + expect(manifest.getArtifactTargetPolicies(artifact)).toStrictEqual( + new Set([TEST_POLICY_ID_1]) + ); + } + }); + + test('when it has endpoint artifact management and response actions app features it should generate all exceptions', async () => { + const exceptionListItem = getExceptionListItemSchemaMock({ os_types: ['macos'] }); + const trustedAppListItem = getExceptionListItemSchemaMock({ + os_types: ['linux'], + tags: ['policy:all'], + }); + const eventFiltersListItem = getExceptionListItemSchemaMock({ + os_types: ['windows'], + tags: ['policy:all'], + }); + const hostIsolationExceptionsItem = getExceptionListItemSchemaMock({ + os_types: ['linux'], + tags: ['policy:all'], + }); + const blocklistsListItem = getExceptionListItemSchemaMock({ + os_types: ['macos'], + tags: ['policy:all'], + }); + const context = buildManifestManagerContextMock({}, [ + AppFeatureSecurityKey.endpointArtifactManagement, + AppFeatureSecurityKey.endpointResponseActions, + ]); + const manifestManager = new ManifestManager(context); + + context.exceptionListClient.findExceptionListItem = mockFindExceptionListItemResponses({ + [ENDPOINT_LIST_ID]: { macos: [exceptionListItem] }, + [ENDPOINT_TRUSTED_APPS_LIST_ID]: { linux: [trustedAppListItem] }, + [ENDPOINT_EVENT_FILTERS_LIST_ID]: { linux: [eventFiltersListItem] }, + [ENDPOINT_HOST_ISOLATION_EXCEPTIONS_LIST_ID]: { linux: [hostIsolationExceptionsItem] }, + [ENDPOINT_BLOCKLISTS_LIST_ID]: { linux: [blocklistsListItem] }, + }); + context.savedObjectsClient.create = jest + .fn() + .mockImplementation((_type: string, object: InternalManifestSchema) => ({ + attributes: object, + })); + context.packagePolicyService.listIds = mockPolicyListIdsResponse([TEST_POLICY_ID_1]); + + const manifest = await manifestManager.buildNewManifest(); + + expect(manifest?.getSchemaVersion()).toStrictEqual('v1'); + expect(manifest?.getSemanticVersion()).toStrictEqual('1.0.0'); + expect(manifest?.getSavedObjectVersion()).toBeUndefined(); + + const artifacts = manifest.getAllArtifacts(); + + expect(artifacts.length).toBe(15); + expect(getArtifactIds(artifacts)).toStrictEqual(SUPPORTED_ARTIFACT_NAMES); + + expect(getArtifactObject(artifacts[0])).toStrictEqual({ + entries: translateToEndpointExceptions([exceptionListItem], 'v1'), + }); + expect(getArtifactObject(artifacts[1])).toStrictEqual({ entries: [] }); + expect(getArtifactObject(artifacts[2])).toStrictEqual({ entries: [] }); + expect(getArtifactObject(artifacts[3])).toStrictEqual({ entries: [] }); + expect(getArtifactObject(artifacts[4])).toStrictEqual({ entries: [] }); + expect(getArtifactObject(artifacts[5])).toStrictEqual({ + entries: translateToEndpointExceptions([trustedAppListItem], 'v1'), + }); + expect(getArtifactObject(artifacts[6])).toStrictEqual({ entries: [] }); + expect(getArtifactObject(artifacts[7])).toStrictEqual({ entries: [] }); + expect(getArtifactObject(artifacts[8])).toStrictEqual({ + entries: translateToEndpointExceptions([eventFiltersListItem], 'v1'), + }); + expect(getArtifactObject(artifacts[9])).toStrictEqual({ entries: [] }); + expect(getArtifactObject(artifacts[10])).toStrictEqual({ entries: [] }); + expect(getArtifactObject(artifacts[11])).toStrictEqual({ + entries: translateToEndpointExceptions([hostIsolationExceptionsItem], 'v1'), + }); + expect(getArtifactObject(artifacts[12])).toStrictEqual({ entries: [] }); + expect(getArtifactObject(artifacts[13])).toStrictEqual({ entries: [] }); + expect(getArtifactObject(artifacts[14])).toStrictEqual({ + entries: translateToEndpointExceptions([blocklistsListItem], 'v1'), + }); + + for (const artifact of artifacts) { + expect(manifest.isDefaultArtifact(artifact)).toBe(true); + expect(manifest.getArtifactTargetPolicies(artifact)).toStrictEqual( + new Set([TEST_POLICY_ID_1]) + ); + } + }); + + test('when does not have right app features, should not generate any exception', async () => { + const exceptionListItem = getExceptionListItemSchemaMock({ os_types: ['macos'] }); + const trustedAppListItem = getExceptionListItemSchemaMock({ + os_types: ['linux'], + tags: ['policy:all'], + }); + const eventFiltersListItem = getExceptionListItemSchemaMock({ + os_types: ['windows'], + tags: ['policy:all'], + }); + const hostIsolationExceptionsItem = getExceptionListItemSchemaMock({ + os_types: ['linux'], + tags: ['policy:all'], + }); + const blocklistsListItem = getExceptionListItemSchemaMock({ + os_types: ['macos'], + tags: ['policy:all'], + }); + const context = buildManifestManagerContextMock({}, []); + const manifestManager = new ManifestManager(context); + + context.exceptionListClient.findExceptionListItem = mockFindExceptionListItemResponses({ + [ENDPOINT_LIST_ID]: { macos: [exceptionListItem] }, + [ENDPOINT_TRUSTED_APPS_LIST_ID]: { linux: [trustedAppListItem] }, + [ENDPOINT_EVENT_FILTERS_LIST_ID]: { linux: [eventFiltersListItem] }, + [ENDPOINT_HOST_ISOLATION_EXCEPTIONS_LIST_ID]: { linux: [hostIsolationExceptionsItem] }, + [ENDPOINT_BLOCKLISTS_LIST_ID]: { linux: [blocklistsListItem] }, + }); + context.savedObjectsClient.create = jest + .fn() + .mockImplementation((_type: string, object: InternalManifestSchema) => ({ + attributes: object, + })); + context.packagePolicyService.listIds = mockPolicyListIdsResponse([TEST_POLICY_ID_1]); + + const manifest = await manifestManager.buildNewManifest(); + + expect(manifest?.getSchemaVersion()).toStrictEqual('v1'); + expect(manifest?.getSemanticVersion()).toStrictEqual('1.0.0'); + expect(manifest?.getSavedObjectVersion()).toBeUndefined(); + + const artifacts = manifest.getAllArtifacts(); + + expect(artifacts.length).toBe(15); + expect(getArtifactIds(artifacts)).toStrictEqual(SUPPORTED_ARTIFACT_NAMES); + + expect(getArtifactObject(artifacts[0])).toStrictEqual({ entries: [] }); + expect(getArtifactObject(artifacts[1])).toStrictEqual({ entries: [] }); + expect(getArtifactObject(artifacts[2])).toStrictEqual({ entries: [] }); + expect(getArtifactObject(artifacts[3])).toStrictEqual({ entries: [] }); + expect(getArtifactObject(artifacts[4])).toStrictEqual({ entries: [] }); + expect(getArtifactObject(artifacts[5])).toStrictEqual({ entries: [] }); + expect(getArtifactObject(artifacts[6])).toStrictEqual({ entries: [] }); + expect(getArtifactObject(artifacts[7])).toStrictEqual({ entries: [] }); + expect(getArtifactObject(artifacts[8])).toStrictEqual({ entries: [] }); + expect(getArtifactObject(artifacts[9])).toStrictEqual({ entries: [] }); + expect(getArtifactObject(artifacts[10])).toStrictEqual({ entries: [] }); + expect(getArtifactObject(artifacts[11])).toStrictEqual({ entries: [] }); + expect(getArtifactObject(artifacts[12])).toStrictEqual({ entries: [] }); + expect(getArtifactObject(artifacts[13])).toStrictEqual({ entries: [] }); + expect(getArtifactObject(artifacts[14])).toStrictEqual({ entries: [] }); + + for (const artifact of artifacts) { + expect(manifest.isDefaultArtifact(artifact)).toBe(true); + expect(manifest.getArtifactTargetPolicies(artifact)).toStrictEqual( + new Set([TEST_POLICY_ID_1]) + ); + } + }); + }); + describe('deleteArtifacts', () => { test('Successfully invokes saved objects client', async () => { const context = buildManifestManagerContextMock({}); diff --git a/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.ts b/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.ts index 2dd607604b82f..865a75fc4b5ab 100644 --- a/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.ts +++ b/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.ts @@ -20,6 +20,8 @@ import type { ListResult, PackagePolicy } from '@kbn/fleet-plugin/common'; import type { Artifact, PackagePolicyClient } from '@kbn/fleet-plugin/server'; import type { ExceptionListClient } from '@kbn/lists-plugin/server'; import type { ExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; +import { AppFeatureKey } from '../../../../../common/types/app_features'; +import type { AppFeatures } from '../../../../lib/app_features'; import type { ManifestSchemaVersion } from '../../../../../common/endpoint/schema/common'; import type { ManifestSchema } from '../../../../../common/endpoint/schema/manifest'; import { manifestDispatchSchema } from '../../../../../common/endpoint/schema/manifest'; @@ -97,6 +99,7 @@ export interface ManifestManagerContext { experimentalFeatures: ExperimentalFeatures; packagerTaskPackagePolicyUpdateBatchSize: number; esClient: ElasticsearchClient; + appFeatures: AppFeatures; } const getArtifactIds = (manifest: ManifestSchema) => @@ -118,6 +121,7 @@ export class ManifestManager { protected cachedExceptionsListsByOs: Map; protected packagerTaskPackagePolicyUpdateBatchSize: number; protected esClient: ElasticsearchClient; + protected appFeatures: AppFeatures; constructor(context: ManifestManagerContext) { this.artifactClient = context.artifactClient; @@ -131,6 +135,7 @@ export class ManifestManager { this.packagerTaskPackagePolicyUpdateBatchSize = context.packagerTaskPackagePolicyUpdateBatchSize; this.esClient = context.esClient; + this.appFeatures = context.appFeatures; } /** @@ -159,11 +164,19 @@ export class ManifestManager { schemaVersion: string; }): Promise { if (!this.cachedExceptionsListsByOs.has(`${listId}-${os}`)) { - const itemsByListId = await getAllItemsFromEndpointExceptionList({ - elClient, - os, - listId, - }); + let itemsByListId: ExceptionListItemSchema[] = []; + if ( + (listId === ENDPOINT_HOST_ISOLATION_EXCEPTIONS_LIST_ID && + this.appFeatures.isEnabled(AppFeatureKey.endpointResponseActions)) || + (listId !== ENDPOINT_HOST_ISOLATION_EXCEPTIONS_LIST_ID && + this.appFeatures.isEnabled(AppFeatureKey.endpointArtifactManagement)) + ) { + itemsByListId = await getAllItemsFromEndpointExceptionList({ + elClient, + os, + listId, + }); + } this.cachedExceptionsListsByOs.set(`${listId}-${os}`, itemsByListId); } diff --git a/x-pack/plugins/security_solution/server/plugin.ts b/x-pack/plugins/security_solution/server/plugin.ts index 70b368244b613..db285ae678ab5 100644 --- a/x-pack/plugins/security_solution/server/plugin.ts +++ b/x-pack/plugins/security_solution/server/plugin.ts @@ -457,6 +457,7 @@ export class Plugin implements ISecuritySolutionPlugin { experimentalFeatures: config.experimentalFeatures, packagerTaskPackagePolicyUpdateBatchSize: config.packagerTaskPackagePolicyUpdateBatchSize, esClient: core.elasticsearch.client.asInternalUser, + appFeatures: this.appFeatures, }); // Migrate artifacts to fleet and then start the manifest task after that is done From 23d39555e0d0fc36c760f0c148913db69749cb47 Mon Sep 17 00:00:00 2001 From: Jean-Louis Leysens Date: Mon, 21 Aug 2023 11:55:33 +0200 Subject: [PATCH 04/19] [HTTP] Allow for internal requests to also specify special query param `elasticInternalOrigin` (#163796) ## Summary Closes https://github.com/elastic/kibana/issues/163678 * Raise the notion of "internal" into `CoreKibanaRequest`. This enables us to share this with lifecycle handlers and control validation of query params * Added new `isInternalRequest` alongside `isSystemRequest` and `isFakeRequest` * Slight simplification to existing internal restriction check * Some other chores and minor fixes ## Test * Start ES with `yarn es serverless` and Kibana with `yarn start --serverless --server.restrictInternalApis=true` * Add the service account token to `kibana.dev.yml`: `elasticsearch.serviceAccountToken: ` * Send a request to an internal endpoint like: `curl -XPOST -uelastic:changeme http://localhost:5601//api/files/find -H 'kbn-xsrf: foo' -H 'content-type: application/json' -d '{}'` * Should give you a 400 result * message like `{"statusCode":400,"error":"Bad Request","message":"uri [http://localhost:5603/api/files/find] with method [post] exists but is not available with the current configuration"}` * Send the same request, but include the query param: `elasticInternalOrigin=true` * Should give you a 200 result --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- packages/core/http/core-http-common/index.ts | 1 + .../http/core-http-common/src/constants.ts | 2 +- .../src/request.test.ts | 56 ++++++++++++ .../src/request.ts | 67 +++++++++----- .../src/lifecycle_handlers.test.ts | 25 +++++- .../src/lifecycle_handlers.ts | 8 +- .../core-http-server/src/router/request.ts | 6 ++ packages/kbn-hapi-mocks/src/request.ts | 5 ++ .../http/lifecycle_handlers.test.ts | 89 ++++++++++++++----- ...rting_authorization_client_factory.test.ts | 27 +----- .../maintenance_window_client_factory.test.ts | 31 ++----- .../server/rules_client_factory.test.ts | 38 +++----- .../rules_settings_client_factory.test.ts | 30 ++----- x-pack/plugins/alerting/tsconfig.json | 1 + .../alerts_client_factory.test.ts | 26 ++---- x-pack/plugins/rule_registry/tsconfig.json | 1 + 16 files changed, 242 insertions(+), 171 deletions(-) diff --git a/packages/core/http/core-http-common/index.ts b/packages/core/http/core-http-common/index.ts index 0d093fdf10863..07dbfa5e14d89 100644 --- a/packages/core/http/core-http-common/index.ts +++ b/packages/core/http/core-http-common/index.ts @@ -12,5 +12,6 @@ export type { ApiVersion } from './src/versioning'; export { ELASTIC_HTTP_VERSION_HEADER, ELASTIC_HTTP_VERSION_QUERY_PARAM, + ELASTIC_INTERNAL_ORIGIN_QUERY_PARAM, X_ELASTIC_INTERNAL_ORIGIN_REQUEST, } from './src/constants'; diff --git a/packages/core/http/core-http-common/src/constants.ts b/packages/core/http/core-http-common/src/constants.ts index 2047f27a345c6..fd7beef090f63 100644 --- a/packages/core/http/core-http-common/src/constants.ts +++ b/packages/core/http/core-http-common/src/constants.ts @@ -9,5 +9,5 @@ /** @public */ export const ELASTIC_HTTP_VERSION_HEADER = 'elastic-api-version' as const; export const ELASTIC_HTTP_VERSION_QUERY_PARAM = 'apiVersion' as const; - +export const ELASTIC_INTERNAL_ORIGIN_QUERY_PARAM = 'elasticInternalOrigin' as const; export const X_ELASTIC_INTERNAL_ORIGIN_REQUEST = 'x-elastic-internal-origin' as const; diff --git a/packages/core/http/core-http-router-server-internal/src/request.test.ts b/packages/core/http/core-http-router-server-internal/src/request.test.ts index 8d3143bac02ef..388f183fd0ba3 100644 --- a/packages/core/http/core-http-router-server-internal/src/request.test.ts +++ b/packages/core/http/core-http-router-server-internal/src/request.test.ts @@ -15,6 +15,10 @@ import { hapiMocks } from '@kbn/hapi-mocks'; import type { FakeRawRequest } from '@kbn/core-http-server'; import { CoreKibanaRequest } from './request'; import { schema } from '@kbn/config-schema'; +import { + ELASTIC_INTERNAL_ORIGIN_QUERY_PARAM, + X_ELASTIC_INTERNAL_ORIGIN_REQUEST, +} from '@kbn/core-http-common'; describe('CoreKibanaRequest', () => { describe('using real requests', () => { @@ -145,6 +149,58 @@ describe('CoreKibanaRequest', () => { }); }); + describe('isInternalApiRequest property', () => { + it('is true when header is set', () => { + const request = hapiMocks.createRequest({ + headers: { [X_ELASTIC_INTERNAL_ORIGIN_REQUEST]: 'true' }, + }); + const kibanaRequest = CoreKibanaRequest.from(request); + expect(kibanaRequest.isInternalApiRequest).toBe(true); + }); + it('is true when query param is set', () => { + const request = hapiMocks.createRequest({ + query: { [ELASTIC_INTERNAL_ORIGIN_QUERY_PARAM]: 'true' }, + }); + const kibanaRequest = CoreKibanaRequest.from(request); + expect(kibanaRequest.isInternalApiRequest).toBe(true); + }); + it('is true when both header and query param is set', () => { + const request = hapiMocks.createRequest({ + headers: { [X_ELASTIC_INTERNAL_ORIGIN_REQUEST]: 'true' }, + query: { [ELASTIC_INTERNAL_ORIGIN_QUERY_PARAM]: 'true' }, + }); + const kibanaRequest = CoreKibanaRequest.from(request); + expect(kibanaRequest.isInternalApiRequest).toBe(true); + }); + it('is false when neither header nor query param is set', () => { + const request = hapiMocks.createRequest(); + const kibanaRequest = CoreKibanaRequest.from(request); + expect(kibanaRequest.isInternalApiRequest).toBe(false); + }); + }); + + describe('sanitize input', () => { + it('does not pass the reserved query parameter to consumers', () => { + const request = hapiMocks.createRequest({ + query: { [ELASTIC_INTERNAL_ORIGIN_QUERY_PARAM]: 'true', myCoolValue: 'cool!' }, + }); + const kibanaRequest = CoreKibanaRequest.from(request, { + query: schema.object({ myCoolValue: schema.string() }), + }); + expect(kibanaRequest.query).toEqual({ myCoolValue: 'cool!' }); + }); + it('pass nothing if only the reserved query param is present', () => { + const request = hapiMocks.createRequest({ + query: { [ELASTIC_INTERNAL_ORIGIN_QUERY_PARAM]: 'true' }, + }); + expect(() => + CoreKibanaRequest.from(request, { + query: schema.object({}, { unknowns: 'forbid' }), // we require an empty object + }) + ).not.toThrow(); + }); + }); + describe('route.options.authRequired property', () => { it('handles required auth: undefined', () => { const auth: RouteOptions['auth'] = undefined; diff --git a/packages/core/http/core-http-router-server-internal/src/request.ts b/packages/core/http/core-http-router-server-internal/src/request.ts index 8c31635feb8c2..03348e1e9f577 100644 --- a/packages/core/http/core-http-router-server-internal/src/request.ts +++ b/packages/core/http/core-http-router-server-internal/src/request.ts @@ -29,6 +29,10 @@ import { RawRequest, FakeRawRequest, } from '@kbn/core-http-server'; +import { + ELASTIC_INTERNAL_ORIGIN_QUERY_PARAM, + X_ELASTIC_INTERNAL_ORIGIN_REQUEST, +} from '@kbn/core-http-common'; import { RouteValidator } from './validator'; import { isSafeMethod } from './route'; import { KibanaSocket } from './socket'; @@ -59,7 +63,13 @@ export class CoreKibanaRequest< withoutSecretHeaders: boolean = true ) { const routeValidator = RouteValidator.from(routeSchemas); - const requestParts = CoreKibanaRequest.validate(req, routeValidator); + let requestParts: { params: P; query: Q; body: B }; + if (isFakeRawRequest(req)) { + requestParts = { query: {} as Q, params: {} as P, body: {} as B }; + } else { + const rawParts = CoreKibanaRequest.sanitizeRequest(req); + requestParts = CoreKibanaRequest.validate(rawParts, routeValidator); + } return new CoreKibanaRequest( req, requestParts.params, @@ -69,6 +79,22 @@ export class CoreKibanaRequest< ); } + /** + * We have certain values that may be passed via query params that we want to + * exclude from further processing like validation. This method removes those + * internal values. + */ + private static sanitizeRequest( + req: Request + ): { query: unknown; params: unknown; body: unknown } { + const { [ELASTIC_INTERNAL_ORIGIN_QUERY_PARAM]: __, ...query } = req.query ?? {}; + return { + query, + params: req.params, + body: req.payload, + }; + } + /** * Validates the different parts of a request based on the schemas defined for * the route. Builds up the actual params, query and body object that will be @@ -76,43 +102,42 @@ export class CoreKibanaRequest< * @internal */ private static validate( - req: RawRequest, + raw: { params: unknown; query: unknown; body: unknown }, routeValidator: RouteValidator ): { params: P; query: Q; body: B; } { - if (isFakeRawRequest(req)) { - return { query: {} as Q, params: {} as P, body: {} as B }; - } - const params = routeValidator.getParams(req.params, 'request params'); - const query = routeValidator.getQuery(req.query, 'request query'); - const body = routeValidator.getBody(req.payload, 'request body'); + const params = routeValidator.getParams(raw.params, 'request params'); + const query = routeValidator.getQuery(raw.query, 'request query'); + const body = routeValidator.getBody(raw.body, 'request body'); return { query, params, body }; } - /** {@inheritDoc IKibanaRequest.id} */ + /** {@inheritDoc KibanaRequest.id} */ public readonly id: string; - /** {@inheritDoc IKibanaRequest.uuid} */ + /** {@inheritDoc KibanaRequest.uuid} */ public readonly uuid: string; - /** {@inheritDoc IKibanaRequest.url} */ + /** {@inheritDoc KibanaRequest.url} */ public readonly url: URL; - /** {@inheritDoc IKibanaRequest.route} */ + /** {@inheritDoc KibanaRequest.route} */ public readonly route: RecursiveReadonly>; - /** {@inheritDoc IKibanaRequest.headers} */ + /** {@inheritDoc KibanaRequest.headers} */ public readonly headers: Headers; - /** {@inheritDoc IKibanaRequest.isSystemRequest} */ + /** {@inheritDoc KibanaRequest.isSystemRequest} */ public readonly isSystemRequest: boolean; - /** {@inheritDoc IKibanaRequest.socket} */ + /** {@inheritDoc KibanaRequest.socket} */ public readonly socket: IKibanaSocket; - /** {@inheritDoc IKibanaRequest.events} */ + /** {@inheritDoc KibanaRequest.events} */ public readonly events: KibanaRequestEvents; - /** {@inheritDoc IKibanaRequest.auth} */ + /** {@inheritDoc KibanaRequest.auth} */ public readonly auth: KibanaRequestAuth; - /** {@inheritDoc IKibanaRequest.isFakeRequest} */ + /** {@inheritDoc KibanaRequest.isFakeRequest} */ public readonly isFakeRequest: boolean; - /** {@inheritDoc IKibanaRequest.rewrittenUrl} */ + /** {@inheritDoc KibanaRequest.isInternalApiRequest} */ + public readonly isInternalApiRequest: boolean; + /** {@inheritDoc KibanaRequest.rewrittenUrl} */ public readonly rewrittenUrl?: URL; /** @internal */ @@ -139,7 +164,9 @@ export class CoreKibanaRequest< this.headers = isRealRawRequest(request) ? deepFreeze({ ...request.headers }) : request.headers; this.isSystemRequest = this.headers['kbn-system-request'] === 'true'; this.isFakeRequest = isFakeRawRequest(request); - + this.isInternalApiRequest = + X_ELASTIC_INTERNAL_ORIGIN_REQUEST in this.headers || + Boolean(this.url?.searchParams?.has(ELASTIC_INTERNAL_ORIGIN_QUERY_PARAM)); // prevent Symbol exposure via Object.getOwnPropertySymbols() Object.defineProperty(this, requestSymbol, { value: request, diff --git a/packages/core/http/core-http-server-internal/src/lifecycle_handlers.test.ts b/packages/core/http/core-http-server-internal/src/lifecycle_handlers.test.ts index 9e1d0191d0f5e..6e2c53af82679 100644 --- a/packages/core/http/core-http-server-internal/src/lifecycle_handlers.test.ts +++ b/packages/core/http/core-http-server-internal/src/lifecycle_handlers.test.ts @@ -39,11 +39,13 @@ const createToolkit = (): ToolkitMock => { const forgeRequest = ({ headers = {}, + query = {}, path = '/', method = 'get', kibanaRouteOptions, }: Partial<{ headers: Record; + query: Record; path: string; method: RouteMethod; kibanaRouteOptions: KibanaRouteOptions; @@ -51,6 +53,7 @@ const forgeRequest = ({ return mockRouter.createKibanaRequest({ headers, path, + query, method, kibanaRouteOptions, }); @@ -259,11 +262,13 @@ describe('restrictInternal post-auth handler', () => { }); const createForgeRequest = ( access: 'internal' | 'public', - headers: Record | undefined = {} + headers: Record | undefined = {}, + query: Record | undefined = {} ) => { return forgeRequest({ method: 'get', headers, + query, path: `/${access}/some-path`, kibanaRouteOptions: { xsrfRequired: false, @@ -318,6 +323,24 @@ describe('restrictInternal post-auth handler', () => { const request = createForgeRequest('public'); createForwardSuccess(handler, request); }); + + it('forward the request to the next interceptor if called with internal origin query param for internal API', () => { + const handler = createRestrictInternalRoutesPostAuthHandler(config as HttpConfig); + const request = createForgeRequest('internal', undefined, { elasticInternalOrigin: 'true' }); + createForwardSuccess(handler, request); + }); + + it('forward the request to the next interceptor if called with internal origin query param for public APIs', () => { + const handler = createRestrictInternalRoutesPostAuthHandler(config as HttpConfig); + const request = createForgeRequest('internal', undefined, { elasticInternalOrigin: 'true' }); + createForwardSuccess(handler, request); + }); + + it('forward the request to the next interceptor if called without internal origin query param for public APIs', () => { + const handler = createRestrictInternalRoutesPostAuthHandler(config as HttpConfig); + const request = createForgeRequest('public'); + createForwardSuccess(handler, request); + }); }); describe('when restriction is not enabled', () => { diff --git a/packages/core/http/core-http-server-internal/src/lifecycle_handlers.ts b/packages/core/http/core-http-server-internal/src/lifecycle_handlers.ts index 90b09ee8349db..a86a0e230f609 100644 --- a/packages/core/http/core-http-server-internal/src/lifecycle_handlers.ts +++ b/packages/core/http/core-http-server-internal/src/lifecycle_handlers.ts @@ -8,7 +8,6 @@ import type { OnPostAuthHandler, OnPreResponseHandler } from '@kbn/core-http-server'; import { isSafeMethod } from '@kbn/core-http-router-server-internal'; -import { X_ELASTIC_INTERNAL_ORIGIN_REQUEST } from '@kbn/core-http-common/src/constants'; import { HttpConfig } from './http_config'; const VERSION_HEADER = 'kbn-version'; @@ -45,11 +44,7 @@ export const createRestrictInternalRoutesPostAuthHandler = ( return (request, response, toolkit) => { const isInternalRoute = request.route.options.access === 'internal'; - - // only check if the header is present, not it's content. - const hasInternalKibanaRequestHeader = X_ELASTIC_INTERNAL_ORIGIN_REQUEST in request.headers; - - if (isRestrictionEnabled && isInternalRoute && !hasInternalKibanaRequestHeader) { + if (isRestrictionEnabled && isInternalRoute && !request.isInternalApiRequest) { // throw 400 return response.badRequest({ body: `uri [${request.url}] with method [${request.route.method}] exists but is not available with the current configuration`, @@ -75,7 +70,6 @@ export const createVersionCheckPostAuthHandler = (kibanaVersion: string): OnPost }, }); } - return toolkit.next(); }; }; diff --git a/packages/core/http/core-http-server/src/router/request.ts b/packages/core/http/core-http-server/src/router/request.ts index a92f2d496705a..e1242dee7eb67 100644 --- a/packages/core/http/core-http-server/src/router/request.ts +++ b/packages/core/http/core-http-server/src/router/request.ts @@ -135,6 +135,12 @@ export interface KibanaRequest< */ readonly isFakeRequest: boolean; + /** + * An internal request has access to internal routes. + * @note See the {@link KibanaRequestRouteOptions#access} route option. + */ + readonly isInternalApiRequest: boolean; + /** * The socket associated with this request. * See {@link IKibanaSocket}. diff --git a/packages/kbn-hapi-mocks/src/request.ts b/packages/kbn-hapi-mocks/src/request.ts index ee8d1e657f5ef..511e580071954 100644 --- a/packages/kbn-hapi-mocks/src/request.ts +++ b/packages/kbn-hapi-mocks/src/request.ts @@ -18,6 +18,11 @@ export const createRequestMock = (customization: DeepPartial = {}): Req formatUrl(Object.assign({ pathname, path, href: path }, customization.url)), 'http://localhost' ); + if (customization.query) { + Object.entries(customization.query).forEach(([key, value]) => { + url.searchParams.set(key, value); + }); + } return merge( {}, diff --git a/src/core/server/integration_tests/http/lifecycle_handlers.test.ts b/src/core/server/integration_tests/http/lifecycle_handlers.test.ts index b7d1ec5e9e670..96d9c06e80776 100644 --- a/src/core/server/integration_tests/http/lifecycle_handlers.test.ts +++ b/src/core/server/integration_tests/http/lifecycle_handlers.test.ts @@ -13,6 +13,7 @@ import { contextServiceMock } from '@kbn/core-http-context-server-mocks'; import { createConfigService, createHttpServer } from '@kbn/core-http-server-mocks'; import { HttpService, HttpServerSetup } from '@kbn/core-http-server-internal'; import { executionContextServiceMock } from '@kbn/core-execution-context-server-mocks'; +import { schema } from '@kbn/config-schema'; const actualVersion = kibanaPackageJson.version; const versionHeader = 'kbn-version'; @@ -22,37 +23,39 @@ const allowlistedTestPath = '/xsrf/test/route/whitelisted'; const xsrfDisabledTestPath = '/xsrf/test/route/disabled'; const kibanaName = 'my-kibana-name'; const internalProductHeader = 'x-elastic-internal-origin'; +const internalProductQueryParam = 'elasticInternalOrigin'; const setupDeps = { context: contextServiceMock.createSetupContract(), executionContext: executionContextServiceMock.createInternalSetupContract(), }; +const testConfig: Parameters[0] = { + server: { + name: kibanaName, + securityResponseHeaders: { + // reflects default config + strictTransportSecurity: null, + xContentTypeOptions: 'nosniff', + referrerPolicy: 'strict-origin-when-cross-origin', + permissionsPolicy: null, + crossOriginOpenerPolicy: 'same-origin', + } as any, + customResponseHeaders: { + 'some-header': 'some-value', + 'referrer-policy': 'strict-origin', // overrides a header that is defined by securityResponseHeaders + }, + xsrf: { disableProtection: false, allowlist: [allowlistedTestPath] }, + }, +}; + describe('core lifecycle handlers', () => { let server: HttpService; let innerServer: HttpServerSetup['server']; let router: IRouter; beforeEach(async () => { - const configService = createConfigService({ - server: { - name: kibanaName, - securityResponseHeaders: { - // reflects default config - strictTransportSecurity: null, - xContentTypeOptions: 'nosniff', - referrerPolicy: 'strict-origin-when-cross-origin', - permissionsPolicy: null, - crossOriginOpenerPolicy: 'same-origin', - } as any, - customResponseHeaders: { - 'some-header': 'some-value', - 'referrer-policy': 'strict-origin', // overrides a header that is defined by securityResponseHeaders - }, - xsrf: { disableProtection: false, allowlist: [allowlistedTestPath] }, - }, - }); + const configService = createConfigService(testConfig); server = createHttpServer({ configService }); - await server.preboot({ context: contextServiceMock.createPrebootContract() }); const serverSetup = await server.setup(setupDeps); router = serverSetup.createRouter('/'); @@ -217,15 +220,36 @@ describe('core lifecycle handlers', () => { describe('restrictInternalRoutes post-auth handler', () => { const testInternalRoute = '/restrict_internal_routes/test/route_internal'; const testPublicRoute = '/restrict_internal_routes/test/route_public'; + beforeEach(async () => { + await server?.stop(); + const configService = createConfigService({ + server: { + ...testConfig.server, + restrictInternalApis: true, + }, + }); + server = createHttpServer({ configService }); + await server.preboot({ context: contextServiceMock.createPrebootContract() }); + const serverSetup = await server.setup(setupDeps); + router = serverSetup.createRouter('/'); + innerServer = serverSetup.server; router.get( - { path: testInternalRoute, validate: false, options: { access: 'internal' } }, + { + path: testInternalRoute, + validate: { query: schema.object({ myValue: schema.string() }) }, + options: { access: 'internal' }, + }, (context, req, res) => { return res.ok({ body: 'ok()' }); } ); router.get( - { path: testPublicRoute, validate: false, options: { access: 'public' } }, + { + path: testPublicRoute, + validate: { query: schema.object({ myValue: schema.string() }) }, + options: { access: 'public' }, + }, (context, req, res) => { return res.ok({ body: 'ok()' }); } @@ -233,10 +257,18 @@ describe('core lifecycle handlers', () => { await server.start(); }); + it('rejects requests to internal routes without special values', async () => { + await supertest(innerServer.listener) + .get(testInternalRoute) + .query({ myValue: 'test' }) + .expect(400); + }); + it('accepts requests with the internal product header to internal routes', async () => { await supertest(innerServer.listener) .get(testInternalRoute) .set(internalProductHeader, 'anything') + .query({ myValue: 'test' }) .expect(200, 'ok()'); }); @@ -244,6 +276,21 @@ describe('core lifecycle handlers', () => { await supertest(innerServer.listener) .get(testPublicRoute) .set(internalProductHeader, 'anything') + .query({ myValue: 'test' }) + .expect(200, 'ok()'); + }); + + it('accepts requests with the internal product query param to internal routes', async () => { + await supertest(innerServer.listener) + .get(testInternalRoute) + .query({ [internalProductQueryParam]: 'anything', myValue: 'test' }) + .expect(200, 'ok()'); + }); + + it('accepts requests with the internal product query param to public routes', async () => { + await supertest(innerServer.listener) + .get(testInternalRoute) + .query({ [internalProductQueryParam]: 'anything', myValue: 'test' }) .expect(200, 'ok()'); }); }); diff --git a/x-pack/plugins/alerting/server/alerting_authorization_client_factory.test.ts b/x-pack/plugins/alerting/server/alerting_authorization_client_factory.test.ts index 1283d5094c690..dca53bb3188e9 100644 --- a/x-pack/plugins/alerting/server/alerting_authorization_client_factory.test.ts +++ b/x-pack/plugins/alerting/server/alerting_authorization_client_factory.test.ts @@ -4,11 +4,8 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ - -import { Request } from '@hapi/hapi'; +import { mockRouter } from '@kbn/core-http-router-server-mocks'; import { ruleTypeRegistryMock } from './rule_type_registry.mock'; -import { CoreKibanaRequest } from '@kbn/core/server'; -import { savedObjectsClientMock } from '@kbn/core/server/mocks'; import { securityMock } from '@kbn/security-plugin/server/mocks'; import { AlertingAuthorizationClientFactory, @@ -18,7 +15,6 @@ import { featuresPluginMock } from '@kbn/features-plugin/server/mocks'; jest.mock('./authorization/alerting_authorization'); -const savedObjectsClient = savedObjectsClientMock.create(); const features = featuresPluginMock.createStart(); const securityPluginSetup = securityMock.createSetup(); @@ -32,23 +28,6 @@ const alertingAuthorizationClientFactoryParams: jest.Mocked '', - path: '/', - route: { settings: {} }, - url: { - href: '/', - }, - raw: { - req: { - url: '/', - }, - }, - getSavedObjectsClient: () => savedObjectsClient, -} as unknown as Request; - beforeEach(() => { jest.resetAllMocks(); }); @@ -60,7 +39,7 @@ test('creates an alerting authorization client with proper constructor arguments securityPluginStart, ...alertingAuthorizationClientFactoryParams, }); - const request = CoreKibanaRequest.from(fakeRequest); + const request = mockRouter.createKibanaRequest(); factory.create(request); @@ -78,7 +57,7 @@ test('creates an alerting authorization client with proper constructor arguments test('creates an alerting authorization client with proper constructor arguments', async () => { const factory = new AlertingAuthorizationClientFactory(); factory.initialize(alertingAuthorizationClientFactoryParams); - const request = CoreKibanaRequest.from(fakeRequest); + const request = mockRouter.createKibanaRequest(); factory.create(request); diff --git a/x-pack/plugins/alerting/server/maintenance_window_client_factory.test.ts b/x-pack/plugins/alerting/server/maintenance_window_client_factory.test.ts index 987492e42ea9e..9f3f2d26447d1 100644 --- a/x-pack/plugins/alerting/server/maintenance_window_client_factory.test.ts +++ b/x-pack/plugins/alerting/server/maintenance_window_client_factory.test.ts @@ -4,9 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ - -import { Request } from '@hapi/hapi'; -import { CoreKibanaRequest } from '@kbn/core/server'; +import { mockRouter } from '@kbn/core-http-router-server-mocks'; import { MaintenanceWindowClientFactory, MaintenanceWindowClientFactoryOpts, @@ -33,23 +31,6 @@ const maintenanceWindowClientFactoryParams: jest.Mocked '', - path: '/', - route: { settings: {} }, - url: { - href: '/', - }, - raw: { - req: { - url: '/', - }, - }, - getSavedObjectsClient: () => savedObjectsClient, -} as unknown as Request; - beforeEach(() => { jest.resetAllMocks(); }); @@ -60,7 +41,7 @@ test('creates a maintenance window client with proper constructor arguments when securityPluginStart, ...maintenanceWindowClientFactoryParams, }); - const request = CoreKibanaRequest.from(fakeRequest); + const request = mockRouter.createKibanaRequest(); savedObjectsService.getScopedClient.mockReturnValue(savedObjectsClient); @@ -82,7 +63,7 @@ test('creates a maintenance window client with proper constructor arguments when test('creates a maintenance window client with proper constructor arguments', async () => { const factory = new MaintenanceWindowClientFactory(); factory.initialize(maintenanceWindowClientFactoryParams); - const request = CoreKibanaRequest.from(fakeRequest); + const request = mockRouter.createKibanaRequest(); savedObjectsService.getScopedClient.mockReturnValue(savedObjectsClient); @@ -107,7 +88,7 @@ test('creates an unauthorized maintenance window client', async () => { securityPluginStart, ...maintenanceWindowClientFactoryParams, }); - const request = CoreKibanaRequest.from(fakeRequest); + const request = mockRouter.createKibanaRequest(); savedObjectsService.getScopedClient.mockReturnValue(savedObjectsClient); @@ -130,7 +111,7 @@ test('creates an unauthorized maintenance window client', async () => { test('getUserName() returns null when security is disabled', async () => { const factory = new MaintenanceWindowClientFactory(); factory.initialize(maintenanceWindowClientFactoryParams); - const request = CoreKibanaRequest.from(fakeRequest); + const request = mockRouter.createKibanaRequest(); factory.createWithAuthorization(request); const constructorCall = jest.requireMock('./maintenance_window_client').MaintenanceWindowClient @@ -146,7 +127,7 @@ test('getUserName() returns a name when security is enabled', async () => { securityPluginStart, ...maintenanceWindowClientFactoryParams, }); - const request = CoreKibanaRequest.from(fakeRequest); + const request = mockRouter.createKibanaRequest(); factory.createWithAuthorization(request); diff --git a/x-pack/plugins/alerting/server/rules_client_factory.test.ts b/x-pack/plugins/alerting/server/rules_client_factory.test.ts index 18364256ce4a9..d1554a46991fd 100644 --- a/x-pack/plugins/alerting/server/rules_client_factory.test.ts +++ b/x-pack/plugins/alerting/server/rules_client_factory.test.ts @@ -5,11 +5,9 @@ * 2.0. */ -import { Request } from '@hapi/hapi'; import { RulesClientFactory, RulesClientFactoryOpts } from './rules_client_factory'; import { ruleTypeRegistryMock } from './rule_type_registry.mock'; import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks'; -import { CoreKibanaRequest } from '@kbn/core/server'; import { savedObjectsClientMock, savedObjectsServiceMock, @@ -26,6 +24,7 @@ import { alertingAuthorizationClientFactoryMock } from './alerting_authorization import { AlertingAuthorization } from './authorization'; import { AlertingAuthorizationClientFactory } from './alerting_authorization_client_factory'; import { SECURITY_EXTENSION_ID } from '@kbn/core-saved-objects-server'; +import { mockRouter } from '@kbn/core-http-router-server-mocks'; jest.mock('./rules_client'); jest.mock('./authorization/alerting_authorization'); @@ -54,23 +53,6 @@ const rulesClientFactoryParams: jest.Mocked = { alertingAuthorizationClientFactory as unknown as AlertingAuthorizationClientFactory, }; -const fakeRequest = { - app: {}, - headers: {}, - getBasePath: () => '', - path: '/', - route: { settings: {} }, - url: { - href: '/', - }, - raw: { - req: { - url: '/', - }, - }, - getSavedObjectsClient: () => savedObjectsClient, -} as unknown as Request; - const actionsAuthorization = actionsAuthorizationMock.create(); beforeEach(() => { @@ -86,7 +68,7 @@ beforeEach(() => { test('creates a rules client with proper constructor arguments when security is enabled', async () => { const factory = new RulesClientFactory(); factory.initialize({ securityPluginSetup, securityPluginStart, ...rulesClientFactoryParams }); - const request = CoreKibanaRequest.from(fakeRequest); + const request = mockRouter.createKibanaRequest(); savedObjectsService.getScopedClient.mockReturnValue(savedObjectsClient); alertingAuthorizationClientFactory.create.mockReturnValue( @@ -130,7 +112,7 @@ test('creates a rules client with proper constructor arguments when security is test('creates a rules client with proper constructor arguments', async () => { const factory = new RulesClientFactory(); factory.initialize(rulesClientFactoryParams); - const request = CoreKibanaRequest.from(fakeRequest); + const request = mockRouter.createKibanaRequest(); savedObjectsService.getScopedClient.mockReturnValue(savedObjectsClient); alertingAuthorizationClientFactory.create.mockReturnValue( @@ -170,7 +152,7 @@ test('creates a rules client with proper constructor arguments', async () => { test('getUserName() returns null when security is disabled', async () => { const factory = new RulesClientFactory(); factory.initialize(rulesClientFactoryParams); - factory.create(CoreKibanaRequest.from(fakeRequest), savedObjectsService); + factory.create(mockRouter.createKibanaRequest(), savedObjectsService); const constructorCall = jest.requireMock('./rules_client').RulesClient.mock.calls[0][0]; const userNameResult = await constructorCall.getUserName(); @@ -184,7 +166,7 @@ test('getUserName() returns a name when security is enabled', async () => { securityPluginSetup, securityPluginStart, }); - factory.create(CoreKibanaRequest.from(fakeRequest), savedObjectsService); + factory.create(mockRouter.createKibanaRequest(), savedObjectsService); const constructorCall = jest.requireMock('./rules_client').RulesClient.mock.calls[0][0]; securityPluginStart.authc.getCurrentUser.mockReturnValueOnce({ @@ -197,7 +179,7 @@ test('getUserName() returns a name when security is enabled', async () => { test('getActionsClient() returns ActionsClient', async () => { const factory = new RulesClientFactory(); factory.initialize(rulesClientFactoryParams); - factory.create(CoreKibanaRequest.from(fakeRequest), savedObjectsService); + factory.create(mockRouter.createKibanaRequest(), savedObjectsService); const constructorCall = jest.requireMock('./rules_client').RulesClient.mock.calls[0][0]; const actionsClient = await constructorCall.getActionsClient(); @@ -207,7 +189,7 @@ test('getActionsClient() returns ActionsClient', async () => { test('createAPIKey() returns { apiKeysEnabled: false } when security is disabled', async () => { const factory = new RulesClientFactory(); factory.initialize(rulesClientFactoryParams); - factory.create(CoreKibanaRequest.from(fakeRequest), savedObjectsService); + factory.create(mockRouter.createKibanaRequest(), savedObjectsService); const constructorCall = jest.requireMock('./rules_client').RulesClient.mock.calls[0][0]; const createAPIKeyResult = await constructorCall.createAPIKey(); @@ -217,7 +199,7 @@ test('createAPIKey() returns { apiKeysEnabled: false } when security is disabled test('createAPIKey() returns { apiKeysEnabled: false } when security is enabled but ES security is disabled', async () => { const factory = new RulesClientFactory(); factory.initialize(rulesClientFactoryParams); - factory.create(CoreKibanaRequest.from(fakeRequest), savedObjectsService); + factory.create(mockRouter.createKibanaRequest(), savedObjectsService); const constructorCall = jest.requireMock('./rules_client').RulesClient.mock.calls[0][0]; securityPluginStart.authc.apiKeys.grantAsInternalUser.mockResolvedValueOnce(null); @@ -232,7 +214,7 @@ test('createAPIKey() returns an API key when security is enabled', async () => { securityPluginSetup, securityPluginStart, }); - factory.create(CoreKibanaRequest.from(fakeRequest), savedObjectsService); + factory.create(mockRouter.createKibanaRequest(), savedObjectsService); const constructorCall = jest.requireMock('./rules_client').RulesClient.mock.calls[0][0]; securityPluginStart.authc.apiKeys.grantAsInternalUser.mockResolvedValueOnce({ @@ -254,7 +236,7 @@ test('createAPIKey() throws when security plugin createAPIKey throws an error', securityPluginSetup, securityPluginStart, }); - factory.create(CoreKibanaRequest.from(fakeRequest), savedObjectsService); + factory.create(mockRouter.createKibanaRequest(), savedObjectsService); const constructorCall = jest.requireMock('./rules_client').RulesClient.mock.calls[0][0]; securityPluginStart.authc.apiKeys.grantAsInternalUser.mockRejectedValueOnce( diff --git a/x-pack/plugins/alerting/server/rules_settings_client_factory.test.ts b/x-pack/plugins/alerting/server/rules_settings_client_factory.test.ts index 176082ee02336..a91e6697a4d8c 100644 --- a/x-pack/plugins/alerting/server/rules_settings_client_factory.test.ts +++ b/x-pack/plugins/alerting/server/rules_settings_client_factory.test.ts @@ -5,8 +5,7 @@ * 2.0. */ -import { Request } from '@hapi/hapi'; -import { CoreKibanaRequest } from '@kbn/core/server'; +import { mockRouter } from '@kbn/core-http-router-server-mocks'; import { RulesSettingsClientFactory, RulesSettingsClientFactoryOpts, @@ -33,23 +32,6 @@ const rulesSettingsClientFactoryParams: jest.Mocked '', - path: '/', - route: { settings: {} }, - url: { - href: '/', - }, - raw: { - req: { - url: '/', - }, - }, - getSavedObjectsClient: () => savedObjectsClient, -} as unknown as Request; - beforeEach(() => { jest.resetAllMocks(); }); @@ -60,7 +42,7 @@ test('creates a rules settings client with proper constructor arguments when sec securityPluginStart, ...rulesSettingsClientFactoryParams, }); - const request = CoreKibanaRequest.from(fakeRequest); + const request = mockRouter.createKibanaRequest(); savedObjectsService.getScopedClient.mockReturnValue(savedObjectsClient); @@ -82,7 +64,7 @@ test('creates a rules settings client with proper constructor arguments when sec test('creates a rules settings client with proper constructor arguments', async () => { const factory = new RulesSettingsClientFactory(); factory.initialize(rulesSettingsClientFactoryParams); - const request = CoreKibanaRequest.from(fakeRequest); + const request = mockRouter.createKibanaRequest(); savedObjectsService.getScopedClient.mockReturnValue(savedObjectsClient); @@ -107,7 +89,7 @@ test('creates an unauthorized rules settings client', async () => { securityPluginStart, ...rulesSettingsClientFactoryParams, }); - const request = CoreKibanaRequest.from(fakeRequest); + const request = mockRouter.createKibanaRequest(); savedObjectsService.getScopedClient.mockReturnValue(savedObjectsClient); @@ -130,7 +112,7 @@ test('creates an unauthorized rules settings client', async () => { test('getUserName() returns null when security is disabled', async () => { const factory = new RulesSettingsClientFactory(); factory.initialize(rulesSettingsClientFactoryParams); - const request = CoreKibanaRequest.from(fakeRequest); + const request = mockRouter.createKibanaRequest(); factory.createWithAuthorization(request); const constructorCall = @@ -146,7 +128,7 @@ test('getUserName() returns a name when security is enabled', async () => { securityPluginStart, ...rulesSettingsClientFactoryParams, }); - const request = CoreKibanaRequest.from(fakeRequest); + const request = mockRouter.createKibanaRequest(); factory.createWithAuthorization(request); diff --git a/x-pack/plugins/alerting/tsconfig.json b/x-pack/plugins/alerting/tsconfig.json index 362013f577219..9a3976445c235 100644 --- a/x-pack/plugins/alerting/tsconfig.json +++ b/x-pack/plugins/alerting/tsconfig.json @@ -56,6 +56,7 @@ "@kbn/core-capabilities-common", "@kbn/unified-search-plugin", "@kbn/core-http-server-mocks", + "@kbn/core-http-router-server-mocks", ], "exclude": ["target/**/*"] } diff --git a/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client_factory.test.ts b/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client_factory.test.ts index 8952ee9550fba..bbb33244e2975 100644 --- a/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client_factory.test.ts +++ b/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client_factory.test.ts @@ -5,10 +5,9 @@ * 2.0. */ -import { Request } from '@hapi/hapi'; - +import { mockRouter } from '@kbn/core-http-router-server-mocks'; import { AlertsClientFactory, AlertsClientFactoryProps } from './alerts_client_factory'; -import { ElasticsearchClient, KibanaRequest, CoreKibanaRequest } from '@kbn/core/server'; +import { ElasticsearchClient, KibanaRequest } from '@kbn/core/server'; import { loggingSystemMock } from '@kbn/core/server/mocks'; import { securityMock } from '@kbn/security-plugin/server/mocks'; import { auditLoggerMock } from '@kbn/security-plugin/server/audit/mocks'; @@ -29,22 +28,6 @@ const alertsClientFactoryParams: AlertsClientFactoryProps = { getRuleType: jest.fn(), }; -const fakeRequest = { - app: {}, - headers: {}, - getBasePath: () => '', - path: '/', - route: { settings: {} }, - url: { - href: '/', - }, - raw: { - req: { - url: '/', - }, - }, -} as unknown as Request; - const auditLogger = auditLoggerMock.create(); describe('AlertsClientFactory', () => { @@ -57,7 +40,10 @@ describe('AlertsClientFactory', () => { test('creates an alerts client with proper constructor arguments', async () => { const factory = new AlertsClientFactory(); factory.initialize({ ...alertsClientFactoryParams }); - const request = CoreKibanaRequest.from(fakeRequest); + const request = mockRouter.createKibanaRequest({ + headers: {}, + path: '/', + }); await factory.create(request); expect(jest.requireMock('./alerts_client').AlertsClient).toHaveBeenCalledWith({ diff --git a/x-pack/plugins/rule_registry/tsconfig.json b/x-pack/plugins/rule_registry/tsconfig.json index eb42db1856f5f..8a08fec6ef6a3 100644 --- a/x-pack/plugins/rule_registry/tsconfig.json +++ b/x-pack/plugins/rule_registry/tsconfig.json @@ -33,6 +33,7 @@ "@kbn/share-plugin", "@kbn/alerting-state-types", "@kbn/alerts-as-data-utils", + "@kbn/core-http-router-server-mocks", ], "exclude": [ "target/**/*", From 037cbce707fc2ffba1397b87673b6da80db3851c Mon Sep 17 00:00:00 2001 From: amyjtechwriter <61687663+amyjtechwriter@users.noreply.github.com> Date: Mon, 21 Aug 2023 12:41:22 +0100 Subject: [PATCH 05/19] [OAS] Adding update and delete to runtime fields OAS (#163777) This PR drafts openAPI specifications for: - [Delete runtime field API](https://www.elastic.co/guide/en/kibana/master/data-views-runtime-field-api-delete.html). - [Update runtime field API](https://www.elastic.co/guide/en/kibana/master/data-views-runtime-field-api-update.html) Relates to https://github.com/elastic/kibana/issues/137240 --- .../data_views/docs/openapi/bundled.json | 103 ++++++++++++++++++ .../data_views/docs/openapi/bundled.yaml | 62 +++++++++++ .../update_runtime_field_request.yaml | 9 ++ ...ew@{viewid}@runtime_field@{fieldname}.yaml | 58 ++++++++++ 4 files changed, 232 insertions(+) create mode 100644 src/plugins/data_views/docs/openapi/components/examples/update_runtime_field_request.yaml diff --git a/src/plugins/data_views/docs/openapi/bundled.json b/src/plugins/data_views/docs/openapi/bundled.json index 09515ba8b1ad4..894e5e02f4564 100644 --- a/src/plugins/data_views/docs/openapi/bundled.json +++ b/src/plugins/data_views/docs/openapi/bundled.json @@ -462,6 +462,99 @@ } } }, + "delete": { + "summary": "Delete a runtime field from a data view.", + "operationId": "deleteRuntimeField", + "description": "This functionality is in technical preview and may be changed or removed in a future release. Elastic will apply best effort to fix any issues, but features in technical preview are not subject to the support SLA of official GA features.\n", + "tags": [ + "data views" + ], + "parameters": [ + { + "$ref": "#/components/parameters/field_name" + }, + { + "$ref": "#/components/parameters/view_id" + } + ], + "responses": { + "200": { + "description": "Indicates a successful call." + }, + "404": { + "description": "Object is not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/404_response" + } + } + } + } + } + }, + "post": { + "summary": "Update an existing runtime field.", + "operationId": "updateRuntimeField", + "description": "This functionality is in technical preview and may be changed or removed in a future release. Elastic will apply best effort to fix any issues, but features in technical preview are not subject to the support SLA of official GA features.\n", + "tags": [ + "data views" + ], + "parameters": [ + { + "$ref": "#/components/parameters/field_name" + }, + { + "$ref": "#/components/parameters/view_id" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data_view": { + "type": "object" + }, + "fields": { + "type": "array", + "items": { + "type": "object" + } + } + } + }, + "examples": { + "updateRuntimeFieldRequest": { + "$ref": "#/components/examples/update_runtime_field_request" + } + } + } + } + }, + "responses": { + "200": { + "description": "Indicates a successful call." + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/400_response" + } + } + } + } + }, + "servers": [ + { + "url": "https://localhost:5601" + } + ] + }, "servers": [ { "url": "https://localhost:5601" @@ -2434,6 +2527,16 @@ } } }, + "update_runtime_field_request": { + "summary": "Update an existing runtime field on a data view.", + "value": { + "runtimeField": { + "script": { + "source": "emit(doc[\"bar\"].value)" + } + } + } + }, "get_default_data_view_response": { "summary": "The get default data view API returns the default data view identifier.", "value": { diff --git a/src/plugins/data_views/docs/openapi/bundled.yaml b/src/plugins/data_views/docs/openapi/bundled.yaml index 01f5b4eb3615c..7fa381a6a3d02 100644 --- a/src/plugins/data_views/docs/openapi/bundled.yaml +++ b/src/plugins/data_views/docs/openapi/bundled.yaml @@ -280,6 +280,62 @@ paths: application/json: schema: $ref: '#/components/schemas/404_response' + delete: + summary: Delete a runtime field from a data view. + operationId: deleteRuntimeField + description: | + This functionality is in technical preview and may be changed or removed in a future release. Elastic will apply best effort to fix any issues, but features in technical preview are not subject to the support SLA of official GA features. + tags: + - data views + parameters: + - $ref: '#/components/parameters/field_name' + - $ref: '#/components/parameters/view_id' + responses: + '200': + description: Indicates a successful call. + '404': + description: Object is not found. + content: + application/json: + schema: + $ref: '#/components/schemas/404_response' + post: + summary: Update an existing runtime field. + operationId: updateRuntimeField + description: | + This functionality is in technical preview and may be changed or removed in a future release. Elastic will apply best effort to fix any issues, but features in technical preview are not subject to the support SLA of official GA features. + tags: + - data views + parameters: + - $ref: '#/components/parameters/field_name' + - $ref: '#/components/parameters/view_id' + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + data_view: + type: object + fields: + type: array + items: + type: object + examples: + updateRuntimeFieldRequest: + $ref: '#/components/examples/update_runtime_field_request' + responses: + '200': + description: Indicates a successful call. + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/400_response' + servers: + - url: https://localhost:5601 servers: - url: https://localhost:5601 /api/data_views/default: @@ -1832,6 +1888,12 @@ components: fieldAttrs: {} allowNoIndex: false name: Kibana Sample Data Flights + update_runtime_field_request: + summary: Update an existing runtime field on a data view. + value: + runtimeField: + script: + source: emit(doc["bar"].value) get_default_data_view_response: summary: The get default data view API returns the default data view identifier. value: diff --git a/src/plugins/data_views/docs/openapi/components/examples/update_runtime_field_request.yaml b/src/plugins/data_views/docs/openapi/components/examples/update_runtime_field_request.yaml new file mode 100644 index 0000000000000..4cc70238b5ee8 --- /dev/null +++ b/src/plugins/data_views/docs/openapi/components/examples/update_runtime_field_request.yaml @@ -0,0 +1,9 @@ +summary: Update an existing runtime field on a data view. +value: + { + "runtimeField": { + "script": { + "source": 'emit(doc["bar"].value)' + } + } +} \ No newline at end of file diff --git a/src/plugins/data_views/docs/openapi/paths/api@data_views@data_view@{viewid}@runtime_field@{fieldname}.yaml b/src/plugins/data_views/docs/openapi/paths/api@data_views@data_view@{viewid}@runtime_field@{fieldname}.yaml index 15c5659f09d4a..55f1e14dafb8a 100644 --- a/src/plugins/data_views/docs/openapi/paths/api@data_views@data_view@{viewid}@runtime_field@{fieldname}.yaml +++ b/src/plugins/data_views/docs/openapi/paths/api@data_views@data_view@{viewid}@runtime_field@{fieldname}.yaml @@ -31,5 +31,63 @@ get: application/json: schema: $ref: '../components/schemas/404_response.yaml' + +delete: + summary: Delete a runtime field from a data view. + operationId: deleteRuntimeField + description: > + This functionality is in technical preview and may be changed or removed in a future release. Elastic will apply best effort to fix any issues, but features in technical preview are not subject to the support SLA of official GA features. + tags: + - data views + parameters: + - $ref: '../components/parameters/field_name.yaml' + - $ref: '../components/parameters/view_id.yaml' + responses: + '200': + description: Indicates a successful call. + '404': + description: Object is not found. + content: + application/json: + schema: + $ref: '../components/schemas/404_response.yaml' + +post: + summary: Update an existing runtime field. + operationId: updateRuntimeField + description: > + This functionality is in technical preview and may be changed or removed in a future release. Elastic will apply best effort to fix any issues, but features in technical preview are not subject to the support SLA of official GA features. + tags: + - data views + parameters: + - $ref: '../components/parameters/field_name.yaml' + - $ref: '../components/parameters/view_id.yaml' + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + data_view: + type: object + fields: + type: array + items: + type: object + examples: + updateRuntimeFieldRequest: + $ref: '../components/examples/update_runtime_field_request.yaml' + responses: + '200': + description: Indicates a successful call. + '400': + description: Bad request + content: + application/json: + schema: + $ref: '../components/schemas/400_response.yaml' + servers: + - url: https://localhost:5601 servers: - url: https://localhost:5601 From 00102e33f3d917f5d2a7add091f3f82d8378fd66 Mon Sep 17 00:00:00 2001 From: Stratoula Kalafateli Date: Mon, 21 Aug 2023 15:12:09 +0300 Subject: [PATCH 06/19] [Sample data][ECommerce] Use Lens instead of TSVB (#164195) ## Summary Closes https://github.com/elastic/kibana/issues/164146 Changes the remaining TSVB panel to a by value Lens metric. Screenshot 2023-08-17 at 6 10 06 PM ### How to test Remove the ecommerce dataset and reinstall it --- .../ecommerce/dashboard.webp | Bin 62402 -> 36638 bytes .../ecommerce/dashboard_dark.webp | Bin 62944 -> 37238 bytes .../data_sets/ecommerce/saved_objects.ts | 37 ++---------------- .../translations/translations/fr-FR.json | 1 - .../translations/translations/ja-JP.json | 1 - .../translations/translations/zh-CN.json | 1 - 6 files changed, 4 insertions(+), 36 deletions(-) diff --git a/src/plugins/home/public/assets/sample_data_resources/ecommerce/dashboard.webp b/src/plugins/home/public/assets/sample_data_resources/ecommerce/dashboard.webp index 59a90157b011167ff980a1217bb1122f588def3a..cf0e40c7694700da39365a22055794528864bfcd 100644 GIT binary patch literal 36638 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 z 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 diff --git a/src/plugins/home/public/assets/sample_data_resources/ecommerce/dashboard_dark.webp b/src/plugins/home/public/assets/sample_data_resources/ecommerce/dashboard_dark.webp index b07db2f4c164a66e04c864e7b0c6538299f68272..8353e897767faf10c7393e23e10f1ec5d66a6998 100644 GIT binary patch literal 37238 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 T7eK;AVY%DLX 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 z z1vPNT8?rVbNZD?-K_*u87kASH0I*+6Wo$-|Fpp6UN%VuUY&YC1A72V!(GIJyt1eNphv)2+N8h-CB8{e8SQ?x(29TL*-KM!W$ zDP$HvS*$Q~CIOg!fhj(eFt+_SOAs3pbBeHt*=r>gf}h_}e(W67rXO5bK=-Ud001rL zFo=eJ{(u_m^YEW#lx*eFHg52*^&sD?!%w9PbQ{UKJENRiRaK)j&-xsrc1hDZO%*3r z1{|TxDqrVVX&8*cGT(-_HrhSdJa)4`v{roO8{10Id9jf66pAQ-m~_I{R(Lw)%Rf4J>-k+a2vz)zkxq1Oq2*S-_-vX!SoBDyzI%BNtaSH~k zX?>$c>zGhDIUnzwMocG_~m(-673lb~WaQblp z<5=u-Vat#QB_tsbaJ%k*js9_cZMC@wc6m{%p0}WGxVckqy(ds$K$&GG4LBqx%6d@N z_3EZTaYQT8BeZBh^Ky1%N4C05CFFay8|8{*;kNdyuhIYddmsXRKTNei+;O%}2wBY* zxyw+HgpvtS&N{JjLe6rw-=$Uatx!PR`T}C$>kJxfOz66m@Sf4h*mA&$ns60qlVFPB zs6lX(=F&@p&9pBWylGS}mDg{5-ZF)Eui}xQEi?D~p_Qu(zW!WaF&AxU;15m3R#b=8 zmYN}{5~II&?KL88HRNppbG0KmKaquwMduP)bX1PF>(2g(-=Zr})3kAH3GHOzds;#D zki1`7Uju>w?K8p7+uX_#rA@eVEmYQEvSiFuK#(&eJ*nN6q`1B4Jz53|RDeH+#&qUMma)WoivAIKd7UZY{muQpOYdEFnoL%YcU>TTDVMvEd9 zw#X**ejCkNJ_U2p=H6j*t(W)5NGBvS|G`tjAIL(4zQOH4okRx(SoCEfKz+&N>lQGx z)eet;+d&)Xn0%DdH_7VwApq(>tLW?rW3!3_(m&DMNC7f8?N|>nmqCl7d<&rx4-2DWS$|Fu;}ud&5tt+uC1&E-x{>?x zI^8$uX=?Jg`rHT3CX4{xKN9&H7M?k1%^64s{5SmY%D-?6Y=|cR!CDbC4ueYfMQga3oEIy%~ULi=1)`3f&Q`-`b`bbA7uzlo4}qON0iJZNDa;T9khk^ ztxJY9(g`mN5_+NlM2KXTYBvlE6@iAggys=QcSl|W?zCSp5GXapeE9}R0p`Zd_>Wal zsU^MwXwZVMD|NQp`dcLBOa6WULSHd?Kiv%OJf!t)97=F`yb(@LG-!f?ywI2xKn?c} zMrD!V`ufJEGt@HJ3uJl?UI00EQB5RZON~Z5wd&;d#l?OrYR0w@Kg6>WDihja#b;rP zZ$YNH;R#2Z#zXCzrfUATGZW4|4Mm%+Yw%pVgJp~0`OC%U8TjlBme-WvP)ulo*)R%;Jm^N_JpF~|cQo^K$WEhC)Ul@PlIeNJa5 zLT3+ZV<}oJ0CpU6EvW$!s%!+WR%K^T)deHtxJ>+2?)1tCt=+bizRJD z-S=3A@eM*8WleByN1bl633yt3Wdgg328|ZGTXn8=Z6{q8J8I35{A5RsZgioez&m1?1X@ z4sDAt8inXD1Bx?v!;LETW^Sz<=k8Q*o-sB`Hp%(aJQ(R(c#aRzcdBUy16|U3l%%gN zq%Xt1zLOxI&p7}4oWEmnmvPp4GlKSWGeYq?LM^1e$x0Y8Koyl1Ub{iQGA9bEEp{gc z=0!p0WAp$H93Ac4;~DA2Y~NhN!YZZ21r53~2&f~4Ue>7RtwnzVI1i+s1-BT-@N)?a zh$?jwElEB7YU)jKYmVP7(Q&0eS&$MdFTSbP*W6}$gJ`HnZ}-PpAl=ynAj8X3C}}b; zkA`|^zLaEt3u*gJrW|WU(N*{KK^4fhmjqnpPPn(PYKlii!_? z<%+QRsva4}e~uv=X6OZzfEC@rfU40K^G$PgeBJ$7h#Bkl@g@jJe)jjjI-ENwb;g8= zjkxDp@5<p6 zeo}doQjgXPf<>tBjsV(J>Ap|G!q>+dTM!beuIgXk33y8qVrN25H9&YFXtl>jU5z~5{PPkk`=@Rc3E8tAl>5yeJfrxcfHo0O78upei!RTodl%7G3o z>9t_FW-vm=zUs>)dkC;0GSqjvWe;$t{o7B&8p!WLF?{_YQID~zvsHdnf7)z+U(I_4 zLA;0SV5c1krKQwC-O1YF3TYS}kAK-Mm=2cRA;35fl#;n8MQkdSxp?$~ol%if@4zsi z@N-#|cR?Y-KXmypn6{!+UrpE|cvDDr`zliUflO;TtvwJ-AkC&@o5LxaQCNzz(7sV=+yiYrjK5XcF zxp7{hQ=qFj&Y`AcN!C{%8g6Z=`TUt6aMDYpJyP}5A#g>sA;RI4!~>YJj=x=jPUkti zoI;)C38Y)DvV0Yiu|C&0K>awlaW&=zudE>`NuF-n-w938e`6ES94LmKpJeWmvckZz zkU=xjqBWsL`zajn`VnJG6b#I+6|?k#qFBU(!=hb>IWIv20(Od?J5r6LlR+L5L>dkJ z%Gl+4xjzf3=Txf8m}r;H2oL@ezXSdJAvd?T36M263D^juA0zOi_4?mYS{&w6Z|Tm< zZQv(>7?zsO{e~rqmg6gy;H$za9|e#n4MImV=-W%5kNPFJroGCM4OX#AyM?DVYxc4- zj;#=!EtEfTawTw{by8F7g1%BBU|z1#09k=jx_agbYmAUZgar|l;N|+kwYMrEG@ORO zW=^r2ILH|RZix>d1CF@`qt{uXEK>O<5L#!$v>RWVO_971e)lW_xQMd<)zkvZcF|e# z&^iOn>gaB)sGiXZMe$CA}}IL*${CO zk=J1k!%d{wi54p30d8H-$Zem%C)%Z+Z$*mcs=JjSKG`s*C%==<1;?jT;B>-hqg@n+ z)z(shM@fU`@fGXb{WUDl5oNWGNkI@$GJ29>{s}77Acg~8$?Y(&^vbdHxn>qoDj?w) z2;v9+d-f3zTs4YEWv!9(>szs+(bt_TUxWEMLh3%yQygFq@(xX)J0u`8UdT*zP3@C_kccM(g%e#i;)}mT;1I6s3SK@Iv4xbCeP> zWho>u6GT{~M^->XwQZReQe$4gYgnOe{0AlvS`Tt7w7x4x>$C7Y3{{Ya?-bLtdk73&pYJ6MTIc(%ai$@41&UaB5@8`~s?c#BvraR}LMkxY6dwvtkzNBcYj2_$OY1Rr`K6VqS;0 zffId*CQjRt}$LP{|t~5 zw>r>seTheVrQR|~0tr>mui-~_DcD|>x+x$lgmL<%URqBSc<`%y7geR3Wj==}W4oiF zc=9^HVP~yf3fbE&21PapE2svPIIYq#kxo-&4NVlsaz;&9+(Q_7;rYgmP40F#Ol>zKVled?AKd3=t}5<=PE!=d z_@$e?OVZW^e!Y$#7J+&If6Hfa)Q-TUKZEg$&sE_lg|m&4rW4nxmJ8+ZW&$`1gah&* z%7EW+pHNK?8N#(i{4il-TYG2Bpc_}4^9LU3BC!8677joXm%iv3Fqv!H*`FG$o>Z}%L^;@y z7;Utm_F-8AZ~5Qiw1@aqGrn%ju|hYx9bheCF@>-kcZt(l(tfUGE|1Tdy%e0GM!zo5 zWV4%ze={I3A_Wf}Com12ZaGn~+R8ZjWPrCAh<8vMU#T38DNjkyf&+De&{&5(tzwPP>40K~5`kkIS!BDZ%TG>ZnTjOp_>vdq%L*ramVFsX zZO%|rGNxJQuwp47cMxQbaSi~1;(oy2KLq}{l5T{B_tv{{M&x3dNf{uTDJ!G2hF}}` z1j2&ug9^FrA$#11G}{*v^{NJcy;R+5U7C+=p;cF=&rcPelDEmd@7LJL1~c*)#VC$( zp&4j97G7jSEcCX%A~{H52-8~DX2}OB7@#QNfe;JF0=f^FAj0R)Gr%gz3d;4|ibf8* zcfVeiZ%+q5@Z|(W#T+lAx-$LT%379JGWM1Tn#&Wxa?W;D4z>rS17NL1TPaFYB}&t; z%p5=|BLvO>X&~wA=>b{eet~@glp2PIVPu0SFmxn1;UMs`s*Qo+*U=74O4ua@N-7Ij zOzo8i)sC&c6l^ZzVTzrfG2F!BKuUI&9l_h0z+v@k3Y=B`$dqYMRem(aB#;wlgw9|) z`E7OeOyUN^-&<~609t$9L6e-?k42vVq2BM)Z9jTdKm}1suT>_1UE~VQZ45cbHB2dgAg=z{{&Tw4koSd zHJ$)hed{4tO^14(;}l2=>oD@^PZ){Xfd~;*VjQk}>*EJ*$Y+vAWF(xJauP%J^hm(6 z$Tw7g5Q%O3V9F4Z&w9!FfuY~QP!nT&ms{|1mIOaF#V=Jfliz#rZ(ux$s4XdJfbQj3 zTJ>J_J)SuSSl2NPPu8YeF7h)W2v=eaD3f?P+J7nzNTU)z8-l&j%hGKOczLK{MKn-KRlxfM)6Z$!kheE=dZ`7^+X2A1H3><58sC zq5sj$&Y37oPu(H#0+9l6SfRV-G4*%VP~!F?+>kD0<;gFFkQdwD4FYUZ&qcbzmc_? z7`Ft#L$^c9hKy#Euj)BAK9>Jy`jMNTdNxppY@ST{QS{hmA))ZcHWaqPMxv0Ty!E1k zfe;wYdBk+LUMjZ=#+n;c`NxOde&aIg(Osk*!irHdhf3Ip%r z1G?5XXt9N*!_L*^#}+~0Uw>_S%4A$vM~tjSb7X+*3IbK?oZ!d$gU}zTnRF7y%15o8 z%Us~`6QN|y^i9=AevNhwyq`45F!U1RlbL(aZ8sk$-7ubC)h zb&^$A?nvJQ`*x(wJBFPDD&BmcNqzqLmEmXpiH?^=VC7{dDgu8 zQ1YFGEHOgtH@e#-&1{hTjWPZPXzQKMI0QvLn4mx4l+yEhpr#DS3MG@I6%()3Bmp@k zS~vy}xGmi=8>3am-QZsu_qk|H-kHcph!DnQKBJ)hl=WhHlg=-HCtO@8d=ECv=kCPcy`LV8Dl4zg zS2m>bv-nn+UI^UXOM8bv;S=!EsD$VC5l;V}#5Bw%fOSbf&?&AHt~$i9VFcAHQ>U8z zDba2&ADkcb*5V;rMw=QI4(R9E8wKAGqFJhW1ym&2!-wj%x+j{<)QVLD(QJ`g&iIVs zL7{w3GZ0b{mh|5C1GEbQxr`9xOrdPADo(mrBE=7FL=p4sQRVB%%0SWfU$Qq0mC9Sn z|41%?YN_v}Z)=Mv3`au2uC68C?hj6gCs7W-z1}rS(Rm^6CBQw6@vd5;r6M6SGI2A* z*CSRo6_$jtr8{L&?=9TxQr~2$NRE+yQQ(n4P37WeyZrD&R0H;uG-gvv6L`B%B? ze!0zZn{uf4n>^!cdJ;Ob2m8N zLhqi&HU;qv096@TG@GsL@pp1qq?w;a88)}=@zoSSXtFyAxaA(8d7oC;Qz;v2@6?y8 z`7)u4()LNw-!TT%(L9sln%@+jw|ra;W$Wef|BZ4v17OPuS{04Bkj6R!(vZa_)aSx> zZEVVbJE;;;5L#26$eCopo*u(QTc-y{rJQUL;mnYt!(o{>o|$JaSsMMPG*ckJ*?J&l z#cMd4_S^JjdohtvEN8Jr>57$qo-;83O5XM@)%~YuXL%lhf*Nhx zwOM_ba|}YGE(%Em5OKZ$(oX`A2NCo8*8bRZC~$I~Xqe6H3ky;MnPHGJr1ntGTAUo{ zS*1}GF2%fQH=q9kkXe6zltU0c(uUz_7Mh}e&{kK2siXQ_&kF1ZKV@aOw*0COqP;(i6xVPS#G+^Uob2QB;yOg2 z%2$*b&0*MoT}>~!t6vhFROJTX0UnjWkuK>wr%4^@Z_43=Ft;-vV1ft3$8xH8zM7nO z=bfh_U{w^Vqtd5xwK58`d?%KpfLc8IYr4*lgIQY<$Hh3rfwM_|&l4+V|IX?O=L(&G zYPW5w03Au-KA3_{CHb)FF>N>zr$GAIqAy@cg9+bgTsn|Q zHn<|Z4#b>u?A_>p1MCj+C-reMUjSA=$4K2PfCmr4*_#g4EXFM+v@5iD)BkcF8iM9! z0k*LV>lF^e^HhFiZsoA*qFBMQ`ZX%*Wy#}V>bLs&OplBZGvjIy`t`S-%gWx*t z7&O%Z2BzAo$$g*E7^+nG7X0Za*KI)zj}ae#(SMPCVv!4GLE^k|QhwPSM-ne4L846! zosJK8c|xYSpi%?=2dBuyY8$f#ocRaHi{<&`w-kBK9l1fjcSvnBTwhFT^fa#dT2RpD zgy@~W*8LzNuBCZbvNYh_%e!Db#Dfto!gSwvo&1D+!gSV_87KpR0A?9fYp#ZqzX%98 z@@l-Lvt?H&|2ogB&Ngt&{*89T{J&Pp9=wO-lW0eFFzsdpfJd(I3eC=Hnz>8mSnaDa zG-^1!+%CKyx1I0XOk_;>VcvA+<^_H3%%h|Wrg05gYtOHV0Awl^IxG^eSLvoWo!HwRP9_(SQ~6^7)$<4Lft#OZaAHc70m zFIRn)PEMjZFqA};492ak+trPjQf9kdMZY<%T5Fvp*q$HNLE;o_?_`%z>)EbZ9 zFoCDH8HORcW4SrnOBOl3ABU8K?}B_!ZPPy3)3QexjhID=)38^~uOaUd4TM(E`*m8) z1^q-K|4`){qb))H6tvyj%-+7C0O1Q$PL}gwZx*kYw6L*X;+%GA5R!k{ZpZ0f77QCP zKM+e%tiPW{gf=`A>BTG{Mv5kFhK^QrW7};AySzU*WNG+y6D4T@9x9ozuNQ-92Z8zw zH`iw*Oi7|-6_cE2?HO;vIhklq#HF0Tkb?2O{?vzLs#%;(D}jrluR6FQAYhUX>shiExRmE4n{a|DGUcEN*sp0q^n^!C%???vVxWZk{CwYhPkd+!KU`{AODMwbvW|mwiC!}(#>hOS$0IJ@@IoGT zf?}?vA{b9d@-Jd5FxbOM2ljB`ikVAy$z*g-=y>5H5Q$$AkT@66Nxb&uZiQ?a}|1^Il~^VN&Q*r_<-Q=K0wpDO^vc8HrB zS}@8zgVZZaV4VXqa}0uF>cCsy zl)e|6pETM-o1omd9|pb^t2jLwl}eaUR;VQ->~^7=-|DvY7(xlI&L2Joc&$a4FYnV& zoA6r9s*zD2WYEeZ?PTxkpZB32Wx!82&=!tnzjlc?-b?C|7pHLG%n%#=_^=MKB4`=TfSLHAf!MuW;8R}Jn}^JAZhZCP3Lk;w1wx)K3kcE za#cL4O=?VqhH32~Tvb0}QZi!2P{}Sr_7#W; zVsQ^1dKuF&8uygwsQyO~b8%VWTTL_|JfP6D1Mc+5S>>DW8Mowq#DR}UIO~ehY|^vb5G;Swyp6(7GaA%JLx}mok1=8a27%`d z)2CeG;#$+VO8b`;TaIC;hS=m9AVf}9R+@=Yo+ZiemrD-3+WV`3Q0yMN#+NrQ-$nga z#Ik{$6tF#l%`393v`Zp~mLW@vtO5~k?ZQGxQL8NzhMgy@o*$wgyri79i)fmC@WYAl zKS`(wZg*uv0z@V3tzb#p4e}yO^HwH|EC#Yh>T?FKSl+t7|#7h z{^LH31R@Uq_1645=q})S2q{eGbyi?ZRwgdu$_r&S*TpsJ?QqI2iJy>=#s8!M`ySQW z2>Jbi(iJpuSVPQ!a*kv!RAK&aujiKue>IrG$6f4w7!P-yT{sBl;bYn+HUesT9b!S) z2&bc!9O$6jsQAV^UUD&HO7uL}3k~x9*lyw>cCr!JkTL!{i_gY0?%;`N&y#zdQ6tcq zEasjmw$Qt_HmNqeV4vfs8_Mb&FsDCq7S0ha0q8Ftkg#6wh zbp_Xs$wdqhLhqdKH70PN@wT11Ahtj7_1zBNND@*EBVXD>?V2tkK&QNW(cRKI;Tsr+ zAEF^1cxA`cvCz$3 zuIA+g*LP>8EjXHnz911&i^K8=;i{4${)C1$z5j$BcVXlc3WA1S6GXrJCV=zA^a)K! zet%uq95<3MNSNYk*3s5L#mRHM2?2{21F(L7jhC9GdA>61<(6ZBT&Xlji zsX=Oza%KO$Cd`IdmA@Bg;az7D8!wq6U**BbLN7Qd^J(t}Le$UcqRFFU5`Vt^oterz z#N=ivO@y%k*Vgv#B!3D$>Z68 zL~w+j%a@f$|1wxG)X&SKI+)Nj<=sItBj5Jj-Q7hwx%u4$1P;ZczTO$tdo-$S1d;B5 zHF2quXd)SSzuLSY7$#Qf1n*K|jfX%gB&%IAw=(;hpOz$Nx_-Q%N91r4DrGuvPscmP zv9#l$TG>R32g)9|nVx9l?W<0MaElzD)#4$|_U*^z-lJ%5xFJL+HDm=VNcky`tPbd7 zLCq1fqRR!|6R^I#c&=m(82kDt+D>I^jM{*#b%QAq13_`F=dALkiOJn+6(1%UUYn^;yX})?}JPZJ&b|=EuRm&ah2fu^>|My+l z^ulrKjj_avezp?4q&s8MrnSFSd(i}o#2geFJiO{1Kll5T;6{udHIntFI-GJ}U> zgeVs#RG)+38S&#QZqFK^TLBh$zBYK?eIP}ZFIDnQz0^43KfgR5>aDM!7MFBcv094%rt{U)wrs{(VQnUYL`iS}6SmOIo22418L zNZ~p)@cuP}*P?Qt-H1@5v)1=aFVLYbZ@MnUxZZ@bv8>p2YlkeMBk$6;7_E!z5si?>ZJpR{2SMMRD->^G26lBf^{mj5Q1lGnJE~F~uYklo7p-eLb{+ zzZix7@VAR!5E0()ZkiEd)430Oc6V!Gk$Xmnz?oLey;~QLz>M36TX)}G`(3{d`2-(T zq$xEl&PVD|x0`#MPeJ z0mkAB;pA!6cCq{+1MoSao_^A`+3w2f?0c7(p*_JGX@KHB0>2fLpfaWt*Twfhvy2TobKaW@3j3ZsBu;WJPq1Ki|b7SgY5P>YR zF_wgs9GzD~p!w24z-5%n#8z|A3BJsYVNQV<9DJ{-7Iz6-XVveAbuPmI6EC3Jik5M)sLN6K z>}YeZmO+eURtYda(wStrqO!&#oV0%tV<`-VgNFS5a=u%(@i$Dv`p6&C7Hm_gXFmU$ zZ(H);&l%}BS57tiD9^}1a;Gki%Qg$d^A5PZ!(USJ-n@n&sY**GIKLdG3hYXSB{4=% zjX{DA6;Voda7tB&o$jyaABRM)`h}<=_tMVh5Df33&Dqa$r`Im94F~$lBZrT=fZnY) z-CfGM4(eC*A+oca)$Ez&YOtbvJOMIYs6-zBcU1rl@~O+kOnFUfTn~Pr_OJObZdy(3 z_X5$IN{#6S%JNjl{f5V(&-*75cxkIqwV7U{rPmr`^o5%Ro*#wXs8G*wZ?~06W!k#B ziACJW`tW-(CU3$gsg6y>(#^o0GQhN5XU@k+w~o(ibQ?XHroAPxWCho~F<)ecID=!D z4HX*;JG#dZpdBEh!yf0hHEn^e|Bqhl(W5uWLju}}3vY0Tzn#D*afZJ%L3yCm;|bY- z0Eubr{3m2r7Wri@Tz35fNyAQL{7Y8x)eSoc)B5oY2~bAt(;W1GAy1Ujq}385m~t=)a8#4uyVL-s#9p3 zEUKxl4r6zT&IkG?EDXk*-kzqKlX z5vi}Igm`X|_l#6v=nz`%csu4mEeBxR&e>cX;KGhq^7p@x9%QEg;_6xcc=5fSL)IgvgClr}%wG=fDY<+l z=s}fV%V^|#dwm`65fNqhvk?KCHvB2FYSPZlzz=GXhgI?>PD~`^9C41p&O~9+@tepT zlTA~fsMImeVApgV97V6z1VG+vU4E=*=o7QcPYeTc@smy7ZJ-6p-~=?Q!82iL9|S&q zXD?`->z-_K{F|n;zfcXuO3xmqxX+5CQa&uIHfh-OSgitRg$vNVX$q1aTVlwEq1juA z1D}2VkzjZAA(o-(v4EgAkC3-=lASwM%O;L^!^%@YxLB)w#AaG1y8d$t> z8y_i=9liNO@aX1<JJ%uQ+b>s)8b}@_Fh-c6U*`K+ zW2+UgWvSrzS-^z!C-9F(2e`o18Eb8jfw277_LJXB0KVMUnA%OP(d){mI9%mLvmk^T zAd1Uk1*=zLXxg1)yJC}gUdxvAh-PgsYj1{d5^=0vWsjE1_>r}F?S*^6ny%FX1;|GT zT!H-1j@nv*wk0)?D1iOe=Z=HvT7scV7BoR^(UAP5O1LYtF)T2ECcPZH^DDZX8ZXx! z8v0Z&A()h2oKV3WlFtHafdCC`gBq~6&iXb@D$1V?Z2Vq@KOdJ=N;B5~HH!0+S(Tyv zBH0+tOEqL38i1GoC%~O0TJ~m0*_slE)42lUMtlgsC)(Qx6~EpsD$jxNW#VtGlNvD! zZ?N|mfnT)_5!4)j7zEqq0DJG5L3-Uu9<*KfrQ@^bCpzk@M>jUD?;yxwH70YPYH)}T zZhDgCQ`~)d&~TRrPt?H!4Lj0tj`mGJhpG8SVweHziSVB?3KavfwE6pXwG*}Q9aUk7 z4u7jSnNFue1pfJq!L$T!1a`chc3(v-IO?a>#92dK8N<7!0?0;ngJd8L=J&+L&p4Ll z)JX+vt}uWl1U5-m%a?kUd~>brC04&OMORjNlQ%4Zr#?$uklFGolM;O$&ugxHBZ4oi z@SC6fzp}4_O6?hB{wo2`=)wOCl2atzw>kKO7|%VHv+lSgRPc5X;h-4L-wo|3KA8>1l02XF4xjb z(nf}P+DC}?9PBE9C+s#I-`Pfp@_G)?qq@EjniyFKp(4FqX~`=`oWzp~>S^rTa{|S* zeT03gv0yVi7P2#9NLt|cFdUqa3IPs3$19-Y`pBdmf5kab{ovF2u) zYj=V2?W?(x2N$6m(ZPrSGc0bkx|o9m&ZZXVww%@?BoD5M6fe2)}=6Fhj0QaD{ z9P9hg<4et-Vw%`j(J#sGUd!er-$$vLj6p3oky^KSaNWQBHPYwYN?&XK8@}NcQix|j ztKwqxqPN%pvUO-Akr8n|@M4{Le4F`F-gQe#xV8>FDxTdACV?XP=wq0sf7bTi(TRXi zrK~^@KRv;?(uMGBg1nQ15>dpv@P*qgO4tR zWm^G&ZeL4jPbd}E>tD~n01Z$ptochkLkLKsnYJU--`Ap1G$P`Hc>afU=ajPq6^=w7 z-geW3Itd9FK>h|M`Jb7yasZhMP;4ql_tN-U{1vxLSgixTb7YXDs4bk`sStf$3`}!g zA-jK`9`D{aUxZkyd9zT3ReuR5T~-H`$jd#&b${QqA_YWRt-yi2++(7OHxTFZ^Yn|~{1B|*1~7S}=y`Xa1z8s64942t6BLvQ zdhhYQkEPvznK6)Pd{INFO_Jx6h7J{(nC-0?4LjLhHVNwOs1L`8PnGE%+}tv+=e|bc z2(3?w2KX#K&Jn;R7sx$4xs!G+O&1o=8f=-C0}eYNq#%U!Qe$NUQ>BYTq%h<3l?zDi zTkw6Nr%$d_onuK&BydbTMrf|B6I{tXe8$8)SHU%r%)c+^(YzE54YaQbhT@fHx852H z9X_C9;S(RyTSAxq{L@3wjgvFYmn%!1l1dmpcBc@vw7ku>u^t6BPeD2SB@*lkz)e_Ao{ zCVB`YQX^n;7ylN$@fobu4bV1(B14 z;5sD?=_slK;GM~m`5*7FlKEdBZ}=LND*CW1BpWlA)G)D$c~UTLwi?7C5ho1nKYe%c zQ2Kb@Y$DPl=~+7g?wRZfKcOi(8$e6>CxpDgqo@NcqVMB29UjLjeR`mj5Q1zmU(*rt zs78uG^yqNNoq3-wePL%N8d6H^r^_Zn9Fl_4kw$3nT@NU7Z{9L=#pqZSYDWyjd_zP% z5y20I4Q#{F&2h-(f>|jP|488&9`EWMM(ejEZldX`at4ejtu}kov*SOdg+V=7l)5>G zV4BafS)7kR>2cAkQ?n=Xu@gEjzsd^3{?sDOsO)$7t#S9aesGj`_Yd86P`nlnj z`I;b}QKFOV5eDKgsDe{JPGEoLcOfAE7G7}*L!0Dp)NjAs<+XW$mVoIi^BnJxt&7xV zz5saT)*#oapx_6<_*GHZ+=)m!N-kyFOGxXITNZmlN&Zkp>u=IFIc$31gZWeai1(Dt2S-H#g4=i>0*+8vzf}|U_oRvN z39jfnVUre`V9V&S1$*%GnU%1&e~Nb|>7Af&_8x;5LHnB=`x@)4r$B%d_CH&aQqrbK z&MTs16&rV`#Y?bOK5Bz3yJlA0C)<0V!X#~wKo7wFrHd?mq6E( z-{Lkd?-Zm_>mv`@OlJenQz*-()UFuoh4Tfb#N9hRcx)~21Ck%|D^i&M-JYoeT8CPJ zcMKZ1j>GX_+3YOvn+9pu!W~h7-R)aNQtzqDYHa$Q9sH1&5FMaDm#1mLldG91UN<=1 z=QH)fELwR17mA{5&tt0kG|MlRML(k>D*P}10}W(C69|!W z{EkYVEWbzw+D(U^flaRAYgb%8peCs<=pmN|C32J0g6K}ys_=aS-ZiPWJJmy$L5H)+ z$@1gjQeLD^5O{5in%w6+?em3HZ-vP%YlW!Gm4lkXu{PD;lAQO|X5e*^CsOlG>n7c? z4=%n(4!ysW-o$kW>$b;^m}Is*c7snEhsBb>u1Ec%dpM&bW(wNzSB>%`AG)E@ItPN!ingHCEotX>i8xcw>l$L(B6gHAdQj6w9ItLCE#DP@F!&&HQ zDbDPRM*8?Du|kePr%%qll<=|8yGG@&PyC#Z8DqKxLKP((d1>aQ?C^p0$l1tsz3uEL zudmzzq$>=o8p_5A?lXDvxd*=^+VPET`%RqF}*7!1x>WHgCKpN~z?VS|d zi-^0(#Bb(ty;DZ6;Q$_;dNHqp(T6ictcZ|CxMj_6t=qu6+y3WsJY1@er5j&7k}RsPSjw>B#*gDos5@ zFQZ`!>bv}g6xJhfmQ4-KdjPx>ESE{c$7-P*^tlD13t$pg zryp6)G5a@EhaB>@e|sbZ1STsT!y=|=P}=cF zlQ8}9#^$p}zeE9vz#7VB%S$|BQM{*bMM66-a{krb7weY1rpf)`CHr^xTcC{<6f=3K z*r+kRBHE71u*AvVa6=or{LAi!=UA@sXkrIB2k5oiqH6YU`{VCqB`$OadFx$iKHTFo zjeHH?6fJOA)qI0A68hx^&mG~F#(aI>bOs|9#J6@>cm-DrMip2aq&(_Je| zv-hxDG4!*Mr~3T30Z51@Pb4Zpfc7h#PN?iIjRP2`*VLeGkhi_dXSrhG>Nm8=0?{mlec!)|ErCMW2QV60Pl~i66cNi+e z`f=CVca=u90bK%vMHGii9M1w}5;=Zv1kqVI4>CYj-7)t`cH)uTJ}W#>9+b3fC=&E# z?D44H3yT?w^~{b{o*;CS4id?R1B&g?+ek&lA-6hjAyRpU$0>cR&Whtjr;@LtG9l#t zT>{+*vbLw70m)eY<)uWG2)vcKRG0<+*VO0GG`nl_AoQAuJu4?cgcELWFM$mnl{#!H zVnb|;U>V3)l2NJP80N^2QnD&ka{2NhY#xs#N?JUwx$EQ8K1(_Wli@(F1=gaCA!v*F zS=!)@81V~{o99ul&IHfTM}PGx{u7PgkudI>=AxmnN-uCVa#^%bdUS|)U0`Rm z^7!q zm7m{yj~`ibkVk8;vSCI*KbU{v3;Kupa3iI>rnFv#cgwE!Y@=D7G{!UaeZ;h~T85s^tPuy8fx0uK-@V7XGFphuz&5Sg3s@!pl2NkDh5*GYicBOn*#sl{i4dZuPRgKHM89jCE#j}vYmBKC(1MitIZk5gPT#izgwsFo x;6W+2nCUtc17pC_uY@DsoMqR|Tv}B@0wG77;i+J!dP3m-Q&-kjs#ZXS{XdSAeL(;K diff --git a/src/plugins/home/server/services/sample_data/data_sets/ecommerce/saved_objects.ts b/src/plugins/home/server/services/sample_data/data_sets/ecommerce/saved_objects.ts index 687372ed0a559..812052480e8b2 100644 --- a/src/plugins/home/server/services/sample_data/data_sets/ecommerce/saved_objects.ts +++ b/src/plugins/home/server/services/sample_data/data_sets/ecommerce/saved_objects.ts @@ -34,35 +34,6 @@ export const getSavedObjects = (): SavedObject[] => [ updated_at: '2021-08-05T12:23:57.577Z', version: 'WzI1LDFd', }, - { - attributes: { - description: '', - kibanaSavedObjectMeta: { - searchSourceJSON: '{"query":{"query":"","language":"kuery"},"filter":[]}', - }, - title: i18n.translate('home.sampleData.ecommerceSpec.soldProductsPerDayTitle', { - defaultMessage: '[eCommerce] Sold Products per Day', - }), - uiStateJSON: '{}', - version: 1, - visState: - '{"title":"[eCommerce] Sold Products per Day","type":"metrics","aggs":[],"params":{"time_range_mode":"entire_time_range","id":"61ca57f0-469d-11e7-af02-69e470af7417","type":"gauge","series":[{"id":"61ca57f1-469d-11e7-af02-69e470af7417","color":"#68BC00","split_mode":"everything","metrics":[{"id":"61ca57f2-469d-11e7-af02-69e470af7417","type":"count"},{"id":"fd1e1b90-e4e3-11eb-8234-cb7bfd534fce","type":"math","variables":[{"id":"00374270-e4e4-11eb-8234-cb7bfd534fce","name":"c","field":"61ca57f2-469d-11e7-af02-69e470af7417"}],"script":"params.c / (params._interval / 1000 / 60 / 60 / 24)"}],"separate_axis":0,"axis_position":"right","formatter":"0.0","chart_type":"line","line_width":1,"point_size":1,"fill":0.5,"stacked":"none","label":"Trxns / day","split_color_mode":"gradient","value_template":""}],"time_field":"order_date","interval":"1d","axis_position":"left","axis_formatter":"number","axis_scale":"normal","show_legend":1,"show_grid":1,"gauge_color_rules":[{"value":150,"id":"6da070c0-b891-11e8-b645-195edeb9de84","gauge":"rgba(104,188,0,1)","operator":"gte"},{"value":150,"id":"9b0cdbc0-b891-11e8-b645-195edeb9de84","gauge":"rgba(244,78,59,1)","operator":"lt"}],"gauge_width":"15","gauge_inner_width":"10","gauge_style":"half","filter":"","gauge_max":"300","use_kibana_indexes":true,"hide_last_value_indicator":true,"tooltip_mode":"show_all","drop_last_bucket":0,"isModelInvalid":false,"index_pattern_ref_name":"metrics_0_index_pattern"}}', - }, - id: 'b80e6540-b891-11e8-a6d9-e546fe2bba5f', - coreMigrationVersion: '8.8.0', - typeMigrationVersion: '7.14.0', - managed: false, - references: [ - { - id: 'ff959d40-b880-11e8-a6d9-e546fe2bba5f', - name: 'metrics_0_index_pattern', - type: 'index-pattern', - }, - ], - type: 'visualization', - updated_at: '2021-08-05T12:23:57.577Z', - version: 'WzIyLDFd', - }, { attributes: { columns: [ @@ -176,7 +147,7 @@ export const getSavedObjects = (): SavedObject[] => [ optionsJSON: '{"useMargins":true,"syncColors":false,"syncCursor":true,"syncTooltips":false,"hidePanelTitles":false}', panelsJSON: - '[{"version":"8.8.0","type":"lens","gridData":{"x":0,"y":21,"w":24,"h":10,"i":"5"},"panelIndex":"5","embeddableConfig":{"attributes":{"title":"[eCommerce] Promotion Tracking (converted)","visualizationType":"lnsXY","type":"lens","references":[{"type":"index-pattern","id":"ff959d40-b880-11e8-a6d9-e546fe2bba5f","name":"indexpattern-datasource-layer-e3b3cb5c-e3b1-497f-a5d5-fddb0dabc94e"},{"type":"index-pattern","id":"ff959d40-b880-11e8-a6d9-e546fe2bba5f","name":"indexpattern-datasource-layer-1d08a43c-8913-4692-a3e0-8d77902f6e46"},{"type":"index-pattern","id":"ff959d40-b880-11e8-a6d9-e546fe2bba5f","name":"indexpattern-datasource-layer-9725cdbd-a9f3-479f-a349-0f11244e5239"},{"type":"index-pattern","id":"ff959d40-b880-11e8-a6d9-e546fe2bba5f","name":"indexpattern-datasource-layer-2031d0f8-01fc-4009-b1ad-a7b7ca9266c0"},{"type":"index-pattern","id":"ff959d40-b880-11e8-a6d9-e546fe2bba5f","name":"xy-visualization-layer-192ad2e4-2bb7-44a9-b345-e96045fa6ccd"}],"state":{"visualization":{"legend":{"isVisible":true,"showSingleSeries":true,"position":"bottom","shouldTruncate":true,"maxLines":1},"valueLabels":"hide","fittingFunction":"None","fillOpacity":0,"yLeftExtent":{"mode":"full"},"yRightExtent":{"mode":"full"},"yLeftScale":"linear","yRightScale":"linear","axisTitlesVisibilitySettings":{"x":true,"yLeft":true,"yRight":true},"tickLabelsVisibilitySettings":{"x":true,"yLeft":true,"yRight":true},"labelsOrientation":{"x":0,"yLeft":0,"yRight":0},"gridlinesVisibilitySettings":{"x":true,"yLeft":true,"yRight":true},"preferredSeriesType":"bar_stacked","layers":[{"seriesType":"line","layerType":"data","layerId":"e3b3cb5c-e3b1-497f-a5d5-fddb0dabc94e","accessors":["a69956c9-43cd-4756-a3c0-e93cb1502a0b"],"yConfig":[{"forAccessor":"a69956c9-43cd-4756-a3c0-e93cb1502a0b","color":"rgba(211,96,134,1)","axisMode":"left"}],"xAccessor":"f3cc8168-6360-4727-a410-a57f5a325091","palette":{"name":"default","type":"palette"}},{"seriesType":"line","layerType":"data","layerId":"1d08a43c-8913-4692-a3e0-8d77902f6e46","accessors":["9a3d8abd-81a5-40ae-9616-020d5a5b2ee2"],"yConfig":[{"forAccessor":"9a3d8abd-81a5-40ae-9616-020d5a5b2ee2","color":"rgba(84,179,153,1)","axisMode":"left"}],"xAccessor":"644b06ea-73a3-47b1-9b40-3035844c4621","palette":{"name":"default","type":"palette"}},{"seriesType":"line","layerType":"data","layerId":"9725cdbd-a9f3-479f-a349-0f11244e5239","accessors":["b5588228-9c46-4a4b-92ee-d140c327bca0"],"yConfig":[{"forAccessor":"b5588228-9c46-4a4b-92ee-d140c327bca0","color":"rgba(96,146,192,1)","axisMode":"left"}],"xAccessor":"6749b404-4784-4fd6-8bf6-5712e84c7310","palette":{"name":"default","type":"palette"}},{"seriesType":"line","layerType":"data","layerId":"2031d0f8-01fc-4009-b1ad-a7b7ca9266c0","accessors":["985e05c0-3a0b-4e55-84bb-1f02128388a9"],"yConfig":[{"forAccessor":"985e05c0-3a0b-4e55-84bb-1f02128388a9","color":"rgba(202,142,174,1)","axisMode":"left"}],"xAccessor":"1b199cb1-b47f-48e6-b209-74eb81b303f5","palette":{"name":"default","type":"palette"}},{"layerId":"192ad2e4-2bb7-44a9-b345-e96045fa6ccd","layerType":"annotations","ignoreGlobalFilters":true,"annotations":[{"type":"query","id":"c8c30be0-b88f-11e8-a451-f37365e9f268","label":"Event","key":{"type":"point_in_time"},"color":"#194D33","timeField":"order_date","icon":"bell","filter":{"type":"kibana_query","query":"taxful_total_price:>250","language":"lucene"},"extraFields":["taxful_total_price"]}]}]},"query":{"query":"","language":"kuery"},"filters":[],"datasourceStates":{"formBased":{"layers":{"e3b3cb5c-e3b1-497f-a5d5-fddb0dabc94e":{"columns":{"f3cc8168-6360-4727-a410-a57f5a325091":{"label":"order_date","dataType":"date","operationType":"date_histogram","sourceField":"order_date","isBucketed":true,"scale":"interval","params":{"interval":"12h","includeEmptyRows":true,"dropPartials":false}},"a69956c9-43cd-4756-a3c0-e93cb1502a0b":{"label":"Revenue Trousers","dataType":"number","operationType":"sum","sourceField":"taxful_total_price","isBucketed":false,"scale":"ratio","filter":{"query":"products.product_name:*trouser*","language":"lucene"},"params":{"format":{"id":"number"},"emptyAsNull":true},"customLabel":true}},"columnOrder":["f3cc8168-6360-4727-a410-a57f5a325091","a69956c9-43cd-4756-a3c0-e93cb1502a0b"],"incompleteColumns":{}},"1d08a43c-8913-4692-a3e0-8d77902f6e46":{"columns":{"644b06ea-73a3-47b1-9b40-3035844c4621":{"label":"order_date","dataType":"date","operationType":"date_histogram","sourceField":"order_date","isBucketed":true,"scale":"interval","params":{"interval":"12h","includeEmptyRows":true,"dropPartials":false}},"9a3d8abd-81a5-40ae-9616-020d5a5b2ee2":{"label":"Revenue Watches","dataType":"number","operationType":"sum","sourceField":"taxful_total_price","isBucketed":false,"scale":"ratio","filter":{"query":"products.product_name:*watch*","language":"lucene"},"params":{"format":{"id":"number"},"emptyAsNull":true},"customLabel":true}},"columnOrder":["644b06ea-73a3-47b1-9b40-3035844c4621","9a3d8abd-81a5-40ae-9616-020d5a5b2ee2"],"incompleteColumns":{}},"9725cdbd-a9f3-479f-a349-0f11244e5239":{"columns":{"6749b404-4784-4fd6-8bf6-5712e84c7310":{"label":"order_date","dataType":"date","operationType":"date_histogram","sourceField":"order_date","isBucketed":true,"scale":"interval","params":{"interval":"12h","includeEmptyRows":true,"dropPartials":false}},"b5588228-9c46-4a4b-92ee-d140c327bca0":{"label":"Revenue Bags","dataType":"number","operationType":"sum","sourceField":"taxful_total_price","isBucketed":false,"scale":"ratio","filter":{"query":"products.product_name:*bag*","language":"lucene"},"params":{"format":{"id":"number"},"emptyAsNull":true},"customLabel":true}},"columnOrder":["6749b404-4784-4fd6-8bf6-5712e84c7310","b5588228-9c46-4a4b-92ee-d140c327bca0"],"incompleteColumns":{}},"2031d0f8-01fc-4009-b1ad-a7b7ca9266c0":{"columns":{"1b199cb1-b47f-48e6-b209-74eb81b303f5":{"label":"order_date","dataType":"date","operationType":"date_histogram","sourceField":"order_date","isBucketed":true,"scale":"interval","params":{"interval":"12h","includeEmptyRows":true,"dropPartials":false}},"985e05c0-3a0b-4e55-84bb-1f02128388a9":{"label":"Revenue Cocktail Dresses","dataType":"number","operationType":"sum","sourceField":"taxful_total_price","isBucketed":false,"scale":"ratio","filter":{"query":"products.product_name:*cocktail dress*","language":"lucene"},"params":{"format":{"id":"number"},"emptyAsNull":true},"customLabel":true}},"columnOrder":["1b199cb1-b47f-48e6-b209-74eb81b303f5","985e05c0-3a0b-4e55-84bb-1f02128388a9"],"incompleteColumns":{}}}},"textBased":{"layers":{}}},"internalReferences":[],"adHocDataViews":{}}},"hidePanelTitles":false,"enhancements":{}},"title":"[eCommerce] Promotion Tracking"},{"version":"8.8.0","type":"visualization","gridData":{"x":36,"y":7,"w":12,"h":7,"i":"7"},"panelIndex":"7","embeddableConfig":{"enhancements":{}},"panelRefName":"panel_7"},{"version":"8.8.0","type":"search","gridData":{"x":0,"y":54,"w":48,"h":18,"i":"10"},"panelIndex":"10","embeddableConfig":{"enhancements":{}},"panelRefName":"panel_10"},{"version":"8.8.0","type":"map","gridData":{"x":0,"y":31,"w":24,"h":14,"i":"11"},"panelIndex":"11","embeddableConfig":{"isLayerTOCOpen":false,"hiddenLayers":[],"mapCenter":{"lat":45.88578,"lon":-15.07605,"zoom":2.11},"openTOCDetails":[],"enhancements":{}},"panelRefName":"panel_11"},{"version":"8.8.0","type":"visualization","gridData":{"x":0,"y":0,"w":24,"h":7,"i":"a71cf076-6895-491c-8878-63592e429ed5"},"panelIndex":"a71cf076-6895-491c-8878-63592e429ed5","embeddableConfig":{"enhancements":{}},"panelRefName":"panel_a71cf076-6895-491c-8878-63592e429ed5"},{"version":"8.8.0","type":"lens","gridData":{"x":24,"y":0,"w":12,"h":7,"i":"75283285-dffd-48a7-a0c2-2235184b5282"},"panelIndex":"75283285-dffd-48a7-a0c2-2235184b5282","embeddableConfig":{"enhancements":{},"attributes":{"visualizationType":"lnsMetric","state":{"visualization":{"layerId":"c7478794-6767-4286-9d65-1c0ecd909dd8","layerType":"data","metricAccessor":"041db33b-5c9c-47f3-a5d3-ef5e255d1663"},"query":{"language":"kuery","query":""},"filters":[],"datasourceStates":{"formBased":{"layers":{"c7478794-6767-4286-9d65-1c0ecd909dd8":{"columnOrder":["041db33b-5c9c-47f3-a5d3-ef5e255d1663"],"columns":{"041db33b-5c9c-47f3-a5d3-ef5e255d1663":{"customLabel":true,"dataType":"number","isBucketed":false,"label":"Sum of revenue ($)","operationType":"sum","scale":"ratio","sourceField":"taxful_total_price","params":{}}},"incompleteColumns":{}}}}},"internalReferences":[],"adHocDataViews":{}},"references":[{"type":"index-pattern","id":"ff959d40-b880-11e8-a6d9-e546fe2bba5f","name":"indexpattern-datasource-layer-c7478794-6767-4286-9d65-1c0ecd909dd8"}]},"hidePanelTitles":true},"title":"Sum of revenue"},{"version":"8.8.0","type":"lens","gridData":{"x":36,"y":0,"w":12,"h":7,"i":"58774330-b1b3-42dd-a04c-fbce9cc4d288"},"panelIndex":"58774330-b1b3-42dd-a04c-fbce9cc4d288","embeddableConfig":{"enhancements":{},"attributes":{"title":"Median spending","visualizationType":"lnsMetric","type":"lens","references":[{"type":"index-pattern","id":"ff959d40-b880-11e8-a6d9-e546fe2bba5f","name":"indexpattern-datasource-layer-4fb42a8e-b133-43c8-805c-a38472053938"}],"state":{"visualization":{"layerId":"4fb42a8e-b133-43c8-805c-a38472053938","layerType":"data","metricAccessor":"020bbfdf-9ef8-4802-aa9e-342d2ea0bebf"},"query":{"language":"kuery","query":""},"filters":[],"datasourceStates":{"formBased":{"layers":{"4fb42a8e-b133-43c8-805c-a38472053938":{"columnOrder":["020bbfdf-9ef8-4802-aa9e-342d2ea0bebf"],"columns":{"020bbfdf-9ef8-4802-aa9e-342d2ea0bebf":{"customLabel":true,"dataType":"number","isBucketed":false,"label":"Median spending ($)","operationType":"median","scale":"ratio","sourceField":"taxful_total_price","params":{}}},"incompleteColumns":{}}}}},"internalReferences":[],"adHocDataViews":{}}},"hidePanelTitles":true},"title":"Median spending"},{"version":"8.8.0","type":"lens","gridData":{"x":24,"y":7,"w":12,"h":7,"i":"b63ec47d-aace-4980-b928-6be8adafa5a4"},"panelIndex":"b63ec47d-aace-4980-b928-6be8adafa5a4","embeddableConfig":{"enhancements":{},"attributes":{"visualizationType":"lnsMetric","state":{"visualization":{"layerId":"667067a2-7cdf-4f0e-a9fe-eb4f4f1f2f17","layerType":"data","metricAccessor":"c52c2003-ae58-4604-bae7-52ba0fb38a01"},"query":{"language":"kuery","query":""},"filters":[],"datasourceStates":{"formBased":{"layers":{"667067a2-7cdf-4f0e-a9fe-eb4f4f1f2f17":{"columnOrder":["c52c2003-ae58-4604-bae7-52ba0fb38a01"],"columns":{"c52c2003-ae58-4604-bae7-52ba0fb38a01":{"customLabel":true,"dataType":"number","isBucketed":false,"label":"Avg. items sold","operationType":"average","params":{"format":{"id":"number","params":{"decimals":1}}},"scale":"ratio","sourceField":"total_quantity"}},"incompleteColumns":{}}}}},"internalReferences":[],"adHocDataViews":{}},"references":[{"type":"index-pattern","id":"ff959d40-b880-11e8-a6d9-e546fe2bba5f","name":"indexpattern-datasource-layer-667067a2-7cdf-4f0e-a9fe-eb4f4f1f2f17"}]},"hidePanelTitles":true},"title":"Avg. items sold"},{"version":"8.8.0","type":"lens","gridData":{"x":0,"y":14,"w":24,"h":7,"i":"d9495793-80ba-4a9a-b0e3-d1155ec99b09"},"panelIndex":"d9495793-80ba-4a9a-b0e3-d1155ec99b09","embeddableConfig":{"enhancements":{},"attributes":{"state":{"datasourceStates":{"formBased":{"layers":{"b6093a53-884f-42c2-9fcc-ba56cfb66c53":{"columnOrder":["15c45f89-a149-443a-a830-aa8c3a9317db","2b41b3d8-2f62-407a-a866-960f254c679d","eadae280-2da3-4d1d-a0e1-f9733f89c15b","ddc92e50-4d5c-413e-b91b-3e504889fa65","5e31e5d3-2aaa-4475-a130-3b69bf2f748a"],"columns":{"15c45f89-a149-443a-a830-aa8c3a9317db":{"dataType":"date","isBucketed":true,"label":"order_date","operationType":"date_histogram","params":{"interval":"1d","includeEmptyRows":true},"scale":"interval","sourceField":"order_date"},"2b41b3d8-2f62-407a-a866-960f254c679d":{"customLabel":true,"dataType":"number","isBucketed":false,"label":"Total items","operationType":"sum","scale":"ratio","sourceField":"products.quantity"},"5e31e5d3-2aaa-4475-a130-3b69bf2f748a":{"customLabel":true,"dataType":"number","isBucketed":false,"label":"Tx. last week","operationType":"count","scale":"ratio","sourceField":"___records___","timeShift":"1w"},"ddc92e50-4d5c-413e-b91b-3e504889fa65":{"customLabel":true,"dataType":"number","isBucketed":false,"label":"Transactions","operationType":"count","scale":"ratio","sourceField":"___records___"},"eadae280-2da3-4d1d-a0e1-f9733f89c15b":{"customLabel":true,"dataType":"number","isBucketed":false,"label":"Last week","operationType":"sum","scale":"ratio","sourceField":"products.quantity","timeShift":"1w"}},"incompleteColumns":{}}}}},"filters":[],"query":{"language":"kuery","query":""},"visualization":{"axisTitlesVisibilitySettings":{"x":false,"yLeft":false,"yRight":true},"curveType":"LINEAR","fittingFunction":"None","gridlinesVisibilitySettings":{"x":true,"yLeft":true,"yRight":true},"layers":[{"accessors":["2b41b3d8-2f62-407a-a866-960f254c679d","eadae280-2da3-4d1d-a0e1-f9733f89c15b","5e31e5d3-2aaa-4475-a130-3b69bf2f748a","ddc92e50-4d5c-413e-b91b-3e504889fa65"],"layerId":"b6093a53-884f-42c2-9fcc-ba56cfb66c53","position":"top","seriesType":"line","showGridlines":false,"xAccessor":"15c45f89-a149-443a-a830-aa8c3a9317db","yConfig":[{"color":"#b6e0d5","forAccessor":"eadae280-2da3-4d1d-a0e1-f9733f89c15b"},{"color":"#edafc4","forAccessor":"5e31e5d3-2aaa-4475-a130-3b69bf2f748a"}],"layerType":"data"}],"legend":{"isVisible":true,"position":"right","legendSize":"auto"},"preferredSeriesType":"line","tickLabelsVisibilitySettings":{"x":true,"yLeft":true,"yRight":true},"valueLabels":"hide","yLeftExtent":{"mode":"full"},"yRightExtent":{"mode":"full"}}},"visualizationType":"lnsXY","references":[{"id":"ff959d40-b880-11e8-a6d9-e546fe2bba5f","name":"indexpattern-datasource-current-indexpattern","type":"index-pattern"},{"id":"ff959d40-b880-11e8-a6d9-e546fe2bba5f","name":"indexpattern-datasource-layer-b6093a53-884f-42c2-9fcc-ba56cfb66c53","type":"index-pattern"}]}},"title":"Transactions per day"},{"version":"8.8.0","type":"lens","gridData":{"x":24,"y":31,"w":24,"h":14,"i":"bda054f7-2d06-4936-b461-365d1be621fa"},"panelIndex":"bda054f7-2d06-4936-b461-365d1be621fa","embeddableConfig":{"enhancements":{},"attributes":{"state":{"datasourceStates":{"formBased":{"layers":{"0731ee8b-31c5-4be9-92d9-69ee760465d7":{"columnOrder":["7bf8f089-1542-40bd-b349-45fdfc309ac6","826b2f39-b616-40b2-a222-972fdc1d7596","cfd45c47-fc41-430c-9e7a-b71dc0c916b0","bf51c1af-443e-49f4-a21f-54c87bfc5677","bf51c1af-443e-49f4-a21f-54c87bfc5677X0","bf51c1af-443e-49f4-a21f-54c87bfc5677X1","bf51c1af-443e-49f4-a21f-54c87bfc5677X2"],"columns":{"7bf8f089-1542-40bd-b349-45fdfc309ac6":{"dataType":"date","isBucketed":true,"label":"order_date","operationType":"date_histogram","params":{"interval":"1d","includeEmptyRows":true},"scale":"interval","sourceField":"order_date"},"826b2f39-b616-40b2-a222-972fdc1d7596":{"customLabel":true,"dataType":"number","isBucketed":false,"label":"This week","operationType":"sum","scale":"ratio","sourceField":"taxful_total_price"},"bf51c1af-443e-49f4-a21f-54c87bfc5677":{"customLabel":true,"dataType":"number","isBucketed":false,"label":"Difference","operationType":"formula","params":{"format":{"id":"number","params":{"decimals":2}},"formula":"sum(taxful_total_price) - sum(taxful_total_price, shift=\'1w\')","isFormulaBroken":false},"references":["bf51c1af-443e-49f4-a21f-54c87bfc5677X2"],"scale":"ratio"},"bf51c1af-443e-49f4-a21f-54c87bfc5677X0":{"customLabel":true,"dataType":"number","isBucketed":false,"label":"Part of Difference","operationType":"sum","scale":"ratio","sourceField":"taxful_total_price"},"bf51c1af-443e-49f4-a21f-54c87bfc5677X1":{"customLabel":true,"dataType":"number","isBucketed":false,"label":"Part of Difference","operationType":"sum","scale":"ratio","sourceField":"taxful_total_price","timeShift":"1w"},"bf51c1af-443e-49f4-a21f-54c87bfc5677X2":{"customLabel":true,"dataType":"number","isBucketed":false,"label":"Part of Difference","operationType":"math","params":{"tinymathAst":{"args":["bf51c1af-443e-49f4-a21f-54c87bfc5677X0","bf51c1af-443e-49f4-a21f-54c87bfc5677X1"],"location":{"max":61,"min":0},"name":"subtract","text":"sum(taxful_total_price) - sum(taxful_total_price, shift=\'1w\')","type":"function"}},"references":["bf51c1af-443e-49f4-a21f-54c87bfc5677X0","bf51c1af-443e-49f4-a21f-54c87bfc5677X1"],"scale":"ratio"},"cfd45c47-fc41-430c-9e7a-b71dc0c916b0":{"customLabel":true,"dataType":"number","isBucketed":false,"label":"1 week ago","operationType":"sum","scale":"ratio","sourceField":"taxful_total_price","timeShift":"1w"}},"incompleteColumns":{}}}}},"filters":[],"query":{"language":"kuery","query":""},"visualization":{"columns":[{"columnId":"7bf8f089-1542-40bd-b349-45fdfc309ac6"},{"alignment":"left","columnId":"826b2f39-b616-40b2-a222-972fdc1d7596"},{"columnId":"cfd45c47-fc41-430c-9e7a-b71dc0c916b0"},{"colorMode":"text","columnId":"bf51c1af-443e-49f4-a21f-54c87bfc5677","isTransposed":false,"palette":{"name":"custom","params":{"colorStops":[{"color":"#D36086","stop":-10000},{"color":"#209280","stop":0}],"continuity":"above","name":"custom","rangeMax":0,"rangeMin":-10000,"rangeType":"number","steps":5,"stops":[{"color":"#D36086","stop":0},{"color":"#209280","stop":2249.03125}]},"type":"palette"}}],"layerId":"0731ee8b-31c5-4be9-92d9-69ee760465d7","layerType":"data","rowHeight":"single","rowHeightLines":1}},"visualizationType":"lnsDatatable","references":[{"id":"ff959d40-b880-11e8-a6d9-e546fe2bba5f","name":"indexpattern-datasource-current-indexpattern","type":"index-pattern"},{"id":"ff959d40-b880-11e8-a6d9-e546fe2bba5f","name":"indexpattern-datasource-layer-0731ee8b-31c5-4be9-92d9-69ee760465d7","type":"index-pattern"}]}},"title":"Daily comparison"},{"version":"8.8.0","type":"lens","gridData":{"x":0,"y":45,"w":24,"h":9,"i":"d68e91dd-1539-48b0-9279-b43bba2054fe"},"panelIndex":"d68e91dd-1539-48b0-9279-b43bba2054fe","embeddableConfig":{"hidePanelTitles":false,"enhancements":{},"attributes":{"state":{"datasourceStates":{"formBased":{"layers":{"5ed846c2-a70b-4d9c-a244-f254bef763b8":{"columnOrder":["d77cdd24-dedc-48dd-9a4b-d34c6f1a6c46","7ac31901-277a-46e2-8128-8d684b2c1127"],"columns":{"7ac31901-277a-46e2-8128-8d684b2c1127":{"customLabel":true,"dataType":"number","isBucketed":false,"label":"Items","operationType":"count","scale":"ratio","sourceField":"___records___"},"d77cdd24-dedc-48dd-9a4b-d34c6f1a6c46":{"customLabel":true,"dataType":"string","isBucketed":true,"label":"Product name","operationType":"terms","params":{"missingBucket":false,"orderBy":{"columnId":"7ac31901-277a-46e2-8128-8d684b2c1127","type":"column"},"orderDirection":"desc","otherBucket":false,"size":5,"parentFormat":{"id":"terms"}},"scale":"ordinal","sourceField":"products.product_name.keyword"}},"incompleteColumns":{}}}}},"filters":[],"query":{"language":"kuery","query":""},"visualization":{"axisTitlesVisibilitySettings":{"x":false,"yLeft":true,"yRight":true},"fittingFunction":"None","gridlinesVisibilitySettings":{"x":true,"yLeft":true,"yRight":true},"layers":[{"accessors":["7ac31901-277a-46e2-8128-8d684b2c1127"],"layerId":"5ed846c2-a70b-4d9c-a244-f254bef763b8","position":"top","seriesType":"bar_horizontal","showGridlines":false,"xAccessor":"d77cdd24-dedc-48dd-9a4b-d34c6f1a6c46","layerType":"data"}],"legend":{"isVisible":true,"position":"right","legendSize":"auto"},"preferredSeriesType":"bar_horizontal","tickLabelsVisibilitySettings":{"x":true,"yLeft":true,"yRight":true},"valueLabels":"show","yLeftExtent":{"mode":"full"},"yRightExtent":{"mode":"full"}}},"visualizationType":"lnsXY","references":[{"id":"ff959d40-b880-11e8-a6d9-e546fe2bba5f","name":"indexpattern-datasource-current-indexpattern","type":"index-pattern"},{"id":"ff959d40-b880-11e8-a6d9-e546fe2bba5f","name":"indexpattern-datasource-layer-5ed846c2-a70b-4d9c-a244-f254bef763b8","type":"index-pattern"}]}},"title":"Top products this week"},{"version":"8.8.0","type":"lens","gridData":{"x":24,"y":45,"w":24,"h":9,"i":"39d96714-152f-414b-992c-ce2492fc69f3"},"panelIndex":"39d96714-152f-414b-992c-ce2492fc69f3","embeddableConfig":{"timeRange":{"from":"now-2w","to":"now-1w"},"hidePanelTitles":false,"enhancements":{},"attributes":{"state":{"datasourceStates":{"formBased":{"layers":{"5ed846c2-a70b-4d9c-a244-f254bef763b8":{"columnOrder":["d77cdd24-dedc-48dd-9a4b-d34c6f1a6c46","7ac31901-277a-46e2-8128-8d684b2c1127"],"columns":{"7ac31901-277a-46e2-8128-8d684b2c1127":{"customLabel":true,"dataType":"number","isBucketed":false,"label":"Items","operationType":"count","scale":"ratio","sourceField":"___records___"},"d77cdd24-dedc-48dd-9a4b-d34c6f1a6c46":{"customLabel":true,"dataType":"string","isBucketed":true,"label":"Product name","operationType":"terms","params":{"missingBucket":false,"orderBy":{"columnId":"7ac31901-277a-46e2-8128-8d684b2c1127","type":"column"},"orderDirection":"desc","otherBucket":false,"size":5,"parentFormat":{"id":"terms"}},"scale":"ordinal","sourceField":"products.product_name.keyword"}},"incompleteColumns":{}}}}},"filters":[],"query":{"language":"kuery","query":""},"visualization":{"axisTitlesVisibilitySettings":{"x":false,"yLeft":true,"yRight":true},"fittingFunction":"None","gridlinesVisibilitySettings":{"x":true,"yLeft":true,"yRight":true},"layers":[{"accessors":["7ac31901-277a-46e2-8128-8d684b2c1127"],"layerId":"5ed846c2-a70b-4d9c-a244-f254bef763b8","position":"top","seriesType":"bar_horizontal","showGridlines":false,"xAccessor":"d77cdd24-dedc-48dd-9a4b-d34c6f1a6c46","layerType":"data"}],"legend":{"isVisible":true,"position":"right","legendSize":"auto"},"preferredSeriesType":"bar_horizontal","tickLabelsVisibilitySettings":{"x":true,"yLeft":true,"yRight":true},"valueLabels":"show","yLeftExtent":{"mode":"full"},"yRightExtent":{"mode":"full"}}},"visualizationType":"lnsXY","references":[{"id":"ff959d40-b880-11e8-a6d9-e546fe2bba5f","name":"indexpattern-datasource-current-indexpattern","type":"index-pattern"},{"id":"ff959d40-b880-11e8-a6d9-e546fe2bba5f","name":"indexpattern-datasource-layer-5ed846c2-a70b-4d9c-a244-f254bef763b8","type":"index-pattern"}]}},"title":"Top products last week"},{"version":"8.8.0","type":"lens","gridData":{"x":24,"y":14,"w":24,"h":17,"i":"cd47b7cb-0ac0-43e0-b8c6-53489648bdef"},"panelIndex":"cd47b7cb-0ac0-43e0-b8c6-53489648bdef","embeddableConfig":{"enhancements":{},"attributes":{"state":{"datasourceStates":{"formBased":{"layers":{"97c63ea6-9305-4755-97d1-0f26817c6f9a":{"columnOrder":["9f61a7df-198e-4754-b34c-81ed544136ba","ebcb19af-0900-4439-949f-d8cd9bccde19","5575214b-7f21-4b6c-8bc1-34433c6a0c58"],"columns":{"5575214b-7f21-4b6c-8bc1-34433c6a0c58":{"dataType":"number","isBucketed":false,"label":"Count of records","operationType":"count","scale":"ratio","sourceField":"___records___"},"9f61a7df-198e-4754-b34c-81ed544136ba":{"dataType":"string","isBucketed":true,"label":"Top values of category.keyword","operationType":"terms","params":{"missingBucket":false,"orderBy":{"columnId":"5575214b-7f21-4b6c-8bc1-34433c6a0c58","type":"column"},"orderDirection":"desc","otherBucket":true,"size":10,"parentFormat":{"id":"terms"}},"scale":"ordinal","sourceField":"category.keyword"},"ebcb19af-0900-4439-949f-d8cd9bccde19":{"dataType":"date","isBucketed":true,"label":"order_date","operationType":"date_histogram","params":{"interval":"1d","includeEmptyRows":true},"scale":"interval","sourceField":"order_date"}},"incompleteColumns":{}}}}},"filters":[],"query":{"language":"kuery","query":""},"visualization":{"axisTitlesVisibilitySettings":{"x":false,"yLeft":false,"yRight":true},"fittingFunction":"None","gridlinesVisibilitySettings":{"x":true,"yLeft":true,"yRight":true},"layers":[{"accessors":["5575214b-7f21-4b6c-8bc1-34433c6a0c58"],"layerId":"97c63ea6-9305-4755-97d1-0f26817c6f9a","position":"top","seriesType":"bar_percentage_stacked","showGridlines":false,"splitAccessor":"9f61a7df-198e-4754-b34c-81ed544136ba","xAccessor":"ebcb19af-0900-4439-949f-d8cd9bccde19","layerType":"data"}],"legend":{"isVisible":true,"position":"right","legendSize":"auto"},"preferredSeriesType":"bar_percentage_stacked","tickLabelsVisibilitySettings":{"x":true,"yLeft":true,"yRight":true},"valueLabels":"show","yLeftExtent":{"mode":"full"},"yRightExtent":{"mode":"full"}}},"visualizationType":"lnsXY","references":[{"id":"ff959d40-b880-11e8-a6d9-e546fe2bba5f","name":"indexpattern-datasource-current-indexpattern","type":"index-pattern"},{"id":"ff959d40-b880-11e8-a6d9-e546fe2bba5f","name":"indexpattern-datasource-layer-97c63ea6-9305-4755-97d1-0f26817c6f9a","type":"index-pattern"}]}},"title":"Breakdown by category"},{"version":"8.8.0","type":"lens","gridData":{"x":0,"y":7,"w":24,"h":7,"i":"bdb525ab-270b-46f1-a847-dd29be19aadb"},"panelIndex":"bdb525ab-270b-46f1-a847-dd29be19aadb","embeddableConfig":{"enhancements":{},"hidePanelTitles":false,"attributes":{"state":{"datasourceStates":{"formBased":{"layers":{"c7478794-6767-4286-9d65-1c0ecd909dd8":{"columnOrder":["8289349e-6d1b-4abf-b164-0208183d2c34","041db33b-5c9c-47f3-a5d3-ef5e255d1663","041db33b-5c9c-47f3-a5d3-ef5e255d1663X0","041db33b-5c9c-47f3-a5d3-ef5e255d1663X1"],"columns":{"041db33b-5c9c-47f3-a5d3-ef5e255d1663":{"customLabel":true,"dataType":"number","isBucketed":false,"label":"% of target ($10k)","operationType":"formula","params":{"format":{"id":"percent","params":{"decimals":0}},"formula":"sum(taxful_total_price) / 10000 - 1","isFormulaBroken":false},"references":["041db33b-5c9c-47f3-a5d3-ef5e255d1663X1"],"scale":"ratio"},"041db33b-5c9c-47f3-a5d3-ef5e255d1663X0":{"customLabel":true,"dataType":"number","isBucketed":false,"label":"Part of Weekly revenue","operationType":"sum","scale":"ratio","sourceField":"taxful_total_price"},"041db33b-5c9c-47f3-a5d3-ef5e255d1663X1":{"customLabel":true,"dataType":"number","isBucketed":false,"label":"Part of Weekly revenue","operationType":"math","params":{"tinymathAst":{"args":[{"args":["041db33b-5c9c-47f3-a5d3-ef5e255d1663X0",10000],"location":{"max":32,"min":0},"name":"divide","text":"sum(taxful_total_price) / 10000 ","type":"function"},1],"location":{"max":35,"min":0},"name":"subtract","text":"sum(taxful_total_price) / 10000 - 1","type":"function"}},"references":["041db33b-5c9c-47f3-a5d3-ef5e255d1663X0"],"scale":"ratio"},"8289349e-6d1b-4abf-b164-0208183d2c34":{"dataType":"date","isBucketed":true,"label":"order_date","operationType":"date_histogram","params":{"interval":"1d","includeEmptyRows":true},"scale":"interval","sourceField":"order_date"}},"incompleteColumns":{}}}}},"filters":[],"query":{"language":"kuery","query":""},"visualization":{"axisTitlesVisibilitySettings":{"x":false,"yLeft":false,"yRight":true},"fittingFunction":"None","gridlinesVisibilitySettings":{"x":true,"yLeft":true,"yRight":true},"layers":[{"accessors":["041db33b-5c9c-47f3-a5d3-ef5e255d1663"],"layerId":"c7478794-6767-4286-9d65-1c0ecd909dd8","seriesType":"bar_stacked","xAccessor":"8289349e-6d1b-4abf-b164-0208183d2c34","layerType":"data"}],"legend":{"isVisible":true,"position":"right","legendSize":"auto"},"preferredSeriesType":"bar_stacked","tickLabelsVisibilitySettings":{"x":true,"yLeft":true,"yRight":true},"valueLabels":"hide","yLeftExtent":{"mode":"full"},"yRightExtent":{"mode":"full"}}},"visualizationType":"lnsXY","references":[{"id":"ff959d40-b880-11e8-a6d9-e546fe2bba5f","name":"indexpattern-datasource-current-indexpattern","type":"index-pattern"},{"id":"ff959d40-b880-11e8-a6d9-e546fe2bba5f","name":"indexpattern-datasource-layer-c7478794-6767-4286-9d65-1c0ecd909dd8","type":"index-pattern"}]}},"title":"% of target revenue ($10k)"}]', + '[{"version":"8.11.0","type":"lens","gridData":{"x":0,"y":21,"w":24,"h":10,"i":"5"},"panelIndex":"5","embeddableConfig":{"attributes":{"title":"[eCommerce] Promotion Tracking (converted)","visualizationType":"lnsXY","type":"lens","references":[{"type":"index-pattern","id":"ff959d40-b880-11e8-a6d9-e546fe2bba5f","name":"indexpattern-datasource-layer-e3b3cb5c-e3b1-497f-a5d5-fddb0dabc94e"},{"type":"index-pattern","id":"ff959d40-b880-11e8-a6d9-e546fe2bba5f","name":"indexpattern-datasource-layer-1d08a43c-8913-4692-a3e0-8d77902f6e46"},{"type":"index-pattern","id":"ff959d40-b880-11e8-a6d9-e546fe2bba5f","name":"indexpattern-datasource-layer-9725cdbd-a9f3-479f-a349-0f11244e5239"},{"type":"index-pattern","id":"ff959d40-b880-11e8-a6d9-e546fe2bba5f","name":"indexpattern-datasource-layer-2031d0f8-01fc-4009-b1ad-a7b7ca9266c0"},{"type":"index-pattern","id":"ff959d40-b880-11e8-a6d9-e546fe2bba5f","name":"xy-visualization-layer-192ad2e4-2bb7-44a9-b345-e96045fa6ccd"}],"state":{"visualization":{"legend":{"isVisible":true,"showSingleSeries":true,"position":"bottom","shouldTruncate":true,"maxLines":1},"valueLabels":"hide","fittingFunction":"None","fillOpacity":0,"yLeftExtent":{"mode":"full"},"yRightExtent":{"mode":"full"},"yLeftScale":"linear","yRightScale":"linear","axisTitlesVisibilitySettings":{"x":true,"yLeft":true,"yRight":true},"tickLabelsVisibilitySettings":{"x":true,"yLeft":true,"yRight":true},"labelsOrientation":{"x":0,"yLeft":0,"yRight":0},"gridlinesVisibilitySettings":{"x":true,"yLeft":true,"yRight":true},"preferredSeriesType":"bar_stacked","layers":[{"seriesType":"line","layerType":"data","layerId":"e3b3cb5c-e3b1-497f-a5d5-fddb0dabc94e","accessors":["a69956c9-43cd-4756-a3c0-e93cb1502a0b"],"yConfig":[{"forAccessor":"a69956c9-43cd-4756-a3c0-e93cb1502a0b","color":"rgba(211,96,134,1)","axisMode":"left"}],"xAccessor":"f3cc8168-6360-4727-a410-a57f5a325091","palette":{"name":"default","type":"palette"}},{"seriesType":"line","layerType":"data","layerId":"1d08a43c-8913-4692-a3e0-8d77902f6e46","accessors":["9a3d8abd-81a5-40ae-9616-020d5a5b2ee2"],"yConfig":[{"forAccessor":"9a3d8abd-81a5-40ae-9616-020d5a5b2ee2","color":"rgba(84,179,153,1)","axisMode":"left"}],"xAccessor":"644b06ea-73a3-47b1-9b40-3035844c4621","palette":{"name":"default","type":"palette"}},{"seriesType":"line","layerType":"data","layerId":"9725cdbd-a9f3-479f-a349-0f11244e5239","accessors":["b5588228-9c46-4a4b-92ee-d140c327bca0"],"yConfig":[{"forAccessor":"b5588228-9c46-4a4b-92ee-d140c327bca0","color":"rgba(96,146,192,1)","axisMode":"left"}],"xAccessor":"6749b404-4784-4fd6-8bf6-5712e84c7310","palette":{"name":"default","type":"palette"}},{"seriesType":"line","layerType":"data","layerId":"2031d0f8-01fc-4009-b1ad-a7b7ca9266c0","accessors":["985e05c0-3a0b-4e55-84bb-1f02128388a9"],"yConfig":[{"forAccessor":"985e05c0-3a0b-4e55-84bb-1f02128388a9","color":"rgba(202,142,174,1)","axisMode":"left"}],"xAccessor":"1b199cb1-b47f-48e6-b209-74eb81b303f5","palette":{"name":"default","type":"palette"}},{"layerId":"192ad2e4-2bb7-44a9-b345-e96045fa6ccd","layerType":"annotations","ignoreGlobalFilters":true,"annotations":[{"type":"query","id":"c8c30be0-b88f-11e8-a451-f37365e9f268","label":"Event","key":{"type":"point_in_time"},"color":"#194D33","timeField":"order_date","icon":"bell","filter":{"type":"kibana_query","query":"taxful_total_price:>250","language":"lucene"},"extraFields":["taxful_total_price"]}]}]},"query":{"query":"","language":"kuery"},"filters":[],"datasourceStates":{"formBased":{"layers":{"e3b3cb5c-e3b1-497f-a5d5-fddb0dabc94e":{"columns":{"f3cc8168-6360-4727-a410-a57f5a325091":{"label":"order_date","dataType":"date","operationType":"date_histogram","sourceField":"order_date","isBucketed":true,"scale":"interval","params":{"interval":"12h","includeEmptyRows":true,"dropPartials":false}},"a69956c9-43cd-4756-a3c0-e93cb1502a0b":{"label":"Revenue Trousers","dataType":"number","operationType":"sum","sourceField":"taxful_total_price","isBucketed":false,"scale":"ratio","filter":{"query":"products.product_name:*trouser*","language":"lucene"},"params":{"format":{"id":"number"},"emptyAsNull":true},"customLabel":true}},"columnOrder":["f3cc8168-6360-4727-a410-a57f5a325091","a69956c9-43cd-4756-a3c0-e93cb1502a0b"],"incompleteColumns":{}},"1d08a43c-8913-4692-a3e0-8d77902f6e46":{"columns":{"644b06ea-73a3-47b1-9b40-3035844c4621":{"label":"order_date","dataType":"date","operationType":"date_histogram","sourceField":"order_date","isBucketed":true,"scale":"interval","params":{"interval":"12h","includeEmptyRows":true,"dropPartials":false}},"9a3d8abd-81a5-40ae-9616-020d5a5b2ee2":{"label":"Revenue Watches","dataType":"number","operationType":"sum","sourceField":"taxful_total_price","isBucketed":false,"scale":"ratio","filter":{"query":"products.product_name:*watch*","language":"lucene"},"params":{"format":{"id":"number"},"emptyAsNull":true},"customLabel":true}},"columnOrder":["644b06ea-73a3-47b1-9b40-3035844c4621","9a3d8abd-81a5-40ae-9616-020d5a5b2ee2"],"incompleteColumns":{}},"9725cdbd-a9f3-479f-a349-0f11244e5239":{"columns":{"6749b404-4784-4fd6-8bf6-5712e84c7310":{"label":"order_date","dataType":"date","operationType":"date_histogram","sourceField":"order_date","isBucketed":true,"scale":"interval","params":{"interval":"12h","includeEmptyRows":true,"dropPartials":false}},"b5588228-9c46-4a4b-92ee-d140c327bca0":{"label":"Revenue Bags","dataType":"number","operationType":"sum","sourceField":"taxful_total_price","isBucketed":false,"scale":"ratio","filter":{"query":"products.product_name:*bag*","language":"lucene"},"params":{"format":{"id":"number"},"emptyAsNull":true},"customLabel":true}},"columnOrder":["6749b404-4784-4fd6-8bf6-5712e84c7310","b5588228-9c46-4a4b-92ee-d140c327bca0"],"incompleteColumns":{}},"2031d0f8-01fc-4009-b1ad-a7b7ca9266c0":{"columns":{"1b199cb1-b47f-48e6-b209-74eb81b303f5":{"label":"order_date","dataType":"date","operationType":"date_histogram","sourceField":"order_date","isBucketed":true,"scale":"interval","params":{"interval":"12h","includeEmptyRows":true,"dropPartials":false}},"985e05c0-3a0b-4e55-84bb-1f02128388a9":{"label":"Revenue Cocktail Dresses","dataType":"number","operationType":"sum","sourceField":"taxful_total_price","isBucketed":false,"scale":"ratio","filter":{"query":"products.product_name:*cocktail dress*","language":"lucene"},"params":{"format":{"id":"number"},"emptyAsNull":true},"customLabel":true}},"columnOrder":["1b199cb1-b47f-48e6-b209-74eb81b303f5","985e05c0-3a0b-4e55-84bb-1f02128388a9"],"incompleteColumns":{}}}},"textBased":{"layers":{}}},"internalReferences":[],"adHocDataViews":{}}},"hidePanelTitles":false,"enhancements":{}},"title":"[eCommerce] Promotion Tracking"},{"version":"8.11.0","type":"lens","gridData":{"x":36,"y":7,"w":12,"h":7,"i":"7"},"panelIndex":"7","embeddableConfig":{"attributes":{"title":"Sold Products per Day","description":"","visualizationType":"lnsMetric","type":"lens","references":[{"type":"index-pattern","id":"ff959d40-b880-11e8-a6d9-e546fe2bba5f","name":"indexpattern-datasource-layer-037375ae-9e23-4dd5-a4f0-5f117bb7dac1"}],"state":{"visualization":{"layerId":"037375ae-9e23-4dd5-a4f0-5f117bb7dac1","layerType":"data","metricAccessor":"c27bd77c-68e2-4d75-8fda-41c45d22f8d4","maxAccessor":"ce816876-e92d-4b1a-bbb0-ed7637fc0eea","showBar":true,"color":"#68BC00"},"query":{"query":"","language":"kuery"},"filters":[],"datasourceStates":{"formBased":{"layers":{"037375ae-9e23-4dd5-a4f0-5f117bb7dac1":{"ignoreGlobalFilters":false,"columns":{"c27bd77c-68e2-4d75-8fda-41c45d22f8d4X0":{"label":"Part of count() / (time_range() / 1000 / 60 / 60 / 24)","dataType":"number","operationType":"count","isBucketed":false,"scale":"ratio","sourceField":"___records___","params":{"emptyAsNull":false},"customLabel":true},"c27bd77c-68e2-4d75-8fda-41c45d22f8d4X1":{"label":"Part of count() / (time_range() / 1000 / 60 / 60 / 24)","dataType":"number","operationType":"time_range","isBucketed":false,"scale":"ratio","references":[],"customLabel":true},"c27bd77c-68e2-4d75-8fda-41c45d22f8d4X2":{"label":"Part of count() / (time_range() / 1000 / 60 / 60 / 24)","dataType":"number","operationType":"math","isBucketed":false,"scale":"ratio","params":{"tinymathAst":{"type":"function","name":"divide","args":["c27bd77c-68e2-4d75-8fda-41c45d22f8d4X0",{"type":"function","name":"divide","args":[{"type":"function","name":"divide","args":[{"type":"function","name":"divide","args":[{"type":"function","name":"divide","args":["c27bd77c-68e2-4d75-8fda-41c45d22f8d4X1",1000]},60]},60]},24],"location":{"min":11,"max":45},"text":"time_range() / 1000 / 60 / 60 / 24"}],"location":{"min":0,"max":46},"text":"count() / (time_range() / 1000 / 60 / 60 / 24)"}},"references":["c27bd77c-68e2-4d75-8fda-41c45d22f8d4X0","c27bd77c-68e2-4d75-8fda-41c45d22f8d4X1"],"customLabel":true},"c27bd77c-68e2-4d75-8fda-41c45d22f8d4":{"label":"Trxns / day","dataType":"number","operationType":"formula","isBucketed":false,"scale":"ratio","params":{"format":{"id":"number"},"formula":"count() / (time_range() / 1000 / 60 / 60 / 24)","isFormulaBroken":false},"references":["c27bd77c-68e2-4d75-8fda-41c45d22f8d4X2"],"customLabel":true},"ce816876-e92d-4b1a-bbb0-ed7637fc0eea":{"label":"Static value: 300","dataType":"number","operationType":"static_value","isStaticValue":true,"isBucketed":false,"scale":"ratio","params":{"value":"300"},"references":[]}},"columnOrder":["c27bd77c-68e2-4d75-8fda-41c45d22f8d4X0","c27bd77c-68e2-4d75-8fda-41c45d22f8d4X1","c27bd77c-68e2-4d75-8fda-41c45d22f8d4X2","c27bd77c-68e2-4d75-8fda-41c45d22f8d4","ce816876-e92d-4b1a-bbb0-ed7637fc0eea"],"incompleteColumns":{}}}},"indexpattern":{"layers":{}},"textBased":{"layers":{}}},"internalReferences":[],"adHocDataViews":{}}},"timeRange":{"from":"now-7d","to":"now"},"enhancements":{}}},{"version":"8.11.0","type":"search","gridData":{"x":0,"y":54,"w":48,"h":18,"i":"10"},"panelIndex":"10","embeddableConfig":{"enhancements":{}},"panelRefName":"panel_10"},{"version":"8.11.0","type":"map","gridData":{"x":0,"y":31,"w":24,"h":14,"i":"11"},"panelIndex":"11","embeddableConfig":{"isLayerTOCOpen":false,"hiddenLayers":[],"mapCenter":{"lat":45.88578,"lon":-15.07605,"zoom":2.11},"openTOCDetails":[],"enhancements":{}},"panelRefName":"panel_11"},{"version":"8.11.0","type":"visualization","gridData":{"x":0,"y":0,"w":24,"h":7,"i":"a71cf076-6895-491c-8878-63592e429ed5"},"panelIndex":"a71cf076-6895-491c-8878-63592e429ed5","embeddableConfig":{"enhancements":{}},"panelRefName":"panel_a71cf076-6895-491c-8878-63592e429ed5"},{"version":"8.11.0","type":"lens","gridData":{"x":24,"y":0,"w":12,"h":7,"i":"75283285-dffd-48a7-a0c2-2235184b5282"},"panelIndex":"75283285-dffd-48a7-a0c2-2235184b5282","embeddableConfig":{"enhancements":{},"attributes":{"visualizationType":"lnsMetric","state":{"visualization":{"layerId":"c7478794-6767-4286-9d65-1c0ecd909dd8","layerType":"data","metricAccessor":"041db33b-5c9c-47f3-a5d3-ef5e255d1663"},"query":{"language":"kuery","query":""},"filters":[],"datasourceStates":{"formBased":{"layers":{"c7478794-6767-4286-9d65-1c0ecd909dd8":{"columnOrder":["041db33b-5c9c-47f3-a5d3-ef5e255d1663"],"columns":{"041db33b-5c9c-47f3-a5d3-ef5e255d1663":{"customLabel":true,"dataType":"number","isBucketed":false,"label":"Sum of revenue","operationType":"sum","scale":"ratio","sourceField":"taxful_total_price","params":{}}},"incompleteColumns":{}}}}},"internalReferences":[],"adHocDataViews":{}},"references":[{"type":"index-pattern","id":"ff959d40-b880-11e8-a6d9-e546fe2bba5f","name":"indexpattern-datasource-layer-c7478794-6767-4286-9d65-1c0ecd909dd8"}]},"hidePanelTitles":true},"title":"Sum of revenue"},{"version":"8.11.0","type":"lens","gridData":{"x":36,"y":0,"w":12,"h":7,"i":"58774330-b1b3-42dd-a04c-fbce9cc4d288"},"panelIndex":"58774330-b1b3-42dd-a04c-fbce9cc4d288","embeddableConfig":{"enhancements":{},"attributes":{"title":"Median spending","visualizationType":"lnsMetric","type":"lens","references":[{"type":"index-pattern","id":"ff959d40-b880-11e8-a6d9-e546fe2bba5f","name":"indexpattern-datasource-layer-4fb42a8e-b133-43c8-805c-a38472053938"}],"state":{"visualization":{"layerId":"4fb42a8e-b133-43c8-805c-a38472053938","layerType":"data","metricAccessor":"020bbfdf-9ef8-4802-aa9e-342d2ea0bebf"},"query":{"language":"kuery","query":""},"filters":[],"datasourceStates":{"formBased":{"layers":{"4fb42a8e-b133-43c8-805c-a38472053938":{"columnOrder":["020bbfdf-9ef8-4802-aa9e-342d2ea0bebf"],"columns":{"020bbfdf-9ef8-4802-aa9e-342d2ea0bebf":{"customLabel":true,"dataType":"number","isBucketed":false,"label":"Median spending","operationType":"median","scale":"ratio","sourceField":"taxful_total_price","params":{}}},"incompleteColumns":{}}}}},"internalReferences":[],"adHocDataViews":{}}},"hidePanelTitles":true},"title":"Median spending"},{"version":"8.11.0","type":"lens","gridData":{"x":24,"y":7,"w":12,"h":7,"i":"b63ec47d-aace-4980-b928-6be8adafa5a4"},"panelIndex":"b63ec47d-aace-4980-b928-6be8adafa5a4","embeddableConfig":{"enhancements":{},"attributes":{"visualizationType":"lnsMetric","state":{"visualization":{"layerId":"667067a2-7cdf-4f0e-a9fe-eb4f4f1f2f17","layerType":"data","metricAccessor":"c52c2003-ae58-4604-bae7-52ba0fb38a01"},"query":{"language":"kuery","query":""},"filters":[],"datasourceStates":{"formBased":{"layers":{"667067a2-7cdf-4f0e-a9fe-eb4f4f1f2f17":{"columnOrder":["c52c2003-ae58-4604-bae7-52ba0fb38a01"],"columns":{"c52c2003-ae58-4604-bae7-52ba0fb38a01":{"customLabel":true,"dataType":"number","isBucketed":false,"label":"Avg. items sold","operationType":"average","params":{"format":{"id":"number","params":{"decimals":1,"compact":true}}},"scale":"ratio","sourceField":"total_quantity"}},"incompleteColumns":{}}}}},"internalReferences":[],"adHocDataViews":{}},"references":[{"type":"index-pattern","id":"ff959d40-b880-11e8-a6d9-e546fe2bba5f","name":"indexpattern-datasource-layer-667067a2-7cdf-4f0e-a9fe-eb4f4f1f2f17"}]},"hidePanelTitles":true},"title":"Avg. items sold"},{"version":"8.11.0","type":"lens","gridData":{"x":0,"y":14,"w":24,"h":7,"i":"d9495793-80ba-4a9a-b0e3-d1155ec99b09"},"panelIndex":"d9495793-80ba-4a9a-b0e3-d1155ec99b09","embeddableConfig":{"enhancements":{},"attributes":{"state":{"datasourceStates":{"formBased":{"layers":{"b6093a53-884f-42c2-9fcc-ba56cfb66c53":{"columnOrder":["15c45f89-a149-443a-a830-aa8c3a9317db","2b41b3d8-2f62-407a-a866-960f254c679d","eadae280-2da3-4d1d-a0e1-f9733f89c15b","ddc92e50-4d5c-413e-b91b-3e504889fa65","5e31e5d3-2aaa-4475-a130-3b69bf2f748a"],"columns":{"15c45f89-a149-443a-a830-aa8c3a9317db":{"dataType":"date","isBucketed":true,"label":"order_date","operationType":"date_histogram","params":{"interval":"1d","includeEmptyRows":true},"scale":"interval","sourceField":"order_date"},"2b41b3d8-2f62-407a-a866-960f254c679d":{"customLabel":true,"dataType":"number","isBucketed":false,"label":"Total items","operationType":"sum","scale":"ratio","sourceField":"products.quantity"},"5e31e5d3-2aaa-4475-a130-3b69bf2f748a":{"customLabel":true,"dataType":"number","isBucketed":false,"label":"Tx. last week","operationType":"count","scale":"ratio","sourceField":"___records___","timeShift":"1w"},"ddc92e50-4d5c-413e-b91b-3e504889fa65":{"customLabel":true,"dataType":"number","isBucketed":false,"label":"Transactions","operationType":"count","scale":"ratio","sourceField":"___records___"},"eadae280-2da3-4d1d-a0e1-f9733f89c15b":{"customLabel":true,"dataType":"number","isBucketed":false,"label":"Last week","operationType":"sum","scale":"ratio","sourceField":"products.quantity","timeShift":"1w"}},"incompleteColumns":{}}}}},"filters":[],"query":{"language":"kuery","query":""},"visualization":{"axisTitlesVisibilitySettings":{"x":false,"yLeft":false,"yRight":true},"curveType":"LINEAR","fittingFunction":"None","gridlinesVisibilitySettings":{"x":true,"yLeft":true,"yRight":true},"layers":[{"accessors":["2b41b3d8-2f62-407a-a866-960f254c679d","eadae280-2da3-4d1d-a0e1-f9733f89c15b","5e31e5d3-2aaa-4475-a130-3b69bf2f748a","ddc92e50-4d5c-413e-b91b-3e504889fa65"],"layerId":"b6093a53-884f-42c2-9fcc-ba56cfb66c53","position":"top","seriesType":"line","showGridlines":false,"xAccessor":"15c45f89-a149-443a-a830-aa8c3a9317db","yConfig":[{"color":"#b6e0d5","forAccessor":"eadae280-2da3-4d1d-a0e1-f9733f89c15b"},{"color":"#edafc4","forAccessor":"5e31e5d3-2aaa-4475-a130-3b69bf2f748a"}],"layerType":"data"}],"legend":{"isVisible":true,"position":"right","legendSize":"auto"},"preferredSeriesType":"line","tickLabelsVisibilitySettings":{"x":true,"yLeft":true,"yRight":true},"valueLabels":"hide","yLeftExtent":{"mode":"full"},"yRightExtent":{"mode":"full"}}},"visualizationType":"lnsXY","references":[{"id":"ff959d40-b880-11e8-a6d9-e546fe2bba5f","name":"indexpattern-datasource-current-indexpattern","type":"index-pattern"},{"id":"ff959d40-b880-11e8-a6d9-e546fe2bba5f","name":"indexpattern-datasource-layer-b6093a53-884f-42c2-9fcc-ba56cfb66c53","type":"index-pattern"}]}},"title":"Transactions per day"},{"version":"8.11.0","type":"lens","gridData":{"x":24,"y":31,"w":24,"h":14,"i":"bda054f7-2d06-4936-b461-365d1be621fa"},"panelIndex":"bda054f7-2d06-4936-b461-365d1be621fa","embeddableConfig":{"enhancements":{},"attributes":{"state":{"datasourceStates":{"formBased":{"layers":{"0731ee8b-31c5-4be9-92d9-69ee760465d7":{"columnOrder":["7bf8f089-1542-40bd-b349-45fdfc309ac6","826b2f39-b616-40b2-a222-972fdc1d7596","cfd45c47-fc41-430c-9e7a-b71dc0c916b0","bf51c1af-443e-49f4-a21f-54c87bfc5677","bf51c1af-443e-49f4-a21f-54c87bfc5677X0","bf51c1af-443e-49f4-a21f-54c87bfc5677X1","bf51c1af-443e-49f4-a21f-54c87bfc5677X2"],"columns":{"7bf8f089-1542-40bd-b349-45fdfc309ac6":{"dataType":"date","isBucketed":true,"label":"order_date","operationType":"date_histogram","params":{"interval":"1d","includeEmptyRows":true},"scale":"interval","sourceField":"order_date"},"826b2f39-b616-40b2-a222-972fdc1d7596":{"customLabel":true,"dataType":"number","isBucketed":false,"label":"This week","operationType":"sum","scale":"ratio","sourceField":"taxful_total_price"},"bf51c1af-443e-49f4-a21f-54c87bfc5677":{"customLabel":true,"dataType":"number","isBucketed":false,"label":"Difference","operationType":"formula","params":{"format":{"id":"number","params":{"decimals":2}},"formula":"sum(taxful_total_price) - sum(taxful_total_price, shift=\'1w\')","isFormulaBroken":false},"references":["bf51c1af-443e-49f4-a21f-54c87bfc5677X2"],"scale":"ratio"},"bf51c1af-443e-49f4-a21f-54c87bfc5677X0":{"customLabel":true,"dataType":"number","isBucketed":false,"label":"Part of Difference","operationType":"sum","scale":"ratio","sourceField":"taxful_total_price"},"bf51c1af-443e-49f4-a21f-54c87bfc5677X1":{"customLabel":true,"dataType":"number","isBucketed":false,"label":"Part of Difference","operationType":"sum","scale":"ratio","sourceField":"taxful_total_price","timeShift":"1w"},"bf51c1af-443e-49f4-a21f-54c87bfc5677X2":{"customLabel":true,"dataType":"number","isBucketed":false,"label":"Part of Difference","operationType":"math","params":{"tinymathAst":{"args":["bf51c1af-443e-49f4-a21f-54c87bfc5677X0","bf51c1af-443e-49f4-a21f-54c87bfc5677X1"],"location":{"max":61,"min":0},"name":"subtract","text":"sum(taxful_total_price) - sum(taxful_total_price, shift=\'1w\')","type":"function"}},"references":["bf51c1af-443e-49f4-a21f-54c87bfc5677X0","bf51c1af-443e-49f4-a21f-54c87bfc5677X1"],"scale":"ratio"},"cfd45c47-fc41-430c-9e7a-b71dc0c916b0":{"customLabel":true,"dataType":"number","isBucketed":false,"label":"1 week ago","operationType":"sum","scale":"ratio","sourceField":"taxful_total_price","timeShift":"1w"}},"incompleteColumns":{}}}}},"filters":[],"query":{"language":"kuery","query":""},"visualization":{"columns":[{"columnId":"7bf8f089-1542-40bd-b349-45fdfc309ac6"},{"alignment":"left","columnId":"826b2f39-b616-40b2-a222-972fdc1d7596"},{"columnId":"cfd45c47-fc41-430c-9e7a-b71dc0c916b0"},{"colorMode":"text","columnId":"bf51c1af-443e-49f4-a21f-54c87bfc5677","isTransposed":false,"palette":{"name":"custom","params":{"colorStops":[{"color":"#D36086","stop":-10000},{"color":"#209280","stop":0}],"continuity":"above","name":"custom","rangeMax":0,"rangeMin":-10000,"rangeType":"number","steps":5,"stops":[{"color":"#D36086","stop":0},{"color":"#209280","stop":2249.03125}]},"type":"palette"}}],"layerId":"0731ee8b-31c5-4be9-92d9-69ee760465d7","layerType":"data","rowHeight":"single","rowHeightLines":1}},"visualizationType":"lnsDatatable","references":[{"id":"ff959d40-b880-11e8-a6d9-e546fe2bba5f","name":"indexpattern-datasource-current-indexpattern","type":"index-pattern"},{"id":"ff959d40-b880-11e8-a6d9-e546fe2bba5f","name":"indexpattern-datasource-layer-0731ee8b-31c5-4be9-92d9-69ee760465d7","type":"index-pattern"}]}},"title":"Daily comparison"},{"version":"8.11.0","type":"lens","gridData":{"x":0,"y":45,"w":24,"h":9,"i":"d68e91dd-1539-48b0-9279-b43bba2054fe"},"panelIndex":"d68e91dd-1539-48b0-9279-b43bba2054fe","embeddableConfig":{"hidePanelTitles":false,"enhancements":{},"attributes":{"state":{"datasourceStates":{"formBased":{"layers":{"5ed846c2-a70b-4d9c-a244-f254bef763b8":{"columnOrder":["d77cdd24-dedc-48dd-9a4b-d34c6f1a6c46","7ac31901-277a-46e2-8128-8d684b2c1127"],"columns":{"7ac31901-277a-46e2-8128-8d684b2c1127":{"customLabel":true,"dataType":"number","isBucketed":false,"label":"Items","operationType":"count","scale":"ratio","sourceField":"___records___"},"d77cdd24-dedc-48dd-9a4b-d34c6f1a6c46":{"customLabel":true,"dataType":"string","isBucketed":true,"label":"Product name","operationType":"terms","params":{"missingBucket":false,"orderBy":{"columnId":"7ac31901-277a-46e2-8128-8d684b2c1127","type":"column"},"orderDirection":"desc","otherBucket":false,"size":5,"parentFormat":{"id":"terms"}},"scale":"ordinal","sourceField":"products.product_name.keyword"}},"incompleteColumns":{}}}}},"filters":[],"query":{"language":"kuery","query":""},"visualization":{"axisTitlesVisibilitySettings":{"x":false,"yLeft":true,"yRight":true},"fittingFunction":"None","gridlinesVisibilitySettings":{"x":true,"yLeft":true,"yRight":true},"layers":[{"accessors":["7ac31901-277a-46e2-8128-8d684b2c1127"],"layerId":"5ed846c2-a70b-4d9c-a244-f254bef763b8","position":"top","seriesType":"bar_horizontal","showGridlines":false,"xAccessor":"d77cdd24-dedc-48dd-9a4b-d34c6f1a6c46","layerType":"data"}],"legend":{"isVisible":true,"position":"right","legendSize":"auto"},"preferredSeriesType":"bar_horizontal","tickLabelsVisibilitySettings":{"x":true,"yLeft":true,"yRight":true},"valueLabels":"show","yLeftExtent":{"mode":"full"},"yRightExtent":{"mode":"full"}}},"visualizationType":"lnsXY","references":[{"id":"ff959d40-b880-11e8-a6d9-e546fe2bba5f","name":"indexpattern-datasource-current-indexpattern","type":"index-pattern"},{"id":"ff959d40-b880-11e8-a6d9-e546fe2bba5f","name":"indexpattern-datasource-layer-5ed846c2-a70b-4d9c-a244-f254bef763b8","type":"index-pattern"}]}},"title":"Top products this week"},{"version":"8.11.0","type":"lens","gridData":{"x":24,"y":45,"w":24,"h":9,"i":"39d96714-152f-414b-992c-ce2492fc69f3"},"panelIndex":"39d96714-152f-414b-992c-ce2492fc69f3","embeddableConfig":{"timeRange":{"from":"now-2w","to":"now-1w"},"hidePanelTitles":false,"enhancements":{},"attributes":{"state":{"datasourceStates":{"formBased":{"layers":{"5ed846c2-a70b-4d9c-a244-f254bef763b8":{"columnOrder":["d77cdd24-dedc-48dd-9a4b-d34c6f1a6c46","7ac31901-277a-46e2-8128-8d684b2c1127"],"columns":{"7ac31901-277a-46e2-8128-8d684b2c1127":{"customLabel":true,"dataType":"number","isBucketed":false,"label":"Items","operationType":"count","scale":"ratio","sourceField":"___records___"},"d77cdd24-dedc-48dd-9a4b-d34c6f1a6c46":{"customLabel":true,"dataType":"string","isBucketed":true,"label":"Product name","operationType":"terms","params":{"missingBucket":false,"orderBy":{"columnId":"7ac31901-277a-46e2-8128-8d684b2c1127","type":"column"},"orderDirection":"desc","otherBucket":false,"size":5,"parentFormat":{"id":"terms"}},"scale":"ordinal","sourceField":"products.product_name.keyword"}},"incompleteColumns":{}}}}},"filters":[],"query":{"language":"kuery","query":""},"visualization":{"axisTitlesVisibilitySettings":{"x":false,"yLeft":true,"yRight":true},"fittingFunction":"None","gridlinesVisibilitySettings":{"x":true,"yLeft":true,"yRight":true},"layers":[{"accessors":["7ac31901-277a-46e2-8128-8d684b2c1127"],"layerId":"5ed846c2-a70b-4d9c-a244-f254bef763b8","position":"top","seriesType":"bar_horizontal","showGridlines":false,"xAccessor":"d77cdd24-dedc-48dd-9a4b-d34c6f1a6c46","layerType":"data"}],"legend":{"isVisible":true,"position":"right","legendSize":"auto"},"preferredSeriesType":"bar_horizontal","tickLabelsVisibilitySettings":{"x":true,"yLeft":true,"yRight":true},"valueLabels":"show","yLeftExtent":{"mode":"full"},"yRightExtent":{"mode":"full"}}},"visualizationType":"lnsXY","references":[{"id":"ff959d40-b880-11e8-a6d9-e546fe2bba5f","name":"indexpattern-datasource-current-indexpattern","type":"index-pattern"},{"id":"ff959d40-b880-11e8-a6d9-e546fe2bba5f","name":"indexpattern-datasource-layer-5ed846c2-a70b-4d9c-a244-f254bef763b8","type":"index-pattern"}]}},"title":"Top products last week"},{"version":"8.11.0","type":"lens","gridData":{"x":24,"y":14,"w":24,"h":17,"i":"cd47b7cb-0ac0-43e0-b8c6-53489648bdef"},"panelIndex":"cd47b7cb-0ac0-43e0-b8c6-53489648bdef","embeddableConfig":{"enhancements":{},"attributes":{"state":{"datasourceStates":{"formBased":{"layers":{"97c63ea6-9305-4755-97d1-0f26817c6f9a":{"columnOrder":["9f61a7df-198e-4754-b34c-81ed544136ba","ebcb19af-0900-4439-949f-d8cd9bccde19","5575214b-7f21-4b6c-8bc1-34433c6a0c58"],"columns":{"5575214b-7f21-4b6c-8bc1-34433c6a0c58":{"dataType":"number","isBucketed":false,"label":"Count of records","operationType":"count","scale":"ratio","sourceField":"___records___"},"9f61a7df-198e-4754-b34c-81ed544136ba":{"dataType":"string","isBucketed":true,"label":"Top values of category.keyword","operationType":"terms","params":{"missingBucket":false,"orderBy":{"columnId":"5575214b-7f21-4b6c-8bc1-34433c6a0c58","type":"column"},"orderDirection":"desc","otherBucket":true,"size":10,"parentFormat":{"id":"terms"}},"scale":"ordinal","sourceField":"category.keyword"},"ebcb19af-0900-4439-949f-d8cd9bccde19":{"dataType":"date","isBucketed":true,"label":"order_date","operationType":"date_histogram","params":{"interval":"1d","includeEmptyRows":true},"scale":"interval","sourceField":"order_date"}},"incompleteColumns":{}}}}},"filters":[],"query":{"language":"kuery","query":""},"visualization":{"axisTitlesVisibilitySettings":{"x":false,"yLeft":false,"yRight":true},"fittingFunction":"None","gridlinesVisibilitySettings":{"x":true,"yLeft":true,"yRight":true},"layers":[{"accessors":["5575214b-7f21-4b6c-8bc1-34433c6a0c58"],"layerId":"97c63ea6-9305-4755-97d1-0f26817c6f9a","position":"top","seriesType":"bar_percentage_stacked","showGridlines":false,"splitAccessor":"9f61a7df-198e-4754-b34c-81ed544136ba","xAccessor":"ebcb19af-0900-4439-949f-d8cd9bccde19","layerType":"data"}],"legend":{"isVisible":true,"position":"right","legendSize":"auto"},"preferredSeriesType":"bar_percentage_stacked","tickLabelsVisibilitySettings":{"x":true,"yLeft":true,"yRight":true},"valueLabels":"show","yLeftExtent":{"mode":"full"},"yRightExtent":{"mode":"full"}}},"visualizationType":"lnsXY","references":[{"id":"ff959d40-b880-11e8-a6d9-e546fe2bba5f","name":"indexpattern-datasource-current-indexpattern","type":"index-pattern"},{"id":"ff959d40-b880-11e8-a6d9-e546fe2bba5f","name":"indexpattern-datasource-layer-97c63ea6-9305-4755-97d1-0f26817c6f9a","type":"index-pattern"}]}},"title":"Breakdown by category"},{"version":"8.11.0","type":"lens","gridData":{"x":0,"y":7,"w":24,"h":7,"i":"bdb525ab-270b-46f1-a847-dd29be19aadb"},"panelIndex":"bdb525ab-270b-46f1-a847-dd29be19aadb","embeddableConfig":{"enhancements":{},"hidePanelTitles":false,"attributes":{"state":{"datasourceStates":{"formBased":{"layers":{"c7478794-6767-4286-9d65-1c0ecd909dd8":{"columnOrder":["8289349e-6d1b-4abf-b164-0208183d2c34","041db33b-5c9c-47f3-a5d3-ef5e255d1663","041db33b-5c9c-47f3-a5d3-ef5e255d1663X0","041db33b-5c9c-47f3-a5d3-ef5e255d1663X1"],"columns":{"041db33b-5c9c-47f3-a5d3-ef5e255d1663":{"customLabel":true,"dataType":"number","isBucketed":false,"label":"% of target ($10k)","operationType":"formula","params":{"format":{"id":"percent","params":{"decimals":0}},"formula":"sum(taxful_total_price) / 10000 - 1","isFormulaBroken":false},"references":["041db33b-5c9c-47f3-a5d3-ef5e255d1663X1"],"scale":"ratio"},"041db33b-5c9c-47f3-a5d3-ef5e255d1663X0":{"customLabel":true,"dataType":"number","isBucketed":false,"label":"Part of Weekly revenue","operationType":"sum","scale":"ratio","sourceField":"taxful_total_price"},"041db33b-5c9c-47f3-a5d3-ef5e255d1663X1":{"customLabel":true,"dataType":"number","isBucketed":false,"label":"Part of Weekly revenue","operationType":"math","params":{"tinymathAst":{"args":[{"args":["041db33b-5c9c-47f3-a5d3-ef5e255d1663X0",10000],"location":{"max":32,"min":0},"name":"divide","text":"sum(taxful_total_price) / 10000 ","type":"function"},1],"location":{"max":35,"min":0},"name":"subtract","text":"sum(taxful_total_price) / 10000 - 1","type":"function"}},"references":["041db33b-5c9c-47f3-a5d3-ef5e255d1663X0"],"scale":"ratio"},"8289349e-6d1b-4abf-b164-0208183d2c34":{"dataType":"date","isBucketed":true,"label":"order_date","operationType":"date_histogram","params":{"interval":"1d","includeEmptyRows":true},"scale":"interval","sourceField":"order_date"}},"incompleteColumns":{}}}}},"filters":[],"query":{"language":"kuery","query":""},"visualization":{"axisTitlesVisibilitySettings":{"x":false,"yLeft":false,"yRight":true},"fittingFunction":"None","gridlinesVisibilitySettings":{"x":true,"yLeft":true,"yRight":true},"layers":[{"accessors":["041db33b-5c9c-47f3-a5d3-ef5e255d1663"],"layerId":"c7478794-6767-4286-9d65-1c0ecd909dd8","seriesType":"bar_stacked","xAccessor":"8289349e-6d1b-4abf-b164-0208183d2c34","layerType":"data"}],"legend":{"isVisible":true,"position":"right","legendSize":"auto"},"preferredSeriesType":"bar_stacked","tickLabelsVisibilitySettings":{"x":true,"yLeft":true,"yRight":true},"valueLabels":"hide","yLeftExtent":{"mode":"full"},"yRightExtent":{"mode":"full"}}},"visualizationType":"lnsXY","references":[{"id":"ff959d40-b880-11e8-a6d9-e546fe2bba5f","name":"indexpattern-datasource-current-indexpattern","type":"index-pattern"},{"id":"ff959d40-b880-11e8-a6d9-e546fe2bba5f","name":"indexpattern-datasource-layer-c7478794-6767-4286-9d65-1c0ecd909dd8","type":"index-pattern"}]}},"title":"% of target revenue ($10k)"}]', timeFrom: 'now-7d', title: '[eCommerce] Revenue Dashboard', timeTo: 'now', @@ -209,9 +180,9 @@ export const getSavedObjects = (): SavedObject[] => [ name: '5:xy-visualization-layer-192ad2e4-2bb7-44a9-b345-e96045fa6ccd', }, { - name: '7:panel_7', - type: 'visualization', - id: 'b80e6540-b891-11e8-a6d9-e546fe2bba5f', + type: 'index-pattern', + id: 'ff959d40-b880-11e8-a6d9-e546fe2bba5f', + name: '7:indexpattern-datasource-layer-037375ae-9e23-4dd5-a4f0-5f117bb7dac1', }, { name: '10:panel_10', diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index 9bef8ead17f65..b54778a7ae73a 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -3509,7 +3509,6 @@ "home.sampleData.customIntegrationsTitle": "Exemple de données", "home.sampleData.ecommerceSpec.ordersTitle": "[e-commerce] Commandes", "home.sampleData.ecommerceSpec.salesCountMapTitle": "[e-commerce] Carte du nombre de ventes", - "home.sampleData.ecommerceSpec.soldProductsPerDayTitle": "[e-commerce] Produits vendus par jour", "home.sampleData.ecommerceSpecDescription": "Exemple de données, visualisations et tableaux de bord pour le suivi des commandes d’e-commerce.", "home.sampleData.ecommerceSpecTitle": "Exemple de commandes d’e-commerce", "home.sampleData.flightsSpec.airportConnectionsTitle": "[Vols] Connexions aéroportuaires (passage au-dessus d'un aéroport)", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index b22c36e25a649..a2a5719e9fa21 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -3524,7 +3524,6 @@ "home.sampleData.customIntegrationsTitle": "サンプルデータ", "home.sampleData.ecommerceSpec.ordersTitle": "[e コマース] 注文", "home.sampleData.ecommerceSpec.salesCountMapTitle": "[eコマース] 売上カウントマップ", - "home.sampleData.ecommerceSpec.soldProductsPerDayTitle": "[e コマース] 1 日の販売製品", "home.sampleData.ecommerceSpecDescription": "e コマースの注文をトラッキングするサンプルデータ、ビジュアライゼーション、ダッシュボードです。", "home.sampleData.ecommerceSpecTitle": "サンプル e コマース注文", "home.sampleData.flightsSpec.airportConnectionsTitle": "[フライト] 空港乗り継ぎ(空港にカーソルを合わせてください)", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 89dec8049136f..b65369d942c92 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -3523,7 +3523,6 @@ "home.sampleData.customIntegrationsTitle": "样例数据", "home.sampleData.ecommerceSpec.ordersTitle": "[电子商务] 订单", "home.sampleData.ecommerceSpec.salesCountMapTitle": "[电子商务] 销售计数地图", - "home.sampleData.ecommerceSpec.soldProductsPerDayTitle": "[电子商务] 每天已售产品", "home.sampleData.ecommerceSpecDescription": "用于追踪电子商务订单的样例数据、可视化和仪表板。", "home.sampleData.ecommerceSpecTitle": "样例电子商务订单", "home.sampleData.flightsSpec.airportConnectionsTitle": "[航班] 机场航线(将鼠标悬停在机场上)", From ebe6b4650ae276e73e479bb31d035c62919fd12d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B8ren=20Louv-Jansen?= Date: Mon, 21 Aug 2023 14:51:28 +0200 Subject: [PATCH 07/19] [APM] Remove `power_user` and `read_only_user` folders from e2e (#164242) We currently separate e2e tests into `power_user` tests and `read_only_user` tests. We often want to test different permissions within the same tests, so the distinction becomes a barrier rather than a help. This PR removed the folders and combines all tests regardless of which user they run as. --- src/dev/precommit_hook/casing_check_config.js | 2 +- .../e2e/{read_only_user => }/_404.cy.ts | 0 .../e2e/{read_only_user => }/deep_links.cy.ts | 0 .../{read_only_user => }/dependencies.cy.ts | 6 +-- .../dependency_operation.cy.ts | 4 +- .../apm-diagnostics-8.8.0-1687436214804.json | 0 .../diagnostics/diagnostics.cy.ts | 2 +- .../errors/error_details.cy.ts | 4 +- .../errors/errors_page.cy.ts | 4 +- .../errors/generate_data.ts | 0 .../feature_flag/comparison.cy.ts | 4 +- .../e2e/{read_only_user => }/home.cy.ts | 4 +- .../infrastructure/generate_data.ts | 0 .../infrastructure/infrastructure_page.cy.ts | 4 +- .../integration_policy.cy.ts | 0 .../mobile/generate_data.ts | 0 .../mobile/mobile_transaction_details.cy.ts | 2 +- .../mobile/mobile_transactions.cy.ts | 2 +- .../e2e/{read_only_user => }/navigation.cy.ts | 4 +- .../e2e/{power_user => }/no_data_screen.cy.ts | 0 .../onboarding/onboarding.cy.ts | 2 +- .../{power_user => }/rules/error_count.cy.ts | 2 +- .../{power_user => }/rules/generate_data.ts | 0 .../service_groups/generate_data.ts | 0 .../service_groups/service_groups.cy.ts | 2 +- .../service_inventory/generate_data.ts | 0 .../header_filters/generate_data.ts | 0 .../header_filters/header_filters.cy.ts | 2 +- .../service_inventory/service_inventory.cy.ts | 6 +-- .../service_map/service_map.cy.ts | 4 +- .../service_overview/alerts_table.cy.ts | 4 +- .../aws_lambda/aws_lambda.cy.ts | 2 +- .../aws_lambda/generate_data.ts | 0 .../azure_functions/azure_functions.cy.ts | 2 +- .../azure_functions/generate_data.ts | 0 .../service_overview/errors_table.cy.ts | 4 +- .../service_overview/generate_data.ts | 0 .../service_overview/generate_mobile.data.ts | 0 .../service_overview/header_filters.cy.ts | 4 +- .../service_overview/instances_table.cy.ts | 4 +- ...obile_overview_with_most_used_charts.cy.ts | 2 +- .../service_and_mobile_overview.cy.ts | 2 +- .../service_overview/service_overview.cy.ts | 6 +-- .../service_overview/time_comparison.cy.ts | 4 +- .../settings/agent_configurations.cy.ts | 2 +- .../settings/custom_links.cy.ts | 0 .../storage_explorer/storage_explorer.cy.ts | 6 +-- .../trace_explorer/trace_explorer.cy.ts | 4 +- .../generate_span_links_data.ts | 4 +- .../transaction_details/span_links.cy.ts | 2 +- .../transaction_details.cy.ts | 6 +-- .../transactions_overview.cy.ts | 6 +-- .../tutorial/tutorial.cy.ts | 0 .../apm/ftr_e2e/cypress/tasks/es_archiver.ts | 40 ------------------- 54 files changed, 62 insertions(+), 102 deletions(-) rename x-pack/plugins/apm/ftr_e2e/cypress/e2e/{read_only_user => }/_404.cy.ts (100%) rename x-pack/plugins/apm/ftr_e2e/cypress/e2e/{read_only_user => }/deep_links.cy.ts (100%) rename x-pack/plugins/apm/ftr_e2e/cypress/e2e/{read_only_user => }/dependencies.cy.ts (95%) rename x-pack/plugins/apm/ftr_e2e/cypress/e2e/{read_only_user => }/dependency_operation/dependency_operation.cy.ts (91%) rename x-pack/plugins/apm/ftr_e2e/cypress/e2e/{power_user => }/diagnostics/apm-diagnostics-8.8.0-1687436214804.json (100%) rename x-pack/plugins/apm/ftr_e2e/cypress/e2e/{power_user => }/diagnostics/diagnostics.cy.ts (98%) rename x-pack/plugins/apm/ftr_e2e/cypress/e2e/{read_only_user => }/errors/error_details.cy.ts (97%) rename x-pack/plugins/apm/ftr_e2e/cypress/e2e/{read_only_user => }/errors/errors_page.cy.ts (97%) rename x-pack/plugins/apm/ftr_e2e/cypress/e2e/{read_only_user => }/errors/generate_data.ts (100%) rename x-pack/plugins/apm/ftr_e2e/cypress/e2e/{power_user => }/feature_flag/comparison.cy.ts (96%) rename x-pack/plugins/apm/ftr_e2e/cypress/e2e/{read_only_user => }/home.cy.ts (94%) rename x-pack/plugins/apm/ftr_e2e/cypress/e2e/{power_user => }/infrastructure/generate_data.ts (100%) rename x-pack/plugins/apm/ftr_e2e/cypress/e2e/{power_user => }/infrastructure/infrastructure_page.cy.ts (95%) rename x-pack/plugins/apm/ftr_e2e/cypress/e2e/{power_user => }/integration_settings/integration_policy.cy.ts (100%) rename x-pack/plugins/apm/ftr_e2e/cypress/e2e/{read_only_user => }/mobile/generate_data.ts (100%) rename x-pack/plugins/apm/ftr_e2e/cypress/e2e/{read_only_user => }/mobile/mobile_transaction_details.cy.ts (95%) rename x-pack/plugins/apm/ftr_e2e/cypress/e2e/{read_only_user => }/mobile/mobile_transactions.cy.ts (97%) rename x-pack/plugins/apm/ftr_e2e/cypress/e2e/{read_only_user => }/navigation.cy.ts (95%) rename x-pack/plugins/apm/ftr_e2e/cypress/e2e/{power_user => }/no_data_screen.cy.ts (100%) rename x-pack/plugins/apm/ftr_e2e/cypress/e2e/{power_user => }/onboarding/onboarding.cy.ts (98%) rename x-pack/plugins/apm/ftr_e2e/cypress/e2e/{power_user => }/rules/error_count.cy.ts (98%) rename x-pack/plugins/apm/ftr_e2e/cypress/e2e/{power_user => }/rules/generate_data.ts (100%) rename x-pack/plugins/apm/ftr_e2e/cypress/e2e/{power_user => }/service_groups/generate_data.ts (100%) rename x-pack/plugins/apm/ftr_e2e/cypress/e2e/{power_user => }/service_groups/service_groups.cy.ts (98%) rename x-pack/plugins/apm/ftr_e2e/cypress/e2e/{read_only_user => }/service_inventory/generate_data.ts (100%) rename x-pack/plugins/apm/ftr_e2e/cypress/e2e/{read_only_user => }/service_inventory/header_filters/generate_data.ts (100%) rename x-pack/plugins/apm/ftr_e2e/cypress/e2e/{read_only_user => }/service_inventory/header_filters/header_filters.cy.ts (96%) rename x-pack/plugins/apm/ftr_e2e/cypress/e2e/{read_only_user => }/service_inventory/service_inventory.cy.ts (96%) rename x-pack/plugins/apm/ftr_e2e/cypress/e2e/{power_user => }/service_map/service_map.cy.ts (93%) rename x-pack/plugins/apm/ftr_e2e/cypress/e2e/{read_only_user => }/service_overview/alerts_table.cy.ts (90%) rename x-pack/plugins/apm/ftr_e2e/cypress/e2e/{read_only_user => }/service_overview/aws_lambda/aws_lambda.cy.ts (96%) rename x-pack/plugins/apm/ftr_e2e/cypress/e2e/{read_only_user => }/service_overview/aws_lambda/generate_data.ts (100%) rename x-pack/plugins/apm/ftr_e2e/cypress/e2e/{read_only_user => }/service_overview/azure_functions/azure_functions.cy.ts (96%) rename x-pack/plugins/apm/ftr_e2e/cypress/e2e/{read_only_user => }/service_overview/azure_functions/generate_data.ts (100%) rename x-pack/plugins/apm/ftr_e2e/cypress/e2e/{read_only_user => }/service_overview/errors_table.cy.ts (94%) rename x-pack/plugins/apm/ftr_e2e/cypress/e2e/{power_user => }/service_overview/generate_data.ts (100%) rename x-pack/plugins/apm/ftr_e2e/cypress/e2e/{power_user => }/service_overview/generate_mobile.data.ts (100%) rename x-pack/plugins/apm/ftr_e2e/cypress/e2e/{read_only_user => }/service_overview/header_filters.cy.ts (97%) rename x-pack/plugins/apm/ftr_e2e/cypress/e2e/{read_only_user => }/service_overview/instances_table.cy.ts (97%) rename x-pack/plugins/apm/ftr_e2e/cypress/e2e/{power_user => }/service_overview/mobile_overview_with_most_used_charts.cy.ts (98%) rename x-pack/plugins/apm/ftr_e2e/cypress/e2e/{power_user => }/service_overview/service_and_mobile_overview.cy.ts (98%) rename x-pack/plugins/apm/ftr_e2e/cypress/e2e/{read_only_user => }/service_overview/service_overview.cy.ts (97%) rename x-pack/plugins/apm/ftr_e2e/cypress/e2e/{read_only_user => }/service_overview/time_comparison.cy.ts (98%) rename x-pack/plugins/apm/ftr_e2e/cypress/e2e/{power_user => }/settings/agent_configurations.cy.ts (98%) rename x-pack/plugins/apm/ftr_e2e/cypress/e2e/{power_user => }/settings/custom_links.cy.ts (100%) rename x-pack/plugins/apm/ftr_e2e/cypress/e2e/{power_user => }/storage_explorer/storage_explorer.cy.ts (97%) rename x-pack/plugins/apm/ftr_e2e/cypress/e2e/{read_only_user => }/trace_explorer/trace_explorer.cy.ts (90%) rename x-pack/plugins/apm/ftr_e2e/cypress/e2e/{read_only_user => }/transaction_details/generate_span_links_data.ts (98%) rename x-pack/plugins/apm/ftr_e2e/cypress/e2e/{read_only_user => }/transaction_details/span_links.cy.ts (99%) rename x-pack/plugins/apm/ftr_e2e/cypress/e2e/{read_only_user => }/transaction_details/transaction_details.cy.ts (95%) rename x-pack/plugins/apm/ftr_e2e/cypress/e2e/{read_only_user => }/transactions_overview/transactions_overview.cy.ts (91%) rename x-pack/plugins/apm/ftr_e2e/cypress/e2e/{read_only_user => }/tutorial/tutorial.cy.ts (100%) delete mode 100644 x-pack/plugins/apm/ftr_e2e/cypress/tasks/es_archiver.ts diff --git a/src/dev/precommit_hook/casing_check_config.js b/src/dev/precommit_hook/casing_check_config.js index 45fdb283910b4..c3b1a27491e67 100644 --- a/src/dev/precommit_hook/casing_check_config.js +++ b/src/dev/precommit_hook/casing_check_config.js @@ -30,7 +30,7 @@ export const IGNORE_FILE_GLOBS = [ 'x-pack/plugins/cases/docs/**/*', 'x-pack/plugins/monitoring/public/lib/jquery_flot/**/*', 'x-pack/plugins/fleet/cypress/packages/*.zip', - 'x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/diagnostics/apm-diagnostics-*.json', + '**/apm-diagnostics-*.json', '**/.*', '**/__mocks__/**/*', 'x-pack/docs/**/*', diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/_404.cy.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/_404.cy.ts similarity index 100% rename from x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/_404.cy.ts rename to x-pack/plugins/apm/ftr_e2e/cypress/e2e/_404.cy.ts diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/deep_links.cy.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/deep_links.cy.ts similarity index 100% rename from x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/deep_links.cy.ts rename to x-pack/plugins/apm/ftr_e2e/cypress/e2e/deep_links.cy.ts diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/dependencies.cy.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/dependencies.cy.ts similarity index 95% rename from x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/dependencies.cy.ts rename to x-pack/plugins/apm/ftr_e2e/cypress/e2e/dependencies.cy.ts index 2ef3ae42b1aac..3200ba846fc76 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/dependencies.cy.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/dependencies.cy.ts @@ -4,9 +4,9 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { synthtrace } from '../../../synthtrace'; -import { opbeans } from '../../fixtures/synthtrace/opbeans'; -import { checkA11y } from '../../support/commands'; +import { synthtrace } from '../../synthtrace'; +import { opbeans } from '../fixtures/synthtrace/opbeans'; +import { checkA11y } from '../support/commands'; const start = '2021-10-10T00:00:00.000Z'; const end = '2021-10-10T00:15:00.000Z'; diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/dependency_operation/dependency_operation.cy.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/dependency_operation/dependency_operation.cy.ts similarity index 91% rename from x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/dependency_operation/dependency_operation.cy.ts rename to x-pack/plugins/apm/ftr_e2e/cypress/e2e/dependency_operation/dependency_operation.cy.ts index 095cc5d23bbcc..587bddc278b9d 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/dependency_operation/dependency_operation.cy.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/dependency_operation/dependency_operation.cy.ts @@ -6,8 +6,8 @@ */ import url from 'url'; -import { synthtrace } from '../../../../synthtrace'; -import { opbeans } from '../../../fixtures/synthtrace/opbeans'; +import { synthtrace } from '../../../synthtrace'; +import { opbeans } from '../../fixtures/synthtrace/opbeans'; const start = '2021-10-10T00:00:00.000Z'; const end = '2021-10-10T00:15:00.000Z'; diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/diagnostics/apm-diagnostics-8.8.0-1687436214804.json b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/diagnostics/apm-diagnostics-8.8.0-1687436214804.json similarity index 100% rename from x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/diagnostics/apm-diagnostics-8.8.0-1687436214804.json rename to x-pack/plugins/apm/ftr_e2e/cypress/e2e/diagnostics/apm-diagnostics-8.8.0-1687436214804.json diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/diagnostics/diagnostics.cy.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/diagnostics/diagnostics.cy.ts similarity index 98% rename from x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/diagnostics/diagnostics.cy.ts rename to x-pack/plugins/apm/ftr_e2e/cypress/e2e/diagnostics/diagnostics.cy.ts index 938e6dd67c16f..10b977d7917e8 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/diagnostics/diagnostics.cy.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/diagnostics/diagnostics.cy.ts @@ -158,7 +158,7 @@ describe('Diagnostics', () => { function importBundle() { cy.visitKibana('/app/apm/diagnostics/import-export'); cy.get('#file-picker').selectFile( - './cypress/e2e/power_user/diagnostics/apm-diagnostics-8.8.0-1687436214804.json' + './cypress/e2e/diagnostics/apm-diagnostics-8.8.0-1687436214804.json' ); } diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/errors/error_details.cy.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/errors/error_details.cy.ts similarity index 97% rename from x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/errors/error_details.cy.ts rename to x-pack/plugins/apm/ftr_e2e/cypress/e2e/errors/error_details.cy.ts index c09547abcf7c8..9a34bc65ea509 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/errors/error_details.cy.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/errors/error_details.cy.ts @@ -7,8 +7,8 @@ import { getErrorGroupingKey } from '@kbn/apm-synthtrace-client/src/lib/apm/instance'; import url from 'url'; -import { synthtrace } from '../../../../synthtrace'; -import { checkA11y } from '../../../support/commands'; +import { synthtrace } from '../../../synthtrace'; +import { checkA11y } from '../../support/commands'; import { generateData } from './generate_data'; const start = '2021-10-10T00:00:00.000Z'; diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/errors/errors_page.cy.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/errors/errors_page.cy.ts similarity index 97% rename from x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/errors/errors_page.cy.ts rename to x-pack/plugins/apm/ftr_e2e/cypress/e2e/errors/errors_page.cy.ts index a64dc157d4037..c95d2da00ffcb 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/errors/errors_page.cy.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/errors/errors_page.cy.ts @@ -6,8 +6,8 @@ */ import url from 'url'; -import { synthtrace } from '../../../../synthtrace'; -import { checkA11y } from '../../../support/commands'; +import { synthtrace } from '../../../synthtrace'; +import { checkA11y } from '../../support/commands'; import { generateData, generateErrors } from './generate_data'; const start = '2021-10-10T00:00:00.000Z'; diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/errors/generate_data.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/errors/generate_data.ts similarity index 100% rename from x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/errors/generate_data.ts rename to x-pack/plugins/apm/ftr_e2e/cypress/e2e/errors/generate_data.ts diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/feature_flag/comparison.cy.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/feature_flag/comparison.cy.ts similarity index 96% rename from x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/feature_flag/comparison.cy.ts rename to x-pack/plugins/apm/ftr_e2e/cypress/e2e/feature_flag/comparison.cy.ts index 7d40105db192e..87fd051bbb1b1 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/feature_flag/comparison.cy.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/feature_flag/comparison.cy.ts @@ -5,8 +5,8 @@ * 2.0. */ -import { synthtrace } from '../../../../synthtrace'; -import { opbeans } from '../../../fixtures/synthtrace/opbeans'; +import { synthtrace } from '../../../synthtrace'; +import { opbeans } from '../../fixtures/synthtrace/opbeans'; const start = '2021-10-10T00:00:00.000Z'; const end = '2021-10-10T00:15:00.000Z'; diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/home.cy.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/home.cy.ts similarity index 94% rename from x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/home.cy.ts rename to x-pack/plugins/apm/ftr_e2e/cypress/e2e/home.cy.ts index e0c4a3aedd2b3..924753606ffa0 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/home.cy.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/home.cy.ts @@ -6,8 +6,8 @@ */ import url from 'url'; -import { synthtrace } from '../../../synthtrace'; -import { opbeans } from '../../fixtures/synthtrace/opbeans'; +import { synthtrace } from '../../synthtrace'; +import { opbeans } from '../fixtures/synthtrace/opbeans'; const start = '2021-10-10T00:00:00.000Z'; const end = '2021-10-10T00:15:00.000Z'; diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/infrastructure/generate_data.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/infrastructure/generate_data.ts similarity index 100% rename from x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/infrastructure/generate_data.ts rename to x-pack/plugins/apm/ftr_e2e/cypress/e2e/infrastructure/generate_data.ts diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/infrastructure/infrastructure_page.cy.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/infrastructure/infrastructure_page.cy.ts similarity index 95% rename from x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/infrastructure/infrastructure_page.cy.ts rename to x-pack/plugins/apm/ftr_e2e/cypress/e2e/infrastructure/infrastructure_page.cy.ts index 439b95a796b71..246c62a218317 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/infrastructure/infrastructure_page.cy.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/infrastructure/infrastructure_page.cy.ts @@ -5,8 +5,8 @@ * 2.0. */ import url from 'url'; -import { synthtrace } from '../../../../synthtrace'; -import { checkA11y } from '../../../support/commands'; +import { synthtrace } from '../../../synthtrace'; +import { checkA11y } from '../../support/commands'; import { generateData } from './generate_data'; const start = '2021-10-10T00:00:00.000Z'; diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/integration_settings/integration_policy.cy.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/integration_settings/integration_policy.cy.ts similarity index 100% rename from x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/integration_settings/integration_policy.cy.ts rename to x-pack/plugins/apm/ftr_e2e/cypress/e2e/integration_settings/integration_policy.cy.ts diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/mobile/generate_data.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/mobile/generate_data.ts similarity index 100% rename from x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/mobile/generate_data.ts rename to x-pack/plugins/apm/ftr_e2e/cypress/e2e/mobile/generate_data.ts diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/mobile/mobile_transaction_details.cy.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/mobile/mobile_transaction_details.cy.ts similarity index 95% rename from x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/mobile/mobile_transaction_details.cy.ts rename to x-pack/plugins/apm/ftr_e2e/cypress/e2e/mobile/mobile_transaction_details.cy.ts index 98d6ce665338b..1de2e768753c6 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/mobile/mobile_transaction_details.cy.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/mobile/mobile_transaction_details.cy.ts @@ -6,7 +6,7 @@ */ import url from 'url'; -import { synthtrace } from '../../../../synthtrace'; +import { synthtrace } from '../../../synthtrace'; import { generateMobileData } from './generate_data'; const start = '2021-10-10T00:00:00.000Z'; diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/mobile/mobile_transactions.cy.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/mobile/mobile_transactions.cy.ts similarity index 97% rename from x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/mobile/mobile_transactions.cy.ts rename to x-pack/plugins/apm/ftr_e2e/cypress/e2e/mobile/mobile_transactions.cy.ts index 85cf055507f3b..4d300b4b659dd 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/mobile/mobile_transactions.cy.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/mobile/mobile_transactions.cy.ts @@ -6,7 +6,7 @@ */ import url from 'url'; -import { synthtrace } from '../../../../synthtrace'; +import { synthtrace } from '../../../synthtrace'; import { generateMobileData } from './generate_data'; const start = '2021-10-10T00:00:00.000Z'; diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/navigation.cy.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/navigation.cy.ts similarity index 95% rename from x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/navigation.cy.ts rename to x-pack/plugins/apm/ftr_e2e/cypress/e2e/navigation.cy.ts index 0b060bcafdbf2..d1baefed136ae 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/navigation.cy.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/navigation.cy.ts @@ -6,8 +6,8 @@ */ import url from 'url'; -import { synthtrace } from '../../../synthtrace'; -import { opbeans } from '../../fixtures/synthtrace/opbeans'; +import { synthtrace } from '../../synthtrace'; +import { opbeans } from '../fixtures/synthtrace/opbeans'; const start = '2021-10-10T00:00:00.000Z'; const end = '2021-10-10T00:15:00.000Z'; diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/no_data_screen.cy.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/no_data_screen.cy.ts similarity index 100% rename from x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/no_data_screen.cy.ts rename to x-pack/plugins/apm/ftr_e2e/cypress/e2e/no_data_screen.cy.ts diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/onboarding/onboarding.cy.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/onboarding/onboarding.cy.ts similarity index 98% rename from x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/onboarding/onboarding.cy.ts rename to x-pack/plugins/apm/ftr_e2e/cypress/e2e/onboarding/onboarding.cy.ts index e7298607de8e6..f5371ac983708 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/onboarding/onboarding.cy.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/onboarding/onboarding.cy.ts @@ -5,7 +5,7 @@ * 2.0. */ import { apm, timerange } from '@kbn/apm-synthtrace-client'; -import { synthtrace } from '../../../../synthtrace'; +import { synthtrace } from '../../../synthtrace'; const start = Date.now() - 1000; const end = Date.now(); diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/rules/error_count.cy.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/rules/error_count.cy.ts similarity index 98% rename from x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/rules/error_count.cy.ts rename to x-pack/plugins/apm/ftr_e2e/cypress/e2e/rules/error_count.cy.ts index a9ba45b4ad319..1a5d5b9bb1652 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/rules/error_count.cy.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/rules/error_count.cy.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { synthtrace } from '../../../../synthtrace'; +import { synthtrace } from '../../../synthtrace'; import { generateData } from './generate_data'; function deleteAllRules() { diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/rules/generate_data.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/rules/generate_data.ts similarity index 100% rename from x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/rules/generate_data.ts rename to x-pack/plugins/apm/ftr_e2e/cypress/e2e/rules/generate_data.ts diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/service_groups/generate_data.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/service_groups/generate_data.ts similarity index 100% rename from x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/service_groups/generate_data.ts rename to x-pack/plugins/apm/ftr_e2e/cypress/e2e/service_groups/generate_data.ts diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/service_groups/service_groups.cy.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/service_groups/service_groups.cy.ts similarity index 98% rename from x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/service_groups/service_groups.cy.ts rename to x-pack/plugins/apm/ftr_e2e/cypress/e2e/service_groups/service_groups.cy.ts index a83766389a1f2..bc7e7d331cceb 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/service_groups/service_groups.cy.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/service_groups/service_groups.cy.ts @@ -5,7 +5,7 @@ * 2.0. */ import url from 'url'; -import { synthtrace } from '../../../../synthtrace'; +import { synthtrace } from '../../../synthtrace'; import { generateData } from './generate_data'; const start = Date.now() - 1000; diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/service_inventory/generate_data.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/service_inventory/generate_data.ts similarity index 100% rename from x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/service_inventory/generate_data.ts rename to x-pack/plugins/apm/ftr_e2e/cypress/e2e/service_inventory/generate_data.ts diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/service_inventory/header_filters/generate_data.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/service_inventory/header_filters/generate_data.ts similarity index 100% rename from x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/service_inventory/header_filters/generate_data.ts rename to x-pack/plugins/apm/ftr_e2e/cypress/e2e/service_inventory/header_filters/generate_data.ts diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/service_inventory/header_filters/header_filters.cy.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/service_inventory/header_filters/header_filters.cy.ts similarity index 96% rename from x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/service_inventory/header_filters/header_filters.cy.ts rename to x-pack/plugins/apm/ftr_e2e/cypress/e2e/service_inventory/header_filters/header_filters.cy.ts index 8e30f2784eb34..2582638dc5c69 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/service_inventory/header_filters/header_filters.cy.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/service_inventory/header_filters/header_filters.cy.ts @@ -5,7 +5,7 @@ * 2.0. */ import url from 'url'; -import { synthtrace } from '../../../../../synthtrace'; +import { synthtrace } from '../../../../synthtrace'; import { generateData } from './generate_data'; const start = '2021-10-10T00:00:00.000Z'; diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/service_inventory/service_inventory.cy.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/service_inventory/service_inventory.cy.ts similarity index 96% rename from x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/service_inventory/service_inventory.cy.ts rename to x-pack/plugins/apm/ftr_e2e/cypress/e2e/service_inventory/service_inventory.cy.ts index 032409ec56d40..889724f664f9b 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/service_inventory/service_inventory.cy.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/service_inventory/service_inventory.cy.ts @@ -6,9 +6,9 @@ */ import moment from 'moment'; import url from 'url'; -import { synthtrace } from '../../../../synthtrace'; -import { opbeans } from '../../../fixtures/synthtrace/opbeans'; -import { checkA11y } from '../../../support/commands'; +import { synthtrace } from '../../../synthtrace'; +import { opbeans } from '../../fixtures/synthtrace/opbeans'; +import { checkA11y } from '../../support/commands'; import { generateMultipleServicesData } from './generate_data'; const timeRange = { diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/service_map/service_map.cy.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/service_map/service_map.cy.ts similarity index 93% rename from x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/service_map/service_map.cy.ts rename to x-pack/plugins/apm/ftr_e2e/cypress/e2e/service_map/service_map.cy.ts index 1ff28bfb46cbf..2471617e7b1f4 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/service_map/service_map.cy.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/service_map/service_map.cy.ts @@ -5,8 +5,8 @@ * 2.0. */ import url from 'url'; -import { synthtrace } from '../../../../synthtrace'; -import { opbeans } from '../../../fixtures/synthtrace/opbeans'; +import { synthtrace } from '../../../synthtrace'; +import { opbeans } from '../../fixtures/synthtrace/opbeans'; const start = '2021-10-10T00:00:00.000Z'; const end = '2021-10-10T00:15:00.000Z'; diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/service_overview/alerts_table.cy.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/service_overview/alerts_table.cy.ts similarity index 90% rename from x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/service_overview/alerts_table.cy.ts rename to x-pack/plugins/apm/ftr_e2e/cypress/e2e/service_overview/alerts_table.cy.ts index 6a5cd12bc7842..0bce81a620a51 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/service_overview/alerts_table.cy.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/service_overview/alerts_table.cy.ts @@ -6,8 +6,8 @@ */ import url from 'url'; -import { synthtrace } from '../../../../synthtrace'; -import { opbeans } from '../../../fixtures/synthtrace/opbeans'; +import { synthtrace } from '../../../synthtrace'; +import { opbeans } from '../../fixtures/synthtrace/opbeans'; const start = '2021-10-10T00:00:00.000Z'; const end = '2021-10-10T00:15:00.000Z'; diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/service_overview/aws_lambda/aws_lambda.cy.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/service_overview/aws_lambda/aws_lambda.cy.ts similarity index 96% rename from x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/service_overview/aws_lambda/aws_lambda.cy.ts rename to x-pack/plugins/apm/ftr_e2e/cypress/e2e/service_overview/aws_lambda/aws_lambda.cy.ts index a70620ee18f82..1453983b23a50 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/service_overview/aws_lambda/aws_lambda.cy.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/service_overview/aws_lambda/aws_lambda.cy.ts @@ -5,7 +5,7 @@ * 2.0. */ import url from 'url'; -import { synthtrace } from '../../../../../synthtrace'; +import { synthtrace } from '../../../../synthtrace'; import { generateData } from './generate_data'; const start = '2021-10-10T00:00:00.000Z'; diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/service_overview/aws_lambda/generate_data.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/service_overview/aws_lambda/generate_data.ts similarity index 100% rename from x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/service_overview/aws_lambda/generate_data.ts rename to x-pack/plugins/apm/ftr_e2e/cypress/e2e/service_overview/aws_lambda/generate_data.ts diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/service_overview/azure_functions/azure_functions.cy.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/service_overview/azure_functions/azure_functions.cy.ts similarity index 96% rename from x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/service_overview/azure_functions/azure_functions.cy.ts rename to x-pack/plugins/apm/ftr_e2e/cypress/e2e/service_overview/azure_functions/azure_functions.cy.ts index 8193ff5bb947a..73ccdfefb9a2c 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/service_overview/azure_functions/azure_functions.cy.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/service_overview/azure_functions/azure_functions.cy.ts @@ -5,7 +5,7 @@ * 2.0. */ import url from 'url'; -import { synthtrace } from '../../../../../synthtrace'; +import { synthtrace } from '../../../../synthtrace'; import { generateData } from './generate_data'; const start = '2021-10-10T00:00:00.000Z'; diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/service_overview/azure_functions/generate_data.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/service_overview/azure_functions/generate_data.ts similarity index 100% rename from x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/service_overview/azure_functions/generate_data.ts rename to x-pack/plugins/apm/ftr_e2e/cypress/e2e/service_overview/azure_functions/generate_data.ts diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/service_overview/errors_table.cy.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/service_overview/errors_table.cy.ts similarity index 94% rename from x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/service_overview/errors_table.cy.ts rename to x-pack/plugins/apm/ftr_e2e/cypress/e2e/service_overview/errors_table.cy.ts index 2970aa3887e95..87e9b3fe41b53 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/service_overview/errors_table.cy.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/service_overview/errors_table.cy.ts @@ -6,8 +6,8 @@ */ import url from 'url'; -import { synthtrace } from '../../../../synthtrace'; -import { opbeans } from '../../../fixtures/synthtrace/opbeans'; +import { synthtrace } from '../../../synthtrace'; +import { opbeans } from '../../fixtures/synthtrace/opbeans'; const start = '2021-10-10T00:00:00.000Z'; const end = '2021-10-10T00:15:00.000Z'; diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/service_overview/generate_data.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/service_overview/generate_data.ts similarity index 100% rename from x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/service_overview/generate_data.ts rename to x-pack/plugins/apm/ftr_e2e/cypress/e2e/service_overview/generate_data.ts diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/service_overview/generate_mobile.data.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/service_overview/generate_mobile.data.ts similarity index 100% rename from x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/service_overview/generate_mobile.data.ts rename to x-pack/plugins/apm/ftr_e2e/cypress/e2e/service_overview/generate_mobile.data.ts diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/service_overview/header_filters.cy.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/service_overview/header_filters.cy.ts similarity index 97% rename from x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/service_overview/header_filters.cy.ts rename to x-pack/plugins/apm/ftr_e2e/cypress/e2e/service_overview/header_filters.cy.ts index 05fe508092ff4..0bc56193e3dd9 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/service_overview/header_filters.cy.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/service_overview/header_filters.cy.ts @@ -5,8 +5,8 @@ * 2.0. */ import url from 'url'; -import { synthtrace } from '../../../../synthtrace'; -import { opbeans } from '../../../fixtures/synthtrace/opbeans'; +import { synthtrace } from '../../../synthtrace'; +import { opbeans } from '../../fixtures/synthtrace/opbeans'; const start = '2021-10-10T00:00:00.000Z'; const end = '2021-10-10T00:15:00.000Z'; diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/service_overview/instances_table.cy.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/service_overview/instances_table.cy.ts similarity index 97% rename from x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/service_overview/instances_table.cy.ts rename to x-pack/plugins/apm/ftr_e2e/cypress/e2e/service_overview/instances_table.cy.ts index bda4e78f56c48..8e1dda2b69e5f 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/service_overview/instances_table.cy.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/service_overview/instances_table.cy.ts @@ -6,8 +6,8 @@ */ import url from 'url'; -import { synthtrace } from '../../../../synthtrace'; -import { opbeans } from '../../../fixtures/synthtrace/opbeans'; +import { synthtrace } from '../../../synthtrace'; +import { opbeans } from '../../fixtures/synthtrace/opbeans'; const start = '2021-10-10T00:00:00.000Z'; const end = '2021-10-10T00:15:00.000Z'; diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/service_overview/mobile_overview_with_most_used_charts.cy.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/service_overview/mobile_overview_with_most_used_charts.cy.ts similarity index 98% rename from x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/service_overview/mobile_overview_with_most_used_charts.cy.ts rename to x-pack/plugins/apm/ftr_e2e/cypress/e2e/service_overview/mobile_overview_with_most_used_charts.cy.ts index 6a05a9f0fcb1f..ca9137fd1f573 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/service_overview/mobile_overview_with_most_used_charts.cy.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/service_overview/mobile_overview_with_most_used_charts.cy.ts @@ -6,7 +6,7 @@ */ import url from 'url'; import moment from 'moment/moment'; -import { synthtrace } from '../../../../synthtrace'; +import { synthtrace } from '../../../synthtrace'; import { generateMobileData } from './generate_mobile.data'; const start = Date.now() - 1000; diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/service_overview/service_and_mobile_overview.cy.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/service_overview/service_and_mobile_overview.cy.ts similarity index 98% rename from x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/service_overview/service_and_mobile_overview.cy.ts rename to x-pack/plugins/apm/ftr_e2e/cypress/e2e/service_overview/service_and_mobile_overview.cy.ts index fec0dbbe36686..382dc0cc51240 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/service_overview/service_and_mobile_overview.cy.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/service_overview/service_and_mobile_overview.cy.ts @@ -5,7 +5,7 @@ * 2.0. */ import url from 'url'; -import { synthtrace } from '../../../../synthtrace'; +import { synthtrace } from '../../../synthtrace'; import { generateData } from './generate_data'; const start = Date.now() - 1000; diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/service_overview/service_overview.cy.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/service_overview/service_overview.cy.ts similarity index 97% rename from x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/service_overview/service_overview.cy.ts rename to x-pack/plugins/apm/ftr_e2e/cypress/e2e/service_overview/service_overview.cy.ts index 8173e94557b29..35184a59880d7 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/service_overview/service_overview.cy.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/service_overview/service_overview.cy.ts @@ -7,9 +7,9 @@ import moment from 'moment'; import url from 'url'; -import { synthtrace } from '../../../../synthtrace'; -import { opbeans } from '../../../fixtures/synthtrace/opbeans'; -import { checkA11y } from '../../../support/commands'; +import { synthtrace } from '../../../synthtrace'; +import { opbeans } from '../../fixtures/synthtrace/opbeans'; +import { checkA11y } from '../../support/commands'; const start = '2021-10-10T00:00:00.000Z'; const end = '2021-10-10T00:15:00.000Z'; diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/service_overview/time_comparison.cy.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/service_overview/time_comparison.cy.ts similarity index 98% rename from x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/service_overview/time_comparison.cy.ts rename to x-pack/plugins/apm/ftr_e2e/cypress/e2e/service_overview/time_comparison.cy.ts index f62813a871e70..c3824036283cf 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/service_overview/time_comparison.cy.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/service_overview/time_comparison.cy.ts @@ -6,8 +6,8 @@ */ import url from 'url'; import moment from 'moment'; -import { synthtrace } from '../../../../synthtrace'; -import { opbeans } from '../../../fixtures/synthtrace/opbeans'; +import { synthtrace } from '../../../synthtrace'; +import { opbeans } from '../../fixtures/synthtrace/opbeans'; const start = '2021-10-10T00:00:00.000Z'; const end = '2021-10-10T00:15:00.000Z'; diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/settings/agent_configurations.cy.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/settings/agent_configurations.cy.ts similarity index 98% rename from x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/settings/agent_configurations.cy.ts rename to x-pack/plugins/apm/ftr_e2e/cypress/e2e/settings/agent_configurations.cy.ts index c5342dc251459..f60bdf19b0071 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/settings/agent_configurations.cy.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/settings/agent_configurations.cy.ts @@ -6,7 +6,7 @@ */ import { apm, timerange } from '@kbn/apm-synthtrace-client'; import url from 'url'; -import { synthtrace } from '../../../../synthtrace'; +import { synthtrace } from '../../../synthtrace'; const timeRange = { rangeFrom: '2021-10-10T00:00:00.000Z', diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/settings/custom_links.cy.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/settings/custom_links.cy.ts similarity index 100% rename from x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/settings/custom_links.cy.ts rename to x-pack/plugins/apm/ftr_e2e/cypress/e2e/settings/custom_links.cy.ts diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/storage_explorer/storage_explorer.cy.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/storage_explorer/storage_explorer.cy.ts similarity index 97% rename from x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/storage_explorer/storage_explorer.cy.ts rename to x-pack/plugins/apm/ftr_e2e/cypress/e2e/storage_explorer/storage_explorer.cy.ts index 4894147002a78..5abd41ba5fe0c 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/storage_explorer/storage_explorer.cy.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/storage_explorer/storage_explorer.cy.ts @@ -6,9 +6,9 @@ */ import moment from 'moment'; import url from 'url'; -import { synthtrace } from '../../../../synthtrace'; -import { opbeans } from '../../../fixtures/synthtrace/opbeans'; -import { checkA11y } from '../../../support/commands'; +import { synthtrace } from '../../../synthtrace'; +import { opbeans } from '../../fixtures/synthtrace/opbeans'; +import { checkA11y } from '../../support/commands'; const timeRange = { rangeFrom: '2021-10-10T00:00:00.000Z', diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/trace_explorer/trace_explorer.cy.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/trace_explorer/trace_explorer.cy.ts similarity index 90% rename from x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/trace_explorer/trace_explorer.cy.ts rename to x-pack/plugins/apm/ftr_e2e/cypress/e2e/trace_explorer/trace_explorer.cy.ts index 3dad4bba27d88..7130bdfd0d339 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/trace_explorer/trace_explorer.cy.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/trace_explorer/trace_explorer.cy.ts @@ -6,8 +6,8 @@ */ import url from 'url'; -import { synthtrace } from '../../../../synthtrace'; -import { opbeans } from '../../../fixtures/synthtrace/opbeans'; +import { synthtrace } from '../../../synthtrace'; +import { opbeans } from '../../fixtures/synthtrace/opbeans'; const start = '2021-10-10T00:00:00.000Z'; const end = '2021-10-10T00:15:00.000Z'; diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/transaction_details/generate_span_links_data.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/transaction_details/generate_span_links_data.ts similarity index 98% rename from x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/transaction_details/generate_span_links_data.ts rename to x-pack/plugins/apm/ftr_e2e/cypress/e2e/transaction_details/generate_span_links_data.ts index c9d52c0968089..4558f98fcd421 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/transaction_details/generate_span_links_data.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/transaction_details/generate_span_links_data.ts @@ -5,8 +5,8 @@ * 2.0. */ import { apm, timerange } from '@kbn/apm-synthtrace-client'; -import { SpanLink } from '../../../../../typings/es_schemas/raw/fields/span_links'; -import { synthtrace } from '../../../../synthtrace'; +import { SpanLink } from '../../../../typings/es_schemas/raw/fields/span_links'; +import { synthtrace } from '../../../synthtrace'; function getProducerInternalOnly() { const producerInternalOnlyInstance = apm diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/transaction_details/span_links.cy.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/transaction_details/span_links.cy.ts similarity index 99% rename from x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/transaction_details/span_links.cy.ts rename to x-pack/plugins/apm/ftr_e2e/cypress/e2e/transaction_details/span_links.cy.ts index 0ec3c16e8658b..ec199c618989b 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/transaction_details/span_links.cy.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/transaction_details/span_links.cy.ts @@ -6,7 +6,7 @@ */ import url from 'url'; -import { synthtrace } from '../../../../synthtrace'; +import { synthtrace } from '../../../synthtrace'; import { generateSpanLinksData } from './generate_span_links_data'; const start = '2022-01-01T00:00:00.000Z'; diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/transaction_details/transaction_details.cy.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/transaction_details/transaction_details.cy.ts similarity index 95% rename from x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/transaction_details/transaction_details.cy.ts rename to x-pack/plugins/apm/ftr_e2e/cypress/e2e/transaction_details/transaction_details.cy.ts index 6886fc582f631..4c6a928697fb0 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/transaction_details/transaction_details.cy.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/transaction_details/transaction_details.cy.ts @@ -4,9 +4,9 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import type { APIReturnType } from '../../../../../public/services/rest/create_call_apm_api'; -import { synthtrace } from '../../../../synthtrace'; -import { opbeans } from '../../../fixtures/synthtrace/opbeans'; +import type { APIReturnType } from '../../../../public/services/rest/create_call_apm_api'; +import { synthtrace } from '../../../synthtrace'; +import { opbeans } from '../../fixtures/synthtrace/opbeans'; const start = '2021-10-10T00:00:00.000Z'; const end = '2021-10-10T00:15:00.000Z'; diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/transactions_overview/transactions_overview.cy.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/transactions_overview/transactions_overview.cy.ts similarity index 91% rename from x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/transactions_overview/transactions_overview.cy.ts rename to x-pack/plugins/apm/ftr_e2e/cypress/e2e/transactions_overview/transactions_overview.cy.ts index 2e7e0d336cd5d..dcabd8ee53090 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/transactions_overview/transactions_overview.cy.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/transactions_overview/transactions_overview.cy.ts @@ -6,9 +6,9 @@ */ import url from 'url'; -import { synthtrace } from '../../../../synthtrace'; -import { opbeans } from '../../../fixtures/synthtrace/opbeans'; -import { checkA11y } from '../../../support/commands'; +import { synthtrace } from '../../../synthtrace'; +import { opbeans } from '../../fixtures/synthtrace/opbeans'; +import { checkA11y } from '../../support/commands'; const start = '2021-10-10T00:00:00.000Z'; const end = '2021-10-10T00:15:00.000Z'; diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/tutorial/tutorial.cy.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/tutorial/tutorial.cy.ts similarity index 100% rename from x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/tutorial/tutorial.cy.ts rename to x-pack/plugins/apm/ftr_e2e/cypress/e2e/tutorial/tutorial.cy.ts diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/tasks/es_archiver.ts b/x-pack/plugins/apm/ftr_e2e/cypress/tasks/es_archiver.ts deleted file mode 100644 index 2d9b530ed76a9..0000000000000 --- a/x-pack/plugins/apm/ftr_e2e/cypress/tasks/es_archiver.ts +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import path from 'path'; -import { execSync } from 'child_process'; - -const ES_ARCHIVE_DIR = path.resolve( - __dirname, - '../../cypress/fixtures/es_archiver' -); - -// Otherwise execSync would inject NODE_TLS_REJECT_UNAUTHORIZED=0 and node would abort if used over https -const NODE_TLS_REJECT_UNAUTHORIZED = '1'; - -export const esArchiverLoad = (archiveName: string) => { - const archivePath = path.join(ES_ARCHIVE_DIR, archiveName); - execSync( - `node ../../../../scripts/es_archiver load "${archivePath}" --config ../../../test/functional/config.base.js`, - { env: { ...process.env, NODE_TLS_REJECT_UNAUTHORIZED }, stdio: 'inherit' } - ); -}; - -export const esArchiverUnload = (archiveName: string) => { - const archivePath = path.join(ES_ARCHIVE_DIR, archiveName); - execSync( - `node ../../../../scripts/es_archiver unload "${archivePath}" --config ../../../test/functional/config.base.js`, - { env: { ...process.env, NODE_TLS_REJECT_UNAUTHORIZED }, stdio: 'inherit' } - ); -}; - -export const esArchiverResetKibana = () => { - execSync( - `node ../../../../scripts/es_archiver empty-kibana-index --config ../../../test/functional/config.base.js`, - { env: { ...process.env, NODE_TLS_REJECT_UNAUTHORIZED }, stdio: 'inherit' } - ); -}; From dbb252b02af9b3bd8b1787dc5550e431f19b5ad9 Mon Sep 17 00:00:00 2001 From: Marco Liberati Date: Mon, 21 Aug 2023 15:01:01 +0200 Subject: [PATCH 08/19] [Lens] Reduce the impact of TSDB downsample bug (#164183) ## Summary Fixes #163971 Reduces the impact of the ES promotion issue coming from the ES TSDB downsampling bug to only downsampling tests and not the entire TSDB suite. ### Checklist Delete any items that are not applicable to this PR. - [ ] 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/main/packages/kbn-i18n/README.md) - [ ] [Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html) was added for features that require explanation or tutorials - [ ] [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 - [ ] Any UI touched in this PR is usable by keyboard only (learn more about [keyboard accessibility](https://webaim.org/techniques/keyboard/)) - [ ] Any UI touched in this PR does not create any new axe failures (run axe in browser: [FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/), [Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US)) - [ ] If a plugin configuration key changed, check if it needs to be allowlisted in the cloud and added to the [docker list](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker) - [ ] 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) ### Risk Matrix Delete this section if it is not applicable to this PR. Before closing this PR, invite QA, stakeholders, and other developers to identify risks that should be tested prior to the change/feature release. When forming the risk matrix, consider some of the following examples and how they may potentially impact the change: | Risk | Probability | Severity | Mitigation/Notes | |---------------------------|-------------|----------|-------------------------| | Multiple Spaces—unexpected behavior in non-default Kibana Space. | Low | High | Integration tests will verify that all features are still supported in non-default Kibana Space and when user switches between spaces. | | Multiple nodes—Elasticsearch polling might have race conditions when multiple Kibana nodes are polling for the same tasks. | High | Low | Tasks are idempotent, so executing them multiple times will not result in logical error, but will degrade performance. To test for this case we add plenty of unit tests around this logic and document manual testing procedure. | | Code should gracefully handle cases when feature X or plugin Y are disabled. | Medium | High | Unit tests will verify that any feature flag or plugin combination still results in our service operational. | | [See more potential risk examples](https://github.com/elastic/kibana/blob/main/RISK_MATRIX.mdx) | ### For maintainers - [ ] This was checked for breaking API changes and was [labeled appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) --- .../test/functional/apps/lens/group4/tsdb.ts | 33 +++++++++---------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/x-pack/test/functional/apps/lens/group4/tsdb.ts b/x-pack/test/functional/apps/lens/group4/tsdb.ts index 16d1298eab440..edbef46dc1f08 100644 --- a/x-pack/test/functional/apps/lens/group4/tsdb.ts +++ b/x-pack/test/functional/apps/lens/group4/tsdb.ts @@ -311,8 +311,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { log.info(`Indexed ${res.items.length} test data docs.`); }; - // Failing ES promotion: https://github.com/elastic/kibana/issues/163970 - describe.skip('lens tsdb', function () { + describe('lens tsdb', function () { const tsdbIndex = 'kibana_sample_data_logstsdb'; const tsdbDataView = tsdbIndex; const tsdbEsArchive = 'test/functional/fixtures/es_archiver/kibana_sample_data_logs_tsdb'; @@ -623,21 +622,21 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { { index: 'regular_index', create: true, removeTSDBFields: true }, ], }, - { - name: 'Dataview with an additional downsampled TSDB stream', - indexes: [ - { index: initialIndex }, - { index: 'tsdb_index_2', create: true, tsdb: true, downsample: true }, - ], - }, - { - name: 'Dataview with additional regular index and a downsampled TSDB stream', - indexes: [ - { index: initialIndex }, - { index: 'regular_index', create: true, removeTSDBFields: true }, - { index: 'tsdb_index_2', create: true, tsdb: true, downsample: true }, - ], - }, + // { + // name: 'Dataview with an additional downsampled TSDB stream', + // indexes: [ + // { index: initialIndex }, + // { index: 'tsdb_index_2', create: true, tsdb: true, downsample: true }, + // ], + // }, + // { + // name: 'Dataview with additional regular index and a downsampled TSDB stream', + // indexes: [ + // { index: initialIndex }, + // { index: 'regular_index', create: true, removeTSDBFields: true }, + // { index: 'tsdb_index_2', create: true, tsdb: true, downsample: true }, + // ], + // }, { name: 'Dataview with an additional TSDB stream', indexes: [{ index: initialIndex }, { index: 'tsdb_index_2', create: true, tsdb: true }], From 90b6e4dbe01219d5af51a93943338043bfdd773a Mon Sep 17 00:00:00 2001 From: amyjtechwriter <61687663+amyjtechwriter@users.noreply.github.com> Date: Mon, 21 Aug 2023 14:24:48 +0100 Subject: [PATCH 09/19] [DOCS] Removes 8.9.1 coming tag. (#164302) Removes `coming` tag from the 8.9.1 release notes. --- docs/CHANGELOG.asciidoc | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/CHANGELOG.asciidoc b/docs/CHANGELOG.asciidoc index 5da373c8d9a51..898597eabce5d 100644 --- a/docs/CHANGELOG.asciidoc +++ b/docs/CHANGELOG.asciidoc @@ -49,8 +49,6 @@ Review important information about the {kib} 8.x releases. [[release-notes-8.9.1]] == {kib} 8.9.1 -coming::[8.9.1] - Review the following information about the {kib} 8.9.1 release. [float] From 011ae97061b9f5b5d751fa4a00f19a355c3bb68b Mon Sep 17 00:00:00 2001 From: Devon Thomson Date: Mon, 21 Aug 2023 09:51:07 -0400 Subject: [PATCH 10/19] [Dashboard] Remove clone by reference (#164108) Removes all clone by reference functionality on the Dashboard. This means that we no longer have any `savedObjectsClient` usage in the browser side. --- .../clone_panel_action.test.tsx | 171 ++++++------------ .../dashboard_actions/clone_panel_action.tsx | 158 +++++----------- .../public/dashboard_actions/index.ts | 2 +- .../embeddable/api/index.ts | 2 +- .../embeddable/api/panel_management.ts | 54 ------ .../embeddable/dashboard_container.tsx | 2 - .../public/placeholder_embeddable/index.ts | 11 -- .../placeholder_embeddable.tsx | 52 ------ .../placeholder_embeddable_factory.ts | 41 ----- .../public/placeholder_embeddable/readme.md | 13 -- src/plugins/dashboard/public/plugin.tsx | 4 - .../translations/translations/fr-FR.json | 1 - .../translations/translations/ja-JP.json | 1 - .../translations/translations/zh-CN.json | 1 - 14 files changed, 105 insertions(+), 408 deletions(-) delete mode 100644 src/plugins/dashboard/public/placeholder_embeddable/index.ts delete mode 100644 src/plugins/dashboard/public/placeholder_embeddable/placeholder_embeddable.tsx delete mode 100644 src/plugins/dashboard/public/placeholder_embeddable/placeholder_embeddable_factory.ts delete mode 100644 src/plugins/dashboard/public/placeholder_embeddable/readme.md diff --git a/src/plugins/dashboard/public/dashboard_actions/clone_panel_action.test.tsx b/src/plugins/dashboard/public/dashboard_actions/clone_panel_action.test.tsx index 6c1e8bc6d680e..5ec0ac57c574b 100644 --- a/src/plugins/dashboard/public/dashboard_actions/clone_panel_action.test.tsx +++ b/src/plugins/dashboard/public/dashboard_actions/clone_panel_action.test.tsx @@ -16,17 +16,21 @@ import { import { CoreStart } from '@kbn/core/public'; import { coreMock } from '@kbn/core/public/mocks'; import { embeddablePluginMock } from '@kbn/embeddable-plugin/public/mocks'; -import { ErrorEmbeddable, IContainer, isErrorEmbeddable } from '@kbn/embeddable-plugin/public'; +import { + ErrorEmbeddable, + IContainer, + isErrorEmbeddable, + ReferenceOrValueEmbeddable, +} from '@kbn/embeddable-plugin/public'; -import { DashboardPanelState } from '../../common'; import { ClonePanelAction } from './clone_panel_action'; import { pluginServices } from '../services/plugin_services'; import { buildMockDashboard, getSampleDashboardPanel } from '../mocks'; import { DashboardContainer } from '../dashboard_container/embeddable/dashboard_container'; let container: DashboardContainer; -let byRefOrValEmbeddable: ContactCardEmbeddable; let genericEmbeddable: ContactCardEmbeddable; +let byRefOrValEmbeddable: ContactCardEmbeddable & ReferenceOrValueEmbeddable; let coreStart: CoreStart; beforeEach(async () => { coreStart = coreMock.createStart(); @@ -58,20 +62,22 @@ beforeEach(async () => { >(CONTACT_CARD_EMBEDDABLE, { firstName: 'RefOrValEmbeddable', }); - const genericContactCardEmbeddable = await container.addNewEmbeddable< + + const nonRefOrValueContactCard = await container.addNewEmbeddable< ContactCardEmbeddableInput, ContactCardEmbeddableOutput, ContactCardEmbeddable >(CONTACT_CARD_EMBEDDABLE, { - firstName: 'NotRefOrValEmbeddable', + firstName: 'Not a refOrValEmbeddable', }); if ( isErrorEmbeddable(refOrValContactCardEmbeddable) || - isErrorEmbeddable(genericContactCardEmbeddable) + isErrorEmbeddable(nonRefOrValueContactCard) ) { throw new Error('Failed to create embeddables'); } else { + genericEmbeddable = nonRefOrValueContactCard; byRefOrValEmbeddable = embeddablePluginMock.mockRefOrValEmbeddable< ContactCardEmbeddable, ContactCardEmbeddableInput @@ -80,14 +86,14 @@ beforeEach(async () => { savedObjectId: 'testSavedObjectId', id: refOrValContactCardEmbeddable.id, }, - mockedByValueInput: { firstName: 'Kibanana', id: refOrValContactCardEmbeddable.id }, + mockedByValueInput: { firstName: 'RefOrValEmbeddable', id: refOrValContactCardEmbeddable.id }, }); - genericEmbeddable = genericContactCardEmbeddable; + jest.spyOn(byRefOrValEmbeddable, 'getInputAsValueType'); } }); test('Clone is incompatible with Error Embeddables', async () => { - const action = new ClonePanelAction(coreStart.savedObjects); + const action = new ClonePanelAction(); const errorEmbeddable = new ErrorEmbeddable('Wow what an awful error', { id: ' 404' }, container); expect(await action.isCompatible({ embeddable: errorEmbeddable })).toBe(false); }); @@ -96,134 +102,65 @@ test('Clone adds a new embeddable', async () => { const dashboard = byRefOrValEmbeddable.getRoot() as IContainer; const originalPanelCount = Object.keys(dashboard.getInput().panels).length; const originalPanelKeySet = new Set(Object.keys(dashboard.getInput().panels)); - const action = new ClonePanelAction(coreStart.savedObjects); + const action = new ClonePanelAction(); await action.execute({ embeddable: byRefOrValEmbeddable }); + expect(Object.keys(container.getInput().panels).length).toEqual(originalPanelCount + 1); const newPanelId = Object.keys(container.getInput().panels).find( (key) => !originalPanelKeySet.has(key) ); expect(newPanelId).toBeDefined(); const newPanel = container.getInput().panels[newPanelId!]; - expect(newPanel.type).toEqual('placeholder'); - // let the placeholder load - await dashboard.untilEmbeddableLoaded(newPanelId!); - await new Promise((r) => process.nextTick(r)); // Allow the current loop of the event loop to run to completion - // now wait for the full embeddable to replace it - const loadedPanel = await dashboard.untilEmbeddableLoaded(newPanelId!); - expect(loadedPanel.type).toEqual(byRefOrValEmbeddable.type); + expect(newPanel.type).toEqual(byRefOrValEmbeddable.type); }); test('Clones a RefOrVal embeddable by value', async () => { const dashboard = byRefOrValEmbeddable.getRoot() as IContainer; - const panel = dashboard.getInput().panels[byRefOrValEmbeddable.id] as DashboardPanelState; - const action = new ClonePanelAction(coreStart.savedObjects); - // @ts-ignore - const newPanel = await action.cloneEmbeddable(panel, byRefOrValEmbeddable); - expect(coreStart.savedObjects.client.get).toHaveBeenCalledTimes(0); - expect(coreStart.savedObjects.client.find).toHaveBeenCalledTimes(0); - expect(coreStart.savedObjects.client.create).toHaveBeenCalledTimes(0); - expect(newPanel.type).toEqual(byRefOrValEmbeddable.type); -}); + const originalPanelKeySet = new Set(Object.keys(dashboard.getInput().panels)); + const action = new ClonePanelAction(); + await action.execute({ embeddable: byRefOrValEmbeddable }); + const newPanelId = Object.keys(container.getInput().panels).find( + (key) => !originalPanelKeySet.has(key) + ); -test('Clones a non-RefOrVal embeddable by value if the panel does not have a savedObjectId', async () => { - const dashboard = genericEmbeddable.getRoot() as IContainer; - const panel = dashboard.getInput().panels[genericEmbeddable.id] as DashboardPanelState; - const action = new ClonePanelAction(coreStart.savedObjects); - // @ts-ignore - const newPanelWithoutId = await action.cloneEmbeddable(panel, genericEmbeddable); - expect(coreStart.savedObjects.client.get).toHaveBeenCalledTimes(0); - expect(coreStart.savedObjects.client.find).toHaveBeenCalledTimes(0); - expect(coreStart.savedObjects.client.create).toHaveBeenCalledTimes(0); - expect(newPanelWithoutId.type).toEqual(genericEmbeddable.type); -}); + const originalFirstName = ( + container.getInput().panels[byRefOrValEmbeddable.id].explicitInput as ContactCardEmbeddableInput + ).firstName; -test('Clones a non-RefOrVal embeddable by reference if the panel has a savedObjectId', async () => { - const dashboard = genericEmbeddable.getRoot() as IContainer; - const panel = dashboard.getInput().panels[genericEmbeddable.id] as DashboardPanelState; - panel.explicitInput.savedObjectId = 'holySavedObjectBatman'; - const action = new ClonePanelAction(coreStart.savedObjects); - // @ts-ignore - const newPanel = await action.cloneEmbeddable(panel, genericEmbeddable); - expect(coreStart.savedObjects.client.get).toHaveBeenCalledTimes(1); - expect(coreStart.savedObjects.client.find).toHaveBeenCalledTimes(1); - expect(coreStart.savedObjects.client.create).toHaveBeenCalledTimes(1); - expect(newPanel.type).toEqual(genericEmbeddable.type); + const newFirstName = ( + container.getInput().panels[newPanelId!].explicitInput as ContactCardEmbeddableInput + ).firstName; + + expect(byRefOrValEmbeddable.getInputAsValueType).toHaveBeenCalled(); + + expect(originalFirstName).toEqual(newFirstName); + expect(container.getInput().panels[newPanelId!].type).toEqual(byRefOrValEmbeddable.type); }); -test('Gets a unique title from the saved objects library', async () => { +test('Clones a non RefOrVal embeddable by value', async () => { const dashboard = genericEmbeddable.getRoot() as IContainer; - const panel = dashboard.getInput().panels[genericEmbeddable.id] as DashboardPanelState; - panel.explicitInput.savedObjectId = 'holySavedObjectBatman'; - coreStart.savedObjects.client.find = jest.fn().mockImplementation(({ search }) => { - if (search === '"testFirstClone"') { - return { - savedObjects: [ - { - attributes: { title: 'testFirstClone' }, - get: jest.fn().mockReturnValue('testFirstClone'), - }, - ], - total: 1, - }; - } else if (search === '"testBeforePageLimit"') { - return { - savedObjects: [ - { - attributes: { title: 'testBeforePageLimit (copy 9)' }, - get: jest.fn().mockReturnValue('testBeforePageLimit (copy 9)'), - }, - ], - total: 10, - }; - } else if (search === '"testMaxLogic"') { - return { - savedObjects: [ - { - attributes: { title: 'testMaxLogic (copy 10000)' }, - get: jest.fn().mockReturnValue('testMaxLogic (copy 10000)'), - }, - ], - total: 2, - }; - } else if (search === '"testAfterPageLimit"') { - return { total: 11 }; - } - }); - - const action = new ClonePanelAction(coreStart.savedObjects); - // @ts-ignore - expect(await action.getCloneTitle(genericEmbeddable, 'testFirstClone')).toEqual( - 'testFirstClone (copy)' - ); - // @ts-ignore - expect(await action.getCloneTitle(genericEmbeddable, 'testBeforePageLimit')).toEqual( - 'testBeforePageLimit (copy 10)' - ); - // @ts-ignore - expect(await action.getCloneTitle(genericEmbeddable, 'testBeforePageLimit (copy 9)')).toEqual( - 'testBeforePageLimit (copy 10)' - ); - // @ts-ignore - expect(await action.getCloneTitle(genericEmbeddable, 'testMaxLogic')).toEqual( - 'testMaxLogic (copy 10001)' - ); - // @ts-ignore - expect(await action.getCloneTitle(genericEmbeddable, 'testAfterPageLimit')).toEqual( - 'testAfterPageLimit (copy 11)' - ); - // @ts-ignore - expect(await action.getCloneTitle(genericEmbeddable, 'testAfterPageLimit (copy 10)')).toEqual( - 'testAfterPageLimit (copy 11)' - ); - // @ts-ignore - expect(await action.getCloneTitle(genericEmbeddable, 'testAfterPageLimit (copy 10000)')).toEqual( - 'testAfterPageLimit (copy 11)' + const originalPanelKeySet = new Set(Object.keys(dashboard.getInput().panels)); + const action = new ClonePanelAction(); + await action.execute({ embeddable: genericEmbeddable }); + const newPanelId = Object.keys(container.getInput().panels).find( + (key) => !originalPanelKeySet.has(key) ); + + const originalFirstName = ( + container.getInput().panels[genericEmbeddable.id].explicitInput as ContactCardEmbeddableInput + ).firstName; + + const newFirstName = ( + container.getInput().panels[newPanelId!].explicitInput as ContactCardEmbeddableInput + ).firstName; + + expect(originalFirstName).toEqual(newFirstName); + expect(container.getInput().panels[newPanelId!].type).toEqual(genericEmbeddable.type); }); test('Gets a unique title from the dashboard', async () => { - const dashboard = genericEmbeddable.getRoot() as DashboardContainer; - const action = new ClonePanelAction(coreStart.savedObjects); + const dashboard = byRefOrValEmbeddable.getRoot() as DashboardContainer; + const action = new ClonePanelAction(); // @ts-ignore expect(await action.getCloneTitle(byRefOrValEmbeddable, '')).toEqual(''); diff --git a/src/plugins/dashboard/public/dashboard_actions/clone_panel_action.tsx b/src/plugins/dashboard/public/dashboard_actions/clone_panel_action.tsx index cd65f3b9cff45..e028d8f387312 100644 --- a/src/plugins/dashboard/public/dashboard_actions/clone_panel_action.tsx +++ b/src/plugins/dashboard/public/dashboard_actions/clone_panel_action.tsx @@ -6,11 +6,8 @@ * Side Public License, v 1. */ -import _ from 'lodash'; import { v4 as uuidv4 } from 'uuid'; - -// TODO Remove this usage of the SavedObjectsStart contract. -import { SavedObjectsStart } from '@kbn/core/public'; +import { filter, map, max } from 'lodash'; import { ViewMode, @@ -18,21 +15,17 @@ import { IEmbeddable, PanelNotFoundError, EmbeddableInput, - SavedObjectEmbeddableInput, isErrorEmbeddable, isReferenceOrValueEmbeddable, } from '@kbn/embeddable-plugin/public'; import { Action, IncompatibleActionError } from '@kbn/ui-actions-plugin/public'; -import type { SavedObject } from '@kbn/saved-objects-plugin/public'; -import { - placePanelBeside, - IPanelPlacementBesideArgs, -} from '../dashboard_container/component/panel/dashboard_panel_placement'; import { type DashboardPanelState } from '../../common'; import { pluginServices } from '../services/plugin_services'; +import { createPanelState } from '../dashboard_container/component/panel'; import { dashboardClonePanelActionStrings } from './_dashboard_actions_strings'; import { DASHBOARD_CONTAINER_TYPE, type DashboardContainer } from '../dashboard_container'; +import { placePanelBeside } from '../dashboard_container/component/panel/dashboard_panel_placement'; export const ACTION_CLONE_PANEL = 'clonePanel'; @@ -47,7 +40,7 @@ export class ClonePanelAction implements Action { private toastsService; - constructor(private savedObjects: SavedObjectsStart) { + constructor() { ({ notifications: { toasts: this.toastsService }, } = pluginServices.getServices()); @@ -89,8 +82,37 @@ export class ClonePanelAction implements Action { throw new PanelNotFoundError(); } - dashboard.showPlaceholderUntil( - this.cloneEmbeddable(panelToClone, embeddable), + const clonedPanelState: PanelState = await (async () => { + const newTitle = await this.getCloneTitle(embeddable, embeddable.getTitle() || ''); + const id = uuidv4(); + if (isReferenceOrValueEmbeddable(embeddable)) { + return { + type: embeddable.type, + explicitInput: { + ...(await embeddable.getInputAsValueType()), + hidePanelTitles: panelToClone.explicitInput.hidePanelTitles, + title: newTitle, + id, + }, + }; + } + return { + type: embeddable.type, + explicitInput: { + ...panelToClone.explicitInput, + title: newTitle, + id, + }, + }; + })(); + this.toastsService.addSuccess({ + title: dashboardClonePanelActionStrings.getSuccessMessage(), + 'data-test-subj': 'addObjectToContainerSuccess', + }); + + const { otherPanels, newPanel } = createPanelState( + clonedPanelState, + dashboard.getInput().panels, placePanelBeside, { width: panelToClone.gridData.w, @@ -98,8 +120,15 @@ export class ClonePanelAction implements Action { currentPanels: dashboard.getInput().panels, placeBesideId: panelToClone.explicitInput.id, scrollToPanel: true, - } as IPanelPlacementBesideArgs + } ); + + dashboard.updateInput({ + panels: { + ...otherPanels, + [newPanel.explicitInput.id]: newPanel, + }, + }); } private async getCloneTitle(embeddable: IEmbeddable, rawTitle: string) { @@ -109,109 +138,20 @@ export class ClonePanelAction implements Action { const cloneRegex = new RegExp(`\\(${clonedTag}\\)`, 'g'); const cloneNumberRegex = new RegExp(`\\(${clonedTag} [0-9]+\\)`, 'g'); const baseTitle = rawTitle.replace(cloneNumberRegex, '').replace(cloneRegex, '').trim(); - let similarTitles: string[]; - if ( - isReferenceOrValueEmbeddable(embeddable) || - !_.has(embeddable.getExplicitInput(), 'savedObjectId') - ) { - const dashboard: DashboardContainer = embeddable.getRoot() as DashboardContainer; - similarTitles = _.filter(await dashboard.getPanelTitles(), (title: string) => { - return title.startsWith(baseTitle); - }); - } else { - const perPage = 10; - const similarSavedObjects = await this.savedObjects.client.find({ - type: embeddable.type, - perPage, - fields: ['title'], - searchFields: ['title'], - search: `"${baseTitle}"`, - }); - if (similarSavedObjects.total <= perPage) { - similarTitles = similarSavedObjects.savedObjects.map((savedObject) => { - return savedObject.get('title'); - }); - } else { - similarTitles = [baseTitle + ` (${clonedTag} ${similarSavedObjects.total - 1})`]; - } - } + const dashboard: DashboardContainer = embeddable.getRoot() as DashboardContainer; + const similarTitles = filter(await dashboard.getPanelTitles(), (title: string) => { + return title.startsWith(baseTitle); + }); - const cloneNumbers = _.map(similarTitles, (title: string) => { + const cloneNumbers = map(similarTitles, (title: string) => { if (title.match(cloneRegex)) return 0; const cloneTag = title.match(cloneNumberRegex); return cloneTag ? parseInt(cloneTag[0].replace(/[^0-9.]/g, ''), 10) : -1; }); - const similarBaseTitlesCount = _.max(cloneNumbers) || 0; + const similarBaseTitlesCount = max(cloneNumbers) || 0; return similarBaseTitlesCount < 0 ? baseTitle + ` (${clonedTag})` : baseTitle + ` (${clonedTag} ${similarBaseTitlesCount + 1})`; } - - private async addCloneToLibrary( - embeddable: IEmbeddable, - objectIdToClone: string - ): Promise { - // TODO: Remove this entire functionality. See https://github.com/elastic/kibana/issues/158632 for more info. - const savedObjectToClone = await this.savedObjects.client.get( - embeddable.type, - objectIdToClone - ); - - // Clone the saved object - const newTitle = await this.getCloneTitle(embeddable, savedObjectToClone.attributes.title); - const clonedSavedObject = await this.savedObjects.client.create( - embeddable.type, - { - ..._.cloneDeep(savedObjectToClone.attributes), - title: newTitle, - }, - { references: _.cloneDeep(savedObjectToClone.references) } - ); - return clonedSavedObject.id; - } - - private async cloneEmbeddable( - panelToClone: DashboardPanelState, - embeddable: IEmbeddable - ): Promise> { - let panelState: PanelState; - if (isReferenceOrValueEmbeddable(embeddable)) { - const newTitle = await this.getCloneTitle(embeddable, embeddable.getTitle() || ''); - panelState = { - type: embeddable.type, - explicitInput: { - ...(await embeddable.getInputAsValueType()), - id: uuidv4(), - title: newTitle, - hidePanelTitles: panelToClone.explicitInput.hidePanelTitles, - }, - version: panelToClone.version, - }; - } else { - panelState = { - type: embeddable.type, - explicitInput: { - ...panelToClone.explicitInput, - id: uuidv4(), - }, - version: panelToClone.version, - }; - - // TODO Remove the entire `addCloneToLibrary` section from here. - if (panelToClone.explicitInput.savedObjectId) { - const clonedSavedObjectId = await this.addCloneToLibrary( - embeddable, - panelToClone.explicitInput.savedObjectId - ); - (panelState.explicitInput as SavedObjectEmbeddableInput).savedObjectId = - clonedSavedObjectId; - } - } - this.toastsService.addSuccess({ - title: dashboardClonePanelActionStrings.getSuccessMessage(), - 'data-test-subj': 'addObjectToContainerSuccess', - }); - return panelState; - } } diff --git a/src/plugins/dashboard/public/dashboard_actions/index.ts b/src/plugins/dashboard/public/dashboard_actions/index.ts index 8376ee1e65171..4f0daff8c3390 100644 --- a/src/plugins/dashboard/public/dashboard_actions/index.ts +++ b/src/plugins/dashboard/public/dashboard_actions/index.ts @@ -34,7 +34,7 @@ export const buildAllDashboardActions = async ({ }: BuildAllDashboardActionsProps) => { const { uiActions, share, presentationUtil, savedObjectsTaggingOss, contentManagement } = plugins; - const clonePanelAction = new ClonePanelAction(core.savedObjects); + const clonePanelAction = new ClonePanelAction(); uiActions.registerAction(clonePanelAction); uiActions.attachAction(CONTEXT_MENU_TRIGGER, clonePanelAction.id); diff --git a/src/plugins/dashboard/public/dashboard_container/embeddable/api/index.ts b/src/plugins/dashboard/public/dashboard_container/embeddable/api/index.ts index 2a2d20cc5da14..a97d038d89d95 100644 --- a/src/plugins/dashboard/public/dashboard_container/embeddable/api/index.ts +++ b/src/plugins/dashboard/public/dashboard_container/embeddable/api/index.ts @@ -9,4 +9,4 @@ export { showSettings } from './show_settings'; export { addFromLibrary } from './add_panel_from_library'; export { runSaveAs, runQuickSave, runClone } from './run_save_functions'; -export { addOrUpdateEmbeddable, replacePanel, showPlaceholderUntil } from './panel_management'; +export { addOrUpdateEmbeddable, replacePanel } from './panel_management'; diff --git a/src/plugins/dashboard/public/dashboard_container/embeddable/api/panel_management.ts b/src/plugins/dashboard/public/dashboard_container/embeddable/api/panel_management.ts index 7b02001a93c6c..848600a2767d6 100644 --- a/src/plugins/dashboard/public/dashboard_container/embeddable/api/panel_management.ts +++ b/src/plugins/dashboard/public/dashboard_container/embeddable/api/panel_management.ts @@ -14,14 +14,8 @@ import { } from '@kbn/embeddable-plugin/public'; import { v4 as uuidv4 } from 'uuid'; -import { - IPanelPlacementArgs, - PanelPlacementMethod, -} from '../../component/panel/dashboard_panel_placement'; import { DashboardPanelState } from '../../../../common'; -import { createPanelState } from '../../component/panel'; import { DashboardContainer } from '../dashboard_container'; -import { PLACEHOLDER_EMBEDDABLE } from '../../../placeholder_embeddable'; export async function addOrUpdateEmbeddable< EEI extends EmbeddableInput = EmbeddableInput, @@ -89,51 +83,3 @@ export async function replacePanel( await this.updateInput({ panels }); return panelId; } - -export function showPlaceholderUntil( - this: DashboardContainer, - newStateComplete: Promise>, - placementMethod?: PanelPlacementMethod, - placementArgs?: TPlacementMethodArgs -): void { - const originalPanelState = { - type: PLACEHOLDER_EMBEDDABLE, - explicitInput: { - id: uuidv4(), - disabledActions: [ - 'ACTION_CUSTOMIZE_PANEL', - 'CUSTOM_TIME_RANGE', - 'clonePanel', - 'replacePanel', - 'togglePanel', - ], - }, - } as PanelState; - - const { otherPanels, newPanel: placeholderPanelState } = createPanelState( - originalPanelState, - this.input.panels, - placementMethod, - placementArgs - ); - - this.updateInput({ - panels: { - ...otherPanels, - [placeholderPanelState.explicitInput.id]: placeholderPanelState, - }, - }); - - // wait until the placeholder is ready, then replace it with new panel - // this is useful as sometimes panels can load faster than the placeholder one (i.e. by value embeddables) - this.untilEmbeddableLoaded(originalPanelState.explicitInput.id) - .then(() => newStateComplete) - .then(async (newPanelState: Partial) => { - const panelId = await this.replacePanel(placeholderPanelState, newPanelState); - - if (placementArgs?.scrollToPanel) { - this.setScrollToPanelId(panelId); - this.setHighlightPanelId(panelId); - } - }); -} diff --git a/src/plugins/dashboard/public/dashboard_container/embeddable/dashboard_container.tsx b/src/plugins/dashboard/public/dashboard_container/embeddable/dashboard_container.tsx index 636634d23099f..df0e728a16d1b 100644 --- a/src/plugins/dashboard/public/dashboard_container/embeddable/dashboard_container.tsx +++ b/src/plugins/dashboard/public/dashboard_container/embeddable/dashboard_container.tsx @@ -41,7 +41,6 @@ import { runQuickSave, replacePanel, addFromLibrary, - showPlaceholderUntil, addOrUpdateEmbeddable, } from './api'; @@ -312,7 +311,6 @@ export class DashboardContainer extends Container -
- -
- , - node - ); - } - - public reload() {} -} diff --git a/src/plugins/dashboard/public/placeholder_embeddable/placeholder_embeddable_factory.ts b/src/plugins/dashboard/public/placeholder_embeddable/placeholder_embeddable_factory.ts deleted file mode 100644 index 26cdddbf17d85..0000000000000 --- a/src/plugins/dashboard/public/placeholder_embeddable/placeholder_embeddable_factory.ts +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import { i18n } from '@kbn/i18n'; - -import { - EmbeddableFactoryDefinition, - EmbeddableInput, - IContainer, -} from '@kbn/embeddable-plugin/public'; -import { PLACEHOLDER_EMBEDDABLE } from '.'; - -export class PlaceholderEmbeddableFactory implements EmbeddableFactoryDefinition { - public readonly type = PLACEHOLDER_EMBEDDABLE; - - constructor() {} - - public async isEditable() { - return false; - } - - public canCreateNew() { - return false; - } - - public async create(initialInput: EmbeddableInput, parent?: IContainer) { - const { PlaceholderEmbeddable } = await import('./placeholder_embeddable'); - return new PlaceholderEmbeddable(initialInput, parent); - } - - public getDisplayName() { - return i18n.translate('dashboard.placeholder.factory.displayName', { - defaultMessage: 'placeholder', - }); - } -} diff --git a/src/plugins/dashboard/public/placeholder_embeddable/readme.md b/src/plugins/dashboard/public/placeholder_embeddable/readme.md deleted file mode 100644 index 5bdb0569c50f6..0000000000000 --- a/src/plugins/dashboard/public/placeholder_embeddable/readme.md +++ /dev/null @@ -1,13 +0,0 @@ -## What is this for? - -This Placeholder Embeddable is shown when a BY REFERENCE panel (a panel which is linked to a saved object) is cloned using the Dashboard Panel Clone action. - -## Why was it made? - -This was important for the first iteration of the clone feature so that something could be shown while the saved object was being duplicated, but later iterations of that feature automatically unlink panels on clone. By Value panels don't need a placeholder because they load much faster. - -## Can I delete it? - -Currently, the only embeddable type that cannot be loaded by value is the Discover Saved Search Embeddable. Without a placeholder embeddable, the dashboard wouldn't reflow at all until after the saved object clone operation is complete. - -The placeholder embeddable should be removed as soon as the Discover Saved Search Embeddable can be saved By Value. diff --git a/src/plugins/dashboard/public/plugin.tsx b/src/plugins/dashboard/public/plugin.tsx index b42a13f858965..a28dbe9c45ae7 100644 --- a/src/plugins/dashboard/public/plugin.tsx +++ b/src/plugins/dashboard/public/plugin.tsx @@ -67,7 +67,6 @@ import { SEARCH_SESSION_ID, } from './dashboard_constants'; import { DashboardMountContextProps } from './dashboard_app/types'; -import { PlaceholderEmbeddableFactory } from './placeholder_embeddable'; import type { FindDashboardsService } from './services/dashboard_content_management/types'; import { CONTENT_ID, LATEST_VERSION } from '../common/content_management'; @@ -220,9 +219,6 @@ export class DashboardPlugin dashboardContainerFactory.type, dashboardContainerFactory ); - - const placeholderFactory = new PlaceholderEmbeddableFactory(); - embeddable.registerEmbeddableFactory(placeholderFactory.type, placeholderFactory); }); this.stopUrlTracking = () => { diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index b54778a7ae73a..22ee2086a1a33 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -1225,7 +1225,6 @@ "dashboard.panel.title.clonedTag": "copier", "dashboard.panel.unableToMigratePanelDataForSixOneZeroErrorMessage": "Impossible de migrer les données du panneau pour une rétro-compatibilité \"6.1.0\". Le panneau ne contient pas les champs de colonne et/ou de ligne attendus.", "dashboard.panel.unlinkFromLibrary": "Dissocier de la bibliothèque", - "dashboard.placeholder.factory.displayName": "paramètre fictif", "dashboard.resetChangesConfirmModal.confirmButtonLabel": "Réinitialiser le tableau de bord", "dashboard.resetChangesConfirmModal.resetChangesDescription": "Ce tableau de bord va revenir à son dernier état d'enregistrement. Vous risquez de perdre les modifications apportées aux filtres et aux requêtes.", "dashboard.resetChangesConfirmModal.resetChangesTitle": "Réinitialiser le tableau de bord ?", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index a2a5719e9fa21..84c71c20e176d 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -1239,7 +1239,6 @@ "dashboard.panel.title.clonedTag": "コピー", "dashboard.panel.unableToMigratePanelDataForSixOneZeroErrorMessage": "「6.1.0」のダッシュボードの互換性のため、パネルデータを移行できませんでした。パネルには想定された列または行フィールドがありません", "dashboard.panel.unlinkFromLibrary": "ライブラリからのリンクを解除", - "dashboard.placeholder.factory.displayName": "プレースホルダー", "dashboard.resetChangesConfirmModal.confirmButtonLabel": "ダッシュボードをリセット", "dashboard.resetChangesConfirmModal.resetChangesDescription": "このダッシュボードは最後に保存された状態に戻ります。 フィルターとクエリの変更が失われる場合があります。", "dashboard.resetChangesConfirmModal.resetChangesTitle": "ダッシュボードをリセットしますか?", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index b65369d942c92..c15e2f639c597 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -1239,7 +1239,6 @@ "dashboard.panel.title.clonedTag": "副本", "dashboard.panel.unableToMigratePanelDataForSixOneZeroErrorMessage": "无法迁移用于“6.1.0”向后兼容的面板数据,面板不包含所需的列和/或行字段", "dashboard.panel.unlinkFromLibrary": "取消与库的链接", - "dashboard.placeholder.factory.displayName": "占位符", "dashboard.resetChangesConfirmModal.confirmButtonLabel": "重置仪表板", "dashboard.resetChangesConfirmModal.resetChangesDescription": "此仪表板将返回到其最后保存的状态。 您可能会丢失对筛选和查询的更改。", "dashboard.resetChangesConfirmModal.resetChangesTitle": "重置仪表板?", From 88bd71c0773d158ed1e6312075633ed85abc575e Mon Sep 17 00:00:00 2001 From: Kevin Logan <56395104+kevinlog@users.noreply.github.com> Date: Mon, 21 Aug 2023 10:00:53 -0400 Subject: [PATCH 11/19] [Security Solution] File paths for Blocklist Windows and Mac should be case insensitive (#164200) ## Summary This fixes a bug where Windows and Mac Blocklist file path entries should be passed as case insensitive. This is because Mac and Windows are caseless for most use cases. Bug ticket: https://github.com/elastic/kibana/issues/158581 Here is how it will be displayed in the UI: image Here are the breakdown of the artifacts after the fix: Linux: ``` ------------------------------------------------------------------- Policy: Protect Manifest: 1.0.6 | v1 Artifact: endpoint-blocklist-linux-v1 Relative URL: /api/fleet/artifacts/endpoint-blocklist-linux-v1/f33e6890aeced00861c26a08121dd42d2d29ba08abfeb3c065d0447e32e18640 Encoded SHA256: a907835be40af89b8b7aa23a6efc66c01ceaa5a19622edd378139319f3ca5fa0 Decoded SHA256: f33e6890aeced00861c26a08121dd42d2d29ba08abfeb3c065d0447e32e18640 ------------------------------------------------------------------- { "entries": [ { "type": "simple", "entries": [ { "field": "file.path", "operator": "included", "type": "exact_cased_any", "value": [ "/opt/bin/bin.exe" ] } ] } ] } ``` Mac: ``` ------------------------------------------------------------------- Policy: Protect Manifest: 1.0.6 | v1 Artifact: endpoint-blocklist-macos-v1 Relative URL: /api/fleet/artifacts/endpoint-blocklist-macos-v1/b28e7978da4314ebc2c94770e0638fc4b2270f9dc17a11d6d32b8634b1fbec0f Encoded SHA256: 4f3e80d688f5cae4bf6a88b0704e37909f9fa4f47fe8325b7b154cddd46a2db9 Decoded SHA256: b28e7978da4314ebc2c94770e0638fc4b2270f9dc17a11d6d32b8634b1fbec0f ------------------------------------------------------------------- { "entries": [ { "type": "simple", "entries": [ { "field": "file.path", "operator": "included", "type": "exact_caseless_any", "value": [ "/opt/exe.exe" ] } ] } ``` Windows: ``` ------------------------------------------------------------------- Policy: Protect Manifest: 1.0.6 | v1 Artifact: endpoint-blocklist-windows-v1 Relative URL: /api/fleet/artifacts/endpoint-blocklist-windows-v1/2a6fcc67c696ad4e29d91f8b685bff46977198cd34b9a61e8003d55b78dff6ac Encoded SHA256: c6e045fce97651336eeb400f0123541475b940e3aa38ce721f299585683da288 Decoded SHA256: 2a6fcc67c696ad4e29d91f8b685bff46977198cd34b9a61e8003d55b78dff6ac ------------------------------------------------------------------- { "entries": [ { "type": "simple", "entries": [ { "field": "file.path", "operator": "included", "type": "exact_caseless_any", "value": [ "C:\\path\\path.exe" ] } ] } ] } ``` ### Checklist Delete any items that are not applicable to this PR. - [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/main/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 --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- .../src/path_validations/index.ts | 6 +++- .../cypress/fixtures/artifacts_page.ts | 4 +-- .../pages/blocklist/translations.ts | 12 +++++++ .../view/components/blocklist_form.test.tsx | 32 ++++++++++++++++++ .../view/components/blocklist_form.tsx | 33 ++++++++++++++----- .../validators/blocklist_validator.ts | 6 +++- .../apps/integrations/mocks.ts | 4 +-- 7 files changed, 83 insertions(+), 14 deletions(-) diff --git a/packages/kbn-securitysolution-utils/src/path_validations/index.ts b/packages/kbn-securitysolution-utils/src/path_validations/index.ts index ba17757589613..ac7c17426e723 100644 --- a/packages/kbn-securitysolution-utils/src/path_validations/index.ts +++ b/packages/kbn-securitysolution-utils/src/path_validations/index.ts @@ -33,7 +33,11 @@ export type TrustedAppConditionEntryField = | 'process.hash.*' | 'process.executable.caseless' | 'process.Ext.code_signature'; -export type BlocklistConditionEntryField = 'file.hash.*' | 'file.path' | 'file.Ext.code_signature'; +export type BlocklistConditionEntryField = + | 'file.hash.*' + | 'file.path' + | 'file.Ext.code_signature' + | 'file.path.caseless'; export type AllConditionEntryFields = | TrustedAppConditionEntryField | BlocklistConditionEntryField diff --git a/x-pack/plugins/security_solution/public/management/cypress/fixtures/artifacts_page.ts b/x-pack/plugins/security_solution/public/management/cypress/fixtures/artifacts_page.ts index 77490b84d0773..e6c3c941482a9 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/fixtures/artifacts_page.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/fixtures/artifacts_page.ts @@ -358,7 +358,7 @@ export const getArtifactsListTestsData = (): ArtifactsFixtureType[] => [ }, { type: 'click', - selector: 'blocklist-form-file.path', + selector: 'blocklist-form-file.path.caseless', }, { type: 'click', @@ -379,7 +379,7 @@ export const getArtifactsListTestsData = (): ArtifactsFixtureType[] => [ { selector: 'blocklistPage-card-criteriaConditions', value: - 'OSIS WindowsAND file.pathis one of\nc:\\randomFolder\\randomFile.exe\nc:\\randomFolder\\randomFile2.exe', + 'OSIS WindowsAND file.path.caselessis one of\nc:\\randomFolder\\randomFile.exe\nc:\\randomFolder\\randomFile2.exe', }, { selector: 'blocklistPage-card-header-title', diff --git a/x-pack/plugins/security_solution/public/management/pages/blocklist/translations.ts b/x-pack/plugins/security_solution/public/management/pages/blocklist/translations.ts index c084c9443ba5d..60e87de41bf21 100644 --- a/x-pack/plugins/security_solution/public/management/pages/blocklist/translations.ts +++ b/x-pack/plugins/security_solution/public/management/pages/blocklist/translations.ts @@ -76,6 +76,12 @@ export const CONDITION_FIELD_TITLE: { [K in BlocklistConditionEntryField]: strin 'file.path': i18n.translate('xpack.securitySolution.blocklist.entry.field.path', { defaultMessage: 'Path', }), + 'file.path.caseless': i18n.translate( + 'xpack.securitySolution.blocklist.entry.field.path.caseless', + { + defaultMessage: 'Path', + } + ), 'file.Ext.code_signature': i18n.translate( 'xpack.securitySolution.blocklist.entry.field.signature', { defaultMessage: 'Signature' } @@ -89,6 +95,12 @@ export const CONDITION_FIELD_DESCRIPTION: { [K in BlocklistConditionEntryField]: 'file.path': i18n.translate('xpack.securitySolution.blocklist.entry.field.description.path', { defaultMessage: 'The full path of the application', }), + 'file.path.caseless': i18n.translate( + 'xpack.securitySolution.blocklist.entry.field.description.path.caseless', + { + defaultMessage: 'The full path of the application (case insenstive)', + } + ), 'file.Ext.code_signature': i18n.translate( 'xpack.securitySolution.blocklist.entry.field.description.signature', { defaultMessage: 'The signer of the application' } diff --git a/x-pack/plugins/security_solution/public/management/pages/blocklist/view/components/blocklist_form.test.tsx b/x-pack/plugins/security_solution/public/management/pages/blocklist/view/components/blocklist_form.test.tsx index 5ca42ce213448..e07dc6f2d081b 100644 --- a/x-pack/plugins/security_solution/public/management/pages/blocklist/view/components/blocklist_form.test.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/blocklist/view/components/blocklist_form.test.tsx @@ -225,6 +225,38 @@ describe('blocklist form', () => { userEvent.click(screen.getByRole('option', { name: /path/i })); const expected = createOnChangeArgs({ item: createItem({ + entries: [createEntry('file.path.caseless', [])], + }), + }); + expect(onChangeSpy).toHaveBeenCalledWith(expected); + }); + + it('should correctly create `file.path.caseless` when Mac OS is selected', async () => { + render(createProps({ item: createItem({ os_types: [OperatingSystem.MAC] }) })); + expect(screen.getByTestId('blocklist-form-os-select').textContent).toEqual('Mac'); + + userEvent.click(screen.getByTestId('blocklist-form-field-select')); + await waitForEuiPopoverOpen(); + userEvent.click(screen.getByRole('option', { name: /path/i })); + const expected = createOnChangeArgs({ + item: createItem({ + os_types: [OperatingSystem.MAC], + entries: [createEntry('file.path.caseless', [])], + }), + }); + expect(onChangeSpy).toHaveBeenCalledWith(expected); + }); + + it('should correctly create `file.path` when Linux is selected', async () => { + render(createProps({ item: createItem({ os_types: [OperatingSystem.LINUX] }) })); + expect(screen.getByTestId('blocklist-form-os-select').textContent).toEqual('Linux'); + + userEvent.click(screen.getByTestId('blocklist-form-field-select')); + await waitForEuiPopoverOpen(); + userEvent.click(screen.getByRole('option', { name: /path/i })); + const expected = createOnChangeArgs({ + item: createItem({ + os_types: [OperatingSystem.LINUX], entries: [createEntry('file.path', [])], }), }); diff --git a/x-pack/plugins/security_solution/public/management/pages/blocklist/view/components/blocklist_form.tsx b/x-pack/plugins/security_solution/public/management/pages/blocklist/view/components/blocklist_form.tsx index 612bfdb1b2761..f819a55690563 100644 --- a/x-pack/plugins/security_solution/public/management/pages/blocklist/view/components/blocklist_form.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/blocklist/view/components/blocklist_form.tsx @@ -178,14 +178,31 @@ export const BlockListForm = memo( ); const fieldOptions: Array> = useMemo(() => { - const selectableFields: Array> = ( - ['file.hash.*', 'file.path'] as BlocklistConditionEntryField[] - ).map((field) => ({ - value: field, - inputDisplay: CONDITION_FIELD_TITLE[field], - dropdownDisplay: getDropdownDisplay(field), - 'data-test-subj': getTestId(field), - })); + const selectableFields: Array> = []; + + selectableFields.push({ + value: 'file.hash.*', + inputDisplay: CONDITION_FIELD_TITLE['file.hash.*'], + dropdownDisplay: getDropdownDisplay('file.hash.*'), + 'data-test-subj': getTestId('file.hash.*'), + }); + + if (selectedOs === OperatingSystem.LINUX) { + selectableFields.push({ + value: 'file.path', + inputDisplay: CONDITION_FIELD_TITLE['file.path'], + dropdownDisplay: getDropdownDisplay('file.path'), + 'data-test-subj': getTestId('file.path'), + }); + } else { + selectableFields.push({ + value: 'file.path.caseless', + inputDisplay: CONDITION_FIELD_TITLE['file.path.caseless'], + dropdownDisplay: getDropdownDisplay('file.path.caseless'), + 'data-test-subj': getTestId('file.path.caseless'), + }); + } + if (selectedOs === OperatingSystem.WINDOWS) { selectableFields.push({ value: 'file.Ext.code_signature', diff --git a/x-pack/plugins/security_solution/server/lists_integration/endpoint/validators/blocklist_validator.ts b/x-pack/plugins/security_solution/server/lists_integration/endpoint/validators/blocklist_validator.ts index 0a7c29bb67c2b..3841c6f0e9b67 100644 --- a/x-pack/plugins/security_solution/server/lists_integration/endpoint/validators/blocklist_validator.ts +++ b/x-pack/plugins/security_solution/server/lists_integration/endpoint/validators/blocklist_validator.ts @@ -21,12 +21,16 @@ import { isValidHash } from '../../../../common/endpoint/service/artifacts/valid import { EndpointArtifactExceptionValidationError } from './errors'; const allowedHashes: Readonly = ['file.hash.md5', 'file.hash.sha1', 'file.hash.sha256']; +const allowedFilePaths: Readonly = ['file.path', 'file.path.caseless']; const FileHashField = schema.oneOf( allowedHashes.map((hash) => schema.literal(hash)) as [Type] ); -const FilePath = schema.literal('file.path'); +const FilePath = schema.oneOf( + allowedFilePaths.map((path) => schema.literal(path)) as [Type] +); + const FileCodeSigner = schema.literal('file.Ext.code_signature'); const ConditionEntryTypeSchema = schema.literal('match_any'); diff --git a/x-pack/test/security_solution_endpoint/apps/integrations/mocks.ts b/x-pack/test/security_solution_endpoint/apps/integrations/mocks.ts index d8cdbf5a6f6b6..1d5ab43c28a32 100644 --- a/x-pack/test/security_solution_endpoint/apps/integrations/mocks.ts +++ b/x-pack/test/security_solution_endpoint/apps/integrations/mocks.ts @@ -423,7 +423,7 @@ export const getArtifactsListTestsData = () => [ { selector: 'blocklistPage-card-criteriaConditions', value: - 'OSIS Windows\nAND file.pathIS ONE OF\nc:\\randomFolder\\randomFile.exe\nc:\\randomFolder\\randomFile2.exe', + 'OSIS Windows\nAND file.path.caselessIS ONE OF\nc:\\randomFolder\\randomFile.exe\nc:\\randomFolder\\randomFile2.exe', }, { selector: 'blocklistPage-card-header-title', @@ -499,7 +499,7 @@ export const getArtifactsListTestsData = () => [ { field: 'file.path', operator: 'included', - type: 'exact_cased_any', + type: 'exact_caseless_any', value: ['c:\\randomFolder\\randomFile.exe', ' c:\\randomFolder\\randomFile2.exe'], }, ], From 75d351052dbc5f5a35985a2bf58e83c459a35c9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patryk=20Kopyci=C5=84ski?= Date: Mon, 21 Aug 2023 16:15:30 +0200 Subject: [PATCH 12/19] It adds 8.10 into the .backportrc config file (#164259) ## Summary It adds 8.10 into the .backportrc config file Co-authored-by: Tiago Costa --- .backportrc.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.backportrc.json b/.backportrc.json index f6328c251d7e2..e4b7db154d711 100644 --- a/.backportrc.json +++ b/.backportrc.json @@ -3,6 +3,7 @@ "repoName": "kibana", "targetBranchChoices": [ "main", + "8.10", "8.9", "8.8", "8.7", @@ -46,7 +47,7 @@ "backport" ], "branchLabelMapping": { - "^v8.10.0$": "main", + "^v8.11.0$": "main", "^v(\\d+).(\\d+).\\d+$": "$1.$2" }, "autoMerge": true, From d34c845955e2cb1cd6bae630ac3d0d551544f916 Mon Sep 17 00:00:00 2001 From: Maxim Palenov Date: Mon, 21 Aug 2023 16:31:21 +0200 Subject: [PATCH 13/19] [Security Solution] Fix value lists tests flakiness (#164253) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit **Fixes:** https://github.com/elastic/kibana/issues/164056 ## Summary This PR fixes [value_lists.cy.ts](https://github.com/elastic/kibana/blob/main/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/value_lists/value_lists.cy.ts) tests flakiness. ## The flakiness reason Value list items are processed in a bulk via bulk creation and `refresh=wait_for` is [used](https://github.com/elastic/kibana/blob/main/x-pack/plugins/lists/server/services/items/create_list_items_bulk.ts#L87). The problem it returns sometimes earlier than data is available. [Bulk API docs](https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-bulk.html#bulk-refresh) say the following > Only the shards that receive the bulk request will be affected by refresh. Imagine a _bulk?refresh=wait_for request with three documents in it that happen to be routed to different shards in an index with five shards. The request will only wait for those three shards to refresh. The other two shards that make up the index do not participate in the _bulk request at all. While (it seems) only one shard is used in tests but it still cause issues (approx. 1 test per 50 fails) so adding explicit index refresh helps to get rid of flakiness. ## Flaky test runner [value_lists.cy.ts (150 runs)](https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/2924) 🟢 --- .../value_lists/value_lists.cy.ts | 126 +++++++++++------- .../cypress/tasks/lists.ts | 35 +---- 2 files changed, 84 insertions(+), 77 deletions(-) diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/value_lists/value_lists.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/value_lists/value_lists.cy.ts index 60b0b02d79726..697ccadbdbc7f 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/value_lists/value_lists.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/value_lists/value_lists.cy.ts @@ -17,33 +17,35 @@ import { selectValueListsFile, uploadValueList, selectValueListType, - deleteAllValueListsFromUI, closeValueListsModal, importValueList, deleteValueListsFile, exportValueList, waitForListsIndex, + deleteValueLists, } from '../../../tasks/lists'; import { VALUE_LISTS_TABLE, VALUE_LISTS_ROW, VALUE_LISTS_MODAL_ACTIVATOR, } from '../../../screens/lists'; +import { refreshIndex } from '../../../tasks/api_calls/elasticsearch'; + +const TEXT_LIST_FILE_NAME = 'value_list.txt'; +const IPS_LIST_FILE_NAME = 'ip_list.txt'; +const CIDRS_LIST_FILE_NAME = 'cidr_list.txt'; describe('value lists', () => { describe('management modal', { tags: [tag.ESS, tag.SERVERLESS] }, () => { beforeEach(() => { login(); + deleteValueLists([TEXT_LIST_FILE_NAME, IPS_LIST_FILE_NAME, CIDRS_LIST_FILE_NAME]); createListsIndex(); visitWithoutDateRange(DETECTIONS_RULE_MANAGEMENT_URL); waitForListsIndex(); waitForValueListsModalToBeLoaded(); }); - afterEach(() => { - deleteAllValueListsFromUI(); - }); - it('can open and close the modal', () => { openValueListsModal(); closeValueListsModal(); @@ -55,57 +57,53 @@ describe('value lists', () => { }); it('creates a "keyword" list from an uploaded file', () => { - const listName = 'value_list.txt'; selectValueListType('keyword'); - selectValueListsFile(listName); + selectValueListsFile(TEXT_LIST_FILE_NAME); uploadValueList(); cy.get(VALUE_LISTS_TABLE) .find(VALUE_LISTS_ROW) .should(($row) => { - expect($row.text()).to.contain(listName); + expect($row.text()).to.contain(TEXT_LIST_FILE_NAME); expect($row.text()).to.contain('Keywords'); }); }); it('creates a "text" list from an uploaded file', () => { - const listName = 'value_list.txt'; selectValueListType('text'); - selectValueListsFile(listName); + selectValueListsFile(TEXT_LIST_FILE_NAME); uploadValueList(); cy.get(VALUE_LISTS_TABLE) .find(VALUE_LISTS_ROW) .should(($row) => { - expect($row.text()).to.contain(listName); + expect($row.text()).to.contain(TEXT_LIST_FILE_NAME); expect($row.text()).to.contain('Text'); }); }); it('creates a "ip" list from an uploaded file', () => { - const listName = 'ip_list.txt'; selectValueListType('ip'); - selectValueListsFile(listName); + selectValueListsFile(IPS_LIST_FILE_NAME); uploadValueList(); cy.get(VALUE_LISTS_TABLE) .find(VALUE_LISTS_ROW) .should(($row) => { - expect($row.text()).to.contain(listName); + expect($row.text()).to.contain(IPS_LIST_FILE_NAME); expect($row.text()).to.contain('IP addresses'); }); }); it('creates a "ip_range" list from an uploaded file', () => { - const listName = 'cidr_list.txt'; selectValueListType('ip_range'); - selectValueListsFile(listName); + selectValueListsFile(CIDRS_LIST_FILE_NAME); uploadValueList(); cy.get(VALUE_LISTS_TABLE) .find(VALUE_LISTS_ROW) .should(($row) => { - expect($row.text()).to.contain(listName); + expect($row.text()).to.contain(CIDRS_LIST_FILE_NAME); expect($row.text()).to.contain('IP ranges'); }); }); @@ -113,63 +111,68 @@ describe('value lists', () => { describe('delete list types', () => { it('deletes a "keyword" list from an uploaded file', () => { - const listName = 'value_list.txt'; - importValueList(listName, 'keyword'); + importValueList(TEXT_LIST_FILE_NAME, 'keyword'); openValueListsModal(); - deleteValueListsFile(listName); + deleteValueListsFile(TEXT_LIST_FILE_NAME); cy.get(VALUE_LISTS_TABLE) .find(VALUE_LISTS_ROW) .should(($row) => { - expect($row.text()).not.to.contain(listName); + expect($row.text()).not.to.contain(TEXT_LIST_FILE_NAME); }); }); it('deletes a "text" list from an uploaded file', () => { - const listName = 'value_list.txt'; - importValueList(listName, 'text'); + importValueList(TEXT_LIST_FILE_NAME, 'text'); openValueListsModal(); - deleteValueListsFile(listName); + deleteValueListsFile(TEXT_LIST_FILE_NAME); cy.get(VALUE_LISTS_TABLE) .find(VALUE_LISTS_ROW) .should(($row) => { - expect($row.text()).not.to.contain(listName); + expect($row.text()).not.to.contain(TEXT_LIST_FILE_NAME); }); }); it('deletes a "ip" from an uploaded file', () => { - const listName = 'ip_list.txt'; - importValueList(listName, 'ip'); + importValueList(IPS_LIST_FILE_NAME, 'ip'); openValueListsModal(); - deleteValueListsFile(listName); + deleteValueListsFile(IPS_LIST_FILE_NAME); cy.get(VALUE_LISTS_TABLE) .find(VALUE_LISTS_ROW) .should(($row) => { - expect($row.text()).not.to.contain(listName); + expect($row.text()).not.to.contain(IPS_LIST_FILE_NAME); }); }); it('deletes a "ip_range" from an uploaded file', () => { - const listName = 'cidr_list.txt'; - importValueList(listName, 'ip_range', ['192.168.100.0']); + importValueList(CIDRS_LIST_FILE_NAME, 'ip_range', ['192.168.100.0']); openValueListsModal(); - deleteValueListsFile(listName); + deleteValueListsFile(CIDRS_LIST_FILE_NAME); cy.get(VALUE_LISTS_TABLE) .find(VALUE_LISTS_ROW) .should(($row) => { - expect($row.text()).not.to.contain(listName); + expect($row.text()).not.to.contain(CIDRS_LIST_FILE_NAME); }); }); }); describe('export list types', () => { it('exports a "keyword" list from an uploaded file', () => { - const listName = 'value_list.txt'; - cy.intercept('POST', `/api/lists/items/_export?list_id=${listName}`).as('exportList'); - importValueList('value_list.txt', 'keyword'); + cy.intercept('POST', `/api/lists/items/_export?list_id=${TEXT_LIST_FILE_NAME}`).as( + 'exportList' + ); + importValueList(TEXT_LIST_FILE_NAME, 'keyword'); + + // Importing value lists includes bulk creation of list items with refresh=wait_for + // While it should wait for data update and return after that it's not always a case with bulk operations. + // Sometimes list items are empty making this test flaky. + // To fix it refresh used list items index (for the default space) + refreshIndex('.items-default'); + openValueListsModal(); exportValueList(); + cy.wait('@exportList').then(({ response }) => { - cy.fixture(listName).then((list: string) => { + cy.fixture(TEXT_LIST_FILE_NAME).then((list: string) => { const [lineOne, lineTwo] = list.split('\n'); expect(response?.body).to.contain(lineOne); expect(response?.body).to.contain(lineTwo); @@ -178,13 +181,22 @@ describe('value lists', () => { }); it('exports a "text" list from an uploaded file', () => { - const listName = 'value_list.txt'; - cy.intercept('POST', `/api/lists/items/_export?list_id=${listName}`).as('exportList'); - importValueList(listName, 'text'); + cy.intercept('POST', `/api/lists/items/_export?list_id=${TEXT_LIST_FILE_NAME}`).as( + 'exportList' + ); + importValueList(TEXT_LIST_FILE_NAME, 'text'); + + // Importing value lists includes bulk creation of list items with refresh=wait_for + // While it should wait for data update and return after that it's not always a case with bulk operations. + // Sometimes list items are empty making this test flaky. + // To fix it refresh used list items index (for the default space) + refreshIndex('.items-default'); + openValueListsModal(); exportValueList(); + cy.wait('@exportList').then(({ response }) => { - cy.fixture(listName).then((list: string) => { + cy.fixture(TEXT_LIST_FILE_NAME).then((list: string) => { const [lineOne, lineTwo] = list.split('\n'); expect(response?.body).to.contain(lineOne); expect(response?.body).to.contain(lineTwo); @@ -193,13 +205,21 @@ describe('value lists', () => { }); it('exports a "ip" list from an uploaded file', () => { - const listName = 'ip_list.txt'; - cy.intercept('POST', `/api/lists/items/_export?list_id=${listName}`).as('exportList'); - importValueList(listName, 'ip'); + cy.intercept('POST', `/api/lists/items/_export?list_id=${IPS_LIST_FILE_NAME}`).as( + 'exportList' + ); + importValueList(IPS_LIST_FILE_NAME, 'ip'); + + // Importing value lists includes bulk creation of list items with refresh=wait_for + // While it should wait for data update and return after that it's not always a case with bulk operations. + // Sometimes list items are empty making this test flaky. + // To fix it refresh used list items index (for the default space) + refreshIndex('.items-default'); + openValueListsModal(); exportValueList(); cy.wait('@exportList').then(({ response }) => { - cy.fixture(listName).then((list: string) => { + cy.fixture(IPS_LIST_FILE_NAME).then((list: string) => { const [lineOne, lineTwo] = list.split('\n'); expect(response?.body).to.contain(lineOne); expect(response?.body).to.contain(lineTwo); @@ -208,13 +228,21 @@ describe('value lists', () => { }); it('exports a "ip_range" list from an uploaded file', () => { - const listName = 'cidr_list.txt'; - cy.intercept('POST', `/api/lists/items/_export?list_id=${listName}`).as('exportList'); - importValueList(listName, 'ip_range', ['192.168.100.0']); + cy.intercept('POST', `/api/lists/items/_export?list_id=${CIDRS_LIST_FILE_NAME}`).as( + 'exportList' + ); + importValueList(CIDRS_LIST_FILE_NAME, 'ip_range', ['192.168.100.0']); + + // Importing value lists includes bulk creation of list items with refresh=wait_for + // While it should wait for data update and return after that it's not always a case with bulk operations. + // Sometimes list items are empty making this test flaky. + // To fix it refresh used list items index (for the default space) + refreshIndex('.items-default'); + openValueListsModal(); exportValueList(); cy.wait('@exportList').then(({ response }) => { - cy.fixture(listName).then((list: string) => { + cy.fixture(CIDRS_LIST_FILE_NAME).then((list: string) => { const [lineOne] = list.split('\n'); expect(response?.body).to.contain(lineOne); }); diff --git a/x-pack/test/security_solution_cypress/cypress/tasks/lists.ts b/x-pack/test/security_solution_cypress/cypress/tasks/lists.ts index d160f4c2deb42..e9dd3d882b429 100644 --- a/x-pack/test/security_solution_cypress/cypress/tasks/lists.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/lists.ts @@ -10,7 +10,6 @@ import { VALUE_LIST_CLOSE_BUTTON, VALUE_LIST_DELETE_BUTTON, VALUE_LIST_EXPORT_BUTTON, - VALUE_LIST_FILES, VALUE_LIST_FILE_PICKER, VALUE_LIST_FILE_UPLOAD_BUTTON, VALUE_LIST_TYPE_SELECTOR, @@ -73,9 +72,14 @@ export const exportValueList = (): Cypress.Chainable> => { /** * Given an array of value lists this will delete them all using Cypress Request and the lists REST API + * + * If a list doesn't exist it ignores the error. + * * Ref: https://www.elastic.co/guide/en/security/current/lists-api-delete-container.html */ -const deleteValueLists = (lists: string[]): Array>> => { +export const deleteValueLists = ( + lists: string[] +): Array>> => { return lists.map((list) => deleteValueList(list)); }; @@ -88,6 +92,7 @@ const deleteValueList = (list: string): Cypress.Chainable { return cy.fixture(file).then((data) => uploadListItemData(file, type, data)); }; - -/** - * If you are on the value lists from the UI, this will loop over all the HTML elements - * that have action-delete-value-list-${list_name} and delete all of those value lists - * using Cypress Request and the lists REST API. - * If the UI does not contain any value based lists this will not fail. If the UI does - * contain value based lists but the backend does not return a success on DELETE then this - * will cause errors. - * Ref: https://www.elastic.co/guide/en/security/current/lists-api-delete-container.html - */ -export const deleteAllValueListsFromUI = (): Array< - Cypress.Chainable> -> => { - const lists = Cypress.$(VALUE_LIST_FILES) - .toArray() - .reduce((accum, $el) => { - const attribute = $el.getAttribute('data-test-subj'); - if (attribute != null) { - const list = attribute.substr('data-test-subj-value-list'.length); - return [...accum, list]; - } else { - return accum; - } - }, []); - return deleteValueLists(lists); -}; From 79a0a5e94089121cbce294e0ca899084c63bae0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Istv=C3=A1n=20Zolt=C3=A1n=20Szab=C3=B3?= Date: Mon, 21 Aug 2023 16:33:07 +0200 Subject: [PATCH 14/19] [DOCS] Improves change point detection documentation (#164277) Co-authored-by: Dima Arnautov --- docs/user/ml/index.asciidoc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/user/ml/index.asciidoc b/docs/user/ml/index.asciidoc index e7a60df8d289e..59f7345923870 100644 --- a/docs/user/ml/index.asciidoc +++ b/docs/user/ml/index.asciidoc @@ -223,3 +223,11 @@ point type selector to filter the results by specific types of change points. [role="screenshot"] image::user/ml/images/ml-change-point-detection-selected.png[Selected change points] + + +You can attach change point charts to a dashboard or a case by using the context +menu. If the split field is selected, you can either select specific charts +(partitions) or set the maximum number of top change points to plot. It's +possible to preserve the applied time range or use the time bound from the page +date picker. You can also add or edit change point charts directly from the +**Dashboard** app. \ No newline at end of file From 5f310f773abcd850e739a712082fb188378bb014 Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Mon, 21 Aug 2023 16:48:08 +0200 Subject: [PATCH 15/19] Unskip X-Pack Saved Object Tagging Functional Tests (#164273) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary close https://github.com/elastic/kibana/issues/88639 10 🟢 runs https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/2926 40 🟢 runs https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/2928 --- .../functional/tests/visualize_integration.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/x-pack/test/saved_object_tagging/functional/tests/visualize_integration.ts b/x-pack/test/saved_object_tagging/functional/tests/visualize_integration.ts index 515c79ae5156a..a7a03a58ba0cf 100644 --- a/x-pack/test/saved_object_tagging/functional/tests/visualize_integration.ts +++ b/x-pack/test/saved_object_tagging/functional/tests/visualize_integration.ts @@ -61,8 +61,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { await PageObjects.header.waitUntilLoadingHasFinished(); }; - // Failing: See https://github.com/elastic/kibana/issues/88639 - describe.skip('visualize integration', () => { + describe('visualize integration', () => { before(async () => { // clean up any left-over visualizations and tags from tests that didn't clean up after themselves await kibanaServer.savedObjects.clean({ types: ['tag', 'visualization'] }); From 98a135cc7aba034592e77a3c0a0c9caed6c0615a Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Mon, 21 Aug 2023 11:08:47 -0400 Subject: [PATCH 16/19] skip failing test suite (#164318) --- .../group4/telemetry/task_based/detection_rules.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group4/telemetry/task_based/detection_rules.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group4/telemetry/task_based/detection_rules.ts index 686596b25e008..789d653f5f3aa 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group4/telemetry/task_based/detection_rules.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group4/telemetry/task_based/detection_rules.ts @@ -34,7 +34,8 @@ export default ({ getService }: FtrProviderContext) => { const log = getService('log'); const retry = getService('retry'); - describe('Detection rule task telemetry', async () => { + // Failing: See https://github.com/elastic/kibana/issues/164318 + describe.skip('Detection rule task telemetry', async () => { before(async () => { await esArchiver.load('x-pack/test/functional/es_archives/security_solution/telemetry'); }); From c328d2da218f4da46c73a0e5823e434385c179ca Mon Sep 17 00:00:00 2001 From: Tim Sullivan Date: Mon, 21 Aug 2023 08:10:35 -0700 Subject: [PATCH 17/19] [Reporting] Adjust export type conditionals in server startup (#164232) ## Summary This PR cleans up how config settings are used as conditionals in the Reporting plugin startup phase. The existing code is correct, but it's heavily aligned to certain business requirements that might not be understood by a reader. The change in the PR uses simpler conditionals that are separated from internal business decisions. The result should be clearer readability of the code. --- .../common/constants/report_types.ts | 2 +- .../reporting_panel_content.tsx | 4 +- x-pack/plugins/reporting/server/core.ts | 21 ++-- .../plugins/reporting/server/plugin.test.ts | 97 +++++++++++-------- .../create_mock_reportingplugin.ts | 1 + 5 files changed, 76 insertions(+), 49 deletions(-) diff --git a/x-pack/plugins/reporting/common/constants/report_types.ts b/x-pack/plugins/reporting/common/constants/report_types.ts index 4e9b945aadb72..b66e00de7407f 100644 --- a/x-pack/plugins/reporting/common/constants/report_types.ts +++ b/x-pack/plugins/reporting/common/constants/report_types.ts @@ -6,7 +6,7 @@ */ // Export Type Definitions -export const CSV_REPORT_TYPE = 'CSV'; +export const CSV_REPORT_TYPE = 'csv_searchsource'; export const CSV_REPORT_TYPE_V2 = 'csv_v2'; export const PDF_REPORT_TYPE = 'printablePdf'; diff --git a/x-pack/plugins/reporting/public/share_context_menu/reporting_panel_content/reporting_panel_content.tsx b/x-pack/plugins/reporting/public/share_context_menu/reporting_panel_content/reporting_panel_content.tsx index 2252694fcaa97..58358d33f5b1f 100644 --- a/x-pack/plugins/reporting/public/share_context_menu/reporting_panel_content/reporting_panel_content.tsx +++ b/x-pack/plugins/reporting/public/share_context_menu/reporting_panel_content/reporting_panel_content.tsx @@ -251,8 +251,8 @@ class ReportingPanelContentUi extends Component { case PDF_REPORT_TYPE: case PDF_REPORT_TYPE_V2: return 'PDF'; - case 'csv_searchsource': - return CSV_REPORT_TYPE; + case CSV_REPORT_TYPE: + return 'csv'; case 'png': case PNG_REPORT_TYPE_V2: return PNG_REPORT_TYPE; diff --git a/x-pack/plugins/reporting/server/core.ts b/x-pack/plugins/reporting/server/core.ts index d81f7b8ab9808..453940f3cc914 100644 --- a/x-pack/plugins/reporting/server/core.ts +++ b/x-pack/plugins/reporting/server/core.ts @@ -226,22 +226,27 @@ export class ReportingCore { * only CSV export types should be registered in the export types registry for serverless */ private getExportTypes(): ExportType[] { + const { csv, pdf, png } = this.config.export_types; const exportTypes = []; - if (!this.config.export_types.pdf.enabled || !this.config.export_types.png.enabled) { - exportTypes.push( - new CsvSearchSourceExportType(this.core, this.config, this.logger, this.context) - ); - exportTypes.push(new CsvV2ExportType(this.core, this.config, this.logger, this.context)); - } else { + + if (csv.enabled) { + // NOTE: CsvSearchSourceExportType should be deprecated and replaced with V2 in the UI: https://github.com/elastic/kibana/issues/151190 exportTypes.push( new CsvSearchSourceExportType(this.core, this.config, this.logger, this.context) ); exportTypes.push(new CsvV2ExportType(this.core, this.config, this.logger, this.context)); + } + + if (pdf.enabled) { + // NOTE: PdfV1ExportType is deprecated and tagged for removal: https://github.com/elastic/kibana/issues/154601 + exportTypes.push(new PdfV1ExportType(this.core, this.config, this.logger, this.context)); exportTypes.push(new PdfExportType(this.core, this.config, this.logger, this.context)); + } + + if (png.enabled) { exportTypes.push(new PngExportType(this.core, this.config, this.logger, this.context)); - // deprecated export types for tests - exportTypes.push(new PdfV1ExportType(this.core, this.config, this.logger, this.context)); } + return exportTypes; } diff --git a/x-pack/plugins/reporting/server/plugin.test.ts b/x-pack/plugins/reporting/server/plugin.test.ts index 176b648b9d02a..3e57e3bf3322b 100644 --- a/x-pack/plugins/reporting/server/plugin.test.ts +++ b/x-pack/plugins/reporting/server/plugin.test.ts @@ -7,8 +7,15 @@ import type { CoreSetup, CoreStart, Logger } from '@kbn/core/server'; import { coreMock, loggingSystemMock } from '@kbn/core/server/mocks'; -import { PDF_REPORT_TYPE_V2, PNG_REPORT_TYPE_V2 } from '../common/constants/report_types'; +import { + CSV_REPORT_TYPE, + CSV_REPORT_TYPE_V2, + PDF_REPORT_TYPE, + PDF_REPORT_TYPE_V2, + PNG_REPORT_TYPE_V2, +} from '../common/constants'; import type { ReportingCore, ReportingInternalStart } from './core'; +import { ExportTypesRegistry } from './lib/export_types_registry'; import { ReportingPlugin } from './plugin'; import { createMockConfigSchema, @@ -30,6 +37,8 @@ describe('Reporting Plugin', () => { let plugin: ReportingPlugin; beforeEach(async () => { + jest.clearAllMocks(); + configSchema = createMockConfigSchema(); initContext = coreMock.createPluginInitializerContext(configSchema); coreSetup = coreMock.createSetup(configSchema); @@ -81,50 +90,62 @@ describe('Reporting Plugin', () => { `); expect(logger.error).toHaveBeenCalledTimes(2); }); - describe('config and export types registry validation', () => { - it('expect image reporting to be in registry by default', async () => { - // wait for the setup phase background work - plugin.setup(coreSetup, pluginSetup); - await new Promise(setImmediate); - - // create a way for an error to happen - const reportingCore = (plugin as unknown as { reportingCore: ReportingCore }).reportingCore; - - // wait for the startup phase background work - plugin.start(coreStart, pluginStart); - await new Promise(setImmediate); - expect(reportingCore.getExportTypesRegistry().getById(PDF_REPORT_TYPE_V2)).toHaveProperty( - 'id', - PDF_REPORT_TYPE_V2 - ); - expect(reportingCore.getExportTypesRegistry().getById(PNG_REPORT_TYPE_V2)).toHaveProperty( - 'id', - PNG_REPORT_TYPE_V2 - ); + + describe('config and export types registration', () => { + jest.mock('./lib/export_types_registry'); + ExportTypesRegistry.prototype.getAll = jest.fn(() => []); // code breaks if getAll returns undefined + let registerSpy: jest.SpyInstance; + + beforeEach(async () => { + registerSpy = jest.spyOn(ExportTypesRegistry.prototype, 'register'); + pluginSetup = createMockPluginSetup({}) as unknown as ReportingSetupDeps; + pluginStart = await createMockPluginStart(coreStart, configSchema); + plugin = new ReportingPlugin(initContext); + }); + + it('expect all report types to be in registry', async () => { + // check the spy function + expect(registerSpy).toHaveBeenCalledTimes(5); + expect(registerSpy).toHaveBeenCalledWith(expect.objectContaining({ id: CSV_REPORT_TYPE })); + expect(registerSpy).toHaveBeenCalledWith(expect.objectContaining({ id: CSV_REPORT_TYPE_V2 })); + expect(registerSpy).toHaveBeenCalledWith(expect.objectContaining({ id: PDF_REPORT_TYPE })); + expect(registerSpy).toHaveBeenCalledWith(expect.objectContaining({ id: PDF_REPORT_TYPE_V2 })); + expect(registerSpy).toHaveBeenCalledWith(expect.objectContaining({ id: PNG_REPORT_TYPE_V2 })); }); - it('expect pdf to not be in registry if config does not enable it', async () => { - configSchema = { ...createMockConfigSchema(), export_types: { pdf: { enabled: false } } }; + + it('expect image report types not to be in registry if disabled', async () => { + jest.clearAllMocks(); + + configSchema = createMockConfigSchema({ + export_types: { + csv: { enabled: true }, + pdf: { enabled: false }, + png: { enabled: false }, + }, + }); + initContext = coreMock.createPluginInitializerContext(configSchema); coreSetup = coreMock.createSetup(configSchema); coreStart = coreMock.createStart(); pluginSetup = createMockPluginSetup({}) as unknown as ReportingSetupDeps; pluginStart = await createMockPluginStart(coreStart, configSchema); - plugin = new ReportingPlugin(initContext); - // wait for the setup phase background work - plugin.setup(coreSetup, pluginSetup); - await new Promise(setImmediate); - - // create a way for an error to happen - const reportingCore = (plugin as unknown as { reportingCore: ReportingCore }).reportingCore; - - // wait for the startup phase background work - plugin.start(coreStart, pluginStart); - await new Promise(setImmediate); - const checkPdf = () => reportingCore.getExportTypesRegistry().getById(PDF_REPORT_TYPE_V2); - const checkPng = () => reportingCore.getExportTypesRegistry().getById(PNG_REPORT_TYPE_V2); - expect(checkPdf).toThrowError(`Unknown id ${PDF_REPORT_TYPE_V2}`); - expect(checkPng).toThrowError(`Unknown id ${PNG_REPORT_TYPE_V2}`); + + // check the spy function was called with CSV + expect(registerSpy).toHaveBeenCalledTimes(2); + expect(registerSpy).toHaveBeenCalledWith(expect.objectContaining({ id: CSV_REPORT_TYPE })); + expect(registerSpy).toHaveBeenCalledWith(expect.objectContaining({ id: CSV_REPORT_TYPE_V2 })); + + // check the spy function was NOT called with anything else + expect(registerSpy).not.toHaveBeenCalledWith( + expect.objectContaining({ id: PDF_REPORT_TYPE }) + ); + expect(registerSpy).not.toHaveBeenCalledWith( + expect.objectContaining({ id: PDF_REPORT_TYPE_V2 }) + ); + expect(registerSpy).not.toHaveBeenCalledWith( + expect.objectContaining({ id: PNG_REPORT_TYPE_V2 }) + ); }); }); }); diff --git a/x-pack/plugins/reporting/server/test_helpers/create_mock_reportingplugin.ts b/x-pack/plugins/reporting/server/test_helpers/create_mock_reportingplugin.ts index 4fbacb3a8b994..38a7bb8399abb 100644 --- a/x-pack/plugins/reporting/server/test_helpers/create_mock_reportingplugin.ts +++ b/x-pack/plugins/reporting/server/test_helpers/create_mock_reportingplugin.ts @@ -115,6 +115,7 @@ export const createMockConfigSchema = ( pdf: { enabled: true }, png: { enabled: true }, csv: { enabled: true }, + ...overrides.export_types, }, } as ReportingConfigType; }; From c1d2834f1aa675f2682793d83ac9ad07c3854990 Mon Sep 17 00:00:00 2001 From: Lisa Cawley Date: Mon, 21 Aug 2023 09:29:08 -0700 Subject: [PATCH 18/19] [OAS] Remove redundant connector properties (#163987) --- .../api-generated/connectors/connector-apis-passthru.asciidoc | 4 ++-- x-pack/plugins/actions/docs/openapi/bundled.json | 4 ---- x-pack/plugins/actions/docs/openapi/bundled.yaml | 4 ---- .../schemas/update_connector_request_slack_api.yaml | 2 -- .../schemas/update_connector_request_slack_webhook.yaml | 2 -- 5 files changed, 2 insertions(+), 14 deletions(-) diff --git a/docs/api-generated/connectors/connector-apis-passthru.asciidoc b/docs/api-generated/connectors/connector-apis-passthru.asciidoc index a31c0c5fa963f..64bf78a2b66ed 100644 --- a/docs/api-generated/connectors/connector-apis-passthru.asciidoc +++ b/docs/api-generated/connectors/connector-apis-passthru.asciidoc @@ -2475,7 +2475,7 @@ Any modifications made to this file will be overwritten.
@@ -2483,7 +2483,7 @@ Any modifications made to this file will be overwritten.
name
String The display name for the connector.
-
secrets
+
secrets
diff --git a/x-pack/plugins/actions/docs/openapi/bundled.json b/x-pack/plugins/actions/docs/openapi/bundled.json index 27606af5b7d20..59ca423963caf 100644 --- a/x-pack/plugins/actions/docs/openapi/bundled.json +++ b/x-pack/plugins/actions/docs/openapi/bundled.json @@ -3720,8 +3720,6 @@ "description": "The display name for the connector." }, "secrets": { - "type": "object", - "description": "The secrets object containing the necessary fields for authentication.", "$ref": "#/components/schemas/secrets_properties_slack_api" } } @@ -3739,8 +3737,6 @@ "description": "The display name for the connector." }, "secrets": { - "type": "object", - "description": "The secrets object containing the necessary fields for authentication.", "$ref": "#/components/schemas/secrets_properties_slack_webhook" } } diff --git a/x-pack/plugins/actions/docs/openapi/bundled.yaml b/x-pack/plugins/actions/docs/openapi/bundled.yaml index a784d60473b09..b090dba90a87a 100644 --- a/x-pack/plugins/actions/docs/openapi/bundled.yaml +++ b/x-pack/plugins/actions/docs/openapi/bundled.yaml @@ -2549,8 +2549,6 @@ components: type: string description: The display name for the connector. secrets: - type: object - description: The secrets object containing the necessary fields for authentication. $ref: '#/components/schemas/secrets_properties_slack_api' update_connector_request_slack_webhook: title: Update Slack connector request @@ -2563,8 +2561,6 @@ components: type: string description: The display name for the connector. secrets: - type: object - description: The secrets object containing the necessary fields for authentication. $ref: '#/components/schemas/secrets_properties_slack_webhook' update_connector_request_swimlane: title: Update Swimlane connector request diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/update_connector_request_slack_api.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/update_connector_request_slack_api.yaml index e85a0436a035b..1a0c99c1847a0 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/update_connector_request_slack_api.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/update_connector_request_slack_api.yaml @@ -8,6 +8,4 @@ properties: type: string description: The display name for the connector. secrets: - type: object - description: The secrets object containing the necessary fields for authentication. $ref: 'secrets_properties_slack_api.yaml' diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/update_connector_request_slack_webhook.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/update_connector_request_slack_webhook.yaml index 4ed93f519f3c2..67b0f9bb310ad 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/update_connector_request_slack_webhook.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/update_connector_request_slack_webhook.yaml @@ -8,6 +8,4 @@ properties: type: string description: The display name for the connector. secrets: - type: object - description: The secrets object containing the necessary fields for authentication. $ref: 'secrets_properties_slack_webhook.yaml' From 9cff5fc8440892a45cb5482ab5baf8ba2bb92a09 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Mon, 21 Aug 2023 12:54:39 -0400 Subject: [PATCH 19/19] skip failing test suite (#164334) --- .../group4/telemetry/task_based/security_lists.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group4/telemetry/task_based/security_lists.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group4/telemetry/task_based/security_lists.ts index daf5e6e8a1c74..50661a537472d 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group4/telemetry/task_based/security_lists.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group4/telemetry/task_based/security_lists.ts @@ -31,7 +31,8 @@ export default ({ getService }: FtrProviderContext) => { const retry = getService('retry'); const es = getService('es'); - describe('Security lists task telemetry', async () => { + // Failing: See https://github.com/elastic/kibana/issues/164334 + describe.skip('Security lists task telemetry', async () => { before(async () => { await esArchiver.load('x-pack/test/functional/es_archives/security_solution/telemetry'); });
name
String The display name for the connector.
-
secrets
+
secrets