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,
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]
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
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/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/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/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/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/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
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 59a90157b0111..cf0e40c769470 100644
Binary files a/src/plugins/home/public/assets/sample_data_resources/ecommerce/dashboard.webp and b/src/plugins/home/public/assets/sample_data_resources/ecommerce/dashboard.webp differ
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 b07db2f4c164a..8353e897767fa 100644
Binary files a/src/plugins/home/public/assets/sample_data_resources/ecommerce/dashboard_dark.webp and b/src/plugins/home/public/assets/sample_data_resources/ecommerce/dashboard_dark.webp differ
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/test/api_integration/apis/home/sample_data.ts b/test/api_integration/apis/home/sample_data.ts
index cb0e5a69b6fe4..32f20ad6d10e2 100644
--- a/test/api_integration/apis/home/sample_data.ts
+++ b/test/api_integration/apis/home/sample_data.ts
@@ -68,8 +68,7 @@ export default function ({ getService }: FtrProviderContext) {
});
});
- // Failing: See https://github.com/elastic/kibana/issues/121051
- describe.skip('dates', () => {
+ describe('dates', () => {
it('should load elasticsearch index containing sample data with dates relative to current time', async () => {
const resp = await es.search<{ timestamp: string }>({
index: 'kibana_sample_data_flights',
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/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' }
- );
-};
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];
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}
-
- }
- />
-
+ />
+
+ )}
);
};
diff --git a/x-pack/plugins/ml/public/application/explorer/components/explorer_query_bar/explorer_query_bar.tsx b/x-pack/plugins/ml/public/application/explorer/components/explorer_query_bar/explorer_query_bar.tsx
index aa5b752b1f4f8..a98b4dc861a36 100644
--- a/x-pack/plugins/ml/public/application/explorer/components/explorer_query_bar/explorer_query_bar.tsx
+++ b/x-pack/plugins/ml/public/application/explorer/components/explorer_query_bar/explorer_query_bar.tsx
@@ -5,7 +5,7 @@
* 2.0.
*/
-import React, { FC, useState, useEffect } from 'react';
+import React, { FC, useEffect, useState } from 'react';
import { EuiCode, EuiInputPopover } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { fromKueryExpression, luceneStringToDsl, toElasticsearchQuery } from '@kbn/es-query';
@@ -78,23 +78,16 @@ export function getKqlQueryValues({
}
function getInitSearchInputState({
- filterActive,
queryString,
+ searchInput,
}: {
- filterActive: boolean;
queryString?: string;
+ searchInput?: Query;
}) {
- if (queryString !== undefined && filterActive === true) {
- return {
- language: SEARCH_QUERY_LANGUAGE.KUERY,
- query: queryString,
- };
- } else {
- return {
- query: '',
- language: DEFAULT_QUERY_LANG,
- };
- }
+ return {
+ language: searchInput?.language ?? DEFAULT_QUERY_LANG,
+ query: queryString ?? '',
+ };
}
interface ExplorerQueryBarProps {
@@ -129,18 +122,17 @@ export const ExplorerQueryBar: FC = ({
} = services;
// The internal state of the input query bar updated on every key stroke.
- const [searchInput, setSearchInput] = useState(
- getInitSearchInputState({ filterActive, queryString })
- );
+ const [searchInput, setSearchInput] = useState(getInitSearchInputState({ queryString }));
const [queryErrorMessage, setQueryErrorMessage] = useState(
undefined
);
useEffect(
function updateSearchInputFromFilter() {
- setSearchInput(getInitSearchInputState({ filterActive, queryString }));
+ setSearchInput(getInitSearchInputState({ queryString, searchInput }));
},
- [filterActive, queryString]
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ [queryString, searchInput.language]
);
const searchChangeHandler = (query: Query) => {
diff --git a/x-pack/plugins/osquery/cypress/e2e/all/packs_create_edit.cy.ts b/x-pack/plugins/osquery/cypress/e2e/all/packs_create_edit.cy.ts
index da32bf75ba1ae..c9c3a065bcc42 100644
--- a/x-pack/plugins/osquery/cypress/e2e/all/packs_create_edit.cy.ts
+++ b/x-pack/plugins/osquery/cypress/e2e/all/packs_create_edit.cy.ts
@@ -178,7 +178,7 @@ describe('Packs - Create and Edit', () => {
cy.react('EuiFlyoutFooter').react('EuiButton').contains('Save').click();
findFormFieldByRowsLabelAndType(
'Scheduled agent policies (optional)',
- 'fleet server {downArrow} {enter}'
+ `${DEFAULT_POLICY} {downArrow} {enter}`
);
findAndClickButton('Update pack');
closeModalIfVisible();
@@ -211,7 +211,7 @@ describe('Packs - Create and Edit', () => {
},
}).then((response) => {
const item = response.body.items.find(
- (policy: PackagePolicy) => policy.policy_id === 'fleet-server-policy'
+ (policy: PackagePolicy) => policy.name === `Policy for ${DEFAULT_POLICY}`
);
expect(item?.inputs[0].config?.osquery.value.packs[packName].queries).to.deep.equal(
@@ -268,15 +268,24 @@ describe('Packs - Create and Edit', () => {
let packName: string;
before(() => {
- loadPack({
- policy_ids: ['fleet-server-policy'],
- queries: {
- [savedQueryName]: { ecs_mapping: {}, interval: 3600, query: 'select * from uptime;' },
+ request<{ items: PackagePolicy[] }>({
+ url: '/internal/osquery/fleet_wrapper/package_policies',
+ headers: {
+ 'Elastic-Api-Version': API_VERSIONS.internal.v1,
},
- }).then((pack) => {
- packId = pack.saved_object_id;
- packName = pack.name;
- });
+ })
+ .then((response) =>
+ loadPack({
+ policy_ids: [response.body.items[0].policy_id],
+ queries: {
+ [savedQueryName]: { ecs_mapping: {}, interval: 3600, query: 'select * from uptime;' },
+ },
+ })
+ )
+ .then((pack) => {
+ packId = pack.saved_object_id;
+ packName = pack.name;
+ });
});
after(() => {
@@ -310,15 +319,24 @@ describe('Packs - Create and Edit', () => {
let packName: string;
before(() => {
- loadPack({
- policy_ids: ['fleet-server-policy'],
- queries: {
- [savedQueryName]: { ecs_mapping: {}, interval: 3600, query: 'select * from uptime;' },
+ request<{ items: PackagePolicy[] }>({
+ url: '/internal/osquery/fleet_wrapper/package_policies',
+ headers: {
+ 'Elastic-Api-Version': API_VERSIONS.internal.v1,
},
- }).then((pack) => {
- packId = pack.saved_object_id;
- packName = pack.name;
- });
+ })
+ .then((response) =>
+ loadPack({
+ policy_ids: [response.body.items[0].policy_id],
+ queries: {
+ [savedQueryName]: { ecs_mapping: {}, interval: 3600, query: 'select * from uptime;' },
+ },
+ })
+ )
+ .then((pack) => {
+ packId = pack.saved_object_id;
+ packName = pack.name;
+ });
});
after(() => {
@@ -343,15 +361,24 @@ describe('Packs - Create and Edit', () => {
let packName: string;
before(() => {
- loadPack({
- policy_ids: ['fleet-server-policy'],
- queries: {
- [savedQueryName]: { ecs_mapping: {}, interval: 3600, query: 'select * from uptime;' },
+ request<{ items: PackagePolicy[] }>({
+ url: '/internal/osquery/fleet_wrapper/package_policies',
+ headers: {
+ 'Elastic-Api-Version': API_VERSIONS.internal.v1,
},
- }).then((pack) => {
- packId = pack.saved_object_id;
- packName = pack.name;
- });
+ })
+ .then((response) =>
+ loadPack({
+ policy_ids: [response.body.items[0].policy_id],
+ queries: {
+ [savedQueryName]: { ecs_mapping: {}, interval: 3600, query: 'select * from uptime;' },
+ },
+ })
+ )
+ .then((pack) => {
+ packId = pack.saved_object_id;
+ packName = pack.name;
+ });
});
after(() => {
@@ -386,15 +413,24 @@ describe('Packs - Create and Edit', () => {
let packName: string;
before(() => {
- loadPack({
- policy_ids: ['fleet-server-policy'],
- queries: {
- [savedQueryName]: { ecs_mapping: {}, interval: 3600, query: 'select * from uptime;' },
+ request<{ items: PackagePolicy[] }>({
+ url: '/internal/osquery/fleet_wrapper/package_policies',
+ headers: {
+ 'Elastic-Api-Version': API_VERSIONS.internal.v1,
},
- }).then((pack) => {
- packId = pack.saved_object_id;
- packName = pack.name;
- });
+ })
+ .then((response) =>
+ loadPack({
+ policy_ids: [response.body.items[0].policy_id],
+ queries: {
+ [savedQueryName]: { ecs_mapping: {}, interval: 3600, query: 'select * from uptime;' },
+ },
+ })
+ )
+ .then((pack) => {
+ packId = pack.saved_object_id;
+ packName = pack.name;
+ });
});
after(() => {
@@ -430,15 +466,24 @@ describe('Packs - Create and Edit', () => {
let packName: string;
before(() => {
- loadPack({
- policy_ids: ['fleet-server-policy'],
- queries: {
- [savedQueryName]: { ecs_mapping: {}, interval: 3600, query: 'select * from uptime;' },
+ request<{ items: PackagePolicy[] }>({
+ url: '/internal/osquery/fleet_wrapper/package_policies',
+ headers: {
+ 'Elastic-Api-Version': API_VERSIONS.internal.v1,
},
- }).then((pack) => {
- packId = pack.saved_object_id;
- packName = pack.name;
- });
+ })
+ .then((response) =>
+ loadPack({
+ policy_ids: [response.body.items[0].policy_id],
+ queries: {
+ [savedQueryName]: { ecs_mapping: {}, interval: 3600, query: 'select * from uptime;' },
+ },
+ })
+ )
+ .then((pack) => {
+ packId = pack.saved_object_id;
+ packName = pack.name;
+ });
});
after(() => {
@@ -457,15 +502,24 @@ describe('Packs - Create and Edit', () => {
let packName: string;
before(() => {
- loadPack({
- policy_ids: ['fleet-server-policy'],
- queries: {
- [savedQueryName]: { ecs_mapping: {}, interval: 60, query: 'select * from uptime;' },
+ request<{ items: PackagePolicy[] }>({
+ url: '/internal/osquery/fleet_wrapper/package_policies',
+ headers: {
+ 'Elastic-Api-Version': API_VERSIONS.internal.v1,
},
- }).then((pack) => {
- packId = pack.saved_object_id;
- packName = pack.name;
- });
+ })
+ .then((response) =>
+ loadPack({
+ policy_ids: [response.body.items[0].policy_id],
+ queries: {
+ [savedQueryName]: { ecs_mapping: {}, interval: 60, query: 'select * from uptime;' },
+ },
+ })
+ )
+ .then((pack) => {
+ packId = pack.saved_object_id;
+ packName = pack.name;
+ });
});
after(() => {
@@ -515,15 +569,24 @@ describe('Packs - Create and Edit', () => {
let packName: string;
before(() => {
- loadPack({
- policy_ids: ['fleet-server-policy'],
- queries: {
- [savedQueryName]: { ecs_mapping: {}, interval: 3600, query: 'select * from uptime;' },
+ request<{ items: PackagePolicy[] }>({
+ url: '/internal/osquery/fleet_wrapper/package_policies',
+ headers: {
+ 'Elastic-Api-Version': API_VERSIONS.internal.v1,
},
- }).then((pack) => {
- packId = pack.saved_object_id;
- packName = pack.name;
- });
+ })
+ .then((response) =>
+ loadPack({
+ policy_ids: [response.body.items[0].policy_id],
+ queries: {
+ [savedQueryName]: { ecs_mapping: {}, interval: 3600, query: 'select * from uptime;' },
+ },
+ })
+ )
+ .then((pack) => {
+ packId = pack.saved_object_id;
+ packName = pack.name;
+ });
});
after(() => {
@@ -552,15 +615,24 @@ describe('Packs - Create and Edit', () => {
let packName: string;
before(() => {
- loadPack({
- policy_ids: ['fleet-server-policy'],
- queries: {
- [savedQueryName]: { ecs_mapping: {}, interval: 3600, query: 'select * from uptime;' },
+ request<{ items: PackagePolicy[] }>({
+ url: '/internal/osquery/fleet_wrapper/package_policies',
+ headers: {
+ 'Elastic-Api-Version': API_VERSIONS.internal.v1,
},
- }).then((pack) => {
- packId = pack.saved_object_id;
- packName = pack.name;
- });
+ })
+ .then((response) =>
+ loadPack({
+ policy_ids: [response.body.items[0].policy_id],
+ queries: {
+ [savedQueryName]: { ecs_mapping: {}, interval: 3600, query: 'select * from uptime;' },
+ },
+ })
+ )
+ .then((pack) => {
+ packId = pack.saved_object_id;
+ packName = pack.name;
+ });
});
after(() => {
@@ -609,14 +681,23 @@ describe('Packs - Create and Edit', () => {
let packName: string;
before(() => {
- loadPack({
- policy_ids: ['fleet-server-policy'],
- queries: {
- [savedQueryName]: { ecs_mapping: {}, interval: 3600, query: 'select * from uptime;' },
+ request<{ items: PackagePolicy[] }>({
+ url: '/internal/osquery/fleet_wrapper/package_policies',
+ headers: {
+ 'Elastic-Api-Version': API_VERSIONS.internal.v1,
},
- }).then((pack) => {
- packName = pack.name;
- });
+ })
+ .then((response) =>
+ loadPack({
+ policy_ids: [response.body.items[0].policy_id],
+ queries: {
+ [savedQueryName]: { ecs_mapping: {}, interval: 3600, query: 'select * from uptime;' },
+ },
+ })
+ )
+ .then((pack) => {
+ packName = pack.name;
+ });
});
it('', () => {
diff --git a/x-pack/plugins/osquery/cypress/e2e/all/packs_integration.cy.ts b/x-pack/plugins/osquery/cypress/e2e/all/packs_integration.cy.ts
index c29000a79d171..39c720525103a 100644
--- a/x-pack/plugins/osquery/cypress/e2e/all/packs_integration.cy.ts
+++ b/x-pack/plugins/osquery/cypress/e2e/all/packs_integration.cy.ts
@@ -117,7 +117,7 @@ describe('ALL - Packs', () => {
cy.contains('Edit').click();
findFormFieldByRowsLabelAndType(
'Scheduled agent policies (optional)',
- 'fleet server {downArrow}{enter}'
+ `${DEFAULT_POLICY} {downArrow}{enter}`
);
cy.contains('Update pack').click();
cy.getBySel('confirmModalConfirmButton').click();
@@ -284,7 +284,7 @@ describe('ALL - Packs', () => {
},
}).then((response) => {
const shardPolicy = response.body.items.find(
- (policy: PackagePolicy) => policy.policy_id === 'fleet-server-policy'
+ (policy: PackagePolicy) => policy.name === `Policy for ${DEFAULT_POLICY}`
);
expect(shardPolicy?.inputs[0].config?.osquery.value.packs[shardPack]).to.deep.equal({
diff --git a/x-pack/plugins/osquery/cypress/e2e/all/timelines.cy.ts b/x-pack/plugins/osquery/cypress/e2e/all/timelines.cy.ts
index f50fa298045df..c65f131185b29 100644
--- a/x-pack/plugins/osquery/cypress/e2e/all/timelines.cy.ts
+++ b/x-pack/plugins/osquery/cypress/e2e/all/timelines.cy.ts
@@ -18,7 +18,7 @@ describe('ALL - Timelines', () => {
cy.getBySel('flyoutBottomBar').within(() => {
cy.getBySel('flyoutOverlay').click();
});
- cy.getBySel('timelineQueryInput').type('_id:*{enter}');
+ cy.getBySel('timelineQueryInput').type('NOT host.name: "dev-fleet-server.8220"{enter}');
// Filter out alerts
cy.getBySel('timeline-sourcerer-trigger').click();
cy.getBySel('sourcerer-advanced-options-toggle').click();
diff --git a/x-pack/plugins/osquery/cypress/e2e/roles/alert_test.cy.ts b/x-pack/plugins/osquery/cypress/e2e/roles/alert_test.cy.ts
index 69ae9de00611d..e30f39ce4b77f 100644
--- a/x-pack/plugins/osquery/cypress/e2e/roles/alert_test.cy.ts
+++ b/x-pack/plugins/osquery/cypress/e2e/roles/alert_test.cy.ts
@@ -16,6 +16,7 @@ import { closeModalIfVisible, closeToastIfVisible } from '../../tasks/integratio
import { navigateTo } from '../../tasks/navigation';
import { loadPack, loadRule, cleanupRule, cleanupPack } from '../../tasks/api_fixtures';
import { preparePack } from '../../tasks/packs';
+import { DEFAULT_POLICY } from '../../screens/fleet';
describe('Alert Test', () => {
let packName: string;
@@ -65,7 +66,7 @@ describe('Alert Test', () => {
cy.contains(`Edit ${packName}`);
findFormFieldByRowsLabelAndType(
'Scheduled agent policies (optional)',
- 'fleet server {downArrow}{enter}'
+ `${DEFAULT_POLICY} {downArrow}{enter}`
);
findAndClickButton('Update pack');
closeModalIfVisible();
diff --git a/x-pack/plugins/osquery/cypress/screens/fleet.ts b/x-pack/plugins/osquery/cypress/screens/fleet.ts
index 4b819e5f523b1..0c419cff1c95f 100644
--- a/x-pack/plugins/osquery/cypress/screens/fleet.ts
+++ b/x-pack/plugins/osquery/cypress/screens/fleet.ts
@@ -9,5 +9,5 @@ export const ADD_AGENT_BUTTON = 'addAgentButton';
export const AGENT_POLICIES_TAB = 'fleet-agent-policies-tab';
export const ENROLLMENT_TOKENS_TAB = 'fleet-enrollment-tokens-tab';
-export const DEFAULT_POLICY = 'Fleet Server policy';
+export const DEFAULT_POLICY = 'Default policy';
export const OSQUERY_POLICY = 'Osquery policy';
diff --git a/x-pack/plugins/osquery/cypress/tasks/api_fixtures.ts b/x-pack/plugins/osquery/cypress/tasks/api_fixtures.ts
index 172f7a1cbedcc..91f32126b55e4 100644
--- a/x-pack/plugins/osquery/cypress/tasks/api_fixtures.ts
+++ b/x-pack/plugins/osquery/cypress/tasks/api_fixtures.ts
@@ -86,6 +86,7 @@ export const cleanupSavedQuery = (id: string) => {
headers: {
'Elastic-Api-Version': API_VERSIONS.public.v1,
},
+ failOnStatusCode: false,
});
};
@@ -112,6 +113,7 @@ export const cleanupPack = (id: string, space = 'default') => {
headers: {
'Elastic-Api-Version': API_VERSIONS.public.v1,
},
+ failOnStatusCode: false,
});
};
@@ -148,7 +150,30 @@ export const loadRule = (includeResponseActions = false) =>
'winlogbeat-*',
'-*elastic-cloud-logs-*',
],
- filters: [],
+ filters: [
+ {
+ meta: {
+ type: 'custom',
+ disabled: false,
+ negate: false,
+ alias: null,
+ key: 'query',
+ value: '{"bool":{"must_not":{"wildcard":{"host.name":"dev-fleet-server.*"}}}}',
+ },
+ query: {
+ bool: {
+ must_not: {
+ wildcard: {
+ 'host.name': 'dev-fleet-server.*',
+ },
+ },
+ },
+ },
+ $state: {
+ store: 'appState',
+ },
+ },
+ ],
language: 'kuery',
query: '_id:*',
author: [],
@@ -205,6 +230,7 @@ export const cleanupRule = (id: string) => {
headers: {
'Elastic-Api-Version': API_VERSIONS.public.v1,
},
+ failOnStatusCode: false,
});
};
diff --git a/x-pack/plugins/osquery/cypress/tasks/inventory.ts b/x-pack/plugins/osquery/cypress/tasks/inventory.ts
index 933efd91d79ce..30ffdede7a347 100644
--- a/x-pack/plugins/osquery/cypress/tasks/inventory.ts
+++ b/x-pack/plugins/osquery/cypress/tasks/inventory.ts
@@ -9,7 +9,7 @@ export const triggerLoadData = () => {
cy.getBySel('infraWaffleTimeControlsAutoRefreshButton').should('exist');
cy.wait(1000);
cy.getBySel('infraWaffleTimeControlsAutoRefreshButton').click();
- cy.getBySel('nodeContainer').first().should('exist');
+ cy.getBySel('nodeContainer').eq(2).should('exist');
cy.getBySel('infraWaffleTimeControlsStopRefreshingButton').click();
- cy.getBySel('nodeContainer').first().click();
+ cy.getBySel('nodeContainer').eq(2).click();
};
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;
};
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/**/*",
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/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/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/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
diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json
index 9bef8ead17f65..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 ?",
@@ -3509,7 +3508,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..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": "ダッシュボードをリセットしますか?",
@@ -3524,7 +3523,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..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": "重置仪表板?",
@@ -3523,7 +3522,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": "[航班] 机场航线(将鼠标悬停在机场上)",
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');
});
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 }],
diff --git a/x-pack/test/osquery_cypress/agent.ts b/x-pack/test/osquery_cypress/agent.ts
index 323ed0e0098c6..07ee5e79d9635 100644
--- a/x-pack/test/osquery_cypress/agent.ts
+++ b/x-pack/test/osquery_cypress/agent.ts
@@ -7,60 +7,25 @@
import { ToolingLog } from '@kbn/tooling-log';
import execa from 'execa';
-import { KbnClient } from '@kbn/test';
-import {
- GetEnrollmentAPIKeysResponse,
- CreateAgentPolicyResponse,
-} from '@kbn/fleet-plugin/common/types';
+
import { getLatestVersion } from './artifact_manager';
import { Manager } from './resource_manager';
-import { addIntegrationToAgentPolicy } from './utils';
export class AgentManager extends Manager {
private log: ToolingLog;
- private kbnClient: KbnClient;
+ private policyEnrollmentKey: string;
private fleetServerPort: string;
private agentContainerId?: string;
- constructor(kbnClient: KbnClient, fleetServerPort: string, log: ToolingLog) {
+ constructor(policyEnrollmentKey: string, fleetServerPort: string, log: ToolingLog) {
super();
this.log = log;
this.fleetServerPort = fleetServerPort;
- this.kbnClient = kbnClient;
+ this.policyEnrollmentKey = policyEnrollmentKey;
}
public async setup() {
this.log.info('Running agent preconfig');
- const agentPolicyName = 'Osquery policy';
-
- const {
- data: {
- item: { id: agentPolicyId },
- },
- } = await this.kbnClient.request({
- method: 'POST',
- path: `/api/fleet/agent_policies?sys_monitoring=true`,
- body: {
- name: agentPolicyName,
- description: '',
- namespace: 'default',
- monitoring_enabled: ['logs', 'metrics'],
- inactivity_timeout: 1209600,
- },
- });
-
- this.log.info(`Adding integration to ${agentPolicyId}`);
-
- await addIntegrationToAgentPolicy(this.kbnClient, agentPolicyId, agentPolicyName);
-
- this.log.info('Getting agent enrollment key');
- const { data: apiKeys } = await this.kbnClient.request({
- method: 'GET',
- path: '/api/fleet/enrollment_api_keys',
- });
- const policy = apiKeys.items[0];
-
- this.log.info('Running the agent');
const artifact = `docker.elastic.co/beats/elastic-agent:${await getLatestVersion()}`;
this.log.info(artifact);
@@ -75,7 +40,7 @@ export class AgentManager extends Manager {
'--env',
`FLEET_URL=https://host.docker.internal:${this.fleetServerPort}`,
'--env',
- `FLEET_ENROLLMENT_TOKEN=${policy.api_key}`,
+ `FLEET_ENROLLMENT_TOKEN=${this.policyEnrollmentKey}`,
'--env',
'FLEET_INSECURE=true',
'--rm',
@@ -83,8 +48,6 @@ export class AgentManager extends Manager {
];
this.agentContainerId = (await execa('docker', dockerArgs)).stdout;
-
- return { policyId: policy.policy_id as string };
}
public cleanup() {
diff --git a/x-pack/test/osquery_cypress/fleet_server.ts b/x-pack/test/osquery_cypress/fleet_server.ts
index dce159ae27305..f1fa7a174ae37 100644
--- a/x-pack/test/osquery_cypress/fleet_server.ts
+++ b/x-pack/test/osquery_cypress/fleet_server.ts
@@ -8,19 +8,15 @@
import { ToolingLog } from '@kbn/tooling-log';
import execa from 'execa';
import { runFleetServerIfNeeded } from '@kbn/security-solution-plugin/scripts/endpoint/endpoint_agent_runner/fleet_server';
-import { KbnClient } from '@kbn/test';
import { Manager } from './resource_manager';
-import { addIntegrationToAgentPolicy } from './utils';
export class FleetManager extends Manager {
private fleetContainerId?: string;
private log: ToolingLog;
- private kbnClient: KbnClient;
- constructor(kbnClient: KbnClient, log: ToolingLog) {
+ constructor(log: ToolingLog) {
super();
this.log = log;
- this.kbnClient = kbnClient;
}
public async setup(): Promise {
@@ -30,13 +26,6 @@ export class FleetManager extends Manager {
throw new Error('Fleet server config not found');
}
- await addIntegrationToAgentPolicy(
- this.kbnClient,
- 'fleet-server-policy',
- 'Default Fleet Server Policy',
- 'osquery_manager'
- );
-
this.fleetContainerId = fleetServerConfig.fleetServerContainerId;
}
diff --git a/x-pack/test/osquery_cypress/runner.ts b/x-pack/test/osquery_cypress/runner.ts
index fcead589247a6..08162b4670350 100644
--- a/x-pack/test/osquery_cypress/runner.ts
+++ b/x-pack/test/osquery_cypress/runner.ts
@@ -12,7 +12,7 @@ import { FtrProviderContext } from './ftr_provider_context';
import { AgentManager } from './agent';
import { FleetManager } from './fleet_server';
-import { getLatestAvailableAgentVersion } from './utils';
+import { createAgentPolicy, getLatestAvailableAgentVersion } from './utils';
async function setupFleetAgent({ getService }: FtrProviderContext) {
const log = getService('log');
@@ -39,11 +39,17 @@ async function setupFleetAgent({ getService }: FtrProviderContext) {
version: await getLatestAvailableAgentVersion(kbnClient),
});
- const fleetManager = new FleetManager(kbnClient, log);
- const agentManager = new AgentManager(kbnClient, config.get('servers.fleetserver.port'), log);
+ await new FleetManager(log).setup();
- await fleetManager.setup();
- await agentManager.setup();
+ const policyEnrollmentKey = await createAgentPolicy(kbnClient, log, 'Default policy');
+ const policyEnrollmentKeyTwo = await createAgentPolicy(kbnClient, log, 'Osquery policy');
+
+ await new AgentManager(policyEnrollmentKey, config.get('servers.fleetserver.port'), log).setup();
+ await new AgentManager(
+ policyEnrollmentKeyTwo,
+ config.get('servers.fleetserver.port'),
+ log
+ ).setup();
}
export async function startOsqueryCypress(context: FtrProviderContext) {
diff --git a/x-pack/test/osquery_cypress/utils.ts b/x-pack/test/osquery_cypress/utils.ts
index 5fbbdd7131f53..84c591dbc58bb 100644
--- a/x-pack/test/osquery_cypress/utils.ts
+++ b/x-pack/test/osquery_cypress/utils.ts
@@ -10,6 +10,11 @@ import semver from 'semver';
import { map } from 'lodash';
import { PackagePolicy, CreatePackagePolicyResponse } from '@kbn/fleet-plugin/common';
import { KbnClient } from '@kbn/test';
+import {
+ GetEnrollmentAPIKeysResponse,
+ CreateAgentPolicyResponse,
+} from '@kbn/fleet-plugin/common/types';
+import { ToolingLog } from '@kbn/tooling-log';
export const getInstalledIntegration = async (kbnClient: KbnClient, integrationName: string) => {
const {
@@ -22,6 +27,42 @@ export const getInstalledIntegration = async (kbnClient: KbnClient, integrationN
return item;
};
+export const createAgentPolicy = async (
+ kbnClient: KbnClient,
+ log: ToolingLog,
+ agentPolicyName = 'Osquery policy'
+) => {
+ log.info(`Creating "${agentPolicyName}" agent policy`);
+
+ const {
+ data: {
+ item: { id: agentPolicyId },
+ },
+ } = await kbnClient.request({
+ method: 'POST',
+ path: `/api/fleet/agent_policies?sys_monitoring=true`,
+ body: {
+ name: agentPolicyName,
+ description: '',
+ namespace: 'default',
+ monitoring_enabled: ['logs', 'metrics'],
+ inactivity_timeout: 1209600,
+ },
+ });
+
+ log.info(`Adding integration to ${agentPolicyId}`);
+
+ await addIntegrationToAgentPolicy(kbnClient, agentPolicyId, agentPolicyName);
+
+ log.info('Getting agent enrollment key');
+ const { data: apiKeys } = await kbnClient.request({
+ method: 'GET',
+ path: '/api/fleet/enrollment_api_keys',
+ });
+
+ return apiKeys.items[0].api_key;
+};
+
export const addIntegrationToAgentPolicy = async (
kbnClient: KbnClient,
agentPolicyId: string,
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'] });
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);
-};
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'],
},
],