boolean | Whether or not the request is a "system request" rather than an application-level request. Can be set on the client using the HttpFetchOptions#asSystemRequest
option. |
| [params](./kibana-plugin-core-server.kibanarequest.params.md) | | Params
| |
| [query](./kibana-plugin-core-server.kibanarequest.query.md) | | Query
| |
-| [rewrittenUrl](./kibana-plugin-core-server.kibanarequest.rewrittenurl.md) | | Url
| URL rewritten in onPreRouting request interceptor. |
+| [rewrittenUrl](./kibana-plugin-core-server.kibanarequest.rewrittenurl.md) | | URL
| URL rewritten in onPreRouting request interceptor. |
| [route](./kibana-plugin-core-server.kibanarequest.route.md) | | RecursiveReadonly<KibanaRequestRoute<Method>>
| matched route details |
| [socket](./kibana-plugin-core-server.kibanarequest.socket.md) | | IKibanaSocket
| [IKibanaSocket](./kibana-plugin-core-server.ikibanasocket.md) |
-| [url](./kibana-plugin-core-server.kibanarequest.url.md) | | Url
| a WHATWG URL standard object. |
+| [url](./kibana-plugin-core-server.kibanarequest.url.md) | | URL
| a WHATWG URL standard object. |
| [uuid](./kibana-plugin-core-server.kibanarequest.uuid.md) | | string
| A UUID to identify this request. |
diff --git a/docs/development/core/server/kibana-plugin-core-server.kibanarequest.rewrittenurl.md b/docs/development/core/server/kibana-plugin-core-server.kibanarequest.rewrittenurl.md
index 10628bafaf1d4..fb547330ee6ea 100644
--- a/docs/development/core/server/kibana-plugin-core-server.kibanarequest.rewrittenurl.md
+++ b/docs/development/core/server/kibana-plugin-core-server.kibanarequest.rewrittenurl.md
@@ -9,5 +9,5 @@ URL rewritten in onPreRouting request interceptor.
Signature:
```typescript
-readonly rewrittenUrl?: Url;
+readonly rewrittenUrl?: URL;
```
diff --git a/docs/development/core/server/kibana-plugin-core-server.kibanarequest.url.md b/docs/development/core/server/kibana-plugin-core-server.kibanarequest.url.md
index 31d1348197201..b72760e272bb2 100644
--- a/docs/development/core/server/kibana-plugin-core-server.kibanarequest.url.md
+++ b/docs/development/core/server/kibana-plugin-core-server.kibanarequest.url.md
@@ -9,5 +9,5 @@ a WHATWG URL standard object.
Signature:
```typescript
-readonly url: Url;
+readonly url: URL;
```
diff --git a/src/core/server/http/http_server.mocks.ts b/src/core/server/http/http_server.mocks.ts
index 6aad232cf42b6..d615e799f383f 100644
--- a/src/core/server/http/http_server.mocks.ts
+++ b/src/core/server/http/http_server.mocks.ts
@@ -16,6 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
+import { parse as parseUrl } from 'url';
import { Request } from 'hapi';
import { merge } from 'lodash';
import { Socket } from 'net';
@@ -72,6 +73,7 @@ function createKibanaRequestMock({
auth = { isAuthenticated: true },
}: RequestFixtureOptions
= {}) {
const queryString = stringify(query, { sort: false });
+ const url = parseUrl(`${path}${queryString ? `?${queryString}` : ''}`);
return KibanaRequest.from
(
createRawRequestMock({
@@ -83,12 +85,7 @@ function createKibanaRequestMock
({
payload: body,
path,
method,
- url: {
- path,
- pathname: path,
- query: queryString,
- search: queryString ? `?${queryString}` : queryString,
- },
+ url,
route: {
settings: { tags: routeTags, auth: routeAuthRequired, app: kibanaRouteOptions },
},
@@ -121,6 +118,11 @@ interface DeepPartialArray extends Array> {}
type DeepPartialObject = { [P in keyof T]+?: DeepPartial };
function createRawRequestMock(customization: DeepPartial = {}) {
+ const pathname = customization.url?.pathname || '/';
+ const path = `${pathname}${customization.url?.search || ''}`;
+ const url = Object.assign({ pathname, path, href: path }, customization.url);
+
+ // @ts-expect-error _core isn't supposed to be accessed - remove once we upgrade to hapi v18
return merge(
{},
{
@@ -129,17 +131,21 @@ function createRawRequestMock(customization: DeepPartial = {}) {
isAuthenticated: true,
},
headers: {},
- path: '/',
+ path,
route: { settings: {} },
- url: {
- href: '/',
- },
+ url,
raw: {
req: {
- url: '/',
+ url: path,
socket: {},
},
},
+ // TODO: Remove once we upgrade to hapi v18
+ _core: {
+ info: {
+ uri: 'http://localhost',
+ },
+ },
},
customization
) as Request;
diff --git a/src/core/server/http/http_server.ts b/src/core/server/http/http_server.ts
index 2440f2b1da0bd..d94bce12fb439 100644
--- a/src/core/server/http/http_server.ts
+++ b/src/core/server/http/http_server.ts
@@ -271,7 +271,7 @@ export class HttpServer {
}
this.registerOnPreRouting((request, response, toolkit) => {
- const oldUrl = request.url.href!;
+ const oldUrl = request.url.pathname + request.url.search;
const newURL = basePathService.remove(oldUrl);
const shouldRedirect = newURL !== oldUrl;
if (shouldRedirect) {
diff --git a/src/core/server/http/integration_tests/lifecycle.test.ts b/src/core/server/http/integration_tests/lifecycle.test.ts
index 01817b29de8ac..37401a2c24ccd 100644
--- a/src/core/server/http/integration_tests/lifecycle.test.ts
+++ b/src/core/server/http/integration_tests/lifecycle.test.ts
@@ -124,7 +124,13 @@ describe('OnPreRouting', () => {
const router = createRouter('/');
router.get({ path: '/login', validate: false }, (context, req, res) => {
- return res.ok({ body: { rewrittenUrl: req.rewrittenUrl?.path } });
+ return res.ok({
+ body: {
+ rewrittenUrl: req.rewrittenUrl
+ ? `${req.rewrittenUrl.pathname}${req.rewrittenUrl.search}`
+ : undefined,
+ },
+ });
});
registerOnPreRouting((req, res, t) => t.rewriteUrl('/login'));
@@ -143,7 +149,13 @@ describe('OnPreRouting', () => {
const router = createRouter('/');
router.get({ path: '/reroute-2', validate: false }, (context, req, res) => {
- return res.ok({ body: { rewrittenUrl: req.rewrittenUrl?.path } });
+ return res.ok({
+ body: {
+ rewrittenUrl: req.rewrittenUrl
+ ? `${req.rewrittenUrl.pathname}${req.rewrittenUrl.search}`
+ : undefined,
+ },
+ });
});
registerOnPreRouting((req, res, t) => t.rewriteUrl('/reroute-1'));
@@ -163,7 +175,13 @@ describe('OnPreRouting', () => {
const router = createRouter('/');
router.get({ path: '/login', validate: false }, (context, req, res) => {
- return res.ok({ body: { rewrittenUrl: req.rewrittenUrl?.path } });
+ return res.ok({
+ body: {
+ rewrittenUrl: req.rewrittenUrl
+ ? `${req.rewrittenUrl.pathname}${req.rewrittenUrl.search}`
+ : undefined,
+ },
+ });
});
registerOnPreRouting((req, res, t) => t.next());
diff --git a/src/core/server/http/lifecycle/on_pre_routing.ts b/src/core/server/http/lifecycle/on_pre_routing.ts
index 92ae1f0b7bbdf..e553f113a7cf8 100644
--- a/src/core/server/http/lifecycle/on_pre_routing.ts
+++ b/src/core/server/http/lifecycle/on_pre_routing.ts
@@ -17,6 +17,7 @@
* under the License.
*/
+import { URL } from 'url';
import { Lifecycle, Request, ResponseToolkit as HapiResponseToolkit } from 'hapi';
import { Logger } from '../../logging';
import {
@@ -110,10 +111,30 @@ export function adoptToHapiOnRequest(fn: OnPreRoutingHandler, log: Logger) {
if (preRoutingResult.isRewriteUrl(result)) {
const appState = request.app as KibanaRequestState;
- appState.rewrittenUrl = appState.rewrittenUrl ?? request.url;
+ appState.rewrittenUrl =
+ // @ts-expect-error request._core isn't supposed to be accessed - remove once we upgrade to hapi v18
+ appState.rewrittenUrl ?? new URL(request.url.href!, request._core.info.uri);
const { url } = result;
- request.setUrl(url);
+
+ // TODO: Remove once we upgrade to Node.js 12!
+ //
+ // Warning: The following for-loop took 10 days to write, and is a hack
+ // to force V8 to make a copy of the string in memory.
+ //
+ // The reason why we need this is because of what appears to be a bug
+ // in V8 that caused some URL paths to not be routed correctly once
+ // `request.setUrl` was called with the path.
+ //
+ // The details can be seen in this discussion on Twitter:
+ // https://twitter.com/wa7son/status/1319992632366518277
+ let urlCopy = '';
+ for (let i = 0; i < url.length; i++) {
+ urlCopy += url[i];
+ }
+
+ request.setUrl(urlCopy);
+
// We should update raw request as well since it can be proxied to the old platform
request.raw.req.url = url;
return responseToolkit.continue;
diff --git a/src/core/server/http/router/request.ts b/src/core/server/http/router/request.ts
index 2d0e8d6c1a6ad..561bf742050c3 100644
--- a/src/core/server/http/router/request.ts
+++ b/src/core/server/http/router/request.ts
@@ -17,7 +17,7 @@
* under the License.
*/
-import { Url } from 'url';
+import { URL } from 'url';
import uuid from 'uuid';
import { Request, RouteOptionsApp, ApplicationState } from 'hapi';
import { Observable, fromEvent, merge } from 'rxjs';
@@ -45,7 +45,7 @@ export interface KibanaRouteOptions extends RouteOptionsApp {
export interface KibanaRequestState extends ApplicationState {
requestId: string;
requestUuid: string;
- rewrittenUrl?: Url;
+ rewrittenUrl?: URL;
}
/**
@@ -163,7 +163,7 @@ export class KibanaRequest<
*/
public readonly uuid: string;
/** a WHATWG URL standard object. */
- public readonly url: Url;
+ public readonly url: URL;
/** matched route details */
public readonly route: RecursiveReadonly>;
/**
@@ -190,7 +190,7 @@ export class KibanaRequest<
/**
* URL rewritten in onPreRouting request interceptor.
*/
- public readonly rewrittenUrl?: Url;
+ public readonly rewrittenUrl?: URL;
/** @internal */
protected readonly [requestSymbol]: Request;
@@ -212,7 +212,8 @@ export class KibanaRequest<
this.uuid = appState?.requestUuid ?? uuid.v4();
this.rewrittenUrl = appState?.rewrittenUrl;
- this.url = request.url;
+ // @ts-expect-error request._core isn't supposed to be accessed - remove once we upgrade to hapi v18
+ this.url = new URL(request.url.href!, request._core.info.uri);
this.headers = deepFreeze({ ...request.headers });
this.isSystemRequest =
request.headers['kbn-system-request'] === 'true' ||
@@ -304,8 +305,8 @@ export class KibanaRequest<
if (authOptions === false) return false;
throw new Error(
`unexpected authentication options: ${JSON.stringify(authOptions)} for route: ${
- this.url.href
- }`
+ this.url.pathname
+ }${this.url.search}`
);
}
}
diff --git a/src/core/server/server.api.md b/src/core/server/server.api.md
index d9dc46d2cad99..914b5fbdb5196 100644
--- a/src/core/server/server.api.md
+++ b/src/core/server/server.api.md
@@ -162,7 +162,7 @@ import { Type } from '@kbn/config-schema';
import { TypeOf } from '@kbn/config-schema';
import { UpdateDocumentByQueryParams } from 'elasticsearch';
import { UpdateDocumentParams } from 'elasticsearch';
-import { Url } from 'url';
+import { URL } from 'url';
// @public
export interface AppCategory {
@@ -1007,11 +1007,11 @@ export class KibanaRequest>;
// (undocumented)
readonly socket: IKibanaSocket;
- readonly url: Url;
+ readonly url: URL;
readonly uuid: string;
}
diff --git a/x-pack/plugins/actions/server/lib/task_runner_factory.test.ts b/x-pack/plugins/actions/server/lib/task_runner_factory.test.ts
index 18cbd9f9c5fad..c8e2684651598 100644
--- a/x-pack/plugins/actions/server/lib/task_runner_factory.test.ts
+++ b/x-pack/plugins/actions/server/lib/task_runner_factory.test.ts
@@ -145,6 +145,12 @@ test('executes the task by calling the executor with proper parameters', async (
url: '/',
},
},
+ // TODO: Remove once we upgrade to hapi v18
+ _core: {
+ info: {
+ uri: 'http://localhost',
+ },
+ },
},
});
});
@@ -271,6 +277,12 @@ test('uses API key when provided', async () => {
url: '/',
},
},
+ // TODO: Remove once we upgrade to hapi v18
+ _core: {
+ info: {
+ uri: 'http://localhost',
+ },
+ },
},
});
});
@@ -310,6 +322,12 @@ test(`doesn't use API key when not provided`, async () => {
url: '/',
},
},
+ // TODO: Remove once we upgrade to hapi v18
+ _core: {
+ info: {
+ uri: 'http://localhost',
+ },
+ },
},
});
});
diff --git a/x-pack/plugins/actions/server/lib/task_runner_factory.ts b/x-pack/plugins/actions/server/lib/task_runner_factory.ts
index aeeeb4ed7d520..93ae5a2c807f9 100644
--- a/x-pack/plugins/actions/server/lib/task_runner_factory.ts
+++ b/x-pack/plugins/actions/server/lib/task_runner_factory.ts
@@ -102,6 +102,12 @@ export class TaskRunnerFactory {
url: '/',
},
},
+ // TODO: Remove once we upgrade to hapi v18
+ _core: {
+ info: {
+ uri: 'http://localhost',
+ },
+ },
} as unknown) as KibanaRequest;
let executorResult: ActionTypeExecutorResult;
diff --git a/x-pack/plugins/alerts/server/alerts_client_factory.test.ts b/x-pack/plugins/alerts/server/alerts_client_factory.test.ts
index 55c2f3ddd18a4..4e457cdb12bd3 100644
--- a/x-pack/plugins/alerts/server/alerts_client_factory.test.ts
+++ b/x-pack/plugins/alerts/server/alerts_client_factory.test.ts
@@ -60,6 +60,12 @@ const fakeRequest = ({
url: '/',
},
},
+ // TODO: Remove once we upgrade to hapi v18
+ _core: {
+ info: {
+ uri: 'http://localhost',
+ },
+ },
getSavedObjectsClient: () => savedObjectsClient,
} as unknown) as Request;
diff --git a/x-pack/plugins/alerts/server/plugin.test.ts b/x-pack/plugins/alerts/server/plugin.test.ts
index b13a1c62f6602..ece7d31d2f7fd 100644
--- a/x-pack/plugins/alerts/server/plugin.test.ts
+++ b/x-pack/plugins/alerts/server/plugin.test.ts
@@ -149,6 +149,12 @@ describe('Alerting Plugin', () => {
url: '/',
},
},
+ // TODO: Remove once we upgrade to hapi v18
+ _core: {
+ info: {
+ uri: 'http://localhost',
+ },
+ },
getSavedObjectsClient: jest.fn(),
} as unknown) as KibanaRequest;
await startContract.getAlertsClientWithRequest(fakeRequest);
diff --git a/x-pack/plugins/alerts/server/task_runner/task_runner.test.ts b/x-pack/plugins/alerts/server/task_runner/task_runner.test.ts
index 8e345d6ff66a8..17d5fcd31b745 100644
--- a/x-pack/plugins/alerts/server/task_runner/task_runner.test.ts
+++ b/x-pack/plugins/alerts/server/task_runner/task_runner.test.ts
@@ -364,6 +364,12 @@ describe('Task Runner', () => {
url: '/',
},
},
+ // TODO: Remove once we upgrade to hapi v18
+ _core: {
+ info: {
+ uri: 'http://localhost',
+ },
+ },
});
expect(actionsClient.enqueueExecution).toHaveBeenCalledTimes(1);
expect(actionsClient.enqueueExecution.mock.calls[0]).toMatchInlineSnapshot(`
@@ -662,6 +668,12 @@ describe('Task Runner', () => {
url: '/',
},
},
+ // TODO: Remove once we upgrade to hapi v18
+ _core: {
+ info: {
+ uri: 'http://localhost',
+ },
+ },
});
});
@@ -694,6 +706,12 @@ describe('Task Runner', () => {
url: '/',
},
},
+ // TODO: Remove once we upgrade to hapi v18
+ _core: {
+ info: {
+ uri: 'http://localhost',
+ },
+ },
});
});
diff --git a/x-pack/plugins/alerts/server/task_runner/task_runner.ts b/x-pack/plugins/alerts/server/task_runner/task_runner.ts
index 954c5675df89c..76125da20d552 100644
--- a/x-pack/plugins/alerts/server/task_runner/task_runner.ts
+++ b/x-pack/plugins/alerts/server/task_runner/task_runner.ts
@@ -101,6 +101,12 @@ export class TaskRunner {
url: '/',
},
},
+ // TODO: Remove once we upgrade to hapi v18
+ _core: {
+ info: {
+ uri: 'http://localhost',
+ },
+ },
} as unknown) as KibanaRequest;
}
diff --git a/x-pack/plugins/dashboard_mode/server/interceptors/dashboard_mode_request_interceptor.test.ts b/x-pack/plugins/dashboard_mode/server/interceptors/dashboard_mode_request_interceptor.test.ts
index 67fc1a98ad4d1..4b1e4b34da86a 100644
--- a/x-pack/plugins/dashboard_mode/server/interceptors/dashboard_mode_request_interceptor.test.ts
+++ b/x-pack/plugins/dashboard_mode/server/interceptors/dashboard_mode_request_interceptor.test.ts
@@ -4,6 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
+import { parse as parseUrl } from 'url';
import {
OnPostAuthHandler,
OnPostAuthToolkit,
@@ -45,7 +46,7 @@ describe('DashboardOnlyModeRequestInterceptor', () => {
test('should not redirects for not app/* requests', async () => {
const request = ({
url: {
- path: 'api/test',
+ pathname: 'api/test',
},
} as unknown) as KibanaRequest;
@@ -57,7 +58,7 @@ describe('DashboardOnlyModeRequestInterceptor', () => {
test('should not redirects not authenticated users', async () => {
const request = ({
url: {
- path: '/app/home',
+ pathname: '/app/home',
},
} as unknown) as KibanaRequest;
@@ -70,10 +71,9 @@ describe('DashboardOnlyModeRequestInterceptor', () => {
function testRedirectToDashboardModeApp(url: string) {
describe(`requests to url:"${url}"`, () => {
test('redirects to the dashboard_mode app instead', async () => {
+ const { pathname, search, hash } = parseUrl(url);
const request = ({
- url: {
- path: url,
- },
+ url: { pathname, search, hash },
credentials: {
roles: [DASHBOARD_ONLY_MODE_ROLE],
},
diff --git a/x-pack/plugins/dashboard_mode/server/interceptors/dashboard_mode_request_interceptor.ts b/x-pack/plugins/dashboard_mode/server/interceptors/dashboard_mode_request_interceptor.ts
index 4378c818f087c..9978d18142ff5 100644
--- a/x-pack/plugins/dashboard_mode/server/interceptors/dashboard_mode_request_interceptor.ts
+++ b/x-pack/plugins/dashboard_mode/server/interceptors/dashboard_mode_request_interceptor.ts
@@ -22,7 +22,7 @@ export const setupDashboardModeRequestInterceptor = ({
getUiSettingsClient,
}: DashboardModeRequestInterceptorDependencies) =>
(async (request, response, toolkit) => {
- const path = request.url.path || '';
+ const path = request.url.pathname;
const isAppRequest = path.startsWith('/app/');
if (!isAppRequest) {
diff --git a/x-pack/plugins/enterprise_search/server/lib/enterprise_search_config_api.test.ts b/x-pack/plugins/enterprise_search/server/lib/enterprise_search_config_api.test.ts
index 2bddc9f1c80bd..5bd15ce411002 100644
--- a/x-pack/plugins/enterprise_search/server/lib/enterprise_search_config_api.test.ts
+++ b/x-pack/plugins/enterprise_search/server/lib/enterprise_search_config_api.test.ts
@@ -21,7 +21,6 @@ describe('callEnterpriseSearchConfigAPI', () => {
accessCheckTimeoutWarning: 100,
};
const mockRequest = {
- url: { path: '/app/kibana' },
headers: { authorization: '==someAuth' },
};
const mockDependencies = {
diff --git a/x-pack/plugins/event_log/server/event_log_client.test.ts b/x-pack/plugins/event_log/server/event_log_client.test.ts
index d6793be425585..d9846428b9488 100644
--- a/x-pack/plugins/event_log/server/event_log_client.test.ts
+++ b/x-pack/plugins/event_log/server/event_log_client.test.ts
@@ -322,6 +322,12 @@ function FakeRequest(): KibanaRequest {
url: '/',
},
},
+ // TODO: Remove once we upgrade to hapi v18
+ _core: {
+ info: {
+ uri: 'http://localhost',
+ },
+ },
getSavedObjectsClient: () => savedObjectGetter,
} as unknown) as KibanaRequest;
}
diff --git a/x-pack/plugins/event_log/server/event_log_start_service.test.ts b/x-pack/plugins/event_log/server/event_log_start_service.test.ts
index 0a5b169e87d4d..db6f4a1ad0f27 100644
--- a/x-pack/plugins/event_log/server/event_log_start_service.test.ts
+++ b/x-pack/plugins/event_log/server/event_log_start_service.test.ts
@@ -56,6 +56,12 @@ function fakeRequest(): KibanaRequest {
url: '/',
},
},
+ // TODO: Remove once we upgrade to hapi v18
+ _core: {
+ info: {
+ uri: 'http://localhost',
+ },
+ },
getSavedObjectsClient: () => savedObjectsClient,
} as unknown) as KibanaRequest;
}
diff --git a/x-pack/plugins/event_log/server/saved_object_provider_registry.test.ts b/x-pack/plugins/event_log/server/saved_object_provider_registry.test.ts
index 6a02d54c87514..076260ab2fe53 100644
--- a/x-pack/plugins/event_log/server/saved_object_provider_registry.test.ts
+++ b/x-pack/plugins/event_log/server/saved_object_provider_registry.test.ts
@@ -93,6 +93,12 @@ function fakeRequest(): KibanaRequest {
url: '/',
},
},
+ // TODO: Remove once we upgrade to hapi v18
+ _core: {
+ info: {
+ uri: 'http://localhost',
+ },
+ },
getSavedObjectsClient: () => savedObjectsClient,
} as unknown) as KibanaRequest;
}
diff --git a/x-pack/plugins/ingest_manager/server/services/agent_policy_update.ts b/x-pack/plugins/ingest_manager/server/services/agent_policy_update.ts
index fe06de765bbff..1ad710ba70e29 100644
--- a/x-pack/plugins/ingest_manager/server/services/agent_policy_update.ts
+++ b/x-pack/plugins/ingest_manager/server/services/agent_policy_update.ts
@@ -23,6 +23,12 @@ const fakeRequest = ({
url: '/',
},
},
+ // TODO: Remove once we upgrade to hapi v18
+ _core: {
+ info: {
+ uri: 'http://localhost',
+ },
+ },
} as unknown) as KibanaRequest;
export async function agentPolicyUpdateEventHandler(
diff --git a/x-pack/plugins/ingest_manager/server/services/agents/checkin/state_connected_agents.ts b/x-pack/plugins/ingest_manager/server/services/agents/checkin/state_connected_agents.ts
index 994ecc64c82a7..b9ef36ecaae54 100644
--- a/x-pack/plugins/ingest_manager/server/services/agents/checkin/state_connected_agents.ts
+++ b/x-pack/plugins/ingest_manager/server/services/agents/checkin/state_connected_agents.ts
@@ -23,6 +23,12 @@ function getInternalUserSOClient() {
url: '/',
},
},
+ // TODO: Remove once we upgrade to hapi v18
+ _core: {
+ info: {
+ uri: 'http://localhost',
+ },
+ },
} as unknown) as KibanaRequest;
return appContextService.getInternalUserSOClient(fakeRequest);
diff --git a/x-pack/plugins/ingest_manager/server/services/agents/checkin/state_new_actions.ts b/x-pack/plugins/ingest_manager/server/services/agents/checkin/state_new_actions.ts
index aa48d8fe18e9f..c0e8540004930 100644
--- a/x-pack/plugins/ingest_manager/server/services/agents/checkin/state_new_actions.ts
+++ b/x-pack/plugins/ingest_manager/server/services/agents/checkin/state_new_actions.ts
@@ -58,6 +58,12 @@ function getInternalUserSOClient() {
url: '/',
},
},
+ // TODO: Remove once we upgrade to hapi v18
+ _core: {
+ info: {
+ uri: 'http://localhost',
+ },
+ },
} as unknown) as KibanaRequest;
return appContextService.getInternalUserSOClient(fakeRequest);
diff --git a/x-pack/plugins/ml/server/routes/data_frame_analytics.ts b/x-pack/plugins/ml/server/routes/data_frame_analytics.ts
index e0f1b01dafa13..48aed19ea9050 100644
--- a/x-pack/plugins/ml/server/routes/data_frame_analytics.ts
+++ b/x-pack/plugins/ml/server/routes/data_frame_analytics.ts
@@ -456,16 +456,10 @@ export function dataFrameAnalyticsRoutes({ router, mlLicense }: RouteInitializat
},
mlLicense.fullLicenseAPIGuard(async ({ client, request, response }) => {
try {
- const options: { id: string; force?: boolean | undefined } = {
+ const { body } = await client.asInternalUser.ml.stopDataFrameAnalytics({
id: request.params.analyticsId,
- };
- // @ts-expect-error TODO: update types
- if (request.url?.query?.force !== undefined) {
- // @ts-expect-error TODO: update types
- options.force = request.url.query.force;
- }
-
- const { body } = await client.asInternalUser.ml.stopDataFrameAnalytics(options);
+ force: request.query.force,
+ });
return response.ok({
body,
});
diff --git a/x-pack/plugins/reporting/server/core.ts b/x-pack/plugins/reporting/server/core.ts
index abd86d51fb6b6..d62adc62bc9aa 100644
--- a/x-pack/plugins/reporting/server/core.ts
+++ b/x-pack/plugins/reporting/server/core.ts
@@ -210,11 +210,18 @@ export class ReportingCore {
}
public getFakeRequest(baseRequest: object, spaceId: string | undefined, logger = this.logger) {
+ // @ts-expect-error _core isn't supposed to be accessed - remove once we upgrade to hapi v18
const fakeRequest = KibanaRequest.from({
path: '/',
route: { settings: {} },
url: { href: '/' },
raw: { req: { url: '/' } },
+ // TODO: Remove once we upgrade to hapi v18
+ _core: {
+ info: {
+ uri: 'http://localhost',
+ },
+ },
...baseRequest,
} as Hapi.Request);
diff --git a/x-pack/plugins/reporting/server/routes/lib/authorized_user_pre_routing.test.ts b/x-pack/plugins/reporting/server/routes/lib/authorized_user_pre_routing.test.ts
index cee8a88000e29..cce002a0e6935 100644
--- a/x-pack/plugins/reporting/server/routes/lib/authorized_user_pre_routing.test.ts
+++ b/x-pack/plugins/reporting/server/routes/lib/authorized_user_pre_routing.test.ts
@@ -27,7 +27,7 @@ const getMockContext = () =>
const getMockRequest = () =>
({
- url: { port: '5601', query: '', path: '/foo' },
+ url: { port: '5601', search: '', pathname: '/foo' },
route: { path: '/foo', options: {} },
} as KibanaRequest);
diff --git a/x-pack/plugins/security/server/audit/audit_events.test.ts b/x-pack/plugins/security/server/audit/audit_events.test.ts
index 1978795f82a24..f153b9efb9d43 100644
--- a/x-pack/plugins/security/server/audit/audit_events.test.ts
+++ b/x-pack/plugins/security/server/audit/audit_events.test.ts
@@ -4,6 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
+import { URL } from 'url';
import {
EventOutcome,
SavedObjectAction,
@@ -192,11 +193,11 @@ describe('#httpRequestEvent', () => {
},
"message": "User is requesting [/path] endpoint",
"url": Object {
- "domain": undefined,
+ "domain": "localhost",
"path": "/path",
"port": undefined,
"query": undefined,
- "scheme": undefined,
+ "scheme": "http:",
},
}
`);
@@ -211,12 +212,7 @@ describe('#httpRequestEvent', () => {
kibanaRequestState: {
requestId: '123',
requestUuid: '123e4567-e89b-12d3-a456-426614174000',
- rewrittenUrl: {
- path: '/original/path',
- pathname: '/original/path',
- query: 'query=param',
- search: '?query=param',
- },
+ rewrittenUrl: new URL('http://localhost/original/path?query=param'),
},
}),
})
@@ -234,11 +230,11 @@ describe('#httpRequestEvent', () => {
},
"message": "User is requesting [/original/path] endpoint",
"url": Object {
- "domain": undefined,
+ "domain": "localhost",
"path": "/original/path",
"port": undefined,
"query": "query=param",
- "scheme": undefined,
+ "scheme": "http:",
},
}
`);
diff --git a/x-pack/plugins/security/server/audit/audit_events.ts b/x-pack/plugins/security/server/audit/audit_events.ts
index 1ff9da3a95ff4..d91c18bf82e02 100644
--- a/x-pack/plugins/security/server/audit/audit_events.ts
+++ b/x-pack/plugins/security/server/audit/audit_events.ts
@@ -105,10 +105,10 @@ export interface HttpRequestParams {
}
export function httpRequestEvent({ request }: HttpRequestParams): AuditEvent {
- const { pathname, search } = request.rewrittenUrl ?? request.url;
+ const url = request.rewrittenUrl ?? request.url;
return {
- message: `User is requesting [${pathname}] endpoint`,
+ message: `User is requesting [${url.pathname}] endpoint`,
event: {
action: 'http_request',
category: EventCategory.WEB,
@@ -120,11 +120,11 @@ export function httpRequestEvent({ request }: HttpRequestParams): AuditEvent {
},
},
url: {
- domain: request.url.hostname,
- path: pathname,
- port: request.url.port ? parseInt(request.url.port, 10) : undefined,
- query: search?.slice(1) || undefined,
- scheme: request.url.protocol,
+ domain: url.hostname,
+ path: url.pathname,
+ port: url.port ? parseInt(url.port, 10) : undefined,
+ query: url.search ? url.search.slice(1) : undefined,
+ scheme: url.protocol,
},
};
}
diff --git a/x-pack/plugins/security/server/authentication/authenticator.ts b/x-pack/plugins/security/server/authentication/authenticator.ts
index 3b587182c491c..80aeb4f8b2959 100644
--- a/x-pack/plugins/security/server/authentication/authenticator.ts
+++ b/x-pack/plugins/security/server/authentication/authenticator.ts
@@ -333,7 +333,7 @@ export class Authenticator {
this.logger.debug('Redirecting request to Login Selector.');
return AuthenticationResult.redirectTo(
`${this.options.basePath.serverBasePath}/login?next=${encodeURIComponent(
- `${this.options.basePath.get(request)}${request.url.path}`
+ `${this.options.basePath.get(request)}${request.url.pathname}${request.url.search}`
)}`
);
}
@@ -728,7 +728,7 @@ export class Authenticator {
preAccessRedirectURL = `${preAccessRedirectURL}?next=${encodeURIComponent(
authenticationResult.redirectURL ||
redirectURL ||
- `${this.options.basePath.get(request)}${request.url.path}`
+ `${this.options.basePath.get(request)}${request.url.pathname}${request.url.search}`
)}`;
} else if (redirectURL && !authenticationResult.redirectURL) {
preAccessRedirectURL = redirectURL;
diff --git a/x-pack/plugins/security/server/authentication/providers/basic.test.ts b/x-pack/plugins/security/server/authentication/providers/basic.test.ts
index 2481844abb389..87002ebed5672 100644
--- a/x-pack/plugins/security/server/authentication/providers/basic.test.ts
+++ b/x-pack/plugins/security/server/authentication/providers/basic.test.ts
@@ -101,13 +101,13 @@ describe('BasicAuthenticationProvider', () => {
await expect(
provider.authenticate(
httpServerMock.createKibanaRequest({
- path: '/s/foo/some-path # that needs to be encoded',
+ path: '/s/foo/some path that needs to be encoded',
}),
null
)
).resolves.toEqual(
AuthenticationResult.redirectTo(
- '/mock-server-basepath/login?next=%2Fmock-server-basepath%2Fs%2Ffoo%2Fsome-path%20%23%20that%20needs%20to%20be%20encoded'
+ '/mock-server-basepath/login?next=%2Fmock-server-basepath%2Fs%2Ffoo%2Fsome%2520path%2520that%2520needs%2520to%2520be%2520encoded'
)
);
});
diff --git a/x-pack/plugins/security/server/authentication/providers/basic.ts b/x-pack/plugins/security/server/authentication/providers/basic.ts
index 35ab2d242659a..28b671346ee7f 100644
--- a/x-pack/plugins/security/server/authentication/providers/basic.ts
+++ b/x-pack/plugins/security/server/authentication/providers/basic.ts
@@ -90,7 +90,9 @@ export class BasicAuthenticationProvider extends BaseAuthenticationProvider {
* @param [state] Optional state object associated with the provider.
*/
public async authenticate(request: KibanaRequest, state?: ProviderState | null) {
- this.logger.debug(`Trying to authenticate user request to ${request.url.path}.`);
+ this.logger.debug(
+ `Trying to authenticate user request to ${request.url.pathname}${request.url.search}.`
+ );
if (HTTPAuthorizationHeader.parseFromRequest(request) != null) {
this.logger.debug('Cannot authenticate requests with `Authorization` header.');
@@ -106,7 +108,9 @@ export class BasicAuthenticationProvider extends BaseAuthenticationProvider {
this.logger.debug('Redirecting request to Login page.');
const basePath = this.options.basePath.get(request);
return AuthenticationResult.redirectTo(
- `${basePath}/login?next=${encodeURIComponent(`${basePath}${request.url.path}`)}`
+ `${basePath}/login?next=${encodeURIComponent(
+ `${basePath}${request.url.pathname}${request.url.search}`
+ )}`
);
}
@@ -119,7 +123,7 @@ export class BasicAuthenticationProvider extends BaseAuthenticationProvider {
* @param [state] Optional state object associated with the provider.
*/
public async logout(request: KibanaRequest, state?: ProviderState | null) {
- this.logger.debug(`Trying to log user out via ${request.url.path}.`);
+ this.logger.debug(`Trying to log user out via ${request.url.pathname}${request.url.search}.`);
// Having a `null` state means that provider was specifically called to do a logout, but when
// session isn't defined then provider is just being probed whether or not it can perform logout.
diff --git a/x-pack/plugins/security/server/authentication/providers/http.ts b/x-pack/plugins/security/server/authentication/providers/http.ts
index 3e33a52cbbc6b..933685d68978f 100644
--- a/x-pack/plugins/security/server/authentication/providers/http.ts
+++ b/x-pack/plugins/security/server/authentication/providers/http.ts
@@ -56,7 +56,9 @@ export class HTTPAuthenticationProvider extends BaseAuthenticationProvider {
* @param request Request instance.
*/
public async authenticate(request: KibanaRequest) {
- this.logger.debug(`Trying to authenticate user request to ${request.url.path}.`);
+ this.logger.debug(
+ `Trying to authenticate user request to ${request.url.pathname}${request.url.search}.`
+ );
const authorizationHeader = HTTPAuthorizationHeader.parseFromRequest(request);
if (authorizationHeader == null) {
@@ -72,12 +74,12 @@ export class HTTPAuthenticationProvider extends BaseAuthenticationProvider {
try {
const user = await this.getUser(request);
this.logger.debug(
- `Request to ${request.url.path} has been authenticated via authorization header with "${authorizationHeader.scheme}" scheme.`
+ `Request to ${request.url.pathname}${request.url.search} has been authenticated via authorization header with "${authorizationHeader.scheme}" scheme.`
);
return AuthenticationResult.succeeded(user);
} catch (err) {
this.logger.debug(
- `Failed to authenticate request to ${request.url.path} via authorization header with "${authorizationHeader.scheme}" scheme: ${err.message}`
+ `Failed to authenticate request to ${request.url.pathname}${request.url.search} via authorization header with "${authorizationHeader.scheme}" scheme: ${err.message}`
);
return AuthenticationResult.failed(err);
}
diff --git a/x-pack/plugins/security/server/authentication/providers/kerberos.ts b/x-pack/plugins/security/server/authentication/providers/kerberos.ts
index 5b593851cc2f2..d7de71f4da9ed 100644
--- a/x-pack/plugins/security/server/authentication/providers/kerberos.ts
+++ b/x-pack/plugins/security/server/authentication/providers/kerberos.ts
@@ -65,7 +65,9 @@ export class KerberosAuthenticationProvider extends BaseAuthenticationProvider {
* @param [state] Optional state object associated with the provider.
*/
public async authenticate(request: KibanaRequest, state?: ProviderState | null) {
- this.logger.debug(`Trying to authenticate user request to ${request.url.path}.`);
+ this.logger.debug(
+ `Trying to authenticate user request to ${request.url.pathname}${request.url.search}.`
+ );
const authorizationHeader = HTTPAuthorizationHeader.parseFromRequest(request);
if (authorizationHeader && authorizationHeader.scheme.toLowerCase() !== 'negotiate') {
@@ -100,7 +102,7 @@ export class KerberosAuthenticationProvider extends BaseAuthenticationProvider {
* @param state State value previously stored by the provider.
*/
public async logout(request: KibanaRequest, state?: ProviderState | null) {
- this.logger.debug(`Trying to log user out via ${request.url.path}.`);
+ this.logger.debug(`Trying to log user out via ${request.url.pathname}${request.url.search}.`);
// Having a `null` state means that provider was specifically called to do a logout, but when
// session isn't defined then provider is just being probed whether or not it can perform logout.
diff --git a/x-pack/plugins/security/server/authentication/providers/oidc.ts b/x-pack/plugins/security/server/authentication/providers/oidc.ts
index 75c909cdcd94b..9570c59f8ea1d 100644
--- a/x-pack/plugins/security/server/authentication/providers/oidc.ts
+++ b/x-pack/plugins/security/server/authentication/providers/oidc.ts
@@ -166,7 +166,9 @@ export class OIDCAuthenticationProvider extends BaseAuthenticationProvider {
* @param [state] Optional state object associated with the provider.
*/
public async authenticate(request: KibanaRequest, state?: ProviderState | null) {
- this.logger.debug(`Trying to authenticate user request to ${request.url.path}.`);
+ this.logger.debug(
+ `Trying to authenticate user request to ${request.url.pathname}${request.url.search}.`
+ );
if (HTTPAuthorizationHeader.parseFromRequest(request) != null) {
this.logger.debug('Cannot authenticate requests with `Authorization` header.');
@@ -418,7 +420,7 @@ export class OIDCAuthenticationProvider extends BaseAuthenticationProvider {
* @param state State value previously stored by the provider.
*/
public async logout(request: KibanaRequest, state?: ProviderState | null) {
- this.logger.debug(`Trying to log user out via ${request.url.path}.`);
+ this.logger.debug(`Trying to log user out via ${request.url.pathname}${request.url.search}.`);
// Having a `null` state means that provider was specifically called to do a logout, but when
// session isn't defined then provider is just being probed whether or not it can perform logout.
@@ -477,7 +479,7 @@ export class OIDCAuthenticationProvider extends BaseAuthenticationProvider {
`${
this.options.basePath.serverBasePath
}/internal/security/capture-url?next=${encodeURIComponent(
- `${this.options.basePath.get(request)}${request.url.path}`
+ `${this.options.basePath.get(request)}${request.url.pathname}${request.url.search}`
)}&providerType=${encodeURIComponent(this.type)}&providerName=${encodeURIComponent(
this.options.name
)}`,
diff --git a/x-pack/plugins/security/server/authentication/providers/pki.ts b/x-pack/plugins/security/server/authentication/providers/pki.ts
index f3cc21500df26..6dcb448e08150 100644
--- a/x-pack/plugins/security/server/authentication/providers/pki.ts
+++ b/x-pack/plugins/security/server/authentication/providers/pki.ts
@@ -61,7 +61,9 @@ export class PKIAuthenticationProvider extends BaseAuthenticationProvider {
* @param [state] Optional state object associated with the provider.
*/
public async authenticate(request: KibanaRequest, state?: ProviderState | null) {
- this.logger.debug(`Trying to authenticate user request to ${request.url.path}.`);
+ this.logger.debug(
+ `Trying to authenticate user request to ${request.url.pathname}${request.url.search}.`
+ );
if (HTTPAuthorizationHeader.parseFromRequest(request) != null) {
this.logger.debug('Cannot authenticate requests with `Authorization` header.');
@@ -105,7 +107,7 @@ export class PKIAuthenticationProvider extends BaseAuthenticationProvider {
* @param state State value previously stored by the provider.
*/
public async logout(request: KibanaRequest, state?: ProviderState | null) {
- this.logger.debug(`Trying to log user out via ${request.url.path}.`);
+ this.logger.debug(`Trying to log user out via ${request.url.pathname}${request.url.search}.`);
// Having a `null` state means that provider was specifically called to do a logout, but when
// session isn't defined then provider is just being probed whether or not it can perform logout.
diff --git a/x-pack/plugins/security/server/authentication/providers/saml.ts b/x-pack/plugins/security/server/authentication/providers/saml.ts
index cf6772332b8b6..59a1782c1f1fd 100644
--- a/x-pack/plugins/security/server/authentication/providers/saml.ts
+++ b/x-pack/plugins/security/server/authentication/providers/saml.ts
@@ -193,7 +193,9 @@ export class SAMLAuthenticationProvider extends BaseAuthenticationProvider {
* @param [state] Optional state object associated with the provider.
*/
public async authenticate(request: KibanaRequest, state?: ProviderState | null) {
- this.logger.debug(`Trying to authenticate user request to ${request.url.path}.`);
+ this.logger.debug(
+ `Trying to authenticate user request to ${request.url.pathname}${request.url.search}`
+ );
if (HTTPAuthorizationHeader.parseFromRequest(request) != null) {
this.logger.debug('Cannot authenticate requests with `Authorization` header.');
@@ -232,7 +234,7 @@ export class SAMLAuthenticationProvider extends BaseAuthenticationProvider {
* @param state State value previously stored by the provider.
*/
public async logout(request: KibanaRequest, state?: ProviderState | null) {
- this.logger.debug(`Trying to log user out via ${request.url.path}.`);
+ this.logger.debug(`Trying to log user out via ${request.url.pathname}${request.url.search}.`);
// Normally when there is no active session in Kibana, `logout` method shouldn't do anything
// and user will eventually be redirected to the home page to log in. But when SAML SLO is
@@ -631,7 +633,7 @@ export class SAMLAuthenticationProvider extends BaseAuthenticationProvider {
`${
this.options.basePath.serverBasePath
}/internal/security/capture-url?next=${encodeURIComponent(
- `${this.options.basePath.get(request)}${request.url.path}`
+ `${this.options.basePath.get(request)}${request.url.pathname}${request.url.search}`
)}&providerType=${encodeURIComponent(this.type)}&providerName=${encodeURIComponent(
this.options.name
)}`,
diff --git a/x-pack/plugins/security/server/authentication/providers/token.test.ts b/x-pack/plugins/security/server/authentication/providers/token.test.ts
index 0264edf4fc082..ffb1c89b24e47 100644
--- a/x-pack/plugins/security/server/authentication/providers/token.test.ts
+++ b/x-pack/plugins/security/server/authentication/providers/token.test.ts
@@ -173,13 +173,13 @@ describe('TokenAuthenticationProvider', () => {
await expect(
provider.authenticate(
httpServerMock.createKibanaRequest({
- path: '/s/foo/some-path # that needs to be encoded',
+ path: '/s/foo/some path that needs to be encoded',
}),
null
)
).resolves.toEqual(
AuthenticationResult.redirectTo(
- '/mock-server-basepath/login?next=%2Fmock-server-basepath%2Fs%2Ffoo%2Fsome-path%20%23%20that%20needs%20to%20be%20encoded'
+ '/mock-server-basepath/login?next=%2Fmock-server-basepath%2Fs%2Ffoo%2Fsome%2520path%2520that%2520needs%2520to%2520be%2520encoded'
)
);
});
diff --git a/x-pack/plugins/security/server/authentication/providers/token.ts b/x-pack/plugins/security/server/authentication/providers/token.ts
index 869fd69173e2e..7dace488bc95a 100644
--- a/x-pack/plugins/security/server/authentication/providers/token.ts
+++ b/x-pack/plugins/security/server/authentication/providers/token.ts
@@ -92,7 +92,9 @@ export class TokenAuthenticationProvider extends BaseAuthenticationProvider {
* @param [state] Optional state object associated with the provider.
*/
public async authenticate(request: KibanaRequest, state?: ProviderState | null) {
- this.logger.debug(`Trying to authenticate user request to ${request.url.path}.`);
+ this.logger.debug(
+ `Trying to authenticate user request to ${request.url.pathname}${request.url.search}.`
+ );
if (HTTPAuthorizationHeader.parseFromRequest(request) != null) {
this.logger.debug('Cannot authenticate requests with `Authorization` header.');
@@ -126,7 +128,7 @@ export class TokenAuthenticationProvider extends BaseAuthenticationProvider {
* @param state State value previously stored by the provider.
*/
public async logout(request: KibanaRequest, state?: ProviderState | null) {
- this.logger.debug(`Trying to log user out via ${request.url.path}.`);
+ this.logger.debug(`Trying to log user out via ${request.url.pathname}${request.url.search}.`);
// Having a `null` state means that provider was specifically called to do a logout, but when
// session isn't defined then provider is just being probed whether or not it can perform logout.
@@ -241,7 +243,9 @@ export class TokenAuthenticationProvider extends BaseAuthenticationProvider {
* @param request Request instance.
*/
private getLoginPageURL(request: KibanaRequest) {
- const nextURL = encodeURIComponent(`${this.options.basePath.get(request)}${request.url.path}`);
+ const nextURL = encodeURIComponent(
+ `${this.options.basePath.get(request)}${request.url.pathname}${request.url.search}`
+ );
return `${this.options.basePath.get(request)}/login?next=${nextURL}`;
}
}
diff --git a/x-pack/plugins/security/server/authorization/api_authorization.ts b/x-pack/plugins/security/server/authorization/api_authorization.ts
index 813ed8d064d94..9cf090ab271ae 100644
--- a/x-pack/plugins/security/server/authorization/api_authorization.ts
+++ b/x-pack/plugins/security/server/authorization/api_authorization.ts
@@ -33,11 +33,13 @@ export function initAPIAuthorization(
// we've actually authorized the request
if (checkPrivilegesResponse.hasAllRequested) {
- logger.debug(`User authorized for "${request.url.path}"`);
+ logger.debug(`User authorized for "${request.url.pathname}${request.url.search}"`);
return toolkit.next();
}
- logger.warn(`User not authorized for "${request.url.path}": responding with 403`);
+ logger.warn(
+ `User not authorized for "${request.url.pathname}${request.url.search}": responding with 403`
+ );
return response.forbidden();
});
}
diff --git a/x-pack/plugins/security/server/authorization/authorization_service.tsx b/x-pack/plugins/security/server/authorization/authorization_service.tsx
index 9547295af4dfb..a45bca90d8b56 100644
--- a/x-pack/plugins/security/server/authorization/authorization_service.tsx
+++ b/x-pack/plugins/security/server/authorization/authorization_service.tsx
@@ -168,7 +168,7 @@ export class AuthorizationService {
http.registerOnPreResponse((request, preResponse, toolkit) => {
if (preResponse.statusCode === 403 && canRedirectRequest(request)) {
const basePath = http.basePath.get(request);
- const next = `${basePath}${request.url.path}`;
+ const next = `${basePath}${request.url.pathname}${request.url.search}`;
const regularBundlePath = `${basePath}/${buildNumber}/bundles`;
const logoutUrl = http.basePath.prepend(
diff --git a/x-pack/plugins/security/server/routes/authentication/oidc.ts b/x-pack/plugins/security/server/routes/authentication/oidc.ts
index 5d8a7ae7bdfea..7eaa619b330e0 100644
--- a/x-pack/plugins/security/server/routes/authentication/oidc.ts
+++ b/x-pack/plugins/security/server/routes/authentication/oidc.ts
@@ -135,7 +135,7 @@ export function defineOIDCRoutes({
loginAttempt = {
type: OIDCLogin.LoginWithAuthorizationCodeFlow,
// We pass the path only as we can't be sure of the full URL and Elasticsearch doesn't need it anyway.
- authenticationResponseURI: request.url.path!,
+ authenticationResponseURI: request.url.pathname + request.url.search,
};
} else if (request.query.iss) {
logger.warn(
diff --git a/x-pack/plugins/security/server/routes/views/login.test.ts b/x-pack/plugins/security/server/routes/views/login.test.ts
index fee3adbb19f97..b90a44be7aade 100644
--- a/x-pack/plugins/security/server/routes/views/login.test.ts
+++ b/x-pack/plugins/security/server/routes/views/login.test.ts
@@ -100,7 +100,7 @@ describe('Login view routes', () => {
auth: { isAuthenticated: true },
});
(request as any).url = new URL(
- `${request.url.path}${request.url.search}`,
+ `${request.url.pathname}${request.url.search}`,
'https://kibana.co'
);
license.getFeatures.mockReturnValue({ showLogin: true } as any);
@@ -114,7 +114,7 @@ describe('Login view routes', () => {
// Redirect if `showLogin` is `false` even if user is not authenticated.
request = httpServerMock.createKibanaRequest({ query, auth: { isAuthenticated: false } });
(request as any).url = new URL(
- `${request.url.path}${request.url.search}`,
+ `${request.url.pathname}${request.url.search}`,
'https://kibana.co'
);
license.getFeatures.mockReturnValue({ showLogin: false } as any);
diff --git a/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.ts b/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.ts
index e3a724e153688..1aa2011a15b35 100644
--- a/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.ts
+++ b/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.ts
@@ -28,7 +28,7 @@ export function initSpacesOnPostAuthRequestInterceptor({
http.registerOnPostAuth(async (request, response, toolkit) => {
const serverBasePath = http.basePath.serverBasePath;
- const path = request.url.pathname!;
+ const path = request.url.pathname;
const spaceId = spacesService.getSpaceId(request);
diff --git a/x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.ts b/x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.ts
index 6408803c2114b..a3335b1e075f2 100644
--- a/x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.ts
+++ b/x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.ts
@@ -9,8 +9,6 @@ import {
LifecycleResponseFactory,
CoreSetup,
} from 'src/core/server';
-import { format } from 'url';
-import { modifyUrl } from '../utils/url';
import { getSpaceIdFromPath } from '../../../common';
export interface OnRequestInterceptorDeps {
@@ -34,16 +32,9 @@ export function initSpacesOnRequestInterceptor({ http }: OnRequestInterceptorDep
http.basePath.set(request, reqBasePath);
- const newLocation = (path && path.substr(reqBasePath.length)) || '/';
+ const newPathname = path.substr(reqBasePath.length) || '/';
- const newUrl = modifyUrl(format(request.url), (parts) => {
- return {
- ...parts,
- pathname: newLocation,
- };
- });
-
- return toolkit.rewriteUrl(newUrl);
+ return toolkit.rewriteUrl(`${newPathname}${request.url.search}`);
}
return toolkit.next();
diff --git a/x-pack/plugins/spaces/server/spaces_service/spaces_service.test.ts b/x-pack/plugins/spaces/server/spaces_service/spaces_service.test.ts
index b48bf971d0c1b..d1e1d81134940 100644
--- a/x-pack/plugins/spaces/server/spaces_service/spaces_service.test.ts
+++ b/x-pack/plugins/spaces/server/spaces_service/spaces_service.test.ts
@@ -58,7 +58,7 @@ const createService = async (serverBasePath: string = '') => {
serverBasePath,
} as HttpServiceSetup['basePath'];
httpSetup.basePath.get = jest.fn().mockImplementation((request: KibanaRequest) => {
- const { spaceId } = getSpaceIdFromPath(request.url.path);
+ const { spaceId } = getSpaceIdFromPath(request.url.pathname);
if (spaceId !== DEFAULT_SPACE_ID) {
return `/s/${spaceId}`;
@@ -83,7 +83,7 @@ describe('SpacesService', () => {
const spacesServiceSetup = await createService();
const request: KibanaRequest = {
- url: { path: '/app/kibana' },
+ url: { pathname: '/app/kibana' },
} as KibanaRequest;
expect(spacesServiceSetup.getSpaceId(request)).toEqual(DEFAULT_SPACE_ID);
@@ -93,7 +93,7 @@ describe('SpacesService', () => {
const spacesServiceSetup = await createService();
const request: KibanaRequest = {
- url: { path: '/s/foo/app/kibana' },
+ url: { pathname: '/s/foo/app/kibana' },
} as KibanaRequest;
expect(spacesServiceSetup.getSpaceId(request)).toEqual('foo');
@@ -140,7 +140,7 @@ describe('SpacesService', () => {
const spacesServiceSetup = await createService();
const request: KibanaRequest = {
- url: { path: '/app/kibana' },
+ url: { pathname: '/app/kibana' },
} as KibanaRequest;
expect(spacesServiceSetup.isInDefaultSpace(request)).toEqual(true);
@@ -150,7 +150,7 @@ describe('SpacesService', () => {
const spacesServiceSetup = await createService();
const request: KibanaRequest = {
- url: { path: '/s/foo/app/kibana' },
+ url: { pathname: '/s/foo/app/kibana' },
} as KibanaRequest;
expect(spacesServiceSetup.isInDefaultSpace(request)).toEqual(false);
From 2d49dea005847cac6855deb7c41ab18241af02e6 Mon Sep 17 00:00:00 2001
From: Jonathan Budzenski
Date: Thu, 29 Oct 2020 08:53:12 -0500
Subject: [PATCH 27/73] [deb/rpm] set logging.dest (#74896)
Co-authored-by: Elastic Machine
---
.../tasks/os_packages/package_scripts/post_install.sh | 9 ++++++---
src/dev/build/tasks/os_packages/run_fpm.ts | 2 ++
.../systemd/etc/systemd/system/kibana.service | 2 +-
.../os_packages/service_templates/sysv/etc/init.d/kibana | 9 +++------
4 files changed, 12 insertions(+), 10 deletions(-)
diff --git a/src/dev/build/tasks/os_packages/package_scripts/post_install.sh b/src/dev/build/tasks/os_packages/package_scripts/post_install.sh
index 1c679bdb40b59..939226b565f79 100644
--- a/src/dev/build/tasks/os_packages/package_scripts/post_install.sh
+++ b/src/dev/build/tasks/os_packages/package_scripts/post_install.sh
@@ -7,14 +7,17 @@ set_chmod() {
chmod -f 660 ${KBN_PATH_CONF}/kibana.yml || true
chmod -f 2750 <%= dataDir %> || true
chmod -f 2750 ${KBN_PATH_CONF} || true
+ chmod -f 2750 <%= logDir %> || true
}
set_chown() {
+ chown <%= user %>:<%= group %> <%= logDir %>
chown -R <%= user %>:<%= group %> <%= dataDir %>
chown -R root:<%= group %> ${KBN_PATH_CONF}
}
-set_access() {
+setup() {
+ [ ! -d "<%= logDir %>" ] && mkdir "<%= logDir %>"
set_chmod
set_chown
}
@@ -35,7 +38,7 @@ case $1 in
IS_UPGRADE=true
fi
- set_access
+ setup
;;
abort-deconfigure|abort-upgrade|abort-remove)
;;
@@ -55,7 +58,7 @@ case $1 in
IS_UPGRADE=true
fi
- set_access
+ setup
;;
*)
diff --git a/src/dev/build/tasks/os_packages/run_fpm.ts b/src/dev/build/tasks/os_packages/run_fpm.ts
index b5169ec3d43b6..b8289f1da194f 100644
--- a/src/dev/build/tasks/os_packages/run_fpm.ts
+++ b/src/dev/build/tasks/os_packages/run_fpm.ts
@@ -109,6 +109,8 @@ export async function runFpm(
`pluginsDir=/usr/share/kibana/plugins`,
'--template-value',
`dataDir=/var/lib/kibana`,
+ '--template-value',
+ `logDir=/var/log/kibana`,
// config and data directories are copied to /usr/share and /var/lib
// below, so exclude them from the main package source located in
diff --git a/src/dev/build/tasks/os_packages/service_templates/systemd/etc/systemd/system/kibana.service b/src/dev/build/tasks/os_packages/service_templates/systemd/etc/systemd/system/kibana.service
index df33b82f1f967..05724db8799f3 100644
--- a/src/dev/build/tasks/os_packages/service_templates/systemd/etc/systemd/system/kibana.service
+++ b/src/dev/build/tasks/os_packages/service_templates/systemd/etc/systemd/system/kibana.service
@@ -15,7 +15,7 @@ Environment=KBN_PATH_CONF=/etc/kibana
EnvironmentFile=-/etc/default/kibana
EnvironmentFile=-/etc/sysconfig/kibana
-ExecStart=/usr/share/kibana/bin/kibana
+ExecStart=/usr/share/kibana/bin/kibana --logging.dest="/var/log/kibana/kibana.log"
Restart=on-failure
RestartSec=3
diff --git a/src/dev/build/tasks/os_packages/service_templates/sysv/etc/init.d/kibana b/src/dev/build/tasks/os_packages/service_templates/sysv/etc/init.d/kibana
index c13676ef031b0..eedd4898ce6c3 100755
--- a/src/dev/build/tasks/os_packages/service_templates/sysv/etc/init.d/kibana
+++ b/src/dev/build/tasks/os_packages/service_templates/sysv/etc/init.d/kibana
@@ -35,6 +35,7 @@ fi
name=kibana
program=/usr/share/kibana/bin/kibana
+args="--logging.dest=/var/log/kibana/kibana.log"
pidfile="/var/run/kibana/$name.pid"
[ -r /etc/default/$name ] && . /etc/default/$name
@@ -55,10 +56,6 @@ emit() {
}
start() {
- [ ! -d "/var/log/kibana/" ] && mkdir "/var/log/kibana/"
- chown "$user":"$group" "/var/log/kibana/"
- chmod 2750 "/var/log/kibana/"
-
[ ! -d "/var/run/kibana/" ] && mkdir "/var/run/kibana/"
chown "$user":"$group" "/var/run/kibana/"
chmod 755 "/var/run/kibana/"
@@ -66,8 +63,8 @@ start() {
chroot --userspec "$user":"$group" "$chroot" sh -c "
cd \"$chdir\"
- exec \"$program\"
- " >> /var/log/kibana/kibana.stdout 2>> /var/log/kibana/kibana.stderr &
+ exec \"$program $args\"
+ " >> /var/log/kibana/kibana.log 2>&1 &
# Generate the pidfile from here. If we instead made the forked process
# generate it there will be a race condition between the pidfile writing
From 40fc944f30b121a6986df50dd30ef77ad90aad41 Mon Sep 17 00:00:00 2001
From: Sandra Gonzales
Date: Thu, 29 Oct 2020 10:32:13 -0400
Subject: [PATCH 28/73] add experimental when getting packages, add integration
tests for side effects like recreation of index patterns (#81940)
---
.../server/services/epm/packages/get.ts | 2 +-
.../apis/epm/install_remove_multiple.ts | 106 ++++++++++++++++++
.../data_stream/test_logs/fields/ecs.yml | 3 +
.../data_stream/test_logs/fields/fields.yml | 16 +++
.../0.1.0/data_stream/test_logs/manifest.yml | 9 ++
.../data_stream/test_metrics/fields/ecs.yml | 3 +
.../test_metrics/fields/fields.yml | 16 +++
.../data_stream/test_metrics/manifest.yml | 3 +
.../experimental/0.1.0/docs/README.md | 3 +
.../0.1.0/img/logo_overrides_64_color.svg | 7 ++
.../experimental/0.1.0/manifest.yml | 20 ++++
.../data_stream/test_logs/fields/ecs.yml | 3 +
.../data_stream/test_logs/fields/fields.yml | 16 +++
.../0.1.0/data_stream/test_logs/manifest.yml | 9 ++
.../data_stream/test_metrics/fields/ecs.yml | 3 +
.../test_metrics/fields/fields.yml | 16 +++
.../data_stream/test_metrics/manifest.yml | 3 +
.../experimental2/0.1.0/docs/README.md | 3 +
.../0.1.0/img/logo_overrides_64_color.svg | 7 ++
.../experimental2/0.1.0/manifest.yml | 20 ++++
20 files changed, 267 insertions(+), 1 deletion(-)
create mode 100644 x-pack/test/ingest_manager_api_integration/apis/epm/install_remove_multiple.ts
create mode 100644 x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/experimental/0.1.0/data_stream/test_logs/fields/ecs.yml
create mode 100644 x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/experimental/0.1.0/data_stream/test_logs/fields/fields.yml
create mode 100644 x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/experimental/0.1.0/data_stream/test_logs/manifest.yml
create mode 100644 x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/experimental/0.1.0/data_stream/test_metrics/fields/ecs.yml
create mode 100644 x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/experimental/0.1.0/data_stream/test_metrics/fields/fields.yml
create mode 100644 x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/experimental/0.1.0/data_stream/test_metrics/manifest.yml
create mode 100644 x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/experimental/0.1.0/docs/README.md
create mode 100644 x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/experimental/0.1.0/img/logo_overrides_64_color.svg
create mode 100644 x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/experimental/0.1.0/manifest.yml
create mode 100644 x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/experimental2/0.1.0/data_stream/test_logs/fields/ecs.yml
create mode 100644 x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/experimental2/0.1.0/data_stream/test_logs/fields/fields.yml
create mode 100644 x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/experimental2/0.1.0/data_stream/test_logs/manifest.yml
create mode 100644 x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/experimental2/0.1.0/data_stream/test_metrics/fields/ecs.yml
create mode 100644 x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/experimental2/0.1.0/data_stream/test_metrics/fields/fields.yml
create mode 100644 x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/experimental2/0.1.0/data_stream/test_metrics/manifest.yml
create mode 100644 x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/experimental2/0.1.0/docs/README.md
create mode 100644 x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/experimental2/0.1.0/img/logo_overrides_64_color.svg
create mode 100644 x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/experimental2/0.1.0/manifest.yml
diff --git a/x-pack/plugins/ingest_manager/server/services/epm/packages/get.ts b/x-pack/plugins/ingest_manager/server/services/epm/packages/get.ts
index 2cf94e9c16079..cd0dcba7b97b2 100644
--- a/x-pack/plugins/ingest_manager/server/services/epm/packages/get.ts
+++ b/x-pack/plugins/ingest_manager/server/services/epm/packages/get.ts
@@ -86,7 +86,7 @@ export async function getPackageKeysByStatus(
savedObjectsClient: SavedObjectsClientContract,
status: InstallationStatus
) {
- const allPackages = await getPackages({ savedObjectsClient });
+ const allPackages = await getPackages({ savedObjectsClient, experimental: true });
return allPackages.reduce>((acc, pkg) => {
if (pkg.status === status) {
if (pkg.status === InstallationStatus.installed) {
diff --git a/x-pack/test/ingest_manager_api_integration/apis/epm/install_remove_multiple.ts b/x-pack/test/ingest_manager_api_integration/apis/epm/install_remove_multiple.ts
new file mode 100644
index 0000000000000..82072f59a482b
--- /dev/null
+++ b/x-pack/test/ingest_manager_api_integration/apis/epm/install_remove_multiple.ts
@@ -0,0 +1,106 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import expect from '@kbn/expect';
+import { FtrProviderContext } from '../../../api_integration/ftr_provider_context';
+import { skipIfNoDockerRegistry } from '../../helpers';
+
+export default function (providerContext: FtrProviderContext) {
+ const { getService } = providerContext;
+ const kibanaServer = getService('kibanaServer');
+ const supertest = getService('supertest');
+ const dockerServers = getService('dockerServers');
+ const server = dockerServers.get('registry');
+ const pkgName = 'all_assets';
+ const pkgVersion = '0.1.0';
+ const pkgKey = `${pkgName}-${pkgVersion}`;
+ const experimentalPkgName = 'experimental';
+ const experimentalPkgKey = `${experimentalPkgName}-${pkgVersion}`;
+ const experimental2PkgName = 'experimental2';
+ const experimental2PkgKey = `${experimental2PkgName}-${pkgVersion}`;
+
+ const uninstallPackage = async (pkg: string) => {
+ await supertest.delete(`/api/fleet/epm/packages/${pkg}`).set('kbn-xsrf', 'xxxx');
+ };
+ const installPackage = async (pkg: string) => {
+ await supertest
+ .post(`/api/fleet/epm/packages/${pkg}`)
+ .set('kbn-xsrf', 'xxxx')
+ .send({ force: true });
+ };
+
+ const installPackages = async (pkgs: string[]) => {
+ const installingPackagesPromise = pkgs.map((pkg) => installPackage(pkg));
+ return Promise.all(installingPackagesPromise);
+ };
+ const uninstallPackages = async (pkgs: string[]) => {
+ const uninstallingPackagesPromise = pkgs.map((pkg) => uninstallPackage(pkg));
+ return Promise.all(uninstallingPackagesPromise);
+ };
+ const expectPkgFieldToExist = async (
+ fields: any[],
+ fieldName: string,
+ exists: boolean = true
+ ) => {
+ const fieldExists = fields.find((field: { name: string }) => field.name === fieldName);
+ if (exists) {
+ expect(fieldExists).not.to.be(undefined);
+ } else {
+ expect(fieldExists).to.be(undefined);
+ }
+ };
+ describe('installs and uninstalls multiple packages side effects', async () => {
+ skipIfNoDockerRegistry(providerContext);
+ before(async () => {
+ if (!server.enabled) return;
+ await installPackages([pkgKey, experimentalPkgKey, experimental2PkgKey]);
+ });
+ after(async () => {
+ if (!server.enabled) return;
+ await uninstallPackages([pkgKey, experimentalPkgKey, experimental2PkgKey]);
+ });
+ it('should create index patterns from all installed packages, experimental or beta', async () => {
+ const resIndexPatternLogs = await kibanaServer.savedObjects.get({
+ type: 'index-pattern',
+ id: 'logs-*',
+ });
+
+ const fieldsLogs = JSON.parse(resIndexPatternLogs.attributes.fields);
+
+ expectPkgFieldToExist(fieldsLogs, 'logs_test_name');
+ expectPkgFieldToExist(fieldsLogs, 'logs_experimental_name');
+ expectPkgFieldToExist(fieldsLogs, 'logs_experimental2_name');
+ const resIndexPatternMetrics = await kibanaServer.savedObjects.get({
+ type: 'index-pattern',
+ id: 'metrics-*',
+ });
+ const fieldsMetrics = JSON.parse(resIndexPatternMetrics.attributes.fields);
+ expectPkgFieldToExist(fieldsMetrics, 'metrics_test_name');
+ expectPkgFieldToExist(fieldsMetrics, 'metrics_experimental_name');
+ expectPkgFieldToExist(fieldsMetrics, 'metrics_experimental2_name');
+ });
+ it('should correctly recreate index patterns when a package is uninstalled', async () => {
+ await uninstallPackage(experimental2PkgKey);
+ const resIndexPatternLogs = await kibanaServer.savedObjects.get({
+ type: 'index-pattern',
+ id: 'logs-*',
+ });
+ const fields = JSON.parse(resIndexPatternLogs.attributes.fields);
+ expectPkgFieldToExist(fields, 'logs_test_name');
+ expectPkgFieldToExist(fields, 'logs_experimental_name');
+ expectPkgFieldToExist(fields, 'logs_experimental2_name', false);
+ const resIndexPatternMetrics = await kibanaServer.savedObjects.get({
+ type: 'index-pattern',
+ id: 'metrics-*',
+ });
+ const fieldsMetrics = JSON.parse(resIndexPatternMetrics.attributes.fields);
+
+ expectPkgFieldToExist(fieldsMetrics, 'metrics_test_name');
+ expectPkgFieldToExist(fieldsMetrics, 'metrics_experimental_name');
+ expectPkgFieldToExist(fieldsMetrics, 'metrics_experimental2_name', false);
+ });
+ });
+}
diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/experimental/0.1.0/data_stream/test_logs/fields/ecs.yml b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/experimental/0.1.0/data_stream/test_logs/fields/ecs.yml
new file mode 100644
index 0000000000000..4c18291b7c5ad
--- /dev/null
+++ b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/experimental/0.1.0/data_stream/test_logs/fields/ecs.yml
@@ -0,0 +1,3 @@
+- name: logs_experimental_name
+ title: logs_experimental_title
+ type: keyword
\ No newline at end of file
diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/experimental/0.1.0/data_stream/test_logs/fields/fields.yml b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/experimental/0.1.0/data_stream/test_logs/fields/fields.yml
new file mode 100644
index 0000000000000..6e003ed0ad147
--- /dev/null
+++ b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/experimental/0.1.0/data_stream/test_logs/fields/fields.yml
@@ -0,0 +1,16 @@
+- name: data_stream.type
+ type: constant_keyword
+ description: >
+ Data stream type.
+- name: data_stream.dataset
+ type: constant_keyword
+ description: >
+ Data stream dataset.
+- name: data_stream.namespace
+ type: constant_keyword
+ description: >
+ Data stream namespace.
+- name: '@timestamp'
+ type: date
+ description: >
+ Event timestamp.
diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/experimental/0.1.0/data_stream/test_logs/manifest.yml b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/experimental/0.1.0/data_stream/test_logs/manifest.yml
new file mode 100644
index 0000000000000..9ac3c68a0be9e
--- /dev/null
+++ b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/experimental/0.1.0/data_stream/test_logs/manifest.yml
@@ -0,0 +1,9 @@
+title: Test Dataset
+
+type: logs
+
+elasticsearch:
+ index_template.mappings:
+ dynamic: false
+ index_template.settings:
+ index.lifecycle.name: reference
diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/experimental/0.1.0/data_stream/test_metrics/fields/ecs.yml b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/experimental/0.1.0/data_stream/test_metrics/fields/ecs.yml
new file mode 100644
index 0000000000000..3cd2db230f437
--- /dev/null
+++ b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/experimental/0.1.0/data_stream/test_metrics/fields/ecs.yml
@@ -0,0 +1,3 @@
+- name: metrics_experimental_name
+ title: metrics_experimental_title
+ type: keyword
\ No newline at end of file
diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/experimental/0.1.0/data_stream/test_metrics/fields/fields.yml b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/experimental/0.1.0/data_stream/test_metrics/fields/fields.yml
new file mode 100644
index 0000000000000..6e003ed0ad147
--- /dev/null
+++ b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/experimental/0.1.0/data_stream/test_metrics/fields/fields.yml
@@ -0,0 +1,16 @@
+- name: data_stream.type
+ type: constant_keyword
+ description: >
+ Data stream type.
+- name: data_stream.dataset
+ type: constant_keyword
+ description: >
+ Data stream dataset.
+- name: data_stream.namespace
+ type: constant_keyword
+ description: >
+ Data stream namespace.
+- name: '@timestamp'
+ type: date
+ description: >
+ Event timestamp.
diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/experimental/0.1.0/data_stream/test_metrics/manifest.yml b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/experimental/0.1.0/data_stream/test_metrics/manifest.yml
new file mode 100644
index 0000000000000..6bc20442bd432
--- /dev/null
+++ b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/experimental/0.1.0/data_stream/test_metrics/manifest.yml
@@ -0,0 +1,3 @@
+title: Test Dataset
+
+type: metrics
\ No newline at end of file
diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/experimental/0.1.0/docs/README.md b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/experimental/0.1.0/docs/README.md
new file mode 100644
index 0000000000000..8e524c4c71b5f
--- /dev/null
+++ b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/experimental/0.1.0/docs/README.md
@@ -0,0 +1,3 @@
+# Test package
+
+For testing side effects when installing and removing multiple packages
diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/experimental/0.1.0/img/logo_overrides_64_color.svg b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/experimental/0.1.0/img/logo_overrides_64_color.svg
new file mode 100644
index 0000000000000..b03007a76ffcc
--- /dev/null
+++ b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/experimental/0.1.0/img/logo_overrides_64_color.svg
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/experimental/0.1.0/manifest.yml b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/experimental/0.1.0/manifest.yml
new file mode 100644
index 0000000000000..9c83569a69cbe
--- /dev/null
+++ b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/experimental/0.1.0/manifest.yml
@@ -0,0 +1,20 @@
+format_version: 1.0.0
+name: experimental
+title: experimental integration
+description: This is a test package for testing experimental packages
+version: 0.1.0
+categories: []
+release: experimental
+type: integration
+license: basic
+
+requirement:
+ elasticsearch:
+ versions: '>7.7.0'
+ kibana:
+ versions: '>7.7.0'
+
+icons:
+ - src: '/img/logo_overrides_64_color.svg'
+ size: '16x16'
+ type: 'image/svg+xml'
diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/experimental2/0.1.0/data_stream/test_logs/fields/ecs.yml b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/experimental2/0.1.0/data_stream/test_logs/fields/ecs.yml
new file mode 100644
index 0000000000000..dad07fa9637af
--- /dev/null
+++ b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/experimental2/0.1.0/data_stream/test_logs/fields/ecs.yml
@@ -0,0 +1,3 @@
+- name: logs_experimental2_name
+ title: logs_experimental2_title
+ type: keyword
\ No newline at end of file
diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/experimental2/0.1.0/data_stream/test_logs/fields/fields.yml b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/experimental2/0.1.0/data_stream/test_logs/fields/fields.yml
new file mode 100644
index 0000000000000..6e003ed0ad147
--- /dev/null
+++ b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/experimental2/0.1.0/data_stream/test_logs/fields/fields.yml
@@ -0,0 +1,16 @@
+- name: data_stream.type
+ type: constant_keyword
+ description: >
+ Data stream type.
+- name: data_stream.dataset
+ type: constant_keyword
+ description: >
+ Data stream dataset.
+- name: data_stream.namespace
+ type: constant_keyword
+ description: >
+ Data stream namespace.
+- name: '@timestamp'
+ type: date
+ description: >
+ Event timestamp.
diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/experimental2/0.1.0/data_stream/test_logs/manifest.yml b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/experimental2/0.1.0/data_stream/test_logs/manifest.yml
new file mode 100644
index 0000000000000..9ac3c68a0be9e
--- /dev/null
+++ b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/experimental2/0.1.0/data_stream/test_logs/manifest.yml
@@ -0,0 +1,9 @@
+title: Test Dataset
+
+type: logs
+
+elasticsearch:
+ index_template.mappings:
+ dynamic: false
+ index_template.settings:
+ index.lifecycle.name: reference
diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/experimental2/0.1.0/data_stream/test_metrics/fields/ecs.yml b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/experimental2/0.1.0/data_stream/test_metrics/fields/ecs.yml
new file mode 100644
index 0000000000000..0b6a2efaacd33
--- /dev/null
+++ b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/experimental2/0.1.0/data_stream/test_metrics/fields/ecs.yml
@@ -0,0 +1,3 @@
+- name: metrics_experimental2_name
+ title: metrics_experimental2_title
+ type: keyword
\ No newline at end of file
diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/experimental2/0.1.0/data_stream/test_metrics/fields/fields.yml b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/experimental2/0.1.0/data_stream/test_metrics/fields/fields.yml
new file mode 100644
index 0000000000000..6e003ed0ad147
--- /dev/null
+++ b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/experimental2/0.1.0/data_stream/test_metrics/fields/fields.yml
@@ -0,0 +1,16 @@
+- name: data_stream.type
+ type: constant_keyword
+ description: >
+ Data stream type.
+- name: data_stream.dataset
+ type: constant_keyword
+ description: >
+ Data stream dataset.
+- name: data_stream.namespace
+ type: constant_keyword
+ description: >
+ Data stream namespace.
+- name: '@timestamp'
+ type: date
+ description: >
+ Event timestamp.
diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/experimental2/0.1.0/data_stream/test_metrics/manifest.yml b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/experimental2/0.1.0/data_stream/test_metrics/manifest.yml
new file mode 100644
index 0000000000000..6bc20442bd432
--- /dev/null
+++ b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/experimental2/0.1.0/data_stream/test_metrics/manifest.yml
@@ -0,0 +1,3 @@
+title: Test Dataset
+
+type: metrics
\ No newline at end of file
diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/experimental2/0.1.0/docs/README.md b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/experimental2/0.1.0/docs/README.md
new file mode 100644
index 0000000000000..8e524c4c71b5f
--- /dev/null
+++ b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/experimental2/0.1.0/docs/README.md
@@ -0,0 +1,3 @@
+# Test package
+
+For testing side effects when installing and removing multiple packages
diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/experimental2/0.1.0/img/logo_overrides_64_color.svg b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/experimental2/0.1.0/img/logo_overrides_64_color.svg
new file mode 100644
index 0000000000000..b03007a76ffcc
--- /dev/null
+++ b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/experimental2/0.1.0/img/logo_overrides_64_color.svg
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/experimental2/0.1.0/manifest.yml b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/experimental2/0.1.0/manifest.yml
new file mode 100644
index 0000000000000..766835dbde037
--- /dev/null
+++ b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/experimental2/0.1.0/manifest.yml
@@ -0,0 +1,20 @@
+format_version: 1.0.0
+name: experimental2
+title: experimental integration
+description: This is a test package for testing experimental packages
+version: 0.1.0
+categories: []
+release: experimental
+type: integration
+license: basic
+
+requirement:
+ elasticsearch:
+ versions: '>7.7.0'
+ kibana:
+ versions: '>7.7.0'
+
+icons:
+ - src: '/img/logo_overrides_64_color.svg'
+ size: '16x16'
+ type: 'image/svg+xml'
From 6bff52c66e4e9482b712abacb55a40eb722cc075 Mon Sep 17 00:00:00 2001
From: Andrew Cholakian
Date: Thu, 29 Oct 2020 09:46:23 -0500
Subject: [PATCH 29/73] [Uptime] Fix broken overview page when no summary data
present (#81952)
Fixes https://github.com/elastic/kibana/issues/81950
by not assuming the summary is present in a bucket with partial check
info
---
.../search/refine_potential_matches.ts | 6 +++++
.../uptime/rest/monitor_states_generated.ts | 24 +++++++++++++++++++
2 files changed, 30 insertions(+)
diff --git a/x-pack/plugins/uptime/server/lib/requests/search/refine_potential_matches.ts b/x-pack/plugins/uptime/server/lib/requests/search/refine_potential_matches.ts
index 98db43c5b2623..a864bfa591424 100644
--- a/x-pack/plugins/uptime/server/lib/requests/search/refine_potential_matches.ts
+++ b/x-pack/plugins/uptime/server/lib/requests/search/refine_potential_matches.ts
@@ -38,6 +38,12 @@ export const fullyMatchingIds = (queryResult: any, statusFilter?: string): Monit
for (const locBucket of monBucket.location.buckets) {
const latest = locBucket.summaries.latest.hits.hits[0];
+ // It is possible for no latest summary to exist in this bucket if only partial
+ // non-summary docs exist
+ if (!latest) {
+ continue;
+ }
+
const latestStillMatching = locBucket.latest_matching.top.hits.hits[0];
// If the most recent document still matches the most recent document matching the current filters
// we can include this in the result
diff --git a/x-pack/test/api_integration/apis/uptime/rest/monitor_states_generated.ts b/x-pack/test/api_integration/apis/uptime/rest/monitor_states_generated.ts
index 3e06373042d59..69571099a2642 100644
--- a/x-pack/test/api_integration/apis/uptime/rest/monitor_states_generated.ts
+++ b/x-pack/test/api_integration/apis/uptime/rest/monitor_states_generated.ts
@@ -24,6 +24,30 @@ export default function ({ getService }: FtrProviderContext) {
before('load heartbeat data', () => getService('esArchiver').load('uptime/blank'));
after('unload heartbeat index', () => getService('esArchiver').unload('uptime/blank'));
+ // In this case we don't actually have any monitors to display
+ // but the query should still return successfully. This has
+ // caused bugs in the past because a bucket of monitor data
+ // was available and the query code assumed at least one
+ // event would be a summary for each monitor.
+ // See https://github.com/elastic/kibana/issues/81950
+ describe('checks with no summaries', async () => {
+ const testMonitorId = 'scope-test-id';
+ before(async () => {
+ const es = getService('legacyEs');
+ dateRangeStart = new Date().toISOString();
+ await makeChecksWithStatus(es, testMonitorId, 1, numIps, 1, {}, 'up', (d) => {
+ delete d.summary;
+ return d;
+ });
+ });
+
+ it('should return no monitors and have no errors', async () => {
+ const url = getBaseUrl(dateRangeStart, new Date().toISOString());
+ const apiResponse = await supertest.get(url);
+ expect(apiResponse.status).to.equal(200);
+ });
+ });
+
describe('query document scoping with mismatched check statuses', async () => {
let checks: any[] = [];
let nonSummaryIp: string | null = null;
From b5e3e18ea4b478f5a7dfb4b3a8bfa66ebed07fad Mon Sep 17 00:00:00 2001
From: Wylie Conlon
Date: Thu, 29 Oct 2020 10:48:49 -0400
Subject: [PATCH 30/73] [Lens] Stop using multi-level metrics in Lens pie
charts (#81523)
* [Lens] Stop using multi-level metrics in Lens
* Fix linting
* Simplify even more
---
.../indexpattern.test.ts | 58 ++++++++++-
.../indexpattern_datasource/to_expression.ts | 24 +----
.../pie_visualization/render_function.tsx | 41 +++-----
.../pie_visualization/render_helpers.test.ts | 95 ++++++-------------
.../pie_visualization/render_helpers.ts | 13 +--
.../lens/public/pie_visualization/types.ts | 6 --
6 files changed, 99 insertions(+), 138 deletions(-)
diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.test.ts b/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.test.ts
index 900cd02622aaf..77dc6f97fb236 100644
--- a/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.test.ts
+++ b/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.test.ts
@@ -319,10 +319,10 @@ describe('IndexPattern Data Source', () => {
"1",
],
"metricsAtAllLevels": Array [
- true,
+ false,
],
"partialRows": Array [
- true,
+ false,
],
"timeFields": Array [
"timestamp",
@@ -334,7 +334,7 @@ describe('IndexPattern Data Source', () => {
Object {
"arguments": Object {
"idMap": Array [
- "{\\"col--1-col1\\":{\\"label\\":\\"Count of records\\",\\"dataType\\":\\"number\\",\\"isBucketed\\":false,\\"sourceField\\":\\"Records\\",\\"operationType\\":\\"count\\",\\"id\\":\\"col1\\"},\\"col-2-col2\\":{\\"label\\":\\"Date\\",\\"dataType\\":\\"date\\",\\"isBucketed\\":true,\\"operationType\\":\\"date_histogram\\",\\"sourceField\\":\\"timestamp\\",\\"params\\":{\\"interval\\":\\"1d\\"},\\"id\\":\\"col2\\"}}",
+ "{\\"col-0-col1\\":{\\"label\\":\\"Count of records\\",\\"dataType\\":\\"number\\",\\"isBucketed\\":false,\\"sourceField\\":\\"Records\\",\\"operationType\\":\\"count\\",\\"id\\":\\"col1\\"},\\"col-1-col2\\":{\\"label\\":\\"Date\\",\\"dataType\\":\\"date\\",\\"isBucketed\\":true,\\"operationType\\":\\"date_histogram\\",\\"sourceField\\":\\"timestamp\\",\\"params\\":{\\"interval\\":\\"1d\\"},\\"id\\":\\"col2\\"}}",
],
},
"function": "lens_rename_columns",
@@ -392,6 +392,58 @@ describe('IndexPattern Data Source', () => {
expect(ast.chain[0].arguments.timeFields).toEqual(['timestamp', 'another_datefield']);
});
+ it('should rename the output from esaggs when using flat query', () => {
+ const queryBaseState: IndexPatternBaseState = {
+ currentIndexPatternId: '1',
+ layers: {
+ first: {
+ indexPatternId: '1',
+ columnOrder: ['bucket1', 'bucket2', 'metric'],
+ columns: {
+ metric: {
+ label: 'Count of records',
+ dataType: 'number',
+ isBucketed: false,
+ sourceField: 'Records',
+ operationType: 'count',
+ },
+ bucket1: {
+ label: 'Date',
+ dataType: 'date',
+ isBucketed: true,
+ operationType: 'date_histogram',
+ sourceField: 'timestamp',
+ params: {
+ interval: '1d',
+ },
+ },
+ bucket2: {
+ label: 'Terms',
+ dataType: 'string',
+ isBucketed: true,
+ operationType: 'terms',
+ sourceField: 'geo.src',
+ params: {
+ orderBy: { type: 'alphabetical' },
+ orderDirection: 'asc',
+ size: 10,
+ },
+ },
+ },
+ },
+ },
+ };
+
+ const state = enrichBaseState(queryBaseState);
+ const ast = indexPatternDatasource.toExpression(state, 'first') as Ast;
+ expect(ast.chain[0].arguments.metricsAtAllLevels).toEqual([false]);
+ expect(JSON.parse(ast.chain[1].arguments.idMap[0] as string)).toEqual({
+ 'col-0-bucket1': expect.any(Object),
+ 'col-1-bucket2': expect.any(Object),
+ 'col-2-metric': expect.any(Object),
+ });
+ });
+
it('should not put date fields used outside date_histograms to the esaggs timeFields parameter', async () => {
const queryBaseState: IndexPatternBaseState = {
currentIndexPatternId: '1',
diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/to_expression.ts b/x-pack/plugins/lens/public/indexpattern_datasource/to_expression.ts
index e2c4323b56c2a..ea7aa62054e5c 100644
--- a/x-pack/plugins/lens/public/indexpattern_datasource/to_expression.ts
+++ b/x-pack/plugins/lens/public/indexpattern_datasource/to_expression.ts
@@ -29,34 +29,16 @@ function getExpressionForLayer(
}
const columnEntries = columnOrder.map((colId) => [colId, columns[colId]] as const);
- const bucketsCount = columnEntries.filter(([, entry]) => entry.isBucketed).length;
- const metricsCount = columnEntries.length - bucketsCount;
if (columnEntries.length) {
const aggs = columnEntries.map(([colId, col]) => {
return getEsAggsConfig(col, colId);
});
- /**
- * Because we are turning on metrics at all levels, the sequence generation
- * logic here is more complicated. Examples follow:
- *
- * Example 1: [Count]
- * Output: [`col-0-count`]
- *
- * Example 2: [Terms, Terms, Count]
- * Output: [`col-0-terms0`, `col-2-terms1`, `col-3-count`]
- *
- * Example 3: [Terms, Terms, Count, Max]
- * Output: [`col-0-terms0`, `col-3-terms1`, `col-4-count`, `col-5-max`]
- */
const idMap = columnEntries.reduce((currentIdMap, [colId, column], index) => {
- const newIndex = column.isBucketed
- ? index * (metricsCount + 1) // Buckets are spaced apart by N + 1
- : (index ? index + 1 : 0) - bucketsCount + (bucketsCount - 1) * (metricsCount + 1);
return {
...currentIdMap,
- [`col-${columnEntries.length === 1 ? 0 : newIndex}-${colId}`]: {
+ [`col-${columnEntries.length === 1 ? 0 : index}-${colId}`]: {
...column,
id: colId,
},
@@ -122,8 +104,8 @@ function getExpressionForLayer(
function: 'esaggs',
arguments: {
index: [indexPattern.id],
- metricsAtAllLevels: [true],
- partialRows: [true],
+ metricsAtAllLevels: [false],
+ partialRows: [false],
includeFormatHints: [true],
timeFields: allDateHistogramFields,
aggConfigs: [JSON.stringify(aggs)],
diff --git a/x-pack/plugins/lens/public/pie_visualization/render_function.tsx b/x-pack/plugins/lens/public/pie_visualization/render_function.tsx
index cb2458a76967c..d4c85ce9b8843 100644
--- a/x-pack/plugins/lens/public/pie_visualization/render_function.tsx
+++ b/x-pack/plugins/lens/public/pie_visualization/render_function.tsx
@@ -27,8 +27,8 @@ import {
import { FormatFactory, LensFilterEvent } from '../types';
import { VisualizationContainer } from '../visualization_container';
import { CHART_NAMES, DEFAULT_PERCENT_DECIMALS } from './constants';
-import { ColumnGroups, PieExpressionProps } from './types';
-import { getSliceValueWithFallback, getFilterContext } from './render_helpers';
+import { PieExpressionProps } from './types';
+import { getSliceValue, getFilterContext } from './render_helpers';
import { EmptyPlaceholder } from '../shared_components';
import './visualization.scss';
import { desanitizeFilterContext } from '../utils';
@@ -72,21 +72,6 @@ export function PieComponent(
});
}
- // The datatable for pie charts should include subtotals, like this:
- // [bucket, subtotal, bucket, count]
- // But the user only configured [bucket, bucket, count]
- const columnGroups: ColumnGroups = [];
- firstTable.columns.forEach((col) => {
- if (groups.includes(col.id)) {
- columnGroups.push({
- col,
- metrics: [],
- });
- } else if (columnGroups.length > 0) {
- columnGroups[columnGroups.length - 1].metrics.push(col);
- }
- });
-
const fillLabel: Partial = {
textInvertible: false,
valueFont: {
@@ -100,7 +85,9 @@ export function PieComponent(
fillLabel.valueFormatter = () => '';
}
- const layers: PartitionLayer[] = columnGroups.map(({ col }, layerIndex) => {
+ const bucketColumns = firstTable.columns.filter((col) => groups.includes(col.id));
+
+ const layers: PartitionLayer[] = bucketColumns.map((col, layerIndex) => {
return {
groupByRollup: (d: Datum) => d[col.id] ?? EMPTY_SLICE,
showAccessor: (d: Datum) => d !== EMPTY_SLICE,
@@ -116,7 +103,7 @@ export function PieComponent(
fillLabel:
isDarkMode &&
shape === 'treemap' &&
- layerIndex < columnGroups.length - 1 &&
+ layerIndex < bucketColumns.length - 1 &&
categoryDisplay !== 'hide'
? { ...fillLabel, textColor: euiDarkVars.euiTextColor }
: fillLabel,
@@ -136,10 +123,10 @@ export function PieComponent(
if (shape === 'treemap') {
// Only highlight the innermost color of the treemap, as it accurately represents area
- return layerIndex < columnGroups.length - 1 ? 'rgba(0,0,0,0)' : outputColor;
+ return layerIndex < bucketColumns.length - 1 ? 'rgba(0,0,0,0)' : outputColor;
}
- const lighten = (d.depth - 1) / (columnGroups.length * 2);
+ const lighten = (d.depth - 1) / (bucketColumns.length * 2);
return color(outputColor, 'hsl').lighten(lighten).hex();
},
},
@@ -198,8 +185,6 @@ export function PieComponent(
setState({ isReady: true });
}, []);
- const reverseGroups = [...columnGroups].reverse();
-
const hasNegative = firstTable.rows.some((row) => {
const value = row[metricColumn.id];
return typeof value === 'number' && value < 0;
@@ -243,16 +228,12 @@ export function PieComponent(
showLegend={
!hideLabels &&
(legendDisplay === 'show' ||
- (legendDisplay === 'default' && columnGroups.length > 1 && shape !== 'treemap'))
+ (legendDisplay === 'default' && bucketColumns.length > 1 && shape !== 'treemap'))
}
legendPosition={legendPosition || Position.Right}
legendMaxDepth={nestedLegend ? undefined : 1 /* Color is based only on first layer */}
onElementClick={(args) => {
- const context = getFilterContext(
- args[0][0] as LayerValue[],
- columnGroups.map(({ col }) => col.id),
- firstTable
- );
+ const context = getFilterContext(args[0][0] as LayerValue[], groups, firstTable);
onClickValue(desanitizeFilterContext(context));
}}
@@ -262,7 +243,7 @@ export function PieComponent(
getSliceValueWithFallback(d, reverseGroups, metricColumn)}
+ valueAccessor={(d: Datum) => getSliceValue(d, metricColumn)}
percentFormatter={(d: number) => percentFormatter.convert(d / 100)}
valueGetter={hideLabels || numberDisplay === 'value' ? undefined : 'percent'}
valueFormatter={(d: number) => (hideLabels ? '' : formatters[metricColumn.id].convert(d))}
diff --git a/x-pack/plugins/lens/public/pie_visualization/render_helpers.test.ts b/x-pack/plugins/lens/public/pie_visualization/render_helpers.test.ts
index d9ccda2a99ab2..22c63cd67281b 100644
--- a/x-pack/plugins/lens/public/pie_visualization/render_helpers.test.ts
+++ b/x-pack/plugins/lens/public/pie_visualization/render_helpers.test.ts
@@ -5,86 +5,47 @@
*/
import { Datatable } from 'src/plugins/expressions/public';
-import { getSliceValueWithFallback, getFilterContext } from './render_helpers';
-import { ColumnGroups } from './types';
+import { getSliceValue, getFilterContext } from './render_helpers';
describe('render helpers', () => {
- describe('#getSliceValueWithFallback', () => {
- describe('without fallback', () => {
- const columnGroups: ColumnGroups = [
- { col: { id: 'a', name: 'A', meta: { type: 'string' } }, metrics: [] },
- { col: { id: 'b', name: 'C', meta: { type: 'string' } }, metrics: [] },
- ];
-
- it('returns the metric when positive number', () => {
- expect(
- getSliceValueWithFallback({ a: 'Cat', b: 'Home', c: 5 }, columnGroups, {
+ describe('#getSliceValue', () => {
+ it('returns the metric when positive number', () => {
+ expect(
+ getSliceValue(
+ { a: 'Cat', b: 'Home', c: 5 },
+ {
id: 'c',
name: 'C',
meta: { type: 'number' },
- })
- ).toEqual(5);
- });
+ }
+ )
+ ).toEqual(5);
+ });
- it('returns the metric when negative number', () => {
- expect(
- getSliceValueWithFallback({ a: 'Cat', b: 'Home', c: -100 }, columnGroups, {
+ it('returns the metric when negative number', () => {
+ expect(
+ getSliceValue(
+ { a: 'Cat', b: 'Home', c: -100 },
+ {
id: 'c',
name: 'C',
meta: { type: 'number' },
- })
- ).toEqual(-100);
- });
+ }
+ )
+ ).toEqual(-100);
+ });
- it('returns epsilon when metric is 0 without fallback', () => {
- expect(
- getSliceValueWithFallback({ a: 'Cat', b: 'Home', c: 0 }, columnGroups, {
+ it('returns epsilon when metric is 0 without fallback', () => {
+ expect(
+ getSliceValue(
+ { a: 'Cat', b: 'Home', c: 0 },
+ {
id: 'c',
name: 'C',
meta: { type: 'number' },
- })
- ).toEqual(Number.EPSILON);
- });
- });
-
- describe('fallback behavior', () => {
- const columnGroups: ColumnGroups = [
- {
- col: { id: 'a', name: 'A', meta: { type: 'string' } },
- metrics: [{ id: 'a_subtotal', name: '', meta: { type: 'number' } }],
- },
- { col: { id: 'b', name: 'C', meta: { type: 'string' } }, metrics: [] },
- ];
-
- it('falls back to metric from previous column if available', () => {
- expect(
- getSliceValueWithFallback(
- { a: 'Cat', a_subtotal: 5, b: 'Home', c: undefined },
- columnGroups,
- { id: 'c', name: 'C', meta: { type: 'number' } }
- )
- ).toEqual(5);
- });
-
- it('uses epsilon if fallback is 0', () => {
- expect(
- getSliceValueWithFallback(
- { a: 'Cat', a_subtotal: 0, b: 'Home', c: undefined },
- columnGroups,
- { id: 'c', name: 'C', meta: { type: 'number' } }
- )
- ).toEqual(Number.EPSILON);
- });
-
- it('uses epsilon if fallback is missing', () => {
- expect(
- getSliceValueWithFallback(
- { a: 'Cat', a_subtotal: undefined, b: 'Home', c: undefined },
- columnGroups,
- { id: 'c', name: 'C', meta: { type: 'number' } }
- )
- ).toEqual(Number.EPSILON);
- });
+ }
+ )
+ ).toEqual(Number.EPSILON);
});
});
diff --git a/x-pack/plugins/lens/public/pie_visualization/render_helpers.ts b/x-pack/plugins/lens/public/pie_visualization/render_helpers.ts
index 26b4f9ccda853..978afcca6a550 100644
--- a/x-pack/plugins/lens/public/pie_visualization/render_helpers.ts
+++ b/x-pack/plugins/lens/public/pie_visualization/render_helpers.ts
@@ -6,22 +6,13 @@
import { Datum, LayerValue } from '@elastic/charts';
import { Datatable, DatatableColumn } from 'src/plugins/expressions/public';
-import { ColumnGroups } from './types';
import { LensFilterEvent } from '../types';
-export function getSliceValueWithFallback(
- d: Datum,
- reverseGroups: ColumnGroups,
- metricColumn: DatatableColumn
-) {
+export function getSliceValue(d: Datum, metricColumn: DatatableColumn) {
if (typeof d[metricColumn.id] === 'number' && d[metricColumn.id] !== 0) {
return d[metricColumn.id];
}
- // Sometimes there is missing data for outer groups
- // When there is missing data, we fall back to the next groups
- // This creates a sunburst effect
- const hasMetric = reverseGroups.find((group) => group.metrics.length && d[group.metrics[0].id]);
- return hasMetric ? d[hasMetric.metrics[0].id] || Number.EPSILON : Number.EPSILON;
+ return Number.EPSILON;
}
export function getFilterContext(
diff --git a/x-pack/plugins/lens/public/pie_visualization/types.ts b/x-pack/plugins/lens/public/pie_visualization/types.ts
index 0596e54870a94..54bececa13c2a 100644
--- a/x-pack/plugins/lens/public/pie_visualization/types.ts
+++ b/x-pack/plugins/lens/public/pie_visualization/types.ts
@@ -4,7 +4,6 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { DatatableColumn } from 'src/plugins/expressions/public';
import { LensMultiTable } from '../types';
export interface SharedLayerState {
@@ -38,8 +37,3 @@ export interface PieExpressionProps {
data: LensMultiTable;
args: PieExpressionArgs;
}
-
-export type ColumnGroups = Array<{
- col: DatatableColumn;
- metrics: DatatableColumn[];
-}>;
From 667ff6cd2cf54ace0b67490b2ea6174df3c737e2 Mon Sep 17 00:00:00 2001
From: Kerry Gallagher
Date: Thu, 29 Oct 2020 15:03:18 +0000
Subject: [PATCH 31/73] [User experience] Enhance page load duration metrics
(#81915)
* Enhance page load duration metrics and helper tooltips
---
.../step_definitions/csm/csm_dashboard.ts | 2 +-
.../step_definitions/csm/csm_filters.ts | 4 +-
.../step_definitions/csm/percentile_select.ts | 2 +-
.../csm/service_name_filter.ts | 2 +-
.../app/RumDashboard/ClientMetrics/index.tsx | 44 ++++++++++++++--
.../app/RumDashboard/RumDashboard.tsx | 3 +-
.../RumDashboard/UXMetrics/KeyUXMetrics.tsx | 51 ++++++++++++++++---
.../UXMetrics/__tests__/KeyUXMetrics.test.tsx | 28 +++++++---
.../RumDashboard/UXMetrics/translations.ts | 40 +++++++++++++++
.../app/RumDashboard/translations.ts | 21 ++++++++
.../__snapshots__/queries.test.ts.snap | 4 +-
.../lib/rum_client/get_client_metrics.ts | 24 +++++----
12 files changed, 191 insertions(+), 34 deletions(-)
diff --git a/x-pack/plugins/apm/e2e/cypress/support/step_definitions/csm/csm_dashboard.ts b/x-pack/plugins/apm/e2e/cypress/support/step_definitions/csm/csm_dashboard.ts
index a8edf862ab256..d8540c3f3efd7 100644
--- a/x-pack/plugins/apm/e2e/cypress/support/step_definitions/csm/csm_dashboard.ts
+++ b/x-pack/plugins/apm/e2e/cypress/support/step_definitions/csm/csm_dashboard.ts
@@ -26,7 +26,7 @@ Given(`a user browses the APM UI application for RUM Data`, () => {
});
Then(`should have correct client metrics`, () => {
- const metrics = ['4 ms', '58 ms', '55'];
+ const metrics = ['80 ms', '4 ms', '76 ms', '55'];
verifyClientMetrics(metrics, true);
});
diff --git a/x-pack/plugins/apm/e2e/cypress/support/step_definitions/csm/csm_filters.ts b/x-pack/plugins/apm/e2e/cypress/support/step_definitions/csm/csm_filters.ts
index 5c2109bb518c2..88287286c66c5 100644
--- a/x-pack/plugins/apm/e2e/cypress/support/step_definitions/csm/csm_filters.ts
+++ b/x-pack/plugins/apm/e2e/cypress/support/step_definitions/csm/csm_filters.ts
@@ -56,7 +56,9 @@ Then(/^it filters the client metrics "([^"]*)"$/, (filterName) => {
cy.get('.euiStat__title-isLoading').should('not.be.visible');
const data =
- filterName === 'os' ? ['5 ms', '64 ms', '8'] : ['4 ms', '55 ms', '28'];
+ filterName === 'os'
+ ? ['82 ms', '5 ms', '77 ms', '8']
+ : ['75 ms', '4 ms', '71 ms', '28'];
verifyClientMetrics(data, true);
diff --git a/x-pack/plugins/apm/e2e/cypress/support/step_definitions/csm/percentile_select.ts b/x-pack/plugins/apm/e2e/cypress/support/step_definitions/csm/percentile_select.ts
index 314254883b2fd..44802bbce6208 100644
--- a/x-pack/plugins/apm/e2e/cypress/support/step_definitions/csm/percentile_select.ts
+++ b/x-pack/plugins/apm/e2e/cypress/support/step_definitions/csm/percentile_select.ts
@@ -16,7 +16,7 @@ When('the user changes the selected percentile', () => {
});
Then(`it displays client metric related to that percentile`, () => {
- const metrics = ['14 ms', '131 ms', '55'];
+ const metrics = ['165 ms', '14 ms', '151 ms', '55'];
verifyClientMetrics(metrics, false);
diff --git a/x-pack/plugins/apm/e2e/cypress/support/step_definitions/csm/service_name_filter.ts b/x-pack/plugins/apm/e2e/cypress/support/step_definitions/csm/service_name_filter.ts
index 20c6a3fb72aa9..609d0d18f5bc8 100644
--- a/x-pack/plugins/apm/e2e/cypress/support/step_definitions/csm/service_name_filter.ts
+++ b/x-pack/plugins/apm/e2e/cypress/support/step_definitions/csm/service_name_filter.ts
@@ -15,7 +15,7 @@ When('the user changes the selected service name', () => {
});
Then(`it displays relevant client metrics`, () => {
- const metrics = ['4 ms', '58 ms', '55'];
+ const metrics = ['80 ms', '4 ms', '76 ms', '55'];
verifyClientMetrics(metrics, false);
});
diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/ClientMetrics/index.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/ClientMetrics/index.tsx
index 0b4dcea5d12e0..b6924b9552699 100644
--- a/x-pack/plugins/apm/public/components/app/RumDashboard/ClientMetrics/index.tsx
+++ b/x-pack/plugins/apm/public/components/app/RumDashboard/ClientMetrics/index.tsx
@@ -7,7 +7,13 @@ import * as React from 'react';
import numeral from '@elastic/numeral';
import styled from 'styled-components';
import { useContext, useEffect } from 'react';
-import { EuiFlexGroup, EuiFlexItem, EuiStat, EuiToolTip } from '@elastic/eui';
+import {
+ EuiFlexGroup,
+ EuiFlexItem,
+ EuiStat,
+ EuiToolTip,
+ EuiIconTip,
+} from '@elastic/eui';
import { useFetcher } from '../../../../hooks/useFetcher';
import { I18LABELS } from '../translations';
import { useUxQuery } from '../hooks/useUxQuery';
@@ -70,11 +76,35 @@ export function ClientMetrics() {
return (
+
+
+ {I18LABELS.totalPageLoad}
+
+ >
+ }
+ isLoading={status !== 'success'}
+ />
+
+ {I18LABELS.backEnd}
+
+ >
+ }
isLoading={status !== 'success'}
/>
@@ -82,7 +112,15 @@ export function ClientMetrics() {
+ {I18LABELS.frontEnd}
+
+ >
+ }
isLoading={status !== 'success'}
/>
diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/RumDashboard.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/RumDashboard.tsx
index b19adb12d02d4..e4e9109f007e7 100644
--- a/x-pack/plugins/apm/public/components/app/RumDashboard/RumDashboard.tsx
+++ b/x-pack/plugins/apm/public/components/app/RumDashboard/RumDashboard.tsx
@@ -36,8 +36,7 @@ export function RumDashboard() {
- {I18LABELS.pageLoadDuration} (
- {getPercentileLabel(percentile!)})
+ {I18LABELS.pageLoad} ({getPercentileLabel(percentile!)})
diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/UXMetrics/KeyUXMetrics.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/UXMetrics/KeyUXMetrics.tsx
index e91f129195366..c7fe8e885020a 100644
--- a/x-pack/plugins/apm/public/components/app/RumDashboard/UXMetrics/KeyUXMetrics.tsx
+++ b/x-pack/plugins/apm/public/components/app/RumDashboard/UXMetrics/KeyUXMetrics.tsx
@@ -5,15 +5,20 @@
*/
import React from 'react';
-import { EuiFlexItem, EuiStat, EuiFlexGroup } from '@elastic/eui';
+import { EuiFlexItem, EuiStat, EuiFlexGroup, EuiIconTip } from '@elastic/eui';
import numeral from '@elastic/numeral';
import {
DATA_UNDEFINED_LABEL,
FCP_LABEL,
+ FCP_TOOLTIP,
LONGEST_LONG_TASK,
+ LONGEST_LONG_TASK_TOOLTIP,
NO_OF_LONG_TASK,
+ NO_OF_LONG_TASK_TOOLTIP,
SUM_LONG_TASKS,
+ SUM_LONG_TASKS_TOOLTIP,
TBT_LABEL,
+ TBT_TOOLTIP,
} from './translations';
import { useFetcher } from '../../../../hooks/useFetcher';
import { useUxQuery } from '../hooks/useUxQuery';
@@ -70,7 +75,12 @@ export function KeyUXMetrics({ data, loading }: Props) {
+ {FCP_LABEL}
+
+ >
+ }
isLoading={loading}
/>
@@ -78,7 +88,12 @@ export function KeyUXMetrics({ data, loading }: Props) {
+ {TBT_LABEL}
+
+ >
+ }
isLoading={loading}
/>
@@ -90,7 +105,15 @@ export function KeyUXMetrics({ data, loading }: Props) {
? numeral(longTaskData?.noOfLongTasks).format('0,0')
: DATA_UNDEFINED_LABEL
}
- description={NO_OF_LONG_TASK}
+ description={
+ <>
+ {NO_OF_LONG_TASK}
+
+ >
+ }
isLoading={status !== 'success'}
/>
@@ -98,7 +121,15 @@ export function KeyUXMetrics({ data, loading }: Props) {
+ {LONGEST_LONG_TASK}
+
+ >
+ }
isLoading={status !== 'success'}
/>
@@ -106,7 +137,15 @@ export function KeyUXMetrics({ data, loading }: Props) {
+ {SUM_LONG_TASKS}
+
+ >
+ }
isLoading={status !== 'success'}
/>
diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/UXMetrics/__tests__/KeyUXMetrics.test.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/UXMetrics/__tests__/KeyUXMetrics.test.tsx
index 329339deb2f89..3a6323a747a70 100644
--- a/x-pack/plugins/apm/public/components/app/RumDashboard/UXMetrics/__tests__/KeyUXMetrics.test.tsx
+++ b/x-pack/plugins/apm/public/components/app/RumDashboard/UXMetrics/__tests__/KeyUXMetrics.test.tsx
@@ -19,7 +19,7 @@ describe('KeyUXMetrics', () => {
status: fetcherHook.FETCH_STATUS.SUCCESS,
refetch: jest.fn(),
});
- const { getByText } = render(
+ const { getAllByText } = render(
{
/>
);
- expect(getByText('Longest long task duration 271 ms')).toBeInTheDocument();
- expect(getByText('Total long tasks duration 520 ms')).toBeInTheDocument();
- expect(getByText('No. of long tasks 3')).toBeInTheDocument();
- expect(getByText('Total blocking time 271 ms')).toBeInTheDocument();
- expect(getByText('First contentful paint 1.27 s')).toBeInTheDocument();
+ const checkText = (text: string) => {
+ return (content: any, node: any) => {
+ return node?.textContent?.includes(text);
+ };
+ };
+
+ expect(
+ getAllByText(checkText('Longest long task duration271 ms'))[0]
+ ).toBeInTheDocument();
+ expect(
+ getAllByText(checkText('Total long tasks duration520 ms'))[0]
+ ).toBeInTheDocument();
+ expect(
+ getAllByText(checkText('No. of long tasks3'))[0]
+ ).toBeInTheDocument();
+ expect(
+ getAllByText(checkText('Total blocking time271 ms'))[0]
+ ).toBeInTheDocument();
+ expect(
+ getAllByText(checkText('First contentful paint1.27 s'))[0]
+ ).toBeInTheDocument();
});
});
diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/UXMetrics/translations.ts b/x-pack/plugins/apm/public/components/app/RumDashboard/UXMetrics/translations.ts
index 5920dc92f558d..3795f2f102237 100644
--- a/x-pack/plugins/apm/public/components/app/RumDashboard/UXMetrics/translations.ts
+++ b/x-pack/plugins/apm/public/components/app/RumDashboard/UXMetrics/translations.ts
@@ -18,10 +18,26 @@ export const FCP_LABEL = i18n.translate('xpack.apm.rum.coreVitals.fcp', {
defaultMessage: 'First contentful paint',
});
+export const FCP_TOOLTIP = i18n.translate(
+ 'xpack.apm.rum.coreVitals.fcpTooltip',
+ {
+ defaultMessage:
+ 'First contentful paint (FCP) focusses on the initial rendering and measures the time from when the page starts loading to when any part of the page’s content is displayed on the screen.',
+ }
+);
+
export const TBT_LABEL = i18n.translate('xpack.apm.rum.coreVitals.tbt', {
defaultMessage: 'Total blocking time',
});
+export const TBT_TOOLTIP = i18n.translate(
+ 'xpack.apm.rum.coreVitals.tbtTooltip',
+ {
+ defaultMessage:
+ 'Total blocking time (TBT) is the sum of the blocking time (duration above 50 ms) for each long task that occurs between the First contentful paint and the time when the transaction is completed.',
+ }
+);
+
export const NO_OF_LONG_TASK = i18n.translate(
'xpack.apm.rum.uxMetrics.noOfLongTasks',
{
@@ -29,6 +45,14 @@ export const NO_OF_LONG_TASK = i18n.translate(
}
);
+export const NO_OF_LONG_TASK_TOOLTIP = i18n.translate(
+ 'xpack.apm.rum.uxMetrics.noOfLongTasksTooltip',
+ {
+ defaultMessage:
+ 'The number of long tasks, a long task is defined as any user activity or browser task that monopolizes the UI thread for extended periods (greater than 50 milliseconds) and blocks other critical tasks (frame rate or input latency) from being executed.',
+ }
+);
+
export const LONGEST_LONG_TASK = i18n.translate(
'xpack.apm.rum.uxMetrics.longestLongTasks',
{
@@ -36,6 +60,14 @@ export const LONGEST_LONG_TASK = i18n.translate(
}
);
+export const LONGEST_LONG_TASK_TOOLTIP = i18n.translate(
+ 'xpack.apm.rum.uxMetrics.longestLongTasksTooltip',
+ {
+ defaultMessage:
+ 'The duration of the longest long task, a long task is defined as any user activity or browser task that monopolizes the UI thread for extended periods (greater than 50 milliseconds) and blocks other critical tasks (frame rate or input latency) from being executed.',
+ }
+);
+
export const SUM_LONG_TASKS = i18n.translate(
'xpack.apm.rum.uxMetrics.sumLongTasks',
{
@@ -43,6 +75,14 @@ export const SUM_LONG_TASKS = i18n.translate(
}
);
+export const SUM_LONG_TASKS_TOOLTIP = i18n.translate(
+ 'xpack.apm.rum.uxMetrics.sumLongTasksTooltip',
+ {
+ defaultMessage:
+ 'The total duration of long tasks, a long task is defined as any user activity or browser task that monopolizes the UI thread for extended periods (greater than 50 milliseconds) and blocks other critical tasks (frame rate or input latency) from being executed.',
+ }
+);
+
export const getPercentileLabel = (value: number) => {
if (value === 50) return I18LABELS.median;
diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/translations.ts b/x-pack/plugins/apm/public/components/app/RumDashboard/translations.ts
index b7ecfc08db13b..75df1381d8a1d 100644
--- a/x-pack/plugins/apm/public/components/app/RumDashboard/translations.ts
+++ b/x-pack/plugins/apm/public/components/app/RumDashboard/translations.ts
@@ -10,6 +10,9 @@ export const I18LABELS = {
dataMissing: i18n.translate('xpack.apm.rum.dashboard.dataMissing', {
defaultMessage: 'N/A',
}),
+ totalPageLoad: i18n.translate('xpack.apm.rum.dashboard.totalPageLoad', {
+ defaultMessage: 'Total',
+ }),
backEnd: i18n.translate('xpack.apm.rum.dashboard.backend', {
defaultMessage: 'Backend',
}),
@@ -34,6 +37,9 @@ export const I18LABELS = {
defaultMessage: 'Page load duration',
}
),
+ pageLoad: i18n.translate('xpack.apm.rum.dashboard.pageLoad.label', {
+ defaultMessage: 'Page load',
+ }),
pageLoadDistribution: i18n.translate(
'xpack.apm.rum.dashboard.pageLoadDistribution.label',
{
@@ -156,6 +162,21 @@ export const I18LABELS = {
noData: i18n.translate('xpack.apm.ux.visitorBreakdown.noData', {
defaultMessage: 'No data.',
}),
+ // Helper tooltips
+ totalPageLoadTooltip: i18n.translate(
+ 'xpack.apm.rum.dashboard.tooltips.totalPageLoad',
+ {
+ defaultMessage: 'Total represents the full page load duration',
+ }
+ ),
+ frontEndTooltip: i18n.translate('xpack.apm.rum.dashboard.tooltips.frontEnd', {
+ defaultMessage:
+ 'Frontend time represents the total page load duration minus the backend time',
+ }),
+ backEndTooltip: i18n.translate('xpack.apm.rum.dashboard.tooltips.backEnd', {
+ defaultMessage:
+ 'Backend time represents time to first byte (TTFB), which is when the first response packet is received after the request has been made',
+ }),
};
export const VisitorBreakdownLabel = i18n.translate(
diff --git a/x-pack/plugins/apm/server/lib/rum_client/__snapshots__/queries.test.ts.snap b/x-pack/plugins/apm/server/lib/rum_client/__snapshots__/queries.test.ts.snap
index 53dcd2f469148..b89c46f6e3fc5 100644
--- a/x-pack/plugins/apm/server/lib/rum_client/__snapshots__/queries.test.ts.snap
+++ b/x-pack/plugins/apm/server/lib/rum_client/__snapshots__/queries.test.ts.snap
@@ -22,9 +22,9 @@ Object {
],
},
},
- "domInteractive": Object {
+ "totalPageLoadDuration": Object {
"percentiles": Object {
- "field": "transaction.marks.agent.domInteractive",
+ "field": "transaction.duration.us",
"hdr": Object {
"number_of_significant_value_digits": 3,
},
diff --git a/x-pack/plugins/apm/server/lib/rum_client/get_client_metrics.ts b/x-pack/plugins/apm/server/lib/rum_client/get_client_metrics.ts
index da65e69e7eb7c..6685a60f84f05 100644
--- a/x-pack/plugins/apm/server/lib/rum_client/get_client_metrics.ts
+++ b/x-pack/plugins/apm/server/lib/rum_client/get_client_metrics.ts
@@ -8,8 +8,8 @@ import { getRumPageLoadTransactionsProjection } from '../../projections/rum_page
import { mergeProjection } from '../../projections/util/merge_projection';
import { Setup, SetupTimeRange } from '../helpers/setup_request';
import {
- TRANSACTION_DOM_INTERACTIVE,
TRANSACTION_TIME_TO_FIRST_BYTE,
+ TRANSACTION_DURATION,
} from '../../../common/elasticsearch_fieldnames';
export async function getClientMetrics({
@@ -37,18 +37,18 @@ export async function getClientMetrics({
exists: { field: 'transaction.marks.navigationTiming.fetchStart' },
},
aggs: {
- backEnd: {
+ totalPageLoadDuration: {
percentiles: {
- field: TRANSACTION_TIME_TO_FIRST_BYTE,
+ field: TRANSACTION_DURATION,
percents: [percentile],
hdr: {
number_of_significant_value_digits: 3,
},
},
},
- domInteractive: {
+ backEnd: {
percentiles: {
- field: TRANSACTION_DOM_INTERACTIVE,
+ field: TRANSACTION_TIME_TO_FIRST_BYTE,
percents: [percentile],
hdr: {
number_of_significant_value_digits: 3,
@@ -64,17 +64,19 @@ export async function getClientMetrics({
const { apmEventClient } = setup;
const response = await apmEventClient.search(params);
const {
- hasFetchStartField: { backEnd, domInteractive },
+ hasFetchStartField: { backEnd, totalPageLoadDuration },
} = response.aggregations!;
const pkey = percentile.toFixed(1);
- // Divide by 1000 to convert ms into seconds
+ const totalPageLoadDurationValue = totalPageLoadDuration.values[pkey] ?? 0;
+ const totalPageLoadDurationValueMs = totalPageLoadDurationValue / 1000; // Microseconds to milliseconds
+ const backendValue = backEnd.values[pkey] ?? 0;
+
return {
pageViews: { value: response.hits.total.value ?? 0 },
- backEnd: { value: backEnd.values[pkey] || 0 },
- frontEnd: {
- value: (domInteractive.values[pkey] || 0) - (backEnd.values[pkey] || 0),
- },
+ totalPageLoadDuration: { value: totalPageLoadDurationValueMs },
+ backEnd: { value: backendValue },
+ frontEnd: { value: totalPageLoadDurationValueMs - backendValue },
};
}
From 59662eefd2dbfd98eaae20f04fd8120e15872c20 Mon Sep 17 00:00:00 2001
From: Joe Reuter
Date: Thu, 29 Oct 2020 16:06:12 +0100
Subject: [PATCH 32/73] [Lens] Add loading indicator during debounce time
(#80158)
---
...ressions-public.reactexpressionrenderer.md | 2 +-
...c.reactexpressionrendererprops.debounce.md | 11 +++++++
...ons-public.reactexpressionrendererprops.md | 1 +
src/plugins/expressions/public/public.api.md | 4 ++-
.../public/react_expression_renderer.test.tsx | 33 +++++++++++++++++++
.../public/react_expression_renderer.tsx | 32 ++++++++++++++----
.../editor_frame/suggestion_panel.tsx | 14 +++-----
7 files changed, 79 insertions(+), 18 deletions(-)
create mode 100644 docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.reactexpressionrendererprops.debounce.md
diff --git a/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.reactexpressionrenderer.md b/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.reactexpressionrenderer.md
index 66c2e1e3c0c8d..32a7151578658 100644
--- a/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.reactexpressionrenderer.md
+++ b/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.reactexpressionrenderer.md
@@ -7,5 +7,5 @@
Signature:
```typescript
-ReactExpressionRenderer: ({ className, dataAttrs, padding, renderError, expression, onEvent, reload$, ...expressionLoaderOptions }: ReactExpressionRendererProps) => JSX.Element
+ReactExpressionRenderer: ({ className, dataAttrs, padding, renderError, expression, onEvent, reload$, debounce, ...expressionLoaderOptions }: ReactExpressionRendererProps) => JSX.Element
```
diff --git a/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.reactexpressionrendererprops.debounce.md b/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.reactexpressionrendererprops.debounce.md
new file mode 100644
index 0000000000000..3f7eb12fbb7a8
--- /dev/null
+++ b/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.reactexpressionrendererprops.debounce.md
@@ -0,0 +1,11 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-expressions-public](./kibana-plugin-plugins-expressions-public.md) > [ReactExpressionRendererProps](./kibana-plugin-plugins-expressions-public.reactexpressionrendererprops.md) > [debounce](./kibana-plugin-plugins-expressions-public.reactexpressionrendererprops.debounce.md)
+
+## ReactExpressionRendererProps.debounce property
+
+Signature:
+
+```typescript
+debounce?: number;
+```
diff --git a/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.reactexpressionrendererprops.md b/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.reactexpressionrendererprops.md
index 5622516530edd..e4980ce04b9e2 100644
--- a/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.reactexpressionrendererprops.md
+++ b/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.reactexpressionrendererprops.md
@@ -16,6 +16,7 @@ export interface ReactExpressionRendererProps extends IExpressionLoaderParams
| --- | --- | --- |
| [className](./kibana-plugin-plugins-expressions-public.reactexpressionrendererprops.classname.md) | string
| |
| [dataAttrs](./kibana-plugin-plugins-expressions-public.reactexpressionrendererprops.dataattrs.md) | string[]
| |
+| [debounce](./kibana-plugin-plugins-expressions-public.reactexpressionrendererprops.debounce.md) | number
| |
| [expression](./kibana-plugin-plugins-expressions-public.reactexpressionrendererprops.expression.md) | string | ExpressionAstExpression
| |
| [onEvent](./kibana-plugin-plugins-expressions-public.reactexpressionrendererprops.onevent.md) | (event: ExpressionRendererEvent) => void
| |
| [padding](./kibana-plugin-plugins-expressions-public.reactexpressionrendererprops.padding.md) | 'xs' | 's' | 'm' | 'l' | 'xl'
| |
diff --git a/src/plugins/expressions/public/public.api.md b/src/plugins/expressions/public/public.api.md
index fe95cf5eb0cda..68a3507bbf166 100644
--- a/src/plugins/expressions/public/public.api.md
+++ b/src/plugins/expressions/public/public.api.md
@@ -1039,7 +1039,7 @@ export interface Range {
// Warning: (ae-missing-release-tag) "ReactExpressionRenderer" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
-export const ReactExpressionRenderer: ({ className, dataAttrs, padding, renderError, expression, onEvent, reload$, ...expressionLoaderOptions }: ReactExpressionRendererProps) => JSX.Element;
+export const ReactExpressionRenderer: ({ className, dataAttrs, padding, renderError, expression, onEvent, reload$, debounce, ...expressionLoaderOptions }: ReactExpressionRendererProps) => JSX.Element;
// Warning: (ae-missing-release-tag) "ReactExpressionRendererProps" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
@@ -1050,6 +1050,8 @@ export interface ReactExpressionRendererProps extends IExpressionLoaderParams {
// (undocumented)
dataAttrs?: string[];
// (undocumented)
+ debounce?: number;
+ // (undocumented)
expression: string | ExpressionAstExpression;
// (undocumented)
onEvent?: (event: ExpressionRendererEvent) => void;
diff --git a/src/plugins/expressions/public/react_expression_renderer.test.tsx b/src/plugins/expressions/public/react_expression_renderer.test.tsx
index 7c1711f056d69..052c2a9f6a24a 100644
--- a/src/plugins/expressions/public/react_expression_renderer.test.tsx
+++ b/src/plugins/expressions/public/react_expression_renderer.test.tsx
@@ -113,6 +113,39 @@ describe('ExpressionRenderer', () => {
instance.unmount();
});
+ it('waits for debounce period if specified', () => {
+ jest.useFakeTimers();
+
+ const refreshSubject = new Subject();
+ const loaderUpdate = jest.fn();
+
+ (ExpressionLoader as jest.Mock).mockImplementation(() => {
+ return {
+ render$: new Subject(),
+ data$: new Subject(),
+ loading$: new Subject(),
+ update: loaderUpdate,
+ destroy: jest.fn(),
+ };
+ });
+
+ const instance = mount(
+
+ );
+
+ instance.setProps({ expression: 'abc' });
+
+ expect(loaderUpdate).toHaveBeenCalledTimes(1);
+
+ act(() => {
+ jest.runAllTimers();
+ });
+
+ expect(loaderUpdate).toHaveBeenCalledTimes(2);
+
+ instance.unmount();
+ });
+
it('should display a custom error message if the user provides one and then remove it after successful render', () => {
const dataSubject = new Subject();
const data$ = dataSubject.asObservable().pipe(share());
diff --git a/src/plugins/expressions/public/react_expression_renderer.tsx b/src/plugins/expressions/public/react_expression_renderer.tsx
index 99d170c96666d..fecebf36ab7e6 100644
--- a/src/plugins/expressions/public/react_expression_renderer.tsx
+++ b/src/plugins/expressions/public/react_expression_renderer.tsx
@@ -45,6 +45,7 @@ export interface ReactExpressionRendererProps extends IExpressionLoaderParams {
* An observable which can be used to re-run the expression without destroying the component
*/
reload$?: Observable;
+ debounce?: number;
}
export type ReactExpressionRendererType = React.ComponentType;
@@ -71,6 +72,7 @@ export const ReactExpressionRenderer = ({
expression,
onEvent,
reload$,
+ debounce,
...expressionLoaderOptions
}: ReactExpressionRendererProps) => {
const mountpoint: React.MutableRefObject = useRef(null);
@@ -85,12 +87,28 @@ export const ReactExpressionRenderer = ({
const errorRenderHandlerRef: React.MutableRefObject = useRef(
null
);
+ const [debouncedExpression, setDebouncedExpression] = useState(expression);
+ useEffect(() => {
+ if (debounce === undefined) {
+ return;
+ }
+ const handler = setTimeout(() => {
+ setDebouncedExpression(expression);
+ }, debounce);
+
+ return () => {
+ clearTimeout(handler);
+ };
+ }, [expression, debounce]);
+
+ const activeExpression = debounce !== undefined ? debouncedExpression : expression;
+ const waitingForDebounceToComplete = debounce !== undefined && expression !== debouncedExpression;
/* eslint-disable react-hooks/exhaustive-deps */
// OK to ignore react-hooks/exhaustive-deps because options update is handled by calling .update()
useEffect(() => {
const subs: Subscription[] = [];
- expressionLoaderRef.current = new ExpressionLoader(mountpoint.current!, expression, {
+ expressionLoaderRef.current = new ExpressionLoader(mountpoint.current!, activeExpression, {
...expressionLoaderOptions,
// react component wrapper provides different
// error handling api which is easier to work with from react
@@ -146,21 +164,21 @@ export const ReactExpressionRenderer = ({
useEffect(() => {
const subscription = reload$?.subscribe(() => {
if (expressionLoaderRef.current) {
- expressionLoaderRef.current.update(expression, expressionLoaderOptions);
+ expressionLoaderRef.current.update(activeExpression, expressionLoaderOptions);
}
});
return () => subscription?.unsubscribe();
- }, [reload$, expression, ...Object.values(expressionLoaderOptions)]);
+ }, [reload$, activeExpression, ...Object.values(expressionLoaderOptions)]);
// Re-fetch data automatically when the inputs change
useShallowCompareEffect(
() => {
if (expressionLoaderRef.current) {
- expressionLoaderRef.current.update(expression, expressionLoaderOptions);
+ expressionLoaderRef.current.update(activeExpression, expressionLoaderOptions);
}
},
// when expression is changed by reference and when any other loaderOption is changed by reference
- [{ expression, ...expressionLoaderOptions }]
+ [{ activeExpression, ...expressionLoaderOptions }]
);
/* eslint-enable react-hooks/exhaustive-deps */
@@ -188,7 +206,9 @@ export const ReactExpressionRenderer = ({
return (
{state.isEmpty &&
}
- {state.isLoading &&
}
+ {(state.isLoading || waitingForDebounceToComplete) && (
+
+ )}
{!state.isLoading &&
state.error &&
renderError &&
diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.tsx
index 5e5e9cda954ee..63ee02ac0404d 100644
--- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.tsx
+++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.tsx
@@ -32,16 +32,11 @@ import {
ReactExpressionRendererType,
} from '../../../../../../src/plugins/expressions/public';
import { prependDatasourceExpression } from './expression_helpers';
-import { debouncedComponent } from '../../debounced_component';
import { trackUiEvent, trackSuggestionEvent } from '../../lens_ui_telemetry';
import { DataPublicPluginStart } from '../../../../../../src/plugins/data/public';
const MAX_SUGGESTIONS_DISPLAYED = 5;
-// TODO: Remove this
when upstream fix is merged https://github.com/elastic/eui/issues/2329
-// eslint-disable-next-line
-const EuiPanelFixed = EuiPanel as React.ComponentType;
-
export interface SuggestionPanelProps {
activeDatasourceId: string | null;
datasourceMap: Record;
@@ -82,6 +77,7 @@ const PreviewRenderer = ({
className="lnsSuggestionPanel__expressionRenderer"
padding="s"
expression={expression}
+ debounce={2000}
renderError={() => {
return (
@@ -104,8 +100,6 @@ const PreviewRenderer = ({
);
};
-const DebouncedPreviewRenderer = debouncedComponent(PreviewRenderer, 2000);
-
const SuggestionPreview = ({
preview,
ExpressionRenderer: ExpressionRendererComponent,
@@ -126,7 +120,7 @@ const SuggestionPreview = ({
return (
-
{preview.expression ? (
- {preview.title}
)}
-
+
);
From 995111ad8a4d74fe546f9c77627c865ce4d95747 Mon Sep 17 00:00:00 2001
From: Shahzad
Date: Thu, 29 Oct 2020 16:07:09 +0100
Subject: [PATCH 33/73] [Uptime] Use base path for screenshot url (#81930)
---
.../monitor/synthetics/__tests__/executed_journey.test.tsx | 3 +++
.../components/monitor/synthetics/executed_journey.tsx | 1 +
.../public/components/monitor/synthetics/executed_step.tsx | 3 +--
.../monitor/synthetics/step_screenshot_display.tsx | 6 ++++--
4 files changed, 9 insertions(+), 4 deletions(-)
diff --git a/x-pack/plugins/uptime/public/components/monitor/synthetics/__tests__/executed_journey.test.tsx b/x-pack/plugins/uptime/public/components/monitor/synthetics/__tests__/executed_journey.test.tsx
index 5ab815a3c0b5d..9fec9439b3ad5 100644
--- a/x-pack/plugins/uptime/public/components/monitor/synthetics/__tests__/executed_journey.test.tsx
+++ b/x-pack/plugins/uptime/public/components/monitor/synthetics/__tests__/executed_journey.test.tsx
@@ -253,6 +253,9 @@ describe('ExecutedJourney component', () => {
}
}
/>
+
`);
});
diff --git a/x-pack/plugins/uptime/public/components/monitor/synthetics/executed_journey.tsx b/x-pack/plugins/uptime/public/components/monitor/synthetics/executed_journey.tsx
index 2ffb3f0feb4dd..9a3e045017f9a 100644
--- a/x-pack/plugins/uptime/public/components/monitor/synthetics/executed_journey.tsx
+++ b/x-pack/plugins/uptime/public/components/monitor/synthetics/executed_journey.tsx
@@ -79,6 +79,7 @@ export const ExecutedJourney: FC = ({ journey }) => (
{journey.steps.filter(isStepEnd).map((step, index) => (
))}
+
);
diff --git a/x-pack/plugins/uptime/public/components/monitor/synthetics/executed_step.tsx b/x-pack/plugins/uptime/public/components/monitor/synthetics/executed_step.tsx
index 3c26ba12eea65..5966851973af2 100644
--- a/x-pack/plugins/uptime/public/components/monitor/synthetics/executed_step.tsx
+++ b/x-pack/plugins/uptime/public/components/monitor/synthetics/executed_step.tsx
@@ -41,7 +41,7 @@ export const ExecutedStep: FC = ({ step, index }) => (
-
+
@@ -87,6 +87,5 @@ export const ExecutedStep: FC = ({ step, index }) => (
-
>
);
diff --git a/x-pack/plugins/uptime/public/components/monitor/synthetics/step_screenshot_display.tsx b/x-pack/plugins/uptime/public/components/monitor/synthetics/step_screenshot_display.tsx
index 2e8ad4bd0c9a8..b81cf6bc1ec1d 100644
--- a/x-pack/plugins/uptime/public/components/monitor/synthetics/step_screenshot_display.tsx
+++ b/x-pack/plugins/uptime/public/components/monitor/synthetics/step_screenshot_display.tsx
@@ -16,7 +16,7 @@ import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
import React, { useContext, useEffect, useRef, useState, FC } from 'react';
import { useIntersection } from 'react-use';
-import { UptimeThemeContext } from '../../../contexts';
+import { UptimeSettingsContext, UptimeThemeContext } from '../../../contexts';
interface StepScreenshotDisplayProps {
screenshotExists?: boolean;
@@ -41,6 +41,8 @@ export const StepScreenshotDisplay: FC = ({
colors: { lightestShade: pageBackground },
} = useContext(UptimeThemeContext);
+ const { basePath } = useContext(UptimeSettingsContext);
+
const [isImagePopoverOpen, setIsImagePopoverOpen] = useState(false);
const [isOverlayOpen, setIsOverlayOpen] = useState(false);
@@ -59,7 +61,7 @@ export const StepScreenshotDisplay: FC = ({
}, [hasIntersected, isIntersecting, setHasIntersected]);
let content: JSX.Element | null = null;
- const imgSrc = `/api/uptime/journey/screenshot/${checkGroup}/${stepIndex}`;
+ const imgSrc = basePath + `/api/uptime/journey/screenshot/${checkGroup}/${stepIndex}`;
if (hasIntersected && screenshotExists) {
content = (
<>
From 3ee665683732da596fe32ba3194733d0fee5d2ad Mon Sep 17 00:00:00 2001
From: Jonathan Budzenski
Date: Thu, 29 Oct 2020 10:37:50 -0500
Subject: [PATCH 34/73] [deb/rpm] remove sysv (#74424)
Co-authored-by: Elastic Machine
Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
---
docs/migration/migrate_8_0.asciidoc | 10 +
docs/setup/install/deb-init.asciidoc | 20 --
docs/setup/install/deb.asciidoc | 8 -
docs/setup/install/rpm-init.asciidoc | 20 --
docs/setup/install/rpm.asciidoc | 7 -
docs/setup/start-stop.asciidoc | 21 +--
src/dev/build/tasks/os_packages/run_fpm.ts | 1 -
.../{sysv => systemd}/etc/default/kibana | 0
.../service_templates/sysv/etc/init.d/kibana | 174 ------------------
9 files changed, 12 insertions(+), 249 deletions(-)
delete mode 100644 docs/setup/install/deb-init.asciidoc
delete mode 100644 docs/setup/install/rpm-init.asciidoc
rename src/dev/build/tasks/os_packages/service_templates/{sysv => systemd}/etc/default/kibana (100%)
delete mode 100755 src/dev/build/tasks/os_packages/service_templates/sysv/etc/init.d/kibana
diff --git a/docs/migration/migrate_8_0.asciidoc b/docs/migration/migrate_8_0.asciidoc
index 0cb28ce0fb6e7..ef76121b21d29 100644
--- a/docs/migration/migrate_8_0.asciidoc
+++ b/docs/migration/migrate_8_0.asciidoc
@@ -167,4 +167,14 @@ The `xpack.` prefix has been removed for all telemetry configurations.
*Impact:*
For any configurations beginning with `xpack.telemetry`, remove the `xpack` prefix. Use {kibana-ref}/telemetry-settings-kbn.html#telemetry-general-settings[`telemetry.enabled`] instead.
+[float]
+=== SysV init support has been removed
+
+*Details:*
+All supported operating systems support using systemd service files. Any system that doesn't already have service aliased to use kibana.service should use `systemctl start kibana.service` instead of the `service start kibana`.
+
+*Impact:*
+Any installations using `.deb` or `.rpm` packages using SysV will need to migrate to systemd.
+
+
// end::notable-breaking-changes[]
diff --git a/docs/setup/install/deb-init.asciidoc b/docs/setup/install/deb-init.asciidoc
deleted file mode 100644
index 6e21b8f97cf7e..0000000000000
--- a/docs/setup/install/deb-init.asciidoc
+++ /dev/null
@@ -1,20 +0,0 @@
-==== Run {kib} with SysV `init`
-
-Use the `update-rc.d` command to configure Kibana to start automatically
-when the system boots up:
-
-[source,sh]
---------------------------------------------------
-sudo update-rc.d kibana defaults 95 10
---------------------------------------------------
-
-You can start and stop Kibana using the `service` command:
-
-[source,sh]
---------------------------------------------
-sudo -i service kibana start
-sudo -i service kibana stop
---------------------------------------------
-
-If Kibana fails to start for any reason, it will print the reason for
-failure to `STDOUT`. Log files can be found in `/var/log/kibana/`.
diff --git a/docs/setup/install/deb.asciidoc b/docs/setup/install/deb.asciidoc
index 234c02cee0be1..c830faf1432d7 100644
--- a/docs/setup/install/deb.asciidoc
+++ b/docs/setup/install/deb.asciidoc
@@ -160,15 +160,7 @@ https://artifacts.elastic.co/downloads/kibana/kibana-oss-{version}-amd64.deb
endif::[]
-==== SysV `init` vs `systemd`
-
-include::init-systemd.asciidoc[]
-
-[[deb-running-init]]
-include::deb-init.asciidoc[]
-
[[deb-running-systemd]]
-
include::systemd.asciidoc[]
[[deb-configuring]]
diff --git a/docs/setup/install/rpm-init.asciidoc b/docs/setup/install/rpm-init.asciidoc
deleted file mode 100644
index 08282635a014f..0000000000000
--- a/docs/setup/install/rpm-init.asciidoc
+++ /dev/null
@@ -1,20 +0,0 @@
-==== Run {kib} with SysV `init`
-
-Use the `chkconfig` command to configure Kibana to start automatically
-when the system boots up:
-
-[source,sh]
---------------------------------------------------
-sudo chkconfig --add kibana
---------------------------------------------------
-
-You can start and stop Kibana using the `service` command:
-
-[source,sh]
---------------------------------------------
-sudo -i service kibana start
-sudo -i service kibana stop
---------------------------------------------
-
-If Kibana fails to start for any reason, it will print the reason for
-failure to `STDOUT`. Log files can be found in `/var/log/kibana/`.
diff --git a/docs/setup/install/rpm.asciidoc b/docs/setup/install/rpm.asciidoc
index 1153353aa9a0f..0b63684808d7d 100644
--- a/docs/setup/install/rpm.asciidoc
+++ b/docs/setup/install/rpm.asciidoc
@@ -153,13 +153,6 @@ https://artifacts.elastic.co/downloads/kibana/kibana-oss-{version}-x86_64.rpm
endif::[]
-==== SysV `init` vs `systemd`
-
-include::init-systemd.asciidoc[]
-
-[[rpm-running-init]]
-include::rpm-init.asciidoc[]
-
[[rpm-running-systemd]]
include::systemd.asciidoc[]
diff --git a/docs/setup/start-stop.asciidoc b/docs/setup/start-stop.asciidoc
index 198bc76bbb400..8952cd3a23cd3 100644
--- a/docs/setup/start-stop.asciidoc
+++ b/docs/setup/start-stop.asciidoc
@@ -25,25 +25,8 @@ stop and start {kib} from the command line.
include::install/windows-running.asciidoc[]
[float]
-[[start-stop-deb]]
-=== Debian packages
-
-include::install/init-systemd.asciidoc[]
-
-[float]
-include::install/deb-init.asciidoc[]
-
-[float]
-include::install/systemd.asciidoc[]
-
-[float]
-[[start-stop-rpm]]
-=== RPM packages
-
-include::install/init-systemd.asciidoc[]
-
-[float]
-include::install/rpm-init.asciidoc[]
+[[start-stop-deb-rpm]]
+=== Debian and RPM packages
[float]
include::install/systemd.asciidoc[]
diff --git a/src/dev/build/tasks/os_packages/run_fpm.ts b/src/dev/build/tasks/os_packages/run_fpm.ts
index b8289f1da194f..e5de760ea11d0 100644
--- a/src/dev/build/tasks/os_packages/run_fpm.ts
+++ b/src/dev/build/tasks/os_packages/run_fpm.ts
@@ -134,7 +134,6 @@ export async function runFpm(
`${resolveWithTrailingSlash(fromBuild('data'))}=/var/lib/kibana/`,
// copy package configurations
- `${resolveWithTrailingSlash(__dirname, 'service_templates/sysv/')}=/`,
`${resolveWithTrailingSlash(__dirname, 'service_templates/systemd/')}=/`,
];
diff --git a/src/dev/build/tasks/os_packages/service_templates/sysv/etc/default/kibana b/src/dev/build/tasks/os_packages/service_templates/systemd/etc/default/kibana
similarity index 100%
rename from src/dev/build/tasks/os_packages/service_templates/sysv/etc/default/kibana
rename to src/dev/build/tasks/os_packages/service_templates/systemd/etc/default/kibana
diff --git a/src/dev/build/tasks/os_packages/service_templates/sysv/etc/init.d/kibana b/src/dev/build/tasks/os_packages/service_templates/sysv/etc/init.d/kibana
deleted file mode 100755
index eedd4898ce6c3..0000000000000
--- a/src/dev/build/tasks/os_packages/service_templates/sysv/etc/init.d/kibana
+++ /dev/null
@@ -1,174 +0,0 @@
-#!/bin/sh
-# Init script for kibana
-# Maintained by
-# Generated by pleaserun.
-# Implemented based on LSB Core 3.1:
-# * Sections: 20.2, 20.3
-#
-### BEGIN INIT INFO
-# Provides: kibana
-# Required-Start: $remote_fs $syslog
-# Required-Stop: $remote_fs $syslog
-# Default-Start: 2 3 4 5
-# Default-Stop: 0 1 6
-# Short-Description:
-# Description: Kibana
-### END INIT INFO
-
-#
-# Source function libraries if present.
-# (It improves integration with systemd)
-#
-# Red Hat
-if [ -f /etc/rc.d/init.d/functions ]; then
- . /etc/rc.d/init.d/functions
-
-# Debian
-elif [ -f /lib/lsb/init-functions ]; then
- . /lib/lsb/init-functions
-
-# SUSE
-elif [ -f /etc/rc.status ]; then
- . /etc/rc.status
- rc_reset
-fi
-
-name=kibana
-program=/usr/share/kibana/bin/kibana
-args="--logging.dest=/var/log/kibana/kibana.log"
-pidfile="/var/run/kibana/$name.pid"
-
-[ -r /etc/default/$name ] && . /etc/default/$name
-[ -r /etc/sysconfig/$name ] && . /etc/sysconfig/$name
-
-export KBN_PATH_CONF
-export NODE_OPTIONS
-
-[ -z "$nice" ] && nice=0
-
-trace() {
- logger -t "/etc/init.d/kibana" "$@"
-}
-
-emit() {
- trace "$@"
- echo "$@"
-}
-
-start() {
- [ ! -d "/var/run/kibana/" ] && mkdir "/var/run/kibana/"
- chown "$user":"$group" "/var/run/kibana/"
- chmod 755 "/var/run/kibana/"
-
- chroot --userspec "$user":"$group" "$chroot" sh -c "
-
- cd \"$chdir\"
- exec \"$program $args\"
- " >> /var/log/kibana/kibana.log 2>&1 &
-
- # Generate the pidfile from here. If we instead made the forked process
- # generate it there will be a race condition between the pidfile writing
- # and a process possibly asking for status.
- echo $! > $pidfile
-
- emit "$name started"
- return 0
-}
-
-stop() {
- # Try a few times to kill TERM the program
- if status ; then
- pid=$(cat "$pidfile")
- trace "Killing $name (pid $pid) with SIGTERM"
- kill -TERM $pid
- # Wait for it to exit.
- for i in 1 2 3 4 5 ; do
- trace "Waiting $name (pid $pid) to die..."
- status || break
- sleep 1
- done
- if status ; then
- if [ "$KILL_ON_STOP_TIMEOUT" -eq 1 ] ; then
- trace "Timeout reached. Killing $name (pid $pid) with SIGKILL. This may result in data loss."
- kill -KILL $pid
- emit "$name killed with SIGKILL."
- else
- emit "$name stop failed; still running."
- fi
- else
- emit "$name stopped."
- fi
- fi
-}
-
-status() {
- if [ -f "$pidfile" ] ; then
- pid=$(cat "$pidfile")
- if ps -p $pid > /dev/null 2> /dev/null ; then
- # process by this pid is running.
- # It may not be our pid, but that's what you get with just pidfiles.
- # TODO(sissel): Check if this process seems to be the same as the one we
- # expect. It'd be nice to use flock here, but flock uses fork, not exec,
- # so it makes it quite awkward to use in this case.
- return 0
- else
- return 2 # program is dead but pid file exists
- fi
- else
- return 3 # program is not running
- fi
-}
-
-force_stop() {
- if status ; then
- stop
- status && kill -KILL $(cat "$pidfile")
- fi
-}
-
-
-case "$1" in
- force-start|start|stop|force-stop|restart)
- trace "Attempting '$1' on kibana"
- ;;
-esac
-
-case "$1" in
- force-start)
- PRESTART=no
- exec "$0" start
- ;;
- start)
- status
- code=$?
- if [ $code -eq 0 ]; then
- emit "$name is already running"
- exit $code
- else
- start
- exit $?
- fi
- ;;
- stop) stop ;;
- force-stop) force_stop ;;
- status)
- status
- code=$?
- if [ $code -eq 0 ] ; then
- emit "$name is running"
- else
- emit "$name is not running"
- fi
- exit $code
- ;;
- restart)
-
- stop && start
- ;;
- *)
- echo "Usage: $SCRIPTNAME {start|force-start|stop|force-start|force-stop|status|restart}" >&2
- exit 3
- ;;
-esac
-
-exit $?
From 6deafd06b84d4c94ead42e0860e75d39a0c70ca0 Mon Sep 17 00:00:00 2001
From: Anton Dosov
Date: Thu, 29 Oct 2020 16:43:22 +0100
Subject: [PATCH 35/73] [Search] Use session service on a dashboard (#81297)
---
...ugins-embeddable-public.embeddableinput.md | 1 +
.../application/dashboard_app_controller.tsx | 17 +++----
.../embeddable/dashboard_container.test.tsx | 22 +++++++++
.../embeddable/dashboard_container.tsx | 12 ++++-
.../data/public/search/expressions/esaggs.ts | 7 ++-
.../embeddable/search_embeddable.ts | 9 +++-
src/plugins/embeddable/common/types.ts | 5 ++
.../lib/embeddables/embeddable.test.tsx | 15 ++++++
.../public/lib/embeddables/embeddable.tsx | 7 +--
src/plugins/embeddable/public/public.api.md | 1 +
.../common/adapters/request/types.ts | 1 +
.../requests/components/requests_view.tsx | 15 ++++++
.../public/embeddable/visualize_embeddable.ts | 1 +
.../embeddable/embeddable.test.tsx | 11 ++++-
.../embeddable/embeddable.tsx | 1 +
.../embeddable/expression_wrapper.tsx | 3 ++
.../dashboard/async_search/async_search.ts | 46 ++++++++++++++++--
.../dashboard/async_search/data.json | 48 +++++++++++++++++++
18 files changed, 202 insertions(+), 20 deletions(-)
diff --git a/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.embeddableinput.md b/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.embeddableinput.md
index d1d97d50f5948..f36f7b4ee77a4 100644
--- a/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.embeddableinput.md
+++ b/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.embeddableinput.md
@@ -19,5 +19,6 @@ export declare type EmbeddableInput = {
timeRange?: TimeRange;
query?: Query;
filters?: Filter[];
+ searchSessionId?: string;
};
```
diff --git a/src/plugins/dashboard/public/application/dashboard_app_controller.tsx b/src/plugins/dashboard/public/application/dashboard_app_controller.tsx
index fa45e433050ab..e5947b73b305b 100644
--- a/src/plugins/dashboard/public/application/dashboard_app_controller.tsx
+++ b/src/plugins/dashboard/public/application/dashboard_app_controller.tsx
@@ -139,7 +139,7 @@ export class DashboardAppController {
dashboardCapabilities,
scopedHistory,
embeddableCapabilities: { visualizeCapabilities, mapsCapabilities },
- data: { query: queryService },
+ data: { query: queryService, search: searchService },
core: {
notifications,
overlays,
@@ -412,8 +412,9 @@ export class DashboardAppController {
>(DASHBOARD_CONTAINER_TYPE);
if (dashboardFactory) {
+ const searchSessionId = searchService.session.start();
dashboardFactory
- .create(getDashboardInput())
+ .create({ ...getDashboardInput(), searchSessionId })
.then((container: DashboardContainer | ErrorEmbeddable | undefined) => {
if (container && !isErrorEmbeddable(container)) {
dashboardContainer = container;
@@ -572,7 +573,7 @@ export class DashboardAppController {
differences.filters = appStateDashboardInput.filters;
}
- Object.keys(_.omit(containerInput, ['filters'])).forEach((key) => {
+ Object.keys(_.omit(containerInput, ['filters', 'searchSessionId'])).forEach((key) => {
const containerValue = (containerInput as { [key: string]: unknown })[key];
const appStateValue = ((appStateDashboardInput as unknown) as { [key: string]: unknown })[
key
@@ -590,7 +591,8 @@ export class DashboardAppController {
const refreshDashboardContainer = () => {
const changes = getChangesFromAppStateForContainerState();
if (changes && dashboardContainer) {
- dashboardContainer.updateInput(changes);
+ const searchSessionId = searchService.session.start();
+ dashboardContainer.updateInput({ ...changes, searchSessionId });
}
};
@@ -1109,12 +1111,6 @@ export class DashboardAppController {
$scope.model.filters = filterManager.getFilters();
$scope.model.query = queryStringManager.getQuery();
dashboardStateManager.applyFilters($scope.model.query, $scope.model.filters);
- if (dashboardContainer) {
- dashboardContainer.updateInput({
- filters: $scope.model.filters,
- query: $scope.model.query,
- });
- }
},
});
@@ -1159,6 +1155,7 @@ export class DashboardAppController {
if (dashboardContainer) {
dashboardContainer.destroy();
}
+ searchService.session.clear();
});
}
}
diff --git a/src/plugins/dashboard/public/application/embeddable/dashboard_container.test.tsx b/src/plugins/dashboard/public/application/embeddable/dashboard_container.test.tsx
index a7226082d3dce..89aacf2a84029 100644
--- a/src/plugins/dashboard/public/application/embeddable/dashboard_container.test.tsx
+++ b/src/plugins/dashboard/public/application/embeddable/dashboard_container.test.tsx
@@ -134,3 +134,25 @@ test('Container view mode change propagates to new children', async () => {
expect(embeddable.getInput().viewMode).toBe(ViewMode.EDIT);
});
+
+test('searchSessionId propagates to children', async () => {
+ const searchSessionId1 = 'searchSessionId1';
+ const container = new DashboardContainer(
+ getSampleDashboardInput({ searchSessionId: searchSessionId1 }),
+ options
+ );
+ const embeddable = await container.addNewEmbeddable<
+ ContactCardEmbeddableInput,
+ ContactCardEmbeddableOutput,
+ ContactCardEmbeddable
+ >(CONTACT_CARD_EMBEDDABLE, {
+ firstName: 'Bob',
+ });
+
+ expect(embeddable.getInput().searchSessionId).toBe(searchSessionId1);
+
+ const searchSessionId2 = 'searchSessionId2';
+ container.updateInput({ searchSessionId: searchSessionId2 });
+
+ expect(embeddable.getInput().searchSessionId).toBe(searchSessionId2);
+});
diff --git a/src/plugins/dashboard/public/application/embeddable/dashboard_container.tsx b/src/plugins/dashboard/public/application/embeddable/dashboard_container.tsx
index 036880a1d088b..757488185fe8e 100644
--- a/src/plugins/dashboard/public/application/embeddable/dashboard_container.tsx
+++ b/src/plugins/dashboard/public/application/embeddable/dashboard_container.tsx
@@ -78,6 +78,7 @@ export interface InheritedChildInput extends IndexSignature {
viewMode: ViewMode;
hidePanelTitles?: boolean;
id: string;
+ searchSessionId?: string;
}
export interface DashboardContainerOptions {
@@ -228,7 +229,15 @@ export class DashboardContainer extends Container {
// Create a new search source that inherits the original search source
// but has the appropriate timeRange applied via a filter.
@@ -143,6 +145,7 @@ const handleCourierRequest = async ({
defaultMessage:
'This request queries Elasticsearch to fetch the data for the visualization.',
}),
+ searchSessionId,
}
);
request.stats(getRequestInspectorStats(requestSearchSource));
@@ -150,6 +153,7 @@ const handleCourierRequest = async ({
try {
const response = await requestSearchSource.fetch({
abortSignal,
+ sessionId: searchSessionId,
});
request.stats(getResponseInspectorStats(response, searchSource)).ok({ json: response });
@@ -248,7 +252,7 @@ export const esaggs = (): EsaggsExpressionFunctionDefinition => ({
multi: true,
},
},
- async fn(input, args, { inspectorAdapters, abortSignal }) {
+ async fn(input, args, { inspectorAdapters, abortSignal, getSearchSessionId }) {
const indexPatterns = getIndexPatterns();
const { filterManager } = getQueryService();
const searchService = getSearchService();
@@ -276,6 +280,7 @@ export const esaggs = (): EsaggsExpressionFunctionDefinition => ({
inspectorAdapters: inspectorAdapters as Adapters,
filterManager,
abortSignal: (abortSignal as unknown) as AbortSignal,
+ searchSessionId: getSearchSessionId(),
});
const table: Datatable = {
diff --git a/src/plugins/discover/public/application/embeddable/search_embeddable.ts b/src/plugins/discover/public/application/embeddable/search_embeddable.ts
index af88cacfcf992..170078076ec6f 100644
--- a/src/plugins/discover/public/application/embeddable/search_embeddable.ts
+++ b/src/plugins/discover/public/application/embeddable/search_embeddable.ts
@@ -266,6 +266,8 @@ export class SearchEmbeddable
}
private fetch = async () => {
+ const searchSessionId = this.input.searchSessionId;
+
if (!this.searchScope) return;
const { searchSource } = this.savedSearch;
@@ -292,7 +294,11 @@ export class SearchEmbeddable
const description = i18n.translate('discover.embeddable.inspectorRequestDescription', {
defaultMessage: 'This request queries Elasticsearch to fetch the data for the search.',
});
- const inspectorRequest = this.inspectorAdaptors.requests.start(title, { description });
+
+ const inspectorRequest = this.inspectorAdaptors.requests.start(title, {
+ description,
+ searchSessionId,
+ });
inspectorRequest.stats(getRequestInspectorStats(searchSource));
searchSource.getSearchRequestBody().then((body: Record) => {
inspectorRequest.json(body);
@@ -303,6 +309,7 @@ export class SearchEmbeddable
// Make the request
const resp = await searchSource.fetch({
abortSignal: this.abortController.signal,
+ sessionId: searchSessionId,
});
this.updateOutput({ loading: false, error: undefined });
diff --git a/src/plugins/embeddable/common/types.ts b/src/plugins/embeddable/common/types.ts
index 68b842c934de8..2737f2678ff32 100644
--- a/src/plugins/embeddable/common/types.ts
+++ b/src/plugins/embeddable/common/types.ts
@@ -67,4 +67,9 @@ export type EmbeddableInput = {
* Visualization filters used to narrow down results.
*/
filters?: Filter[];
+
+ /**
+ * Search session id to group searches
+ */
+ searchSessionId?: string;
};
diff --git a/src/plugins/embeddable/public/lib/embeddables/embeddable.test.tsx b/src/plugins/embeddable/public/lib/embeddables/embeddable.test.tsx
index 340d851f3eedf..b020006c0c2bb 100644
--- a/src/plugins/embeddable/public/lib/embeddables/embeddable.test.tsx
+++ b/src/plugins/embeddable/public/lib/embeddables/embeddable.test.tsx
@@ -25,6 +25,7 @@ import { EmbeddableOutput, EmbeddableInput } from './i_embeddable';
import { ViewMode } from '../types';
import { ContactCardEmbeddable } from '../test_samples/embeddables/contact_card/contact_card_embeddable';
import { FilterableEmbeddable } from '../test_samples/embeddables/filterable_embeddable';
+import type { Filter } from '../../../../data/public';
class TestClass {
constructor() {}
@@ -79,6 +80,20 @@ test('Embeddable reload is called if lastReloadRequest input time changes', asyn
expect(hello.reload).toBeCalledTimes(1);
});
+test('Embeddable reload is called if lastReloadRequest input time changed and new input is used', async () => {
+ const hello = new FilterableEmbeddable({ id: '123', filters: [], lastReloadRequestTime: 0 });
+
+ const aFilter = ({} as unknown) as Filter;
+ hello.reload = jest.fn(() => {
+ // when reload is called embeddable already has new input
+ expect(hello.getInput().filters).toEqual([aFilter]);
+ });
+
+ hello.updateInput({ lastReloadRequestTime: 1, filters: [aFilter] });
+
+ expect(hello.reload).toBeCalledTimes(1);
+});
+
test('Embeddable reload is not called if lastReloadRequest input time does not change', async () => {
const hello = new FilterableEmbeddable({ id: '123', filters: [], lastReloadRequestTime: 1 });
diff --git a/src/plugins/embeddable/public/lib/embeddables/embeddable.tsx b/src/plugins/embeddable/public/lib/embeddables/embeddable.tsx
index 9267d600360cf..c7afc157c1452 100644
--- a/src/plugins/embeddable/public/lib/embeddables/embeddable.tsx
+++ b/src/plugins/embeddable/public/lib/embeddables/embeddable.tsx
@@ -195,14 +195,15 @@ export abstract class Embeddable<
private onResetInput(newInput: TEmbeddableInput) {
if (!isEqual(this.input, newInput)) {
- if (this.input.lastReloadRequestTime !== newInput.lastReloadRequestTime) {
- this.reload();
- }
+ const oldLastReloadRequestTime = this.input.lastReloadRequestTime;
this.input = newInput;
this.input$.next(newInput);
this.updateOutput({
title: getPanelTitle(this.input, this.output),
} as Partial);
+ if (oldLastReloadRequestTime !== newInput.lastReloadRequestTime) {
+ this.reload();
+ }
}
}
diff --git a/src/plugins/embeddable/public/public.api.md b/src/plugins/embeddable/public/public.api.md
index 84dd97c8288fc..9939ba2a0f8a1 100644
--- a/src/plugins/embeddable/public/public.api.md
+++ b/src/plugins/embeddable/public/public.api.md
@@ -425,6 +425,7 @@ export type EmbeddableInput = {
timeRange?: TimeRange;
query?: Query;
filters?: Filter[];
+ searchSessionId?: string;
};
// Warning: (ae-missing-release-tag) "EmbeddableInstanceConfiguration" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
diff --git a/src/plugins/inspector/common/adapters/request/types.ts b/src/plugins/inspector/common/adapters/request/types.ts
index 0a62df7c8d10c..c08c2ef6f706f 100644
--- a/src/plugins/inspector/common/adapters/request/types.ts
+++ b/src/plugins/inspector/common/adapters/request/types.ts
@@ -49,6 +49,7 @@ export interface Request extends RequestParams {
export interface RequestParams {
id?: string;
description?: string;
+ searchSessionId?: string;
}
export interface RequestStatistics {
diff --git a/src/plugins/inspector/public/views/requests/components/requests_view.tsx b/src/plugins/inspector/public/views/requests/components/requests_view.tsx
index a433ea70dc35c..13575de0c5064 100644
--- a/src/plugins/inspector/public/views/requests/components/requests_view.tsx
+++ b/src/plugins/inspector/public/views/requests/components/requests_view.tsx
@@ -153,6 +153,21 @@ export class RequestsViewComponent extends Component
)}
+ {this.state.request && this.state.request.searchSessionId && (
+
+
+
+
+
+ )}
+
{this.state.request && }
diff --git a/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts b/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts
index a810b4b65528f..c12a0f0759018 100644
--- a/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts
+++ b/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts
@@ -374,6 +374,7 @@ export class VisualizeEmbeddable
query: this.input.query,
filters: this.input.filters,
},
+ searchSessionId: this.input.searchSessionId,
uiState: this.vis.uiState,
inspectorAdapters: this.inspectorAdapters,
};
diff --git a/x-pack/plugins/lens/public/editor_frame_service/embeddable/embeddable.test.tsx b/x-pack/plugins/lens/public/editor_frame_service/embeddable/embeddable.test.tsx
index 3e05d4ddfbc20..9dc59eacd40d3 100644
--- a/x-pack/plugins/lens/public/editor_frame_service/embeddable/embeddable.test.tsx
+++ b/x-pack/plugins/lens/public/editor_frame_service/embeddable/embeddable.test.tsx
@@ -172,6 +172,7 @@ describe('embeddable', () => {
timeRange,
query,
filters,
+ searchSessionId: 'searchSessionId',
});
expect(expressionRenderer).toHaveBeenCalledTimes(2);
@@ -182,7 +183,13 @@ describe('embeddable', () => {
const query: Query = { language: 'kquery', query: '' };
const filters: Filter[] = [{ meta: { alias: 'test', negate: false, disabled: false } }];
- const input = { savedObjectId: '123', timeRange, query, filters } as LensEmbeddableInput;
+ const input = {
+ savedObjectId: '123',
+ timeRange,
+ query,
+ filters,
+ searchSessionId: 'searchSessionId',
+ } as LensEmbeddableInput;
const embeddable = new Embeddable(
{
@@ -214,6 +221,8 @@ describe('embeddable', () => {
filters,
})
);
+
+ expect(expressionRenderer.mock.calls[0][0].searchSessionId).toBe(input.searchSessionId);
});
it('should merge external context with query and filters of the saved object', async () => {
diff --git a/x-pack/plugins/lens/public/editor_frame_service/embeddable/embeddable.tsx b/x-pack/plugins/lens/public/editor_frame_service/embeddable/embeddable.tsx
index d245b7f2fcde4..10c243a272138 100644
--- a/x-pack/plugins/lens/public/editor_frame_service/embeddable/embeddable.tsx
+++ b/x-pack/plugins/lens/public/editor_frame_service/embeddable/embeddable.tsx
@@ -177,6 +177,7 @@ export class Embeddable
ExpressionRenderer={this.expressionRenderer}
expression={this.expression || null}
searchContext={this.getMergedSearchContext()}
+ searchSessionId={this.input.searchSessionId}
handleEvent={this.handleEvent}
/>,
domNode
diff --git a/x-pack/plugins/lens/public/editor_frame_service/embeddable/expression_wrapper.tsx b/x-pack/plugins/lens/public/editor_frame_service/embeddable/expression_wrapper.tsx
index 4fb0630a305e7..13376e56e2144 100644
--- a/x-pack/plugins/lens/public/editor_frame_service/embeddable/expression_wrapper.tsx
+++ b/x-pack/plugins/lens/public/editor_frame_service/embeddable/expression_wrapper.tsx
@@ -19,6 +19,7 @@ export interface ExpressionWrapperProps {
ExpressionRenderer: ReactExpressionRendererType;
expression: string | null;
searchContext: ExecutionContextSearch;
+ searchSessionId?: string;
handleEvent: (event: ExpressionRendererEvent) => void;
}
@@ -27,6 +28,7 @@ export function ExpressionWrapper({
expression,
searchContext,
handleEvent,
+ searchSessionId,
}: ExpressionWrapperProps) {
return (
@@ -51,6 +53,7 @@ export function ExpressionWrapper({
padding="m"
expression={expression}
searchContext={searchContext}
+ searchSessionId={searchSessionId}
renderError={(errorMessage, error) => (
diff --git a/x-pack/test/functional/apps/dashboard/async_search/async_search.ts b/x-pack/test/functional/apps/dashboard/async_search/async_search.ts
index 6932a88635a67..4d37ee1589169 100644
--- a/x-pack/test/functional/apps/dashboard/async_search/async_search.ts
+++ b/x-pack/test/functional/apps/dashboard/async_search/async_search.ts
@@ -12,6 +12,9 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
const testSubjects = getService('testSubjects');
const log = getService('log');
const PageObjects = getPageObjects(['common', 'header', 'dashboard', 'visChart']);
+ const dashboardPanelActions = getService('dashboardPanelActions');
+ const inspector = getService('inspector');
+ const queryBar = getService('queryBar');
describe('dashboard with async search', () => {
before(async function () {
@@ -24,7 +27,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
it('not delayed should load', async () => {
await PageObjects.common.navigateToApp('dashboard');
- await PageObjects.dashboard.gotoDashboardEditMode('Not Delayed');
+ await PageObjects.dashboard.loadSavedDashboard('Not Delayed');
await PageObjects.header.waitUntilLoadingHasFinished();
await testSubjects.missingOrFail('embeddableErrorLabel');
const data = await PageObjects.visChart.getBarChartData('Sum of bytes');
@@ -33,7 +36,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
it('delayed should load', async () => {
await PageObjects.common.navigateToApp('dashboard');
- await PageObjects.dashboard.gotoDashboardEditMode('Delayed 5s');
+ await PageObjects.dashboard.loadSavedDashboard('Delayed 5s');
await PageObjects.header.waitUntilLoadingHasFinished();
await testSubjects.missingOrFail('embeddableErrorLabel');
const data = await PageObjects.visChart.getBarChartData('');
@@ -42,10 +45,47 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
it('timed out should show error', async () => {
await PageObjects.common.navigateToApp('dashboard');
- await PageObjects.dashboard.gotoDashboardEditMode('Delayed 15s');
+ await PageObjects.dashboard.loadSavedDashboard('Delayed 15s');
await PageObjects.header.waitUntilLoadingHasFinished();
await testSubjects.existOrFail('embeddableErrorLabel');
await testSubjects.existOrFail('searchTimeoutError');
});
+
+ it('multiple searches are grouped and only single error popup is shown', async () => {
+ await PageObjects.common.navigateToApp('dashboard');
+ await PageObjects.dashboard.loadSavedDashboard('Multiple delayed');
+ await PageObjects.header.waitUntilLoadingHasFinished();
+ await testSubjects.existOrFail('embeddableErrorLabel');
+ // there should be two failed panels
+ expect((await testSubjects.findAll('embeddableErrorLabel')).length).to.be(2);
+ // but only single error toast because searches are grouped
+ expect((await testSubjects.findAll('searchTimeoutError')).length).to.be(1);
+
+ // check that session ids are the same
+ const getSearchSessionIdByPanel = async (panelTitle: string) => {
+ await dashboardPanelActions.openInspectorByTitle(panelTitle);
+ await inspector.openInspectorRequestsView();
+ const searchSessionId = await (
+ await testSubjects.find('inspectorRequestSearchSessionId')
+ ).getAttribute('data-search-session-id');
+ await inspector.close();
+ return searchSessionId;
+ };
+
+ const panel1SessionId1 = await getSearchSessionIdByPanel('Sum of Bytes by Extension');
+ const panel2SessionId1 = await getSearchSessionIdByPanel(
+ 'Sum of Bytes by Extension (Delayed 5s)'
+ );
+ expect(panel1SessionId1).to.be(panel2SessionId1);
+
+ await queryBar.clickQuerySubmitButton();
+
+ const panel1SessionId2 = await getSearchSessionIdByPanel('Sum of Bytes by Extension');
+ const panel2SessionId2 = await getSearchSessionIdByPanel(
+ 'Sum of Bytes by Extension (Delayed 5s)'
+ );
+ expect(panel1SessionId2).to.be(panel2SessionId2);
+ expect(panel1SessionId1).not.to.be(panel1SessionId2);
+ });
});
}
diff --git a/x-pack/test/functional/es_archives/dashboard/async_search/data.json b/x-pack/test/functional/es_archives/dashboard/async_search/data.json
index 2990097e88d00..486c73f711a6b 100644
--- a/x-pack/test/functional/es_archives/dashboard/async_search/data.json
+++ b/x-pack/test/functional/es_archives/dashboard/async_search/data.json
@@ -194,4 +194,52 @@
}
}
+{
+ "type": "doc",
+ "value": {
+ "id": "dashboard:a41c6790-075d-11eb-be70-0bd5e8b57d03",
+ "index": ".kibana",
+ "source": {
+ "dashboard": {
+ "description": "",
+ "hits": 0,
+ "kibanaSavedObjectMeta": {
+ "searchSourceJSON": "{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"
+ },
+ "optionsJSON": "{\"useMargins\":true,\"hidePanelTitles\":false}",
+ "panelsJSON": "[{\"version\":\"8.0.0\",\"gridData\":{\"x\":0,\"y\":0,\"w\":24,\"h\":15,\"i\":\"ec585931-ce8e-43fd-aa94-a1a9612d24ba\"},\"panelIndex\":\"ec585931-ce8e-43fd-aa94-a1a9612d24ba\",\"embeddableConfig\":{},\"panelRefName\":\"panel_0\"},{\"version\":\"8.0.0\",\"gridData\":{\"x\":24,\"y\":0,\"w\":24,\"h\":15,\"i\":\"c7b18010-462b-4e55-a974-fdec2ae64b06\"},\"panelIndex\":\"c7b18010-462b-4e55-a974-fdec2ae64b06\",\"embeddableConfig\":{},\"panelRefName\":\"panel_1\"},{\"version\":\"8.0.0\",\"gridData\":{\"x\":0,\"y\":15,\"w\":24,\"h\":15,\"i\":\"e67704f7-20b7-4ade-8dee-972a9d187107\"},\"panelIndex\":\"e67704f7-20b7-4ade-8dee-972a9d187107\",\"embeddableConfig\":{},\"panelRefName\":\"panel_2\"},{\"version\":\"8.0.0\",\"gridData\":{\"x\":24,\"y\":15,\"w\":24,\"h\":15,\"i\":\"f0b03592-10f1-41cd-9929-0cb4163bcd16\"},\"panelIndex\":\"f0b03592-10f1-41cd-9929-0cb4163bcd16\",\"embeddableConfig\":{},\"panelRefName\":\"panel_3\"}]",
+ "refreshInterval": { "pause": true, "value": 0 },
+ "timeFrom": "2015-09-19T17:34:10.297Z",
+ "timeRestore": true,
+ "timeTo": "2015-09-23T00:09:17.180Z",
+ "title": "Multiple delayed",
+ "version": 1
+ },
+ "references": [
+ {
+ "id": "14501a50-01e3-11eb-9b63-176d7b28a352",
+ "name": "panel_0",
+ "type": "visualization"
+ },
+ {
+ "id": "50a67010-075d-11eb-be70-0bd5e8b57d02",
+ "name": "panel_1",
+ "type": "visualization"
+ },
+ {
+ "id": "6c9f3830-01e3-11eb-9b63-176d7b28a352",
+ "name": "panel_2",
+ "type": "visualization"
+ },
+ {
+ "id": "50a67010-075d-11eb-be70-0bd5e8b57d02",
+ "name": "panel_3",
+ "type": "visualization"
+ }
+ ],
+ "type": "dashboard",
+ "updated_at": "2020-03-19T11:59:53.701Z"
+ }
+ }
+}
From afd5fe3b8a197ee0177a661fa65f816031708970 Mon Sep 17 00:00:00 2001
From: Joe Reuter
Date: Thu, 29 Oct 2020 16:47:34 +0100
Subject: [PATCH 36/73] Date column utilities (#81007)
---
packages/kbn-optimizer/limits.yml | 2 +-
.../common/search/aggs/aggs_service.test.ts | 5 +-
.../data/common/search/aggs/aggs_service.ts | 20 ++-
.../search/aggs/buckets/date_histogram.ts | 21 +--
src/plugins/data/common/search/aggs/types.ts | 15 +++
.../data/common/search/aggs/utils/index.ts | 1 +
.../search/aggs/utils/infer_time_zone.test.ts | 79 ++++++++++++
.../search/aggs/utils/infer_time_zone.ts | 46 +++++++
.../aggs/utils/time_column_meta.test.ts | 121 ++++++++++++++++++
.../search/aggs/utils/time_column_meta.ts | 66 ++++++++++
src/plugins/data/public/public.api.md | 3 +-
.../public/search/aggs/aggs_service.test.ts | 5 +-
.../data/public/search/aggs/aggs_service.ts | 17 ++-
src/plugins/data/public/search/aggs/mocks.ts | 1 +
.../data/public/search/expressions/esaggs.ts | 7 +
.../data/public/search/search_service.ts | 2 +-
.../data/server/index_patterns/mocks.ts | 2 +-
.../server/search/aggs/aggs_service.test.ts | 2 +
.../data/server/search/aggs/aggs_service.ts | 19 ++-
src/plugins/data/server/search/aggs/mocks.ts | 1 +
.../data/server/search/search_service.ts | 2 +-
src/plugins/data/server/server.api.md | 1 +
src/plugins/embeddable/public/public.api.md | 1 +
.../snapshots/baseline/combined_test2.json | 2 +-
.../snapshots/baseline/combined_test3.json | 2 +-
.../snapshots/baseline/final_output_test.json | 2 +-
.../snapshots/baseline/metric_all_data.json | 2 +-
.../baseline/metric_multi_metric_data.json | 2 +-
.../baseline/metric_percentage_mode.json | 2 +-
.../baseline/metric_single_metric_data.json | 2 +-
.../snapshots/baseline/partial_test_1.json | 2 +-
.../snapshots/baseline/partial_test_2.json | 2 +-
.../snapshots/baseline/partial_test_3.json | 2 +-
.../snapshots/baseline/step_output_test2.json | 2 +-
.../snapshots/baseline/step_output_test3.json | 2 +-
.../snapshots/baseline/tagcloud_all_data.json | 2 +-
.../snapshots/baseline/tagcloud_fontsize.json | 2 +-
.../baseline/tagcloud_metric_data.json | 2 +-
.../snapshots/baseline/tagcloud_options.json | 2 +-
.../snapshots/session/combined_test2.json | 2 +-
.../snapshots/session/combined_test3.json | 2 +-
.../snapshots/session/final_output_test.json | 2 +-
.../snapshots/session/metric_all_data.json | 2 +-
.../session/metric_multi_metric_data.json | 2 +-
.../session/metric_percentage_mode.json | 2 +-
.../session/metric_single_metric_data.json | 2 +-
.../snapshots/session/partial_test_1.json | 2 +-
.../snapshots/session/partial_test_2.json | 2 +-
.../snapshots/session/partial_test_3.json | 2 +-
.../snapshots/session/step_output_test2.json | 2 +-
.../snapshots/session/step_output_test3.json | 2 +-
.../snapshots/session/tagcloud_all_data.json | 2 +-
.../snapshots/session/tagcloud_fontsize.json | 2 +-
.../session/tagcloud_metric_data.json | 2 +-
.../snapshots/session/tagcloud_options.json | 2 +-
55 files changed, 436 insertions(+), 67 deletions(-)
create mode 100644 src/plugins/data/common/search/aggs/utils/infer_time_zone.test.ts
create mode 100644 src/plugins/data/common/search/aggs/utils/infer_time_zone.ts
create mode 100644 src/plugins/data/common/search/aggs/utils/time_column_meta.test.ts
create mode 100644 src/plugins/data/common/search/aggs/utils/time_column_meta.ts
diff --git a/packages/kbn-optimizer/limits.yml b/packages/kbn-optimizer/limits.yml
index c660d37222504..3f9fdb164e759 100644
--- a/packages/kbn-optimizer/limits.yml
+++ b/packages/kbn-optimizer/limits.yml
@@ -14,7 +14,7 @@ pageLoadAssetSize:
dashboard: 374194
dashboardEnhanced: 65646
dashboardMode: 22716
- data: 1287839
+ data: 1317839
dataEnhanced: 50420
devTools: 38637
discover: 105145
diff --git a/src/plugins/data/common/search/aggs/aggs_service.test.ts b/src/plugins/data/common/search/aggs/aggs_service.test.ts
index bcf2101704c80..160860bcce591 100644
--- a/src/plugins/data/common/search/aggs/aggs_service.test.ts
+++ b/src/plugins/data/common/search/aggs/aggs_service.test.ts
@@ -44,6 +44,8 @@ describe('Aggs service', () => {
};
startDeps = {
getConfig: jest.fn(),
+ getIndexPattern: jest.fn(),
+ isDefaultTimezone: jest.fn(),
};
});
@@ -201,8 +203,9 @@ describe('Aggs service', () => {
describe('start()', () => {
test('exposes proper contract', () => {
const start = service.start(startDeps);
- expect(Object.keys(start).length).toBe(3);
+ expect(Object.keys(start).length).toBe(4);
expect(start).toHaveProperty('calculateAutoTimeExpression');
+ expect(start).toHaveProperty('getDateMetaByDatatableColumn');
expect(start).toHaveProperty('createAggConfigs');
expect(start).toHaveProperty('types');
});
diff --git a/src/plugins/data/common/search/aggs/aggs_service.ts b/src/plugins/data/common/search/aggs/aggs_service.ts
index 6f3e3904dbbd5..b6afa708f9e6f 100644
--- a/src/plugins/data/common/search/aggs/aggs_service.ts
+++ b/src/plugins/data/common/search/aggs/aggs_service.ts
@@ -18,7 +18,7 @@
*/
import { ExpressionsServiceSetup } from 'src/plugins/expressions/common';
-import { UI_SETTINGS } from '../../../common';
+import { IndexPattern, UI_SETTINGS } from '../../../common';
import { GetConfigFn } from '../../types';
import {
AggConfigs,
@@ -28,6 +28,7 @@ import {
getCalculateAutoTimeExpression,
} from './';
import { AggsCommonSetup, AggsCommonStart } from './types';
+import { getDateMetaByDatatableColumn } from './utils/time_column_meta';
/** @internal */
export const aggsRequiredUiSettings = [
@@ -50,6 +51,8 @@ export interface AggsCommonSetupDependencies {
/** @internal */
export interface AggsCommonStartDependencies {
getConfig: GetConfigFn;
+ getIndexPattern(id: string): Promise;
+ isDefaultTimezone: () => boolean;
}
/**
@@ -77,11 +80,22 @@ export class AggsCommonService {
};
}
- public start({ getConfig }: AggsCommonStartDependencies): AggsCommonStart {
+ public start({
+ getConfig,
+ getIndexPattern,
+ isDefaultTimezone,
+ }: AggsCommonStartDependencies): AggsCommonStart {
const aggTypesStart = this.aggTypesRegistry.start();
+ const calculateAutoTimeExpression = getCalculateAutoTimeExpression(getConfig);
return {
- calculateAutoTimeExpression: getCalculateAutoTimeExpression(getConfig),
+ calculateAutoTimeExpression,
+ getDateMetaByDatatableColumn: getDateMetaByDatatableColumn({
+ calculateAutoTimeExpression,
+ getIndexPattern,
+ getConfig,
+ isDefaultTimezone,
+ }),
createAggConfigs: (indexPattern, configStates = [], schemas) => {
return new AggConfigs(indexPattern, configStates, {
typesRegistry: aggTypesStart,
diff --git a/src/plugins/data/common/search/aggs/buckets/date_histogram.ts b/src/plugins/data/common/search/aggs/buckets/date_histogram.ts
index c273ca53a5fed..694b03f660452 100644
--- a/src/plugins/data/common/search/aggs/buckets/date_histogram.ts
+++ b/src/plugins/data/common/search/aggs/buckets/date_histogram.ts
@@ -34,6 +34,7 @@ import { writeParams } from '../agg_params';
import { isMetricAggType } from '../metrics/metric_agg_type';
import { BaseAggParams } from '../types';
import { dateHistogramInterval } from '../utils';
+import { inferTimeZone } from '../utils';
/** @internal */
export type CalculateBoundsFn = (timeRange: TimeRange) => TimeRangeBounds;
@@ -235,25 +236,7 @@ export const getDateHistogramBucketAgg = ({
// time_zones being persisted into saved_objects
serialize: noop,
write(agg, output) {
- // If a time_zone has been set explicitly always prefer this.
- let tz = agg.params.time_zone;
- if (!tz && agg.params.field) {
- // If a field has been configured check the index pattern's typeMeta if a date_histogram on that
- // field requires a specific time_zone
- tz = get(agg.getIndexPattern(), [
- 'typeMeta',
- 'aggs',
- 'date_histogram',
- agg.params.field.name,
- 'time_zone',
- ]);
- }
- if (!tz) {
- // If the index pattern typeMeta data, didn't had a time zone assigned for the selected field use the configured tz
- const detectedTimezone = moment.tz.guess();
- const tzOffset = moment().format('Z');
- tz = isDefaultTimezone() ? detectedTimezone || tzOffset : getConfig('dateFormat:tz');
- }
+ const tz = inferTimeZone(agg.params, agg.getIndexPattern(), isDefaultTimezone, getConfig);
output.params.time_zone = tz;
},
},
diff --git a/src/plugins/data/common/search/aggs/types.ts b/src/plugins/data/common/search/aggs/types.ts
index aec3dcc9d068c..09a13762d4d70 100644
--- a/src/plugins/data/common/search/aggs/types.ts
+++ b/src/plugins/data/common/search/aggs/types.ts
@@ -18,7 +18,9 @@
*/
import { Assign } from '@kbn/utility-types';
+import { DatatableColumn } from 'src/plugins/expressions';
import { IndexPattern } from '../../index_patterns/index_patterns/index_pattern';
+import { TimeRange } from '../../query';
import {
AggConfigSerialized,
AggConfigs,
@@ -80,6 +82,19 @@ export interface AggsCommonSetup {
/** @internal */
export interface AggsCommonStart {
calculateAutoTimeExpression: ReturnType;
+ /**
+ * Helper function returning meta data about use date intervals for a data table column.
+ * If the column is not a column created by a date histogram aggregation of the esaggs data source,
+ * this function will return undefined.
+ *
+ * Otherwise, it will return the following attributes in an object:
+ * * `timeZone` time zone used to create the buckets (important e.g. for DST),
+ * * `timeRange` total time range of the fetch data (to infer partial buckets at the beginning and end of the data)
+ * * `interval` Interval used on elasticsearch (`auto` resolved to the actual interval)
+ */
+ getDateMetaByDatatableColumn: (
+ column: DatatableColumn
+ ) => Promise;
createAggConfigs: (
indexPattern: IndexPattern,
configStates?: CreateAggConfigParams[],
diff --git a/src/plugins/data/common/search/aggs/utils/index.ts b/src/plugins/data/common/search/aggs/utils/index.ts
index 99ce44207d80d..7d6cb1c7ef33f 100644
--- a/src/plugins/data/common/search/aggs/utils/index.ts
+++ b/src/plugins/data/common/search/aggs/utils/index.ts
@@ -23,3 +23,4 @@ export * from './get_format_with_aggs';
export * from './ipv4_address';
export * from './prop_filter';
export * from './to_angular_json';
+export * from './infer_time_zone';
diff --git a/src/plugins/data/common/search/aggs/utils/infer_time_zone.test.ts b/src/plugins/data/common/search/aggs/utils/infer_time_zone.test.ts
new file mode 100644
index 0000000000000..8fc3726ee1b32
--- /dev/null
+++ b/src/plugins/data/common/search/aggs/utils/infer_time_zone.test.ts
@@ -0,0 +1,79 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+jest.mock('moment', () => {
+ const moment: any = jest.fn(() => {
+ return {
+ format: jest.fn(() => '-1;00'),
+ };
+ });
+ moment.tz = {
+ guess: jest.fn(() => 'CET'),
+ };
+ return moment;
+});
+
+import { IndexPattern } from '../../../index_patterns';
+import { AggParamsDateHistogram } from '../buckets';
+import { inferTimeZone } from './infer_time_zone';
+
+describe('inferTimeZone', () => {
+ it('reads time zone from agg params', () => {
+ const params: AggParamsDateHistogram = {
+ time_zone: 'CEST',
+ };
+ expect(inferTimeZone(params, {} as IndexPattern, () => false, jest.fn())).toEqual('CEST');
+ });
+
+ it('reads time zone from index pattern type meta if available', () => {
+ expect(
+ inferTimeZone(
+ { field: 'mydatefield' },
+ ({
+ typeMeta: {
+ aggs: {
+ date_histogram: {
+ mydatefield: {
+ time_zone: 'UTC',
+ },
+ },
+ },
+ },
+ } as unknown) as IndexPattern,
+ () => false,
+ jest.fn()
+ )
+ ).toEqual('UTC');
+ });
+
+ it('reads time zone from moment if set to default', () => {
+ expect(inferTimeZone({}, {} as IndexPattern, () => true, jest.fn())).toEqual('CET');
+ });
+
+ it('reads time zone from config if not set to default', () => {
+ expect(
+ inferTimeZone(
+ {},
+ {} as IndexPattern,
+ () => false,
+ () => 'CET' as any
+ )
+ ).toEqual('CET');
+ });
+});
diff --git a/src/plugins/data/common/search/aggs/utils/infer_time_zone.ts b/src/plugins/data/common/search/aggs/utils/infer_time_zone.ts
new file mode 100644
index 0000000000000..282238c5a0459
--- /dev/null
+++ b/src/plugins/data/common/search/aggs/utils/infer_time_zone.ts
@@ -0,0 +1,46 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import moment from 'moment';
+import { IndexPattern } from '../../../index_patterns';
+import { AggParamsDateHistogram } from '../buckets';
+
+export function inferTimeZone(
+ params: AggParamsDateHistogram,
+ indexPattern: IndexPattern,
+ isDefaultTimezone: () => boolean,
+ getConfig: (key: string) => T
+) {
+ let tz = params.time_zone;
+ if (!tz && params.field) {
+ // If a field has been configured check the index pattern's typeMeta if a date_histogram on that
+ // field requires a specific time_zone
+ tz = indexPattern.typeMeta?.aggs?.date_histogram?.[params.field]?.time_zone;
+ }
+ if (!tz) {
+ // If the index pattern typeMeta data, didn't had a time zone assigned for the selected field use the configured tz
+ const detectedTimezone = moment.tz.guess();
+ const tzOffset = moment().format('Z');
+ tz = isDefaultTimezone()
+ ? detectedTimezone || tzOffset
+ : // if timezone is not the default, this will always return a string
+ (getConfig('dateFormat:tz') as string);
+ }
+ return tz;
+}
diff --git a/src/plugins/data/common/search/aggs/utils/time_column_meta.test.ts b/src/plugins/data/common/search/aggs/utils/time_column_meta.test.ts
new file mode 100644
index 0000000000000..e56d622734554
--- /dev/null
+++ b/src/plugins/data/common/search/aggs/utils/time_column_meta.test.ts
@@ -0,0 +1,121 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { BUCKET_TYPES } from '../buckets';
+import { DateMetaByColumnDeps, getDateMetaByDatatableColumn } from './time_column_meta';
+
+describe('getDateMetaByDatatableColumn', () => {
+ let params: DateMetaByColumnDeps;
+ beforeEach(() => {
+ params = {
+ calculateAutoTimeExpression: jest.fn().mockReturnValue('5m'),
+ getIndexPattern: jest.fn().mockResolvedValue({}),
+ isDefaultTimezone: jest.fn().mockReturnValue(true),
+ getConfig: jest.fn(),
+ };
+ });
+
+ it('returns nothing on column from other data source', async () => {
+ expect(
+ await getDateMetaByDatatableColumn(params)({
+ id: 'test',
+ name: 'test',
+ meta: {
+ type: 'date',
+ source: 'essql',
+ },
+ })
+ ).toEqual(undefined);
+ });
+
+ it('returns nothing on non date histogram column', async () => {
+ expect(
+ await getDateMetaByDatatableColumn(params)({
+ id: 'test',
+ name: 'test',
+ meta: {
+ type: 'date',
+ source: 'esaggs',
+ sourceParams: {
+ type: BUCKET_TYPES.TERMS,
+ },
+ },
+ })
+ ).toEqual(undefined);
+ });
+
+ it('returns time range, time zone and interval', async () => {
+ expect(
+ await getDateMetaByDatatableColumn(params)({
+ id: 'test',
+ name: 'test',
+ meta: {
+ type: 'date',
+ source: 'esaggs',
+ sourceParams: {
+ type: BUCKET_TYPES.DATE_HISTOGRAM,
+ params: {
+ time_zone: 'UTC',
+ interval: '1h',
+ },
+ appliedTimeRange: {
+ from: 'now-5d',
+ to: 'now',
+ },
+ },
+ },
+ })
+ ).toEqual({
+ timeZone: 'UTC',
+ timeRange: {
+ from: 'now-5d',
+ to: 'now',
+ },
+ interval: '1h',
+ });
+ });
+
+ it('returns resolved auto interval', async () => {
+ expect(
+ await getDateMetaByDatatableColumn(params)({
+ id: 'test',
+ name: 'test',
+ meta: {
+ type: 'date',
+ source: 'esaggs',
+ sourceParams: {
+ type: BUCKET_TYPES.DATE_HISTOGRAM,
+ params: {
+ time_zone: 'UTC',
+ interval: 'auto',
+ },
+ appliedTimeRange: {
+ from: 'now-5d',
+ to: 'now',
+ },
+ },
+ },
+ })
+ ).toEqual(
+ expect.objectContaining({
+ interval: '5m',
+ })
+ );
+ });
+});
diff --git a/src/plugins/data/common/search/aggs/utils/time_column_meta.ts b/src/plugins/data/common/search/aggs/utils/time_column_meta.ts
new file mode 100644
index 0000000000000..1bea716c6a049
--- /dev/null
+++ b/src/plugins/data/common/search/aggs/utils/time_column_meta.ts
@@ -0,0 +1,66 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { DatatableColumn } from 'src/plugins/expressions/common';
+import { IndexPattern } from '../../../index_patterns';
+
+import { TimeRange } from '../../../types';
+import { AggParamsDateHistogram, BUCKET_TYPES } from '../buckets';
+import { inferTimeZone } from './infer_time_zone';
+
+export interface DateMetaByColumnDeps {
+ calculateAutoTimeExpression: (range: TimeRange) => string | undefined;
+ getIndexPattern: (id: string) => Promise;
+ isDefaultTimezone: () => boolean;
+ getConfig: (key: string) => T;
+}
+
+export const getDateMetaByDatatableColumn = ({
+ calculateAutoTimeExpression,
+ getIndexPattern,
+ isDefaultTimezone,
+ getConfig,
+}: DateMetaByColumnDeps) => async (
+ column: DatatableColumn
+): Promise => {
+ if (column.meta.source !== 'esaggs') return;
+ if (column.meta.sourceParams?.type !== BUCKET_TYPES.DATE_HISTOGRAM) return;
+ const params = column.meta.sourceParams.params as AggParamsDateHistogram;
+ const appliedTimeRange = column.meta.sourceParams.appliedTimeRange as TimeRange;
+
+ const tz = inferTimeZone(
+ params,
+ await getIndexPattern(column.meta.sourceParams.indexPatternId as string),
+ isDefaultTimezone,
+ getConfig
+ );
+
+ const interval =
+ params.interval === 'auto' ? calculateAutoTimeExpression(appliedTimeRange) : params.interval;
+
+ if (!interval) {
+ throw new Error('time interval could not be determined');
+ }
+
+ return {
+ timeZone: tz,
+ timeRange: appliedTimeRange,
+ interval,
+ };
+};
diff --git a/src/plugins/data/public/public.api.md b/src/plugins/data/public/public.api.md
index 81fa6d4ba20db..7ee21236c1c79 100644
--- a/src/plugins/data/public/public.api.md
+++ b/src/plugins/data/public/public.api.md
@@ -16,6 +16,7 @@ import { CoreSetup } from 'src/core/public';
import { CoreSetup as CoreSetup_2 } from 'kibana/public';
import { CoreStart } from 'kibana/public';
import { CoreStart as CoreStart_2 } from 'src/core/public';
+import { DatatableColumn as DatatableColumn_2 } from 'src/plugins/expressions';
import { Ensure } from '@kbn/utility-types';
import { EnvironmentMode } from '@kbn/config';
import { ErrorToastOptions } from 'src/core/public/notifications';
@@ -2285,7 +2286,7 @@ export const UI_SETTINGS: {
// src/plugins/data/common/es_query/filters/phrase_filter.ts:33:3 - (ae-forgotten-export) The symbol "PhraseFilterMeta" needs to be exported by the entry point index.d.ts
// src/plugins/data/common/es_query/filters/phrases_filter.ts:31:3 - (ae-forgotten-export) The symbol "PhrasesFilterMeta" needs to be exported by the entry point index.d.ts
// src/plugins/data/common/index_patterns/index_patterns/index_pattern.ts:62:5 - (ae-forgotten-export) The symbol "FormatFieldFn" needs to be exported by the entry point index.d.ts
-// src/plugins/data/common/search/aggs/types.ts:98:51 - (ae-forgotten-export) The symbol "AggTypesRegistryStart" needs to be exported by the entry point index.d.ts
+// src/plugins/data/common/search/aggs/types.ts:113:51 - (ae-forgotten-export) The symbol "AggTypesRegistryStart" needs to be exported by the entry point index.d.ts
// src/plugins/data/public/field_formats/field_formats_service.ts:67:3 - (ae-forgotten-export) The symbol "FormatFactory" needs to be exported by the entry point index.d.ts
// src/plugins/data/public/index.ts:66:23 - (ae-forgotten-export) The symbol "FILTERS" needs to be exported by the entry point index.d.ts
// src/plugins/data/public/index.ts:66:23 - (ae-forgotten-export) The symbol "getDisplayValueFromFilter" needs to be exported by the entry point index.d.ts
diff --git a/src/plugins/data/public/search/aggs/aggs_service.test.ts b/src/plugins/data/public/search/aggs/aggs_service.test.ts
index db25dfb300d11..de747d234b441 100644
--- a/src/plugins/data/public/search/aggs/aggs_service.test.ts
+++ b/src/plugins/data/public/search/aggs/aggs_service.test.ts
@@ -23,6 +23,7 @@ import { coreMock } from '../../../../../core/public/mocks';
import { expressionsPluginMock } from '../../../../../plugins/expressions/public/mocks';
import { BucketAggType, getAggTypes, MetricAggType } from '../../../common';
import { fieldFormatsServiceMock } from '../../field_formats/mocks';
+import { dataPluginMock } from '../../mocks';
import {
AggsService,
@@ -46,6 +47,7 @@ describe('AggsService - public', () => {
};
startDeps = {
fieldFormats: fieldFormatsServiceMock.createStartContract(),
+ indexPatterns: dataPluginMock.createStartContract().indexPatterns,
uiSettings,
};
});
@@ -86,8 +88,9 @@ describe('AggsService - public', () => {
describe('start()', () => {
test('exposes proper contract', () => {
const start = service.start(startDeps);
- expect(Object.keys(start).length).toBe(3);
+ expect(Object.keys(start).length).toBe(4);
expect(start).toHaveProperty('calculateAutoTimeExpression');
+ expect(start).toHaveProperty('getDateMetaByDatatableColumn');
expect(start).toHaveProperty('createAggConfigs');
expect(start).toHaveProperty('types');
});
diff --git a/src/plugins/data/public/search/aggs/aggs_service.ts b/src/plugins/data/public/search/aggs/aggs_service.ts
index 4b088ddfe314f..85e0f604bb8b5 100644
--- a/src/plugins/data/public/search/aggs/aggs_service.ts
+++ b/src/plugins/data/public/search/aggs/aggs_service.ts
@@ -32,6 +32,7 @@ import {
AggTypesDependencies,
} from '../../../common/search/aggs';
import { AggsSetup, AggsStart } from './types';
+import { IndexPatternsContract } from '../../index_patterns';
/**
* Aggs needs synchronous access to specific uiSettings. Since settings can change
@@ -68,6 +69,7 @@ export interface AggsSetupDependencies {
export interface AggsStartDependencies {
fieldFormats: FieldFormatsStart;
uiSettings: IUiSettingsClient;
+ indexPatterns: IndexPatternsContract;
}
/**
@@ -94,9 +96,17 @@ export class AggsService {
return this.aggsCommonService.setup({ registerFunction });
}
- public start({ fieldFormats, uiSettings }: AggsStartDependencies): AggsStart {
- const { calculateAutoTimeExpression, types } = this.aggsCommonService.start({
+ public start({ fieldFormats, uiSettings, indexPatterns }: AggsStartDependencies): AggsStart {
+ const isDefaultTimezone = () => uiSettings.isDefault('dateFormat:tz');
+
+ const {
+ calculateAutoTimeExpression,
+ getDateMetaByDatatableColumn,
+ types,
+ } = this.aggsCommonService.start({
getConfig: this.getConfig!,
+ getIndexPattern: indexPatterns.get,
+ isDefaultTimezone,
});
const aggTypesDependencies: AggTypesDependencies = {
@@ -106,7 +116,7 @@ export class AggsService {
deserialize: fieldFormats.deserialize,
getDefaultInstance: fieldFormats.getDefaultInstance,
}),
- isDefaultTimezone: () => uiSettings.isDefault('dateFormat:tz'),
+ isDefaultTimezone,
};
// initialize each agg type and store in memory
@@ -137,6 +147,7 @@ export class AggsService {
return {
calculateAutoTimeExpression,
+ getDateMetaByDatatableColumn,
createAggConfigs: (indexPattern, configStates = [], schemas) => {
return new AggConfigs(indexPattern, configStates, { typesRegistry });
},
diff --git a/src/plugins/data/public/search/aggs/mocks.ts b/src/plugins/data/public/search/aggs/mocks.ts
index ca13343777e63..abc930f00b594 100644
--- a/src/plugins/data/public/search/aggs/mocks.ts
+++ b/src/plugins/data/public/search/aggs/mocks.ts
@@ -67,6 +67,7 @@ export const searchAggsSetupMock = (): AggsSetup => ({
export const searchAggsStartMock = (): AggsStart => ({
calculateAutoTimeExpression: getCalculateAutoTimeExpression(getConfig),
+ getDateMetaByDatatableColumn: jest.fn(),
createAggConfigs: jest.fn().mockImplementation((indexPattern, configStates = [], schemas) => {
return new AggConfigs(indexPattern, configStates, {
typesRegistry: mockAggTypesRegistry(),
diff --git a/src/plugins/data/public/search/expressions/esaggs.ts b/src/plugins/data/public/search/expressions/esaggs.ts
index 0aab345a4ebc0..dba77d398c8b6 100644
--- a/src/plugins/data/public/search/expressions/esaggs.ts
+++ b/src/plugins/data/public/search/expressions/esaggs.ts
@@ -298,6 +298,13 @@ export const esaggs = (): EsaggsExpressionFunctionDefinition => ({
source: 'esaggs',
sourceParams: {
indexPatternId: indexPattern.id,
+ appliedTimeRange:
+ column.aggConfig.params.field?.name &&
+ input?.timeRange &&
+ args.timeFields &&
+ args.timeFields.includes(column.aggConfig.params.field?.name)
+ ? { from: input.timeRange.from, to: input.timeRange.to }
+ : undefined,
...column.aggConfig.serialize(),
},
},
diff --git a/src/plugins/data/public/search/search_service.ts b/src/plugins/data/public/search/search_service.ts
index f955dc5b6ebd5..3dbabfc68fdbc 100644
--- a/src/plugins/data/public/search/search_service.ts
+++ b/src/plugins/data/public/search/search_service.ts
@@ -143,7 +143,7 @@ export class SearchService implements Plugin {
};
return {
- aggs: this.aggsService.start({ fieldFormats, uiSettings }),
+ aggs: this.aggsService.start({ fieldFormats, uiSettings, indexPatterns }),
search,
showError: (e: Error) => {
this.searchInterceptor.showError(e);
diff --git a/src/plugins/data/server/index_patterns/mocks.ts b/src/plugins/data/server/index_patterns/mocks.ts
index 8f95afe3b3c9d..52d8aa1e35093 100644
--- a/src/plugins/data/server/index_patterns/mocks.ts
+++ b/src/plugins/data/server/index_patterns/mocks.ts
@@ -19,6 +19,6 @@
export function createIndexPatternsStartMock() {
return {
- indexPatternsServiceFactory: jest.fn(),
+ indexPatternsServiceFactory: jest.fn().mockResolvedValue({ get: jest.fn() }),
};
}
diff --git a/src/plugins/data/server/search/aggs/aggs_service.test.ts b/src/plugins/data/server/search/aggs/aggs_service.test.ts
index d9a945a15fb67..cb4239cc339c4 100644
--- a/src/plugins/data/server/search/aggs/aggs_service.test.ts
+++ b/src/plugins/data/server/search/aggs/aggs_service.test.ts
@@ -23,6 +23,7 @@ import { coreMock } from '../../../../../core/server/mocks';
import { expressionsPluginMock } from '../../../../../plugins/expressions/server/mocks';
import { BucketAggType, getAggTypes, MetricAggType } from '../../../common';
import { createFieldFormatsStartMock } from '../../field_formats/mocks';
+import { createIndexPatternsStartMock } from '../../index_patterns/mocks';
import { AggsService, AggsSetupDependencies, AggsStartDependencies } from './aggs_service';
@@ -40,6 +41,7 @@ describe('AggsService - server', () => {
};
startDeps = {
fieldFormats: createFieldFormatsStartMock(),
+ indexPatterns: createIndexPatternsStartMock(),
uiSettings,
};
});
diff --git a/src/plugins/data/server/search/aggs/aggs_service.ts b/src/plugins/data/server/search/aggs/aggs_service.ts
index 3e5cd8adb44a6..c805c8af6694c 100644
--- a/src/plugins/data/server/search/aggs/aggs_service.ts
+++ b/src/plugins/data/server/search/aggs/aggs_service.ts
@@ -30,6 +30,7 @@ import {
TimeRange,
} from '../../../common';
import { FieldFormatsStart } from '../../field_formats';
+import { IndexPatternsServiceStart } from '../../index_patterns';
import { AggsSetup, AggsStart } from './types';
/** @internal */
@@ -41,6 +42,7 @@ export interface AggsSetupDependencies {
export interface AggsStartDependencies {
fieldFormats: FieldFormatsStart;
uiSettings: UiSettingsServiceStart;
+ indexPatterns: IndexPatternsServiceStart;
}
/**
@@ -61,7 +63,7 @@ export class AggsService {
return this.aggsCommonService.setup({ registerFunction });
}
- public start({ fieldFormats, uiSettings }: AggsStartDependencies): AggsStart {
+ public start({ fieldFormats, uiSettings, indexPatterns }: AggsStartDependencies): AggsStart {
return {
asScopedToClient: async (savedObjectsClient: SavedObjectsClientContract) => {
const uiSettingsClient = uiSettings.asScopedToClient(savedObjectsClient);
@@ -72,8 +74,18 @@ export class AggsService {
const getConfig = (key: string): T => {
return uiSettingsCache[key];
};
+ const isDefaultTimezone = () => getConfig('dateFormat:tz') === 'Browser';
- const { calculateAutoTimeExpression, types } = this.aggsCommonService.start({ getConfig });
+ const {
+ calculateAutoTimeExpression,
+ getDateMetaByDatatableColumn,
+ types,
+ } = this.aggsCommonService.start({
+ getConfig,
+ getIndexPattern: (await indexPatterns.indexPatternsServiceFactory(savedObjectsClient))
+ .get,
+ isDefaultTimezone,
+ });
const aggTypesDependencies: AggTypesDependencies = {
calculateBounds: this.calculateBounds,
@@ -87,7 +99,7 @@ export class AggsService {
* default timezone, but `isDefault` is not currently offered on the
* server, so we need to manually check for the default value.
*/
- isDefaultTimezone: () => getConfig('dateFormat:tz') === 'Browser',
+ isDefaultTimezone,
};
const typesRegistry = {
@@ -109,6 +121,7 @@ export class AggsService {
return {
calculateAutoTimeExpression,
+ getDateMetaByDatatableColumn,
createAggConfigs: (indexPattern, configStates = [], schemas) => {
return new AggConfigs(indexPattern, configStates, { typesRegistry });
},
diff --git a/src/plugins/data/server/search/aggs/mocks.ts b/src/plugins/data/server/search/aggs/mocks.ts
index b50e22fe87b7c..be060de73b9ff 100644
--- a/src/plugins/data/server/search/aggs/mocks.ts
+++ b/src/plugins/data/server/search/aggs/mocks.ts
@@ -68,6 +68,7 @@ export const searchAggsSetupMock = (): AggsSetup => ({
const commonStartMock = (): AggsCommonStart => ({
calculateAutoTimeExpression: getCalculateAutoTimeExpression(getConfig),
+ getDateMetaByDatatableColumn: jest.fn(),
createAggConfigs: jest.fn().mockImplementation((indexPattern, configStates = [], schemas) => {
return new AggConfigs(indexPattern, configStates, {
typesRegistry: mockAggTypesRegistry(),
diff --git a/src/plugins/data/server/search/search_service.ts b/src/plugins/data/server/search/search_service.ts
index 0130d3aacc91f..04ee0e95c7f08 100644
--- a/src/plugins/data/server/search/search_service.ts
+++ b/src/plugins/data/server/search/search_service.ts
@@ -149,7 +149,7 @@ export class SearchService implements Plugin {
{ fieldFormats, indexPatterns }: SearchServiceStartDependencies
): ISearchStart {
return {
- aggs: this.aggsService.start({ fieldFormats, uiSettings }),
+ aggs: this.aggsService.start({ fieldFormats, uiSettings, indexPatterns }),
getSearchStrategy: this.getSearchStrategy,
search: this.search.bind(this),
searchSource: {
diff --git a/src/plugins/data/server/server.api.md b/src/plugins/data/server/server.api.md
index e5882a6cff809..a3edbbd3844b3 100644
--- a/src/plugins/data/server/server.api.md
+++ b/src/plugins/data/server/server.api.md
@@ -13,6 +13,7 @@ import { CoreSetup } from 'src/core/server';
import { CoreSetup as CoreSetup_2 } from 'kibana/server';
import { CoreStart } from 'src/core/server';
import { CoreStart as CoreStart_2 } from 'kibana/server';
+import { DatatableColumn } from 'src/plugins/expressions';
import { Duration } from 'moment';
import { ElasticsearchClient } from 'kibana/server';
import { Ensure } from '@kbn/utility-types';
diff --git a/src/plugins/embeddable/public/public.api.md b/src/plugins/embeddable/public/public.api.md
index 9939ba2a0f8a1..00971ed37db3a 100644
--- a/src/plugins/embeddable/public/public.api.md
+++ b/src/plugins/embeddable/public/public.api.md
@@ -17,6 +17,7 @@ import { CoreSetup as CoreSetup_2 } from 'src/core/public';
import { CoreSetup as CoreSetup_3 } from 'kibana/public';
import { CoreStart as CoreStart_2 } from 'kibana/public';
import * as CSS from 'csstype';
+import { DatatableColumn as DatatableColumn_2 } from 'src/plugins/expressions';
import { EmbeddableStart as EmbeddableStart_2 } from 'src/plugins/embeddable/public/plugin';
import { Ensure } from '@kbn/utility-types';
import { EnvironmentMode } from '@kbn/config';
diff --git a/test/interpreter_functional/snapshots/baseline/combined_test2.json b/test/interpreter_functional/snapshots/baseline/combined_test2.json
index 550b3b5df12be..4870694e6adbc 100644
--- a/test/interpreter_functional/snapshots/baseline/combined_test2.json
+++ b/test/interpreter_functional/snapshots/baseline/combined_test2.json
@@ -1 +1 @@
-{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"}
\ No newline at end of file
+{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"}
\ No newline at end of file
diff --git a/test/interpreter_functional/snapshots/baseline/combined_test3.json b/test/interpreter_functional/snapshots/baseline/combined_test3.json
index 59de1f285799b..2aa601a8d3631 100644
--- a/test/interpreter_functional/snapshots/baseline/combined_test3.json
+++ b/test/interpreter_functional/snapshots/baseline/combined_test3.json
@@ -1 +1 @@
-{"as":"metric_vis","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visType":"metric"}}
\ No newline at end of file
+{"as":"metric_vis","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visType":"metric"}}
\ No newline at end of file
diff --git a/test/interpreter_functional/snapshots/baseline/final_output_test.json b/test/interpreter_functional/snapshots/baseline/final_output_test.json
index 59de1f285799b..2aa601a8d3631 100644
--- a/test/interpreter_functional/snapshots/baseline/final_output_test.json
+++ b/test/interpreter_functional/snapshots/baseline/final_output_test.json
@@ -1 +1 @@
-{"as":"metric_vis","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visType":"metric"}}
\ No newline at end of file
+{"as":"metric_vis","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visType":"metric"}}
\ No newline at end of file
diff --git a/test/interpreter_functional/snapshots/baseline/metric_all_data.json b/test/interpreter_functional/snapshots/baseline/metric_all_data.json
index cf488ac7f3ffa..dd779800cd452 100644
--- a/test/interpreter_functional/snapshots/baseline/metric_all_data.json
+++ b/test/interpreter_functional/snapshots/baseline/metric_all_data.json
@@ -1 +1 @@
-{"as":"metric_vis","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"dimensions":{"bucket":{"accessor":2,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"},{"id":"col-2-1","meta":{"field":"bytes","index":"logstash-*","params":{"id":"bytes","params":null},"source":"esaggs","sourceParams":{"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{"field":"bytes"},"schema":"metric","type":"max"},"type":"number"},"name":"Max bytes"}],"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"datatable"},"visType":"metric"}}
\ No newline at end of file
+{"as":"metric_vis","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"dimensions":{"bucket":{"accessor":2,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"},{"id":"col-2-1","meta":{"field":"bytes","index":"logstash-*","params":{"id":"bytes","params":null},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{"field":"bytes"},"schema":"metric","type":"max"},"type":"number"},"name":"Max bytes"}],"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"datatable"},"visType":"metric"}}
\ No newline at end of file
diff --git a/test/interpreter_functional/snapshots/baseline/metric_multi_metric_data.json b/test/interpreter_functional/snapshots/baseline/metric_multi_metric_data.json
index 8c272901c4e84..992d667fdce9f 100644
--- a/test/interpreter_functional/snapshots/baseline/metric_multi_metric_data.json
+++ b/test/interpreter_functional/snapshots/baseline/metric_multi_metric_data.json
@@ -1 +1 @@
-{"as":"metric_vis","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"dimensions":{"metrics":[{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"},{"id":"col-2-1","meta":{"field":"bytes","index":"logstash-*","params":{"id":"bytes","params":null},"source":"esaggs","sourceParams":{"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{"field":"bytes"},"schema":"metric","type":"max"},"type":"number"},"name":"Max bytes"}],"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"datatable"},"visType":"metric"}}
\ No newline at end of file
+{"as":"metric_vis","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"dimensions":{"metrics":[{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"},{"id":"col-2-1","meta":{"field":"bytes","index":"logstash-*","params":{"id":"bytes","params":null},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{"field":"bytes"},"schema":"metric","type":"max"},"type":"number"},"name":"Max bytes"}],"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"datatable"},"visType":"metric"}}
\ No newline at end of file
diff --git a/test/interpreter_functional/snapshots/baseline/metric_percentage_mode.json b/test/interpreter_functional/snapshots/baseline/metric_percentage_mode.json
index abc0d3a446987..031c9f9ea5504 100644
--- a/test/interpreter_functional/snapshots/baseline/metric_percentage_mode.json
+++ b/test/interpreter_functional/snapshots/baseline/metric_percentage_mode.json
@@ -1 +1 @@
-{"as":"metric_vis","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"dimensions":{"metrics":[{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":1000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":true,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"},{"id":"col-2-1","meta":{"field":"bytes","index":"logstash-*","params":{"id":"bytes","params":null},"source":"esaggs","sourceParams":{"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{"field":"bytes"},"schema":"metric","type":"max"},"type":"number"},"name":"Max bytes"}],"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"datatable"},"visType":"metric"}}
\ No newline at end of file
+{"as":"metric_vis","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"dimensions":{"metrics":[{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":1000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":true,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"},{"id":"col-2-1","meta":{"field":"bytes","index":"logstash-*","params":{"id":"bytes","params":null},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{"field":"bytes"},"schema":"metric","type":"max"},"type":"number"},"name":"Max bytes"}],"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"datatable"},"visType":"metric"}}
\ No newline at end of file
diff --git a/test/interpreter_functional/snapshots/baseline/metric_single_metric_data.json b/test/interpreter_functional/snapshots/baseline/metric_single_metric_data.json
index 1809df5e709f0..8c6fde201c8f1 100644
--- a/test/interpreter_functional/snapshots/baseline/metric_single_metric_data.json
+++ b/test/interpreter_functional/snapshots/baseline/metric_single_metric_data.json
@@ -1 +1 @@
-{"as":"metric_vis","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"dimensions":{"metrics":[{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"},{"id":"col-2-1","meta":{"field":"bytes","index":"logstash-*","params":{"id":"bytes","params":null},"source":"esaggs","sourceParams":{"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{"field":"bytes"},"schema":"metric","type":"max"},"type":"number"},"name":"Max bytes"}],"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"datatable"},"visType":"metric"}}
\ No newline at end of file
+{"as":"metric_vis","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"dimensions":{"metrics":[{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"},{"id":"col-2-1","meta":{"field":"bytes","index":"logstash-*","params":{"id":"bytes","params":null},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{"field":"bytes"},"schema":"metric","type":"max"},"type":"number"},"name":"Max bytes"}],"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"datatable"},"visType":"metric"}}
\ No newline at end of file
diff --git a/test/interpreter_functional/snapshots/baseline/partial_test_1.json b/test/interpreter_functional/snapshots/baseline/partial_test_1.json
index ec32b07ed9f2e..14c8428c6d432 100644
--- a/test/interpreter_functional/snapshots/baseline/partial_test_1.json
+++ b/test/interpreter_functional/snapshots/baseline/partial_test_1.json
@@ -1 +1 @@
-{"as":"tagloud_vis","type":"render","value":{"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":72,"metric":{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","scale":"linear","showLabel":true},"visType":"tagcloud"}}
\ No newline at end of file
+{"as":"tagloud_vis","type":"render","value":{"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":72,"metric":{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","scale":"linear","showLabel":true},"visType":"tagcloud"}}
\ No newline at end of file
diff --git a/test/interpreter_functional/snapshots/baseline/partial_test_2.json b/test/interpreter_functional/snapshots/baseline/partial_test_2.json
index 59de1f285799b..2aa601a8d3631 100644
--- a/test/interpreter_functional/snapshots/baseline/partial_test_2.json
+++ b/test/interpreter_functional/snapshots/baseline/partial_test_2.json
@@ -1 +1 @@
-{"as":"metric_vis","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visType":"metric"}}
\ No newline at end of file
+{"as":"metric_vis","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visType":"metric"}}
\ No newline at end of file
diff --git a/test/interpreter_functional/snapshots/baseline/partial_test_3.json b/test/interpreter_functional/snapshots/baseline/partial_test_3.json
index 09602eca4abf2..595127526156e 100644
--- a/test/interpreter_functional/snapshots/baseline/partial_test_3.json
+++ b/test/interpreter_functional/snapshots/baseline/partial_test_3.json
@@ -1 +1 @@
-{"as":"visualization","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"bucket":{"accessor":0},"metric":{"accessor":1,"format":{"id":"number"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visType":"region_map"}}
\ No newline at end of file
+{"as":"visualization","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"bucket":{"accessor":0},"metric":{"accessor":1,"format":{"id":"number"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visType":"region_map"}}
\ No newline at end of file
diff --git a/test/interpreter_functional/snapshots/baseline/step_output_test2.json b/test/interpreter_functional/snapshots/baseline/step_output_test2.json
index 550b3b5df12be..4870694e6adbc 100644
--- a/test/interpreter_functional/snapshots/baseline/step_output_test2.json
+++ b/test/interpreter_functional/snapshots/baseline/step_output_test2.json
@@ -1 +1 @@
-{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"}
\ No newline at end of file
+{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"}
\ No newline at end of file
diff --git a/test/interpreter_functional/snapshots/baseline/step_output_test3.json b/test/interpreter_functional/snapshots/baseline/step_output_test3.json
index 59de1f285799b..2aa601a8d3631 100644
--- a/test/interpreter_functional/snapshots/baseline/step_output_test3.json
+++ b/test/interpreter_functional/snapshots/baseline/step_output_test3.json
@@ -1 +1 @@
-{"as":"metric_vis","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visType":"metric"}}
\ No newline at end of file
+{"as":"metric_vis","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visType":"metric"}}
\ No newline at end of file
diff --git a/test/interpreter_functional/snapshots/baseline/tagcloud_all_data.json b/test/interpreter_functional/snapshots/baseline/tagcloud_all_data.json
index 071172c698ad7..073fca760b9a2 100644
--- a/test/interpreter_functional/snapshots/baseline/tagcloud_all_data.json
+++ b/test/interpreter_functional/snapshots/baseline/tagcloud_all_data.json
@@ -1 +1 @@
-{"as":"tagloud_vis","type":"render","value":{"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"bucket":{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","scale":"linear","showLabel":true},"visType":"tagcloud"}}
\ No newline at end of file
+{"as":"tagloud_vis","type":"render","value":{"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"bucket":{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","scale":"linear","showLabel":true},"visType":"tagcloud"}}
\ No newline at end of file
diff --git a/test/interpreter_functional/snapshots/baseline/tagcloud_fontsize.json b/test/interpreter_functional/snapshots/baseline/tagcloud_fontsize.json
index ad38bb28b3329..93f8d8a27d233 100644
--- a/test/interpreter_functional/snapshots/baseline/tagcloud_fontsize.json
+++ b/test/interpreter_functional/snapshots/baseline/tagcloud_fontsize.json
@@ -1 +1 @@
-{"as":"tagloud_vis","type":"render","value":{"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"bucket":{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":40,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":20,"orientation":"single","scale":"linear","showLabel":true},"visType":"tagcloud"}}
\ No newline at end of file
+{"as":"tagloud_vis","type":"render","value":{"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"bucket":{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":40,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":20,"orientation":"single","scale":"linear","showLabel":true},"visType":"tagcloud"}}
\ No newline at end of file
diff --git a/test/interpreter_functional/snapshots/baseline/tagcloud_metric_data.json b/test/interpreter_functional/snapshots/baseline/tagcloud_metric_data.json
index 997285adfe5f4..e8c47efdbe622 100644
--- a/test/interpreter_functional/snapshots/baseline/tagcloud_metric_data.json
+++ b/test/interpreter_functional/snapshots/baseline/tagcloud_metric_data.json
@@ -1 +1 @@
-{"as":"tagloud_vis","type":"render","value":{"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","scale":"linear","showLabel":true},"visType":"tagcloud"}}
\ No newline at end of file
+{"as":"tagloud_vis","type":"render","value":{"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","scale":"linear","showLabel":true},"visType":"tagcloud"}}
\ No newline at end of file
diff --git a/test/interpreter_functional/snapshots/baseline/tagcloud_options.json b/test/interpreter_functional/snapshots/baseline/tagcloud_options.json
index 10e23d860637c..38683082975f8 100644
--- a/test/interpreter_functional/snapshots/baseline/tagcloud_options.json
+++ b/test/interpreter_functional/snapshots/baseline/tagcloud_options.json
@@ -1 +1 @@
-{"as":"tagloud_vis","type":"render","value":{"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"bucket":{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"multiple","scale":"log","showLabel":true},"visType":"tagcloud"}}
\ No newline at end of file
+{"as":"tagloud_vis","type":"render","value":{"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"bucket":{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"multiple","scale":"log","showLabel":true},"visType":"tagcloud"}}
\ No newline at end of file
diff --git a/test/interpreter_functional/snapshots/session/combined_test2.json b/test/interpreter_functional/snapshots/session/combined_test2.json
index 550b3b5df12be..4870694e6adbc 100644
--- a/test/interpreter_functional/snapshots/session/combined_test2.json
+++ b/test/interpreter_functional/snapshots/session/combined_test2.json
@@ -1 +1 @@
-{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"}
\ No newline at end of file
+{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"}
\ No newline at end of file
diff --git a/test/interpreter_functional/snapshots/session/combined_test3.json b/test/interpreter_functional/snapshots/session/combined_test3.json
index 59de1f285799b..2aa601a8d3631 100644
--- a/test/interpreter_functional/snapshots/session/combined_test3.json
+++ b/test/interpreter_functional/snapshots/session/combined_test3.json
@@ -1 +1 @@
-{"as":"metric_vis","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visType":"metric"}}
\ No newline at end of file
+{"as":"metric_vis","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visType":"metric"}}
\ No newline at end of file
diff --git a/test/interpreter_functional/snapshots/session/final_output_test.json b/test/interpreter_functional/snapshots/session/final_output_test.json
index 59de1f285799b..2aa601a8d3631 100644
--- a/test/interpreter_functional/snapshots/session/final_output_test.json
+++ b/test/interpreter_functional/snapshots/session/final_output_test.json
@@ -1 +1 @@
-{"as":"metric_vis","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visType":"metric"}}
\ No newline at end of file
+{"as":"metric_vis","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visType":"metric"}}
\ No newline at end of file
diff --git a/test/interpreter_functional/snapshots/session/metric_all_data.json b/test/interpreter_functional/snapshots/session/metric_all_data.json
index cf488ac7f3ffa..dd779800cd452 100644
--- a/test/interpreter_functional/snapshots/session/metric_all_data.json
+++ b/test/interpreter_functional/snapshots/session/metric_all_data.json
@@ -1 +1 @@
-{"as":"metric_vis","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"dimensions":{"bucket":{"accessor":2,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"},{"id":"col-2-1","meta":{"field":"bytes","index":"logstash-*","params":{"id":"bytes","params":null},"source":"esaggs","sourceParams":{"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{"field":"bytes"},"schema":"metric","type":"max"},"type":"number"},"name":"Max bytes"}],"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"datatable"},"visType":"metric"}}
\ No newline at end of file
+{"as":"metric_vis","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"dimensions":{"bucket":{"accessor":2,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"},{"id":"col-2-1","meta":{"field":"bytes","index":"logstash-*","params":{"id":"bytes","params":null},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{"field":"bytes"},"schema":"metric","type":"max"},"type":"number"},"name":"Max bytes"}],"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"datatable"},"visType":"metric"}}
\ No newline at end of file
diff --git a/test/interpreter_functional/snapshots/session/metric_multi_metric_data.json b/test/interpreter_functional/snapshots/session/metric_multi_metric_data.json
index 8c272901c4e84..992d667fdce9f 100644
--- a/test/interpreter_functional/snapshots/session/metric_multi_metric_data.json
+++ b/test/interpreter_functional/snapshots/session/metric_multi_metric_data.json
@@ -1 +1 @@
-{"as":"metric_vis","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"dimensions":{"metrics":[{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"},{"id":"col-2-1","meta":{"field":"bytes","index":"logstash-*","params":{"id":"bytes","params":null},"source":"esaggs","sourceParams":{"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{"field":"bytes"},"schema":"metric","type":"max"},"type":"number"},"name":"Max bytes"}],"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"datatable"},"visType":"metric"}}
\ No newline at end of file
+{"as":"metric_vis","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"dimensions":{"metrics":[{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"},{"id":"col-2-1","meta":{"field":"bytes","index":"logstash-*","params":{"id":"bytes","params":null},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{"field":"bytes"},"schema":"metric","type":"max"},"type":"number"},"name":"Max bytes"}],"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"datatable"},"visType":"metric"}}
\ No newline at end of file
diff --git a/test/interpreter_functional/snapshots/session/metric_percentage_mode.json b/test/interpreter_functional/snapshots/session/metric_percentage_mode.json
index abc0d3a446987..031c9f9ea5504 100644
--- a/test/interpreter_functional/snapshots/session/metric_percentage_mode.json
+++ b/test/interpreter_functional/snapshots/session/metric_percentage_mode.json
@@ -1 +1 @@
-{"as":"metric_vis","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"dimensions":{"metrics":[{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":1000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":true,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"},{"id":"col-2-1","meta":{"field":"bytes","index":"logstash-*","params":{"id":"bytes","params":null},"source":"esaggs","sourceParams":{"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{"field":"bytes"},"schema":"metric","type":"max"},"type":"number"},"name":"Max bytes"}],"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"datatable"},"visType":"metric"}}
\ No newline at end of file
+{"as":"metric_vis","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"dimensions":{"metrics":[{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":1000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":true,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"},{"id":"col-2-1","meta":{"field":"bytes","index":"logstash-*","params":{"id":"bytes","params":null},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{"field":"bytes"},"schema":"metric","type":"max"},"type":"number"},"name":"Max bytes"}],"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"datatable"},"visType":"metric"}}
\ No newline at end of file
diff --git a/test/interpreter_functional/snapshots/session/metric_single_metric_data.json b/test/interpreter_functional/snapshots/session/metric_single_metric_data.json
index 1809df5e709f0..8c6fde201c8f1 100644
--- a/test/interpreter_functional/snapshots/session/metric_single_metric_data.json
+++ b/test/interpreter_functional/snapshots/session/metric_single_metric_data.json
@@ -1 +1 @@
-{"as":"metric_vis","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"dimensions":{"metrics":[{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"},{"id":"col-2-1","meta":{"field":"bytes","index":"logstash-*","params":{"id":"bytes","params":null},"source":"esaggs","sourceParams":{"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{"field":"bytes"},"schema":"metric","type":"max"},"type":"number"},"name":"Max bytes"}],"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"datatable"},"visType":"metric"}}
\ No newline at end of file
+{"as":"metric_vis","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"dimensions":{"metrics":[{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"},{"id":"col-2-1","meta":{"field":"bytes","index":"logstash-*","params":{"id":"bytes","params":null},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{"field":"bytes"},"schema":"metric","type":"max"},"type":"number"},"name":"Max bytes"}],"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"datatable"},"visType":"metric"}}
\ No newline at end of file
diff --git a/test/interpreter_functional/snapshots/session/partial_test_1.json b/test/interpreter_functional/snapshots/session/partial_test_1.json
index ec32b07ed9f2e..14c8428c6d432 100644
--- a/test/interpreter_functional/snapshots/session/partial_test_1.json
+++ b/test/interpreter_functional/snapshots/session/partial_test_1.json
@@ -1 +1 @@
-{"as":"tagloud_vis","type":"render","value":{"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":72,"metric":{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","scale":"linear","showLabel":true},"visType":"tagcloud"}}
\ No newline at end of file
+{"as":"tagloud_vis","type":"render","value":{"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":72,"metric":{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","scale":"linear","showLabel":true},"visType":"tagcloud"}}
\ No newline at end of file
diff --git a/test/interpreter_functional/snapshots/session/partial_test_2.json b/test/interpreter_functional/snapshots/session/partial_test_2.json
index 59de1f285799b..2aa601a8d3631 100644
--- a/test/interpreter_functional/snapshots/session/partial_test_2.json
+++ b/test/interpreter_functional/snapshots/session/partial_test_2.json
@@ -1 +1 @@
-{"as":"metric_vis","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visType":"metric"}}
\ No newline at end of file
+{"as":"metric_vis","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visType":"metric"}}
\ No newline at end of file
diff --git a/test/interpreter_functional/snapshots/session/partial_test_3.json b/test/interpreter_functional/snapshots/session/partial_test_3.json
index 09602eca4abf2..595127526156e 100644
--- a/test/interpreter_functional/snapshots/session/partial_test_3.json
+++ b/test/interpreter_functional/snapshots/session/partial_test_3.json
@@ -1 +1 @@
-{"as":"visualization","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"bucket":{"accessor":0},"metric":{"accessor":1,"format":{"id":"number"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visType":"region_map"}}
\ No newline at end of file
+{"as":"visualization","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"bucket":{"accessor":0},"metric":{"accessor":1,"format":{"id":"number"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visType":"region_map"}}
\ No newline at end of file
diff --git a/test/interpreter_functional/snapshots/session/step_output_test2.json b/test/interpreter_functional/snapshots/session/step_output_test2.json
index 550b3b5df12be..4870694e6adbc 100644
--- a/test/interpreter_functional/snapshots/session/step_output_test2.json
+++ b/test/interpreter_functional/snapshots/session/step_output_test2.json
@@ -1 +1 @@
-{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"}
\ No newline at end of file
+{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"}
\ No newline at end of file
diff --git a/test/interpreter_functional/snapshots/session/step_output_test3.json b/test/interpreter_functional/snapshots/session/step_output_test3.json
index 59de1f285799b..2aa601a8d3631 100644
--- a/test/interpreter_functional/snapshots/session/step_output_test3.json
+++ b/test/interpreter_functional/snapshots/session/step_output_test3.json
@@ -1 +1 @@
-{"as":"metric_vis","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visType":"metric"}}
\ No newline at end of file
+{"as":"metric_vis","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visType":"metric"}}
\ No newline at end of file
diff --git a/test/interpreter_functional/snapshots/session/tagcloud_all_data.json b/test/interpreter_functional/snapshots/session/tagcloud_all_data.json
index 071172c698ad7..073fca760b9a2 100644
--- a/test/interpreter_functional/snapshots/session/tagcloud_all_data.json
+++ b/test/interpreter_functional/snapshots/session/tagcloud_all_data.json
@@ -1 +1 @@
-{"as":"tagloud_vis","type":"render","value":{"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"bucket":{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","scale":"linear","showLabel":true},"visType":"tagcloud"}}
\ No newline at end of file
+{"as":"tagloud_vis","type":"render","value":{"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"bucket":{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","scale":"linear","showLabel":true},"visType":"tagcloud"}}
\ No newline at end of file
diff --git a/test/interpreter_functional/snapshots/session/tagcloud_fontsize.json b/test/interpreter_functional/snapshots/session/tagcloud_fontsize.json
index ad38bb28b3329..93f8d8a27d233 100644
--- a/test/interpreter_functional/snapshots/session/tagcloud_fontsize.json
+++ b/test/interpreter_functional/snapshots/session/tagcloud_fontsize.json
@@ -1 +1 @@
-{"as":"tagloud_vis","type":"render","value":{"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"bucket":{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":40,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":20,"orientation":"single","scale":"linear","showLabel":true},"visType":"tagcloud"}}
\ No newline at end of file
+{"as":"tagloud_vis","type":"render","value":{"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"bucket":{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":40,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":20,"orientation":"single","scale":"linear","showLabel":true},"visType":"tagcloud"}}
\ No newline at end of file
diff --git a/test/interpreter_functional/snapshots/session/tagcloud_metric_data.json b/test/interpreter_functional/snapshots/session/tagcloud_metric_data.json
index 997285adfe5f4..e8c47efdbe622 100644
--- a/test/interpreter_functional/snapshots/session/tagcloud_metric_data.json
+++ b/test/interpreter_functional/snapshots/session/tagcloud_metric_data.json
@@ -1 +1 @@
-{"as":"tagloud_vis","type":"render","value":{"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","scale":"linear","showLabel":true},"visType":"tagcloud"}}
\ No newline at end of file
+{"as":"tagloud_vis","type":"render","value":{"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","scale":"linear","showLabel":true},"visType":"tagcloud"}}
\ No newline at end of file
diff --git a/test/interpreter_functional/snapshots/session/tagcloud_options.json b/test/interpreter_functional/snapshots/session/tagcloud_options.json
index 10e23d860637c..38683082975f8 100644
--- a/test/interpreter_functional/snapshots/session/tagcloud_options.json
+++ b/test/interpreter_functional/snapshots/session/tagcloud_options.json
@@ -1 +1 @@
-{"as":"tagloud_vis","type":"render","value":{"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"bucket":{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"multiple","scale":"log","showLabel":true},"visType":"tagcloud"}}
\ No newline at end of file
+{"as":"tagloud_vis","type":"render","value":{"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"bucket":{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"multiple","scale":"log","showLabel":true},"visType":"tagcloud"}}
\ No newline at end of file
From 4434c393350ec41f84dce0d3567f0fd52a1dde79 Mon Sep 17 00:00:00 2001
From: Angela Chuang <6295984+angorayc@users.noreply.github.com>
Date: Thu, 29 Oct 2020 16:02:32 +0000
Subject: [PATCH 37/73] fix toast message (#81687)
Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
---
.../detection_engine/rules/api.test.ts | 14 +-
.../containers/detection_engine/rules/api.ts | 18 +-
.../detection_engine/rules/translations.ts | 16 +-
.../rules/use_pre_packaged_rules.test.tsx | 274 +++++++++++++++++-
.../rules/use_pre_packaged_rules.tsx | 34 ++-
5 files changed, 338 insertions(+), 18 deletions(-)
diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/api.test.ts b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/api.test.ts
index 8076733be2d7d..0b708133d947b 100644
--- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/api.test.ts
+++ b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/api.test.ts
@@ -411,7 +411,12 @@ describe('Detections Rules API', () => {
describe('createPrepackagedRules', () => {
beforeEach(() => {
fetchMock.mockClear();
- fetchMock.mockResolvedValue('unknown');
+ fetchMock.mockResolvedValue({
+ rules_installed: 0,
+ rules_updated: 0,
+ timelines_installed: 0,
+ timelines_updated: 0,
+ });
});
test('check parameter url when creating pre-packaged rules', async () => {
@@ -423,7 +428,12 @@ describe('Detections Rules API', () => {
});
test('happy path', async () => {
const resp = await createPrepackagedRules({ signal: abortCtrl.signal });
- expect(resp).toEqual(true);
+ expect(resp).toEqual({
+ rules_installed: 0,
+ rules_updated: 0,
+ timelines_installed: 0,
+ timelines_updated: 0,
+ });
});
});
diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/api.ts b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/api.ts
index 23adfe0228333..ce1fdd18dbdef 100644
--- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/api.ts
+++ b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/api.ts
@@ -245,13 +245,25 @@ export const duplicateRules = async ({ rules }: DuplicateRulesProps): Promise => {
- await KibanaServices.get().http.fetch(DETECTION_ENGINE_PREPACKAGED_URL, {
+export const createPrepackagedRules = async ({
+ signal,
+}: BasicFetchProps): Promise<{
+ rules_installed: number;
+ rules_updated: number;
+ timelines_installed: number;
+ timelines_updated: number;
+}> => {
+ const result = await KibanaServices.get().http.fetch<{
+ rules_installed: number;
+ rules_updated: number;
+ timelines_installed: number;
+ timelines_updated: number;
+ }>(DETECTION_ENGINE_PREPACKAGED_URL, {
method: 'PUT',
signal,
});
- return true;
+ return result;
};
/**
diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/translations.ts b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/translations.ts
index 721790a36b27f..6e2aee9658658 100644
--- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/translations.ts
+++ b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/translations.ts
@@ -30,7 +30,21 @@ export const RULE_AND_TIMELINE_PREPACKAGED_FAILURE = i18n.translate(
export const RULE_AND_TIMELINE_PREPACKAGED_SUCCESS = i18n.translate(
'xpack.securitySolution.containers.detectionEngine.createPrePackagedRuleAndTimelineSuccesDescription',
{
- defaultMessage: 'Installed pre-packaged rules and timelines from elastic',
+ defaultMessage: 'Installed pre-packaged rules and timeline templates from elastic',
+ }
+);
+
+export const RULE_PREPACKAGED_SUCCESS = i18n.translate(
+ 'xpack.securitySolution.containers.detectionEngine.createPrePackagedRuleSuccesDescription',
+ {
+ defaultMessage: 'Installed pre-packaged rules from elastic',
+ }
+);
+
+export const TIMELINE_PREPACKAGED_SUCCESS = i18n.translate(
+ 'xpack.securitySolution.containers.detectionEngine.createPrePackagedTimelineSuccesDescription',
+ {
+ defaultMessage: 'Installed pre-packaged timeline templates from elastic',
}
);
diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_pre_packaged_rules.test.tsx b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_pre_packaged_rules.test.tsx
index 7f74e92584494..f6bd8c4359d6e 100644
--- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_pre_packaged_rules.test.tsx
+++ b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_pre_packaged_rules.test.tsx
@@ -3,12 +3,17 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
-
+import { ReactElement } from 'react';
import { renderHook, act } from '@testing-library/react-hooks';
import { ReturnPrePackagedRulesAndTimelines, usePrePackagedRules } from './use_pre_packaged_rules';
import * as api from './api';
+import { shallow } from 'enzyme';
+import * as i18n from './translations';
-jest.mock('./api');
+jest.mock('./api', () => ({
+ getPrePackagedRulesStatus: jest.fn(),
+ createPrepackagedRules: jest.fn(),
+}));
describe('usePrePackagedRules', () => {
beforeEach(() => {
@@ -52,6 +57,21 @@ describe('usePrePackagedRules', () => {
});
test('fetch getPrePackagedRulesStatus', async () => {
+ (api.getPrePackagedRulesStatus as jest.Mock).mockResolvedValue({
+ rules_custom_installed: 33,
+ rules_installed: 12,
+ rules_not_installed: 0,
+ rules_not_updated: 0,
+ timelines_installed: 0,
+ timelines_not_installed: 0,
+ timelines_not_updated: 0,
+ });
+ (api.createPrepackagedRules as jest.Mock).mockResolvedValue({
+ rules_installed: 0,
+ rules_updated: 0,
+ timelines_installed: 0,
+ timelines_updated: 0,
+ });
await act(async () => {
const { result, waitForNextUpdate } = renderHook(
() =>
@@ -87,7 +107,6 @@ describe('usePrePackagedRules', () => {
});
test('happy path to createPrePackagedRules', async () => {
- const spyOnCreatePrepackagedRules = jest.spyOn(api, 'createPrepackagedRules');
await act(async () => {
const { result, waitForNextUpdate } = renderHook(
() =>
@@ -106,7 +125,7 @@ describe('usePrePackagedRules', () => {
resp = await result.current.createPrePackagedRules();
}
expect(resp).toEqual(true);
- expect(spyOnCreatePrepackagedRules).toHaveBeenCalled();
+ expect(api.createPrepackagedRules).toHaveBeenCalled();
expect(result.current).toEqual({
getLoadPrebuiltRulesAndTemplatesButton:
result.current.getLoadPrebuiltRulesAndTemplatesButton,
@@ -127,6 +146,253 @@ describe('usePrePackagedRules', () => {
});
});
+ test('getLoadPrebuiltRulesAndTemplatesButton - LOAD_PREPACKAGED_RULES', async () => {
+ (api.getPrePackagedRulesStatus as jest.Mock).mockResolvedValue({
+ rules_custom_installed: 0,
+ rules_installed: 0,
+ rules_not_installed: 1,
+ rules_not_updated: 0,
+ timelines_installed: 0,
+ timelines_not_installed: 0,
+ timelines_not_updated: 0,
+ });
+ (api.createPrepackagedRules as jest.Mock).mockResolvedValue({
+ rules_installed: 0,
+ rules_updated: 0,
+ timelines_installed: 0,
+ timelines_updated: 0,
+ });
+ await act(async () => {
+ const { result, waitForNextUpdate } = renderHook(
+ () =>
+ usePrePackagedRules({
+ canUserCRUD: true,
+ hasIndexWrite: true,
+ isAuthenticated: true,
+ hasEncryptionKey: true,
+ isSignalIndexExists: true,
+ })
+ );
+ await waitForNextUpdate();
+ await waitForNextUpdate();
+
+ const button = result.current.getLoadPrebuiltRulesAndTemplatesButton({
+ isDisabled: false,
+ onClick: jest.fn(),
+ 'data-test-subj': 'button',
+ });
+ const wrapper = shallow(button as ReactElement);
+ expect(wrapper.find('[data-test-subj="button"]').text()).toEqual(i18n.LOAD_PREPACKAGED_RULES);
+ });
+ });
+
+ test('getLoadPrebuiltRulesAndTemplatesButton - LOAD_PREPACKAGED_TIMELINE_TEMPLATES', async () => {
+ (api.getPrePackagedRulesStatus as jest.Mock).mockResolvedValue({
+ rules_custom_installed: 0,
+ rules_installed: 0,
+ rules_not_installed: 0,
+ rules_not_updated: 0,
+ timelines_installed: 0,
+ timelines_not_installed: 1,
+ timelines_not_updated: 0,
+ });
+ (api.createPrepackagedRules as jest.Mock).mockResolvedValue({
+ rules_installed: 0,
+ rules_updated: 0,
+ timelines_installed: 0,
+ timelines_updated: 0,
+ });
+ await act(async () => {
+ const { result, waitForNextUpdate } = renderHook(
+ () =>
+ usePrePackagedRules({
+ canUserCRUD: true,
+ hasIndexWrite: true,
+ isAuthenticated: true,
+ hasEncryptionKey: true,
+ isSignalIndexExists: true,
+ })
+ );
+ await waitForNextUpdate();
+ await waitForNextUpdate();
+
+ const button = result.current.getLoadPrebuiltRulesAndTemplatesButton({
+ isDisabled: false,
+ onClick: jest.fn(),
+ 'data-test-subj': 'button',
+ });
+ const wrapper = shallow(button as ReactElement);
+ expect(wrapper.find('[data-test-subj="button"]').text()).toEqual(
+ i18n.LOAD_PREPACKAGED_TIMELINE_TEMPLATES
+ );
+ });
+ });
+
+ test('getLoadPrebuiltRulesAndTemplatesButton - LOAD_PREPACKAGED_RULES_AND_TEMPLATES', async () => {
+ (api.getPrePackagedRulesStatus as jest.Mock).mockResolvedValue({
+ rules_custom_installed: 0,
+ rules_installed: 0,
+ rules_not_installed: 1,
+ rules_not_updated: 0,
+ timelines_installed: 0,
+ timelines_not_installed: 1,
+ timelines_not_updated: 0,
+ });
+ (api.createPrepackagedRules as jest.Mock).mockResolvedValue({
+ rules_installed: 0,
+ rules_updated: 0,
+ timelines_installed: 0,
+ timelines_updated: 0,
+ });
+ await act(async () => {
+ const { result, waitForNextUpdate } = renderHook(
+ () =>
+ usePrePackagedRules({
+ canUserCRUD: true,
+ hasIndexWrite: true,
+ isAuthenticated: true,
+ hasEncryptionKey: true,
+ isSignalIndexExists: true,
+ })
+ );
+ await waitForNextUpdate();
+ await waitForNextUpdate();
+
+ const button = result.current.getLoadPrebuiltRulesAndTemplatesButton({
+ isDisabled: false,
+ onClick: jest.fn(),
+ 'data-test-subj': 'button',
+ });
+ const wrapper = shallow(button as ReactElement);
+ expect(wrapper.find('[data-test-subj="button"]').text()).toEqual(
+ i18n.LOAD_PREPACKAGED_RULES_AND_TEMPLATES
+ );
+ });
+ });
+
+ test('getReloadPrebuiltRulesAndTemplatesButton - missing rules and templates', async () => {
+ (api.getPrePackagedRulesStatus as jest.Mock).mockResolvedValue({
+ rules_custom_installed: 0,
+ rules_installed: 1,
+ rules_not_installed: 1,
+ rules_not_updated: 0,
+ timelines_installed: 0,
+ timelines_not_installed: 1,
+ timelines_not_updated: 0,
+ });
+ (api.createPrepackagedRules as jest.Mock).mockResolvedValue({
+ rules_installed: 0,
+ rules_updated: 0,
+ timelines_installed: 0,
+ timelines_updated: 0,
+ });
+ await act(async () => {
+ const { result, waitForNextUpdate } = renderHook(
+ () =>
+ usePrePackagedRules({
+ canUserCRUD: true,
+ hasIndexWrite: true,
+ isAuthenticated: true,
+ hasEncryptionKey: true,
+ isSignalIndexExists: true,
+ })
+ );
+ await waitForNextUpdate();
+ await waitForNextUpdate();
+
+ const button = result.current.getReloadPrebuiltRulesAndTemplatesButton({
+ isDisabled: false,
+ onClick: jest.fn(),
+ });
+ const wrapper = shallow(button as ReactElement);
+ expect(wrapper.find('[data-test-subj="reloadPrebuiltRulesBtn"]').text()).toEqual(
+ 'Install 1 Elastic prebuilt rule and 1 Elastic prebuilt timeline '
+ );
+ });
+ });
+
+ test('getReloadPrebuiltRulesAndTemplatesButton - missing rules', async () => {
+ (api.getPrePackagedRulesStatus as jest.Mock).mockResolvedValue({
+ rules_custom_installed: 0,
+ rules_installed: 1,
+ rules_not_installed: 1,
+ rules_not_updated: 0,
+ timelines_installed: 0,
+ timelines_not_installed: 0,
+ timelines_not_updated: 0,
+ });
+ (api.createPrepackagedRules as jest.Mock).mockResolvedValue({
+ rules_installed: 0,
+ rules_updated: 0,
+ timelines_installed: 0,
+ timelines_updated: 0,
+ });
+ await act(async () => {
+ const { result, waitForNextUpdate } = renderHook(
+ () =>
+ usePrePackagedRules({
+ canUserCRUD: true,
+ hasIndexWrite: true,
+ isAuthenticated: true,
+ hasEncryptionKey: true,
+ isSignalIndexExists: true,
+ })
+ );
+ await waitForNextUpdate();
+ await waitForNextUpdate();
+
+ const button = result.current.getReloadPrebuiltRulesAndTemplatesButton({
+ isDisabled: false,
+ onClick: jest.fn(),
+ });
+ const wrapper = shallow(button as ReactElement);
+ expect(wrapper.find('[data-test-subj="reloadPrebuiltRulesBtn"]').text()).toEqual(
+ 'Install 1 Elastic prebuilt rule '
+ );
+ });
+ });
+
+ test('getReloadPrebuiltRulesAndTemplatesButton - missing templates', async () => {
+ (api.getPrePackagedRulesStatus as jest.Mock).mockResolvedValue({
+ rules_custom_installed: 0,
+ rules_installed: 1,
+ rules_not_installed: 0,
+ rules_not_updated: 0,
+ timelines_installed: 1,
+ timelines_not_installed: 1,
+ timelines_not_updated: 0,
+ });
+ (api.createPrepackagedRules as jest.Mock).mockResolvedValue({
+ rules_installed: 0,
+ rules_updated: 0,
+ timelines_installed: 0,
+ timelines_updated: 0,
+ });
+ await act(async () => {
+ const { result, waitForNextUpdate } = renderHook(
+ () =>
+ usePrePackagedRules({
+ canUserCRUD: true,
+ hasIndexWrite: true,
+ isAuthenticated: true,
+ hasEncryptionKey: true,
+ isSignalIndexExists: true,
+ })
+ );
+ await waitForNextUpdate();
+ await waitForNextUpdate();
+
+ const button = result.current.getReloadPrebuiltRulesAndTemplatesButton({
+ isDisabled: false,
+ onClick: jest.fn(),
+ });
+ const wrapper = shallow(button as ReactElement);
+ expect(wrapper.find('[data-test-subj="reloadPrebuiltRulesBtn"]').text()).toEqual(
+ 'Install 1 Elastic prebuilt timeline '
+ );
+ });
+ });
+
test('unhappy path to createPrePackagedRules', async () => {
const spyOnCreatePrepackagedRules = jest.spyOn(api, 'createPrepackagedRules');
spyOnCreatePrepackagedRules.mockImplementation(() => {
diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_pre_packaged_rules.tsx b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_pre_packaged_rules.tsx
index 4d19f44bcfc84..48530ddeb181e 100644
--- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_pre_packaged_rules.tsx
+++ b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_pre_packaged_rules.tsx
@@ -114,6 +114,27 @@ export const usePrePackagedRules = ({
const [loadingCreatePrePackagedRules, setLoadingCreatePrePackagedRules] = useState(false);
const [loading, setLoading] = useState(true);
const [, dispatchToaster] = useStateToaster();
+ const getSuccessToastMessage = (result: {
+ rules_installed: number;
+ rules_updated: number;
+ timelines_installed: number;
+ timelines_updated: number;
+ }) => {
+ const {
+ rules_installed: rulesInstalled,
+ rules_updated: rulesUpdated,
+ timelines_installed: timelinesInstalled,
+ timelines_updated: timelinesUpdated,
+ } = result;
+ if (rulesInstalled === 0 && (timelinesInstalled > 0 || timelinesUpdated > 0)) {
+ return i18n.TIMELINE_PREPACKAGED_SUCCESS;
+ } else if ((rulesInstalled > 0 || rulesUpdated > 0) && timelinesInstalled === 0) {
+ return i18n.RULE_PREPACKAGED_SUCCESS;
+ } else {
+ return i18n.RULE_AND_TIMELINE_PREPACKAGED_SUCCESS;
+ }
+ };
+
useEffect(() => {
let isSubscribed = true;
const abortCtrl = new AbortController();
@@ -170,7 +191,7 @@ export const usePrePackagedRules = ({
isSignalIndexExists
) {
setLoadingCreatePrePackagedRules(true);
- await createPrepackagedRules({
+ const result = await createPrepackagedRules({
signal: abortCtrl.signal,
});
@@ -209,11 +230,7 @@ export const usePrePackagedRules = ({
timelinesNotInstalled: prePackagedRuleStatusResponse.timelines_not_installed,
timelinesNotUpdated: prePackagedRuleStatusResponse.timelines_not_updated,
});
-
- displaySuccessToast(
- i18n.RULE_AND_TIMELINE_PREPACKAGED_SUCCESS,
- dispatchToaster
- );
+ displaySuccessToast(getSuccessToastMessage(result), dispatchToaster);
stopTimeOut();
resolve(true);
} else {
@@ -277,8 +294,9 @@ export const usePrePackagedRules = ({
);
const getLoadPrebuiltRulesAndTemplatesButton = useCallback(
({ isDisabled, onClick, fill, 'data-test-subj': dataTestSubj = 'loadPrebuiltRulesBtn' }) => {
- return prePackagedRuleStatus === 'ruleNotInstalled' ||
- prePackagedTimelineStatus === 'timelinesNotInstalled' ? (
+ return (prePackagedRuleStatus === 'ruleNotInstalled' ||
+ prePackagedTimelineStatus === 'timelinesNotInstalled') &&
+ prePackagedRuleStatus !== 'someRuleUninstall' ? (
Date: Thu, 29 Oct 2020 11:23:39 -0500
Subject: [PATCH 38/73] Service overview tab and route (#81972)
Placeholder tab and route for service overview page.
Fixes #81718.
---
.../app/Main/route_config/index.tsx | 14 +
.../app/ServiceDetails/ServiceDetailTabs.tsx | 16 +-
.../components/app/service_overview/index.tsx | 246 ++++++++++++++++++
.../service_overview.test.tsx | 29 +++
.../Links/apm/service_overview_link.tsx | 23 ++
5 files changed, 324 insertions(+), 4 deletions(-)
create mode 100644 x-pack/plugins/apm/public/components/app/service_overview/index.tsx
create mode 100644 x-pack/plugins/apm/public/components/app/service_overview/service_overview.test.tsx
create mode 100644 x-pack/plugins/apm/public/components/shared/Links/apm/service_overview_link.tsx
diff --git a/x-pack/plugins/apm/public/components/app/Main/route_config/index.tsx b/x-pack/plugins/apm/public/components/app/Main/route_config/index.tsx
index 0d61ca8e39845..f96dc14e34264 100644
--- a/x-pack/plugins/apm/public/components/app/Main/route_config/index.tsx
+++ b/x-pack/plugins/apm/public/components/app/Main/route_config/index.tsx
@@ -92,6 +92,12 @@ function ServiceDetailsNodes(
return ;
}
+function ServiceDetailsOverview(
+ props: RouteComponentProps<{ serviceName: string }>
+) {
+ return ;
+}
+
function ServiceDetailsServiceMap(
props: RouteComponentProps<{ serviceName: string }>
) {
@@ -215,6 +221,14 @@ export const routes: APMRouteDefinition[] = [
`/services/${props.match.params.serviceName}/transactions`
)(props),
} as APMRouteDefinition<{ serviceName: string }>,
+ {
+ exact: true,
+ path: '/services/:serviceName/overview',
+ breadcrumb: i18n.translate('xpack.apm.breadcrumb.overviewTitle', {
+ defaultMessage: 'Overview',
+ }),
+ component: ServiceDetailsOverview,
+ } as APMRouteDefinition<{ serviceName: string }>,
// errors
{
exact: true,
diff --git a/x-pack/plugins/apm/public/components/app/ServiceDetails/ServiceDetailTabs.tsx b/x-pack/plugins/apm/public/components/app/ServiceDetails/ServiceDetailTabs.tsx
index 76c8a289b830c..d51e4a2dd3d7c 100644
--- a/x-pack/plugins/apm/public/components/app/ServiceDetails/ServiceDetailTabs.tsx
+++ b/x-pack/plugins/apm/public/components/app/ServiceDetails/ServiceDetailTabs.tsx
@@ -16,16 +16,24 @@ import { ErrorOverviewLink } from '../../shared/Links/apm/ErrorOverviewLink';
import { MetricOverviewLink } from '../../shared/Links/apm/MetricOverviewLink';
import { ServiceMapLink } from '../../shared/Links/apm/ServiceMapLink';
import { ServiceNodeOverviewLink } from '../../shared/Links/apm/ServiceNodeOverviewLink';
+import { ServiceOverviewLink } from '../../shared/Links/apm/service_overview_link';
import { TransactionOverviewLink } from '../../shared/Links/apm/TransactionOverviewLink';
import { ErrorGroupOverview } from '../ErrorGroupOverview';
import { ServiceMap } from '../ServiceMap';
import { ServiceMetrics } from '../ServiceMetrics';
import { ServiceNodeOverview } from '../ServiceNodeOverview';
+import { ServiceOverview } from '../service_overview';
import { TransactionOverview } from '../TransactionOverview';
interface Props {
serviceName: string;
- tab: 'transactions' | 'errors' | 'metrics' | 'nodes' | 'service-map';
+ tab:
+ | 'errors'
+ | 'metrics'
+ | 'nodes'
+ | 'overview'
+ | 'service-map'
+ | 'transactions';
}
export function ServiceDetailTabs({ serviceName, tab }: Props) {
@@ -34,13 +42,13 @@ export function ServiceDetailTabs({ serviceName, tab }: Props) {
const overviewTab = {
link: (
-
+
{i18n.translate('xpack.apm.serviceDetails.overviewTabLabel', {
defaultMessage: 'Overview',
})}
-
+
),
- render: () => <>>,
+ render: () => ,
name: 'overview',
};
diff --git a/x-pack/plugins/apm/public/components/app/service_overview/index.tsx b/x-pack/plugins/apm/public/components/app/service_overview/index.tsx
new file mode 100644
index 0000000000000..81f23b6427508
--- /dev/null
+++ b/x-pack/plugins/apm/public/components/app/service_overview/index.tsx
@@ -0,0 +1,246 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { EuiFlexGroup, EuiFlexItem, EuiPanel, EuiTitle } from '@elastic/eui';
+import { i18n } from '@kbn/i18n';
+import React from 'react';
+import styled from 'styled-components';
+import { useTrackPageview } from '../../../../../observability/public';
+import { ErrorOverviewLink } from '../../shared/Links/apm/ErrorOverviewLink';
+import { ServiceMapLink } from '../../shared/Links/apm/ServiceMapLink';
+import { TransactionOverviewLink } from '../../shared/Links/apm/TransactionOverviewLink';
+
+const rowHeight = 310;
+const latencyChartRowHeight = 230;
+
+const Row = styled(EuiFlexItem)`
+ height: ${rowHeight}px;
+`;
+
+const LatencyChartRow = styled(EuiFlexItem)`
+ height: ${latencyChartRowHeight}px;
+`;
+
+const TableLinkFlexItem = styled(EuiFlexItem)`
+ & > a {
+ text-align: right;
+ }
+`;
+
+interface ServiceOverviewProps {
+ serviceName: string;
+}
+
+export function ServiceOverview({ serviceName }: ServiceOverviewProps) {
+ useTrackPageview({ app: 'apm', path: 'service_overview' });
+ useTrackPageview({ app: 'apm', path: 'service_overview', delay: 15000 });
+
+ return (
+
+
+
+
+ Search bar
+
+
+ Comparison picker
+
+
+ Date picker
+
+
+
+
+
+
+
+ {i18n.translate('xpack.apm.serviceOverview.latencyChartTitle', {
+ defaultMessage: 'Latency',
+ })}
+
+
+
+
+
+
+
+
+
+
+ {i18n.translate(
+ 'xpack.apm.serviceOverview.trafficChartTitle',
+ {
+ defaultMessage: 'Traffic',
+ }
+ )}
+
+
+
+
+
+
+
+
+
+
+ {i18n.translate(
+ 'xpack.apm.serviceOverview.transactionsTableTitle',
+ {
+ defaultMessage: 'Transactions',
+ }
+ )}
+
+
+
+
+
+ {i18n.translate(
+ 'xpack.apm.serviceOverview.transactionsTableLinkText',
+ {
+ defaultMessage: 'View transactions',
+ }
+ )}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {i18n.translate(
+ 'xpack.apm.serviceOverview.errorRateChartTitle',
+ {
+ defaultMessage: 'Error rate',
+ }
+ )}
+
+
+
+
+
+
+
+
+
+
+ {i18n.translate(
+ 'xpack.apm.serviceOverview.errorsTableTitle',
+ {
+ defaultMessage: 'Errors',
+ }
+ )}
+
+
+
+
+
+ {i18n.translate(
+ 'xpack.apm.serviceOverview.errorsTableLinkText',
+ {
+ defaultMessage: 'View errors',
+ }
+ )}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {i18n.translate(
+ 'xpack.apm.serviceOverview.averageDurationBySpanTypeChartTitle',
+ {
+ defaultMessage: 'Average duration by span type',
+ }
+ )}
+
+
+
+
+
+
+
+
+
+
+
+
+ {i18n.translate(
+ 'xpack.apm.serviceOverview.dependenciesTableTitle',
+ {
+ defaultMessage: 'Dependencies',
+ }
+ )}
+
+
+
+
+
+ {i18n.translate(
+ 'xpack.apm.serviceOverview.dependenciesTableLinkText',
+ {
+ defaultMessage: 'View service map',
+ }
+ )}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {i18n.translate(
+ 'xpack.apm.serviceOverview.instancesLatencyDistributionChartTitle',
+ {
+ defaultMessage: 'Instances latency distribution',
+ }
+ )}
+
+
+
+
+
+
+
+
+ {i18n.translate(
+ 'xpack.apm.serviceOverview.instancesTableTitle',
+ {
+ defaultMessage: 'Instances',
+ }
+ )}
+
+
+
+
+
+
+
+ );
+}
diff --git a/x-pack/plugins/apm/public/components/app/service_overview/service_overview.test.tsx b/x-pack/plugins/apm/public/components/app/service_overview/service_overview.test.tsx
new file mode 100644
index 0000000000000..4e2063930a9c9
--- /dev/null
+++ b/x-pack/plugins/apm/public/components/app/service_overview/service_overview.test.tsx
@@ -0,0 +1,29 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { render } from '@testing-library/react';
+import React, { ReactNode } from 'react';
+import { MemoryRouter } from 'react-router-dom';
+import { MockApmPluginContextWrapper } from '../../../context/ApmPluginContext/MockApmPluginContext';
+import { ServiceOverview } from './';
+
+function Wrapper({ children }: { children?: ReactNode }) {
+ return (
+
+ {children}
+
+ );
+}
+
+describe('ServiceOverview', () => {
+ it('renders', () => {
+ expect(() =>
+ render( , {
+ wrapper: Wrapper,
+ })
+ ).not.toThrowError();
+ });
+});
diff --git a/x-pack/plugins/apm/public/components/shared/Links/apm/service_overview_link.tsx b/x-pack/plugins/apm/public/components/shared/Links/apm/service_overview_link.tsx
new file mode 100644
index 0000000000000..5d7859e7362c7
--- /dev/null
+++ b/x-pack/plugins/apm/public/components/shared/Links/apm/service_overview_link.tsx
@@ -0,0 +1,23 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+import React from 'react';
+import { APMLink, APMLinkExtendProps } from './APMLink';
+
+interface ServiceOverviewLinkProps extends APMLinkExtendProps {
+ serviceName: string;
+}
+
+export function ServiceOverviewLink({
+ serviceName,
+ ...rest
+}: ServiceOverviewLinkProps) {
+ return ;
+}
From 84b23b6d7ca021d2674563d7c6cb2ec6c33d08b9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mike=20C=C3=B4t=C3=A9?=
Date: Thu, 29 Oct 2020 12:39:20 -0400
Subject: [PATCH 39/73] Move task manager README.md to root of plugin (#82012)
* Move task manager README.md to root of plugin
* Fix failing test, update task manager plugin description in docs
---
docs/developer/plugin-list.asciidoc | 4 ++--
x-pack/plugins/task_manager/{server => }/README.md | 3 ++-
2 files changed, 4 insertions(+), 3 deletions(-)
rename x-pack/plugins/task_manager/{server => }/README.md (99%)
diff --git a/docs/developer/plugin-list.asciidoc b/docs/developer/plugin-list.asciidoc
index 8e08c3806446d..914bd8fce6dff 100644
--- a/docs/developer/plugin-list.asciidoc
+++ b/docs/developer/plugin-list.asciidoc
@@ -488,8 +488,8 @@ the alertTypes by the Stack in the alerting plugin, register associated HTTP
routes, etc.
-|{kib-repo}blob/{branch}/x-pack/plugins/task_manager[taskManager]
-|WARNING: Missing README.
+|{kib-repo}blob/{branch}/x-pack/plugins/task_manager/README.md[taskManager]
+|The task manager is a generic system for running background tasks.
|{kib-repo}blob/{branch}/x-pack/plugins/telemetry_collection_xpack/README.md[telemetryCollectionXpack]
diff --git a/x-pack/plugins/task_manager/server/README.md b/x-pack/plugins/task_manager/README.md
similarity index 99%
rename from x-pack/plugins/task_manager/server/README.md
rename to x-pack/plugins/task_manager/README.md
index a0b35ad094537..b25d3cc49f980 100644
--- a/x-pack/plugins/task_manager/server/README.md
+++ b/x-pack/plugins/task_manager/README.md
@@ -1,7 +1,8 @@
# Kibana task manager
-The task manager is a generic system for running background tasks. It supports:
+The task manager is a generic system for running background tasks.
+It supports:
- Single-run and recurring tasks
- Scheduling tasks to run after a specified datetime
- Basic retry logic
From 052f8277fea0df42e41cab0dc021b7ef7bddc893 Mon Sep 17 00:00:00 2001
From: CJ Cenizal
Date: Thu, 29 Oct 2020 10:56:42 -0700
Subject: [PATCH 40/73] Add READMEs for ES UI plugins (#81973)
* Add Search Profiler README.
* Add Upgrade Assistant README.
* Add name of plugin to Watcher README.
* Add Console Extensions README.
* Add Grok Debugger README.
* Add Painless Lab README.
* Add License Management README.
* Add Remote Clusters README.
* Add Console README.
---
docs/developer/plugin-list.asciidoc | 37 +++++++-----
src/plugins/console/README.md | 5 ++
x-pack/plugins/console_extensions/README.md | 3 +
x-pack/plugins/grokdebugger/README.md | 6 ++
x-pack/plugins/license_management/README.md | 5 ++
x-pack/plugins/painless_lab/README.md | 5 ++
x-pack/plugins/remote_clusters/README.md | 5 ++
x-pack/plugins/searchprofiler/README.md | 8 +++
x-pack/plugins/upgrade_assistant/README.md | 67 +++++++++++++++++++++
x-pack/plugins/watcher/README.md | 4 +-
10 files changed, 127 insertions(+), 18 deletions(-)
create mode 100644 src/plugins/console/README.md
create mode 100644 x-pack/plugins/console_extensions/README.md
create mode 100644 x-pack/plugins/grokdebugger/README.md
create mode 100644 x-pack/plugins/license_management/README.md
create mode 100644 x-pack/plugins/painless_lab/README.md
create mode 100644 x-pack/plugins/remote_clusters/README.md
create mode 100644 x-pack/plugins/searchprofiler/README.md
create mode 100644 x-pack/plugins/upgrade_assistant/README.md
diff --git a/docs/developer/plugin-list.asciidoc b/docs/developer/plugin-list.asciidoc
index 914bd8fce6dff..f30afce3ee02c 100644
--- a/docs/developer/plugin-list.asciidoc
+++ b/docs/developer/plugin-list.asciidoc
@@ -38,8 +38,8 @@ NOTE:
|The Charts plugin is a way to create easier integration of shared colors, themes, types and other utilities across all Kibana charts and visualizations.
-|{kib-repo}blob/{branch}/src/plugins/console[console]
-|WARNING: Missing README.
+|{kib-repo}blob/{branch}/src/plugins/console/README.md[console]
+|Console provides the user with tools for storing and executing requests against Elasticsearch.
|<>
@@ -307,8 +307,8 @@ Failure to have auth enabled in Kibana will make for a broken UI. UI-based error
|WARNING: Missing README.
-|{kib-repo}blob/{branch}/x-pack/plugins/console_extensions[consoleExtensions]
-|WARNING: Missing README.
+|{kib-repo}blob/{branch}/x-pack/plugins/console_extensions/README.md[consoleExtensions]
+|This plugin provides autocomplete definitions of licensed APIs to the OSS Console plugin.
|{kib-repo}blob/{branch}/x-pack/plugins/cross_cluster_replication/README.md[crossClusterReplication]
@@ -376,8 +376,9 @@ or dashboards from the Kibana instance, from both server and client-side plugins
|This is the main source folder of the Graph plugin. It contains all of the Kibana server and client source code. x-pack/test/functional/apps/graph contains additional functional tests.
-|{kib-repo}blob/{branch}/x-pack/plugins/grokdebugger[grokdebugger]
-|WARNING: Missing README.
+|{kib-repo}blob/{branch}/x-pack/plugins/grokdebugger/README.md[grokdebugger]
+|This plugin helps users define Grok patterns,
+which are particularly useful for ingesting logs.
|{kib-repo}blob/{branch}/x-pack/plugins/index_lifecycle_management/README.md[indexLifecycleManagement]
@@ -406,8 +407,8 @@ the infrastructure monitoring use-case within Kibana.
|Run all tests from the x-pack root directory
-|{kib-repo}blob/{branch}/x-pack/plugins/license_management[licenseManagement]
-|WARNING: Missing README.
+|{kib-repo}blob/{branch}/x-pack/plugins/license_management/README.md[licenseManagement]
+|This plugin enables users to activate a trial license, downgrade to Basic, and upload a new license.
|{kib-repo}blob/{branch}/x-pack/plugins/licensing/README.md[licensing]
@@ -444,12 +445,12 @@ Elastic.
|This plugin provides shared components and services for use across observability solutions, as well as the observability landing page UI.
-|{kib-repo}blob/{branch}/x-pack/plugins/painless_lab[painlessLab]
-|WARNING: Missing README.
+|{kib-repo}blob/{branch}/x-pack/plugins/painless_lab/README.md[painlessLab]
+|This plugin helps users learn how to use the Painless scripting language.
-|{kib-repo}blob/{branch}/x-pack/plugins/remote_clusters[remoteClusters]
-|WARNING: Missing README.
+|{kib-repo}blob/{branch}/x-pack/plugins/remote_clusters/README.md[remoteClusters]
+|This plugin helps users manage their remote clusters, which enable cross-cluster search and cross-cluster replication.
|{kib-repo}blob/{branch}/x-pack/plugins/reporting/README.md[reporting]
@@ -460,8 +461,11 @@ Elastic.
|Welcome to the Kibana rollup plugin! This plugin provides Kibana support for Elasticsearch's rollup feature. Please refer to the Elasticsearch documentation to understand rollup indices and how to create rollup jobs.
-|{kib-repo}blob/{branch}/x-pack/plugins/searchprofiler[searchprofiler]
-|WARNING: Missing README.
+|{kib-repo}blob/{branch}/x-pack/plugins/searchprofiler/README.md[searchprofiler]
+|The search profiler consumes the Profile API
+by sending a search API with profile: true enabled in the request body. The response contains
+detailed information on how Elasticsearch executed the search request. People use this information
+to understand why a search request might be slow.
|{kib-repo}blob/{branch}/x-pack/plugins/security/README.md[security]
@@ -513,8 +517,9 @@ As a developer you can reuse and extend built-in alerts and actions UI functiona
|Registers commercially licensed generic actions like per panel time range and contains some code that supports drilldown work.
-|{kib-repo}blob/{branch}/x-pack/plugins/upgrade_assistant[upgradeAssistant]
-|WARNING: Missing README.
+|{kib-repo}blob/{branch}/x-pack/plugins/upgrade_assistant/README.md[upgradeAssistant]
+|Upgrade Assistant helps users prepare their Stack for being upgraded to the next major. Its primary
+purposes are to:
|{kib-repo}blob/{branch}/x-pack/plugins/uptime/README.md[uptime]
diff --git a/src/plugins/console/README.md b/src/plugins/console/README.md
new file mode 100644
index 0000000000000..07421151f8087
--- /dev/null
+++ b/src/plugins/console/README.md
@@ -0,0 +1,5 @@
+# Console
+
+## About
+
+Console provides the user with tools for storing and executing requests against Elasticsearch.
\ No newline at end of file
diff --git a/x-pack/plugins/console_extensions/README.md b/x-pack/plugins/console_extensions/README.md
new file mode 100644
index 0000000000000..49d83d2888d6b
--- /dev/null
+++ b/x-pack/plugins/console_extensions/README.md
@@ -0,0 +1,3 @@
+# Console extensions
+
+This plugin provides autocomplete definitions of licensed APIs to the OSS Console plugin.
\ No newline at end of file
diff --git a/x-pack/plugins/grokdebugger/README.md b/x-pack/plugins/grokdebugger/README.md
new file mode 100644
index 0000000000000..80729b35500b6
--- /dev/null
+++ b/x-pack/plugins/grokdebugger/README.md
@@ -0,0 +1,6 @@
+# Grok Debugger
+
+## About
+
+This plugin helps users define [Grok patterns](https://www.elastic.co/guide/en/elasticsearch/reference/current/grok-processor.html),
+which are particularly useful for ingesting logs.
\ No newline at end of file
diff --git a/x-pack/plugins/license_management/README.md b/x-pack/plugins/license_management/README.md
new file mode 100644
index 0000000000000..b103c8fcd6721
--- /dev/null
+++ b/x-pack/plugins/license_management/README.md
@@ -0,0 +1,5 @@
+# License Management
+
+## About
+
+This plugin enables users to activate a trial license, downgrade to Basic, and upload a new license.
\ No newline at end of file
diff --git a/x-pack/plugins/painless_lab/README.md b/x-pack/plugins/painless_lab/README.md
new file mode 100644
index 0000000000000..519b6a9dea8ed
--- /dev/null
+++ b/x-pack/plugins/painless_lab/README.md
@@ -0,0 +1,5 @@
+# Painless Lab
+
+## About
+
+This plugin helps users learn how to use the [Painless scripting language](https://www.elastic.co/guide/en/elasticsearch/reference/master/modules-scripting-painless.html).
\ No newline at end of file
diff --git a/x-pack/plugins/remote_clusters/README.md b/x-pack/plugins/remote_clusters/README.md
new file mode 100644
index 0000000000000..1119c98ffe84a
--- /dev/null
+++ b/x-pack/plugins/remote_clusters/README.md
@@ -0,0 +1,5 @@
+# Remote Clusters
+
+## About
+
+This plugin helps users manage their [remote clusters](https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-remote-clusters.html), which enable cross-cluster search and cross-cluster replication.
\ No newline at end of file
diff --git a/x-pack/plugins/searchprofiler/README.md b/x-pack/plugins/searchprofiler/README.md
new file mode 100644
index 0000000000000..6e25163470488
--- /dev/null
+++ b/x-pack/plugins/searchprofiler/README.md
@@ -0,0 +1,8 @@
+# Search Profiler
+
+## About
+
+The search profiler consumes the [Profile API](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-profile.html)
+by sending a `search` API with `profile: true` enabled in the request body. The response contains
+detailed information on how Elasticsearch executed the search request. People use this information
+to understand why a search request might be slow.
\ No newline at end of file
diff --git a/x-pack/plugins/upgrade_assistant/README.md b/x-pack/plugins/upgrade_assistant/README.md
new file mode 100644
index 0000000000000..a6cb3b431c82b
--- /dev/null
+++ b/x-pack/plugins/upgrade_assistant/README.md
@@ -0,0 +1,67 @@
+# Upgrade Assistant
+
+## About
+
+Upgrade Assistant helps users prepare their Stack for being upgraded to the next major. Its primary
+purposes are to:
+
+* **Surface deprecations.** Deprecations are features that are currently being used that will be
+removed in the next major. Surfacing tells the user that there's a problem preventing them
+from upgrading.
+* **Migrate from deprecation features to supported features.** This addresses the problem, clearing
+the path for the upgrade. Generally speaking, once all deprecations are addressed, the user can
+safely upgrade.
+
+### Deprecations
+
+There are two sources of deprecation information:
+
+* [**Deprecation Info API.**](https://www.elastic.co/guide/en/elasticsearch/reference/master/migration-api-deprecation.html)
+This is information about cluster, node, and index level settings that use deprecated features that
+will be removed or changed in the next major version. Currently, only cluster and index deprecations
+will be surfaced in the Upgrade Assistant. ES server engineers are responsible for adding
+deprecations to the Deprecation Info API.
+* [**Deprecation logs.**](https://www.elastic.co/guide/en/elasticsearch/reference/current/logging.html#deprecation-logging)
+These surface runtime deprecations, e.g. a Painless script that uses a deprecated accessor or a
+request to a deprecated API. These are also generally surfaced as deprecation headers within the
+response. Even if the cluster state is good, app maintainers need to watch the logs in case
+deprecations are discovered as data is migrated.
+
+### Fixing problems
+
+Problems can be fixed at various points in the upgrade process. The Upgrade Assistant supports
+various upgrade paths and surfaces various types of upgrade-related issues.
+
+* **Fixing deprecated cluster settings pre-upgrade.** This generally requires fixing some settings
+in `elasticsearch.yml`.
+* **Migrating indices data pre-upgrade.** This can involve deleting indices so that ES can rebuild
+them in the new version, reindexing them so that they're built using a new Lucene version, or
+applying a migration script that reindexes them with new settings/mappings/etc.
+* **Migrating indices data post-upgrade.** As was the case with APM in the 6.8->7.x upgrade,
+sometimes the new data format isn't forwards-compatible. In these cases, the user will perform the
+upgrade first and then use the Upgrade Assistant to reindex their data to be compatible with the new
+version.
+
+Deprecations can be handled in a number of ways:
+
+* **Reindexing.** When a user's index contains deprecations (e.g. mappings) a reindex solves them.
+Upgrade Assistant contains migration scripts that are executed as part of the reindex process.
+The user will see a "Reindex" button they can click which will apply this script and perform the
+reindex.
+ * Reindexing is an atomic process in Upgrade Assistant, so that ingestion is never disrupted.
+ It works like this:
+ * Create a new index with a "reindexed-" prefix ([#30114](https://github.com/elastic/kibana/pull/30114)).
+ * Create an index alias pointing from the original index name to the prefixed index name.
+ * Reindex from the original index into the prefixed index.
+ * Delete the old index and rename the prefixed index.
+ * Some apps might require custom scripts, as was the case with APM ([#29845](https://github.com/elastic/kibana/pull/29845)).
+ In that case the migration performed a reindex with a Painless script (covered by automated tests)
+ that made the required changes to the data.
+* **Update index settings.** Some index settings will need to be updated, which doesn't require a
+reindex. An example of this is the "Fix" button that was added for metricbeat and filebeat indices
+([#32829](https://github.com/elastic/kibana/pull/32829), [#33439](https://github.com/elastic/kibana/pull/33439)).
+* **Following the docs.** The Deprecation Info API provides links to the deprecation docs. Users
+will follow these docs to address the problem and make these warnings or errors disappear in the
+Upgrade Assistant.
+* **Stopping/restarting tasks and jobs.** Users had to stop watches and ML jobs and restart them as
+soon as reindexing was complete ([#29663](https://github.com/elastic/kibana/pull/29663)).
\ No newline at end of file
diff --git a/x-pack/plugins/watcher/README.md b/x-pack/plugins/watcher/README.md
index 4f9111760a0a6..c849a65019174 100644
--- a/x-pack/plugins/watcher/README.md
+++ b/x-pack/plugins/watcher/README.md
@@ -1,4 +1,4 @@
-# Conventions
+# Watcher
This plugins adopts some conventions in addition to or in place of conventions in Kibana (at the time of the plugin's creation):
@@ -69,4 +69,4 @@ encapsulating operations around such relationships — for example, updating the
### Kibana client code
This layer deals almost exclusively with data in the form of client models. The one exception to this rule is when the client code needs
-to bootstrap a model instance from a bare JS object — for example, creating a new `Watch` model from the contents of the Add/Edit Watch Form.
+to bootstrap a model instance from a bare JS object — for example, creating a new `Watch` model from the contents of the Add/Edit Watch Form.
\ No newline at end of file
From d84ac13a4abd5de1f97aede2843b7c62745d191b Mon Sep 17 00:00:00 2001
From: Jason Rhodes
Date: Thu, 29 Oct 2020 14:04:37 -0400
Subject: [PATCH 41/73] [Logs App] Fix logs permissions for alert management
(#81199)
* Mimics metrics permissions for alert mgmt in logs feature
* Updates logs security functional tests
Alert management permissions were added for read and all logs users in this PR, so both of these users now have "Stack Management" appear in the nav.
Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
---
x-pack/plugins/infra/server/features.ts | 9 +++++++++
.../apps/infra/feature_controls/logs_security.ts | 4 ++--
2 files changed, 11 insertions(+), 2 deletions(-)
diff --git a/x-pack/plugins/infra/server/features.ts b/x-pack/plugins/infra/server/features.ts
index d49755b6f68c1..c768cae247a99 100644
--- a/x-pack/plugins/infra/server/features.ts
+++ b/x-pack/plugins/infra/server/features.ts
@@ -68,6 +68,9 @@ export const LOGS_FEATURE = {
category: DEFAULT_APP_CATEGORIES.observability,
app: ['infra', 'logs', 'kibana'],
catalogue: ['infralogging', 'logs'],
+ management: {
+ insightsAndAlerting: ['triggersActions'],
+ },
alerting: [LOG_DOCUMENT_COUNT_ALERT_TYPE_ID],
privileges: {
all: {
@@ -81,6 +84,9 @@ export const LOGS_FEATURE = {
alerting: {
all: [LOG_DOCUMENT_COUNT_ALERT_TYPE_ID],
},
+ management: {
+ insightsAndAlerting: ['triggersActions'],
+ },
ui: ['show', 'configureSource', 'save'],
},
read: {
@@ -90,6 +96,9 @@ export const LOGS_FEATURE = {
alerting: {
read: [LOG_DOCUMENT_COUNT_ALERT_TYPE_ID],
},
+ management: {
+ insightsAndAlerting: ['triggersActions'],
+ },
savedObject: {
all: [],
read: ['infrastructure-ui-source'],
diff --git a/x-pack/test/functional/apps/infra/feature_controls/logs_security.ts b/x-pack/test/functional/apps/infra/feature_controls/logs_security.ts
index de6353d6b0456..78edbafa4ae47 100644
--- a/x-pack/test/functional/apps/infra/feature_controls/logs_security.ts
+++ b/x-pack/test/functional/apps/infra/feature_controls/logs_security.ts
@@ -58,7 +58,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
it('shows logs navlink', async () => {
const navLinks = (await appsMenu.readLinks()).map((link) => link.text);
- expect(navLinks).to.eql(['Overview', 'Logs']);
+ expect(navLinks).to.eql(['Overview', 'Logs', 'Stack Management']);
});
describe('logs landing page without data', () => {
@@ -121,7 +121,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
it('shows logs navlink', async () => {
const navLinks = (await appsMenu.readLinks()).map((link) => link.text);
- expect(navLinks).to.eql(['Overview', 'Logs']);
+ expect(navLinks).to.eql(['Overview', 'Logs', 'Stack Management']);
});
describe('logs landing page without data', () => {
From ee7ce25048818611416e9cc3a9791aa82d19583c Mon Sep 17 00:00:00 2001
From: Jane Miller <57721870+jmiller263@users.noreply.github.com>
Date: Thu, 29 Oct 2020 14:09:01 -0400
Subject: [PATCH 42/73] [SECURITY_SOLUTION] 145: Advanced Policy UI (#80390)
* Create Policies for each generated host
* Refactor Ingest setup to also setup Fleet
* Rename prop name
* Add generic response type to KbnClient.request + support for headers
* first attempt at adding fleet agent registration
* a little closer with fleet integration
* SUCCESS. Able to enroll agent and set it to online
* update names to be policy
* policy generator has advanced types in endpoint confit
* linting
* flesh out callback
* add submit button for verify_peer
* add verify hostname field
* 145 generalize cb
* 145 fix setAgain and getValue
* 145 merge conflict
* 145 add verify_hostname back, start loop for form
* 145 remove OS trick
* 145 make AdvancedPolicyForms its own component
* 145 grid partially working
* 145 back to basics
* 145 back to basics
* 145 rolled back grid
* 145 flex table working
* 145 undo accidental change
* 145 remove extra schema file
* 145 remove unused variable
* 145 kevin's PR feedback
* 145 fix type check and jest
* 145 EuiFlexGroups
* 145 use simple EuiFormRow and add show/hide buttons
* 145 move all advanced policy code to advanced file; remove unnec test code
* 145 fix IDs
* 145 take out unnecessary stuff
* 145 removed a couple more lines
* 145 add some fields back in
* 145 add spacer
Co-authored-by: Paul Tavares
Co-authored-by: Elastic Machine
Co-authored-by: kevinlog
Co-authored-by: Candace Park
---
.../common/endpoint/types/index.ts | 9 +-
.../policy/models/advanced_policy_schema.ts | 315 ++++++++++++++++++
.../policy/models/policy_details_config.ts | 41 +--
.../policy/store/policy_details/index.test.ts | 8 +-
.../policy/store/policy_details/selectors.ts | 3 +
.../management/pages/policy/view/index.ts | 1 +
.../pages/policy/view/policy_advanced.tsx | 124 +++++++
.../pages/policy/view/policy_details.tsx | 18 +
.../view/policy_forms/protections/malware.tsx | 8 +-
9 files changed, 477 insertions(+), 50 deletions(-)
create mode 100644 x-pack/plugins/security_solution/public/management/pages/policy/models/advanced_policy_schema.ts
create mode 100644 x-pack/plugins/security_solution/public/management/pages/policy/view/policy_advanced.tsx
diff --git a/x-pack/plugins/security_solution/common/endpoint/types/index.ts b/x-pack/plugins/security_solution/common/endpoint/types/index.ts
index 882b3e5182bf3..79157018c315a 100644
--- a/x-pack/plugins/security_solution/common/endpoint/types/index.ts
+++ b/x-pack/plugins/security_solution/common/endpoint/types/index.ts
@@ -860,6 +860,7 @@ type KbnConfigSchemaNonOptionalProps> = Pi
*/
export interface PolicyConfig {
windows: {
+ advanced?: {};
events: {
dll_and_driver_load: boolean;
dns: boolean;
@@ -881,6 +882,7 @@ export interface PolicyConfig {
};
};
mac: {
+ advanced?: {};
events: {
file: boolean;
process: boolean;
@@ -898,6 +900,7 @@ export interface PolicyConfig {
};
};
linux: {
+ advanced?: {};
events: {
file: boolean;
process: boolean;
@@ -916,15 +919,15 @@ export interface UIPolicyConfig {
/**
* Windows-specific policy configuration that is supported via the UI
*/
- windows: Pick;
+ windows: Pick;
/**
* Mac-specific policy configuration that is supported via the UI
*/
- mac: Pick;
+ mac: Pick;
/**
* Linux-specific policy configuration that is supported via the UI
*/
- linux: Pick;
+ linux: Pick;
}
/** Policy: Malware protection fields */
diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/models/advanced_policy_schema.ts b/x-pack/plugins/security_solution/public/management/pages/policy/models/advanced_policy_schema.ts
new file mode 100644
index 0000000000000..d25588dabedc6
--- /dev/null
+++ b/x-pack/plugins/security_solution/public/management/pages/policy/models/advanced_policy_schema.ts
@@ -0,0 +1,315 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+interface AdvancedPolicySchemaType {
+ key: string;
+ first_supported_version: string;
+ last_supported_version?: string;
+ documentation: string;
+}
+
+export const AdvancedPolicySchema: AdvancedPolicySchemaType[] = [
+ {
+ key: 'linux.advanced.agent.connection_delay',
+ first_supported_version: '7.11',
+ documentation: '',
+ },
+ {
+ key: 'linux.advanced.artifacts.global.base_url',
+ first_supported_version: '7.11',
+ documentation: '',
+ },
+ {
+ key: 'linux.advanced.artifacts.global.manifest_relative_url',
+ first_supported_version: '7.11',
+ documentation: '',
+ },
+ {
+ key: 'linux.advanced.artifacts.global.ca_cert',
+ first_supported_version: '7.11',
+ documentation: '',
+ },
+ {
+ key: 'linux.advanced.artifacts.global.public_key',
+ first_supported_version: '7.11',
+ documentation: '',
+ },
+ {
+ key: 'linux.advanced.artifacts.global.interval',
+ first_supported_version: '7.11',
+ documentation: '',
+ },
+ {
+ key: 'linux.advanced.artifacts.user.base_url',
+ first_supported_version: '7.11',
+ documentation: '',
+ },
+ {
+ key: 'linux.advanced.artifacts.user.ca_cert',
+ first_supported_version: '7.11',
+ documentation: '',
+ },
+ {
+ key: 'linux.advanced.artifacts.user.public_key',
+ first_supported_version: '7.11',
+ documentation: '',
+ },
+ {
+ key: 'linux.advanced.artifacts.user.interval',
+ first_supported_version: '7.11',
+ documentation: '',
+ },
+ {
+ key: 'linux.advanced.elasticsearch.delay',
+ first_supported_version: '7.11',
+ documentation: '',
+ },
+ {
+ key: 'linux.advanced.elasticsearch.tls.verify_peer',
+ first_supported_version: '7.11',
+ documentation: 'default is true',
+ },
+ {
+ key: 'linux.advanced.elasticsearch.tls.verify_hostname',
+ first_supported_version: '7.11',
+ documentation: 'default is true',
+ },
+ {
+ key: 'linux.advanced.elasticsearch.tls.ca_cert',
+ first_supported_version: '7.11',
+ documentation: '',
+ },
+ {
+ key: 'mac.advanced.agent.connection_delay',
+ first_supported_version: '7.11',
+ documentation: '',
+ },
+ {
+ key: 'mac.advanced.artifacts.global.base_url',
+ first_supported_version: '7.11',
+ documentation: '',
+ },
+ {
+ key: 'mac.advanced.artifacts.global.manifest_relative_url',
+ first_supported_version: '7.11',
+ documentation: '',
+ },
+ {
+ key: 'mac.advanced.artifacts.global.ca_cert',
+ first_supported_version: '7.11',
+ documentation: '',
+ },
+ {
+ key: 'mac.advanced.artifacts.global.public_key',
+ first_supported_version: '7.11',
+ documentation: '',
+ },
+ {
+ key: 'mac.advanced.artifacts.global.interval',
+ first_supported_version: '7.11',
+ documentation: '',
+ },
+ {
+ key: 'mac.advanced.artifacts.user.base_url',
+ first_supported_version: '7.11',
+ documentation: '',
+ },
+ {
+ key: 'mac.advanced.artifacts.user.ca_cert',
+ first_supported_version: '7.11',
+ documentation: '',
+ },
+ {
+ key: 'mac.advanced.artifacts.user.public_key',
+ first_supported_version: '7.11',
+ documentation: '',
+ },
+ {
+ key: 'mac.advanced.artifacts.user.interval',
+ first_supported_version: '7.11',
+ documentation: '',
+ },
+ {
+ key: 'mac.advanced.elasticsearch.delay',
+ first_supported_version: '7.11',
+ documentation: '',
+ },
+ {
+ key: 'mac.advanced.elasticsearch.tls.verify_peer',
+ first_supported_version: '7.11',
+ documentation: 'default is true',
+ },
+ {
+ key: 'mac.advanced.elasticsearch.tls.verify_hostname',
+ first_supported_version: '7.11',
+ documentation: 'default is true',
+ },
+ {
+ key: 'mac.advanced.elasticsearch.tls.ca_cert',
+ first_supported_version: '7.11',
+ documentation: '',
+ },
+ {
+ key: 'mac.advanced.malware.quarantine',
+ first_supported_version: '7.11',
+ documentation: '',
+ },
+ {
+ key: 'mac.advanced.kernel.connect',
+ first_supported_version: '7.11',
+ documentation: '',
+ },
+ {
+ key: 'mac.advanced.kernel.harden',
+ first_supported_version: '7.11',
+ documentation: '',
+ },
+ {
+ key: 'mac.advanced.kernel.process',
+ first_supported_version: '7.11',
+ documentation: '',
+ },
+ {
+ key: 'mac.advanced.kernel.filewrite',
+ first_supported_version: '7.11',
+ documentation: '',
+ },
+ {
+ key: 'mac.advanced.kernel.network',
+ first_supported_version: '7.11',
+ documentation: '',
+ },
+ {
+ key: 'windows.advanced.agent.connection_delay',
+ first_supported_version: '7.11',
+ documentation: '',
+ },
+ {
+ key: 'windows.advanced.artifacts.global.base_url',
+ first_supported_version: '7.11',
+ documentation: '',
+ },
+ {
+ key: 'windows.advanced.artifacts.global.manifest_relative_url',
+ first_supported_version: '7.11',
+ documentation: '',
+ },
+ {
+ key: 'windows.advanced.artifacts.global.ca_cert',
+ first_supported_version: '7.11',
+ documentation: '',
+ },
+ {
+ key: 'windows.advanced.artifacts.global.public_key',
+ first_supported_version: '7.11',
+ documentation: '',
+ },
+ {
+ key: 'windows.advanced.artifacts.global.interval',
+ first_supported_version: '7.11',
+ documentation: '',
+ },
+ {
+ key: 'windows.advanced.artifacts.user.base_url',
+ first_supported_version: '7.11',
+ documentation: '',
+ },
+ {
+ key: 'windows.advanced.artifacts.user.ca_cert',
+ first_supported_version: '7.11',
+ documentation: '',
+ },
+ {
+ key: 'windows.advanced.artifacts.user.public_key',
+ first_supported_version: '7.11',
+ documentation: '',
+ },
+ {
+ key: 'windows.advanced.artifacts.user.interval',
+ first_supported_version: '7.11',
+ documentation: '',
+ },
+ {
+ key: 'windows.advanced.elasticsearch.delay',
+ first_supported_version: '7.11',
+ documentation: '',
+ },
+ {
+ key: 'windows.advanced.elasticsearch.tls.verify_peer',
+ first_supported_version: '7.11',
+ documentation: 'default is true',
+ },
+ {
+ key: 'windows.advanced.elasticsearch.tls.verify_hostname',
+ first_supported_version: '7.11',
+ documentation: 'default is true',
+ },
+ {
+ key: 'windows.advanced.elasticsearch.tls.ca_cert',
+ first_supported_version: '7.11',
+ documentation: '',
+ },
+ {
+ key: 'windows.advanced.malware.quarantine',
+ first_supported_version: '7.11',
+ documentation: '',
+ },
+ {
+ key: 'windows.advanced.ransomware.mbr',
+ first_supported_version: '7.11',
+ documentation: '',
+ },
+ {
+ key: 'windows.advanced.ransomware.canary',
+ first_supported_version: '7.11',
+ documentation: '',
+ },
+ {
+ key: 'windows.advanced.kernel.connect',
+ first_supported_version: '7.11',
+ documentation: '',
+ },
+ {
+ key: 'windows.advanced.kernel.harden',
+ first_supported_version: '7.11',
+ documentation: '',
+ },
+ {
+ key: 'windows.advanced.kernel.process',
+ first_supported_version: '7.11',
+ documentation: '',
+ },
+ {
+ key: 'windows.advanced.kernel.filewrite',
+ first_supported_version: '7.11',
+ documentation: '',
+ },
+ {
+ key: 'windows.advanced.kernel.network',
+ first_supported_version: '7.11',
+ documentation: '',
+ },
+ {
+ key: 'windows.advanced.kernel.fileopen',
+ first_supported_version: '7.11',
+ documentation: '',
+ },
+ {
+ key: 'windows.advanced.kernel.asyncimageload',
+ first_supported_version: '7.11',
+ documentation: '',
+ },
+ {
+ key: 'windows.advanced.kernel.syncimageload',
+ first_supported_version: '7.11',
+ documentation: '',
+ },
+ {
+ key: 'windows.advanced.kernel.registry',
+ first_supported_version: '7.11',
+ documentation: '',
+ },
+];
diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/models/policy_details_config.ts b/x-pack/plugins/security_solution/public/management/pages/policy/models/policy_details_config.ts
index 4d32a9fbec694..8d5c19a9e489a 100644
--- a/x-pack/plugins/security_solution/public/management/pages/policy/models/policy_details_config.ts
+++ b/x-pack/plugins/security_solution/public/management/pages/policy/models/policy_details_config.ts
@@ -4,46 +4,9 @@
* you may not use this file except in compliance with the Elastic License.
*/
+import { cloneDeep } from 'lodash';
import { UIPolicyConfig } from '../../../../../common/endpoint/types';
-/**
- * A typed Object.entries() function where the keys and values are typed based on the given object
- */
-const entries = (o: T): Array<[keyof T, T[keyof T]]> =>
- Object.entries(o) as Array<[keyof T, T[keyof T]]>;
-type DeepPartial = { [K in keyof T]?: DeepPartial };
-
-/**
- * Returns a deep copy of `UIPolicyConfig` object
- */
-export function clone(policyDetailsConfig: UIPolicyConfig): UIPolicyConfig {
- const clonedConfig: DeepPartial = {};
- for (const [key, val] of entries(policyDetailsConfig)) {
- if (typeof val === 'object') {
- const valClone: Partial = {};
- clonedConfig[key] = valClone;
- for (const [key2, val2] of entries(val)) {
- if (typeof val2 === 'object') {
- valClone[key2] = {
- ...val2,
- };
- } else {
- clonedConfig[key] = {
- ...val,
- };
- }
- }
- } else {
- clonedConfig[key] = val;
- }
- }
-
- /**
- * clonedConfig is typed as DeepPartial so we can construct the copy from an empty object
- */
- return clonedConfig as UIPolicyConfig;
-}
-
/**
* Returns value from `configuration`
*/
@@ -69,7 +32,7 @@ export const setIn = (a: UIPolicyConfig) => (k
>(
v: V
): UIPolicyConfig => {
- const c = clone(a);
+ const c = cloneDeep(a);
c[key][subKey][leafKey] = v;
return c;
};
diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/index.test.ts b/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/index.test.ts
index b76e0c8acf4c3..89ba05547f447 100644
--- a/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/index.test.ts
+++ b/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/index.test.ts
@@ -8,7 +8,6 @@ import { PolicyDetailsState } from '../../types';
import { applyMiddleware, createStore, Dispatch, Store } from 'redux';
import { policyDetailsReducer, PolicyDetailsAction, policyDetailsMiddlewareFactory } from './index';
import { policyConfig } from './selectors';
-import { clone } from '../../models/policy_details_config';
import { factory as policyConfigFactory } from '../../../../../../common/endpoint/models/policy_config';
import { PolicyData } from '../../../../../../common/endpoint/types';
import {
@@ -20,6 +19,7 @@ import {
createAppRootMockRenderer,
} from '../../../../../common/mock/endpoint';
import { HttpFetchOptions } from 'kibana/public';
+import { cloneDeep } from 'lodash';
describe('policy details: ', () => {
let store: Store;
@@ -93,7 +93,7 @@ describe('policy details: ', () => {
throw new Error();
}
- const newPayload1 = clone(config);
+ const newPayload1 = cloneDeep(config);
newPayload1.windows.events.process = true;
dispatch({
@@ -115,7 +115,7 @@ describe('policy details: ', () => {
throw new Error();
}
- const newPayload1 = clone(config);
+ const newPayload1 = cloneDeep(config);
newPayload1.mac.events.file = true;
dispatch({
@@ -137,7 +137,7 @@ describe('policy details: ', () => {
throw new Error();
}
- const newPayload1 = clone(config);
+ const newPayload1 = cloneDeep(config);
newPayload1.linux.events.file = true;
dispatch({
diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/selectors.ts b/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/selectors.ts
index 953438526b87e..f275124a73527 100644
--- a/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/selectors.ts
+++ b/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/selectors.ts
@@ -103,16 +103,19 @@ export const policyConfig: (s: PolicyDetailsState) => UIPolicyConfig = createSel
(windows, mac, linux) => {
return {
windows: {
+ advanced: windows.advanced,
events: windows.events,
malware: windows.malware,
popup: windows.popup,
},
mac: {
+ advanced: mac.advanced,
events: mac.events,
malware: mac.malware,
popup: mac.popup,
},
linux: {
+ advanced: linux.advanced,
events: linux.events,
},
};
diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/index.ts b/x-pack/plugins/security_solution/public/management/pages/policy/view/index.ts
index 9c227ca81a426..ce942205b1620 100644
--- a/x-pack/plugins/security_solution/public/management/pages/policy/view/index.ts
+++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/index.ts
@@ -6,3 +6,4 @@
export * from './policy_list';
export * from './policy_details';
+export * from './policy_advanced';
diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_advanced.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_advanced.tsx
new file mode 100644
index 0000000000000..b4b82b7f692b9
--- /dev/null
+++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_advanced.tsx
@@ -0,0 +1,124 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import React, { useCallback } from 'react';
+import { useDispatch } from 'react-redux';
+import { EuiFieldText, EuiFormRow, EuiPanel, EuiText } from '@elastic/eui';
+import { cloneDeep } from 'lodash';
+import { FormattedMessage } from '@kbn/i18n/react';
+import { policyConfig } from '../store/policy_details/selectors';
+import { usePolicyDetailsSelector } from './policy_hooks';
+import { AdvancedPolicySchema } from '../models/advanced_policy_schema';
+
+function setValue(obj: Record, value: string, path: string[]) {
+ let newPolicyConfig = obj;
+ for (let i = 0; i < path.length - 1; i++) {
+ if (!newPolicyConfig[path[i]]) {
+ newPolicyConfig[path[i]] = {} as Record;
+ }
+ newPolicyConfig = newPolicyConfig[path[i]] as Record;
+ }
+ newPolicyConfig[path[path.length - 1]] = value;
+}
+
+function getValue(obj: Record, path: string[]) {
+ let currentPolicyConfig = obj;
+
+ for (let i = 0; i < path.length - 1; i++) {
+ if (currentPolicyConfig[path[i]]) {
+ currentPolicyConfig = currentPolicyConfig[path[i]] as Record;
+ } else {
+ return undefined;
+ }
+ }
+ return currentPolicyConfig[path[path.length - 1]];
+}
+
+export const AdvancedPolicyForms = React.memo(() => {
+ return (
+ <>
+
+
+
+
+
+
+ {AdvancedPolicySchema.map((advancedField, index) => {
+ const configPath = advancedField.key.split('.');
+ return (
+
+ );
+ })}
+
+ >
+ );
+});
+
+AdvancedPolicyForms.displayName = 'AdvancedPolicyForms';
+
+const PolicyAdvanced = React.memo(
+ ({
+ configPath,
+ firstSupportedVersion,
+ lastSupportedVersion,
+ }: {
+ configPath: string[];
+ firstSupportedVersion: string;
+ lastSupportedVersion?: string;
+ }) => {
+ const dispatch = useDispatch();
+ const policyDetailsConfig = usePolicyDetailsSelector(policyConfig);
+ const onChange = useCallback(
+ (event) => {
+ if (policyDetailsConfig) {
+ const newPayload = cloneDeep(policyDetailsConfig);
+ setValue(
+ (newPayload as unknown) as Record,
+ event.target.value,
+ configPath
+ );
+ dispatch({
+ type: 'userChangedPolicyConfig',
+ payload: { policyConfig: newPayload },
+ });
+ }
+ },
+ [dispatch, policyDetailsConfig, configPath]
+ );
+
+ const value =
+ policyDetailsConfig &&
+ getValue((policyDetailsConfig as unknown) as Record, configPath);
+
+ return (
+ <>
+
+ {lastSupportedVersion
+ ? `${firstSupportedVersion}-${lastSupportedVersion}`
+ : `${firstSupportedVersion}+`}
+
+ }
+ >
+
+
+ >
+ );
+ }
+);
+
+PolicyAdvanced.displayName = 'PolicyAdvanced';
diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_details.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_details.tsx
index 40c982cfc071b..8fc5de48f36db 100644
--- a/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_details.tsx
+++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_details.tsx
@@ -47,6 +47,7 @@ import { MANAGEMENT_APP_ID } from '../../../common/constants';
import { PolicyDetailsRouteState } from '../../../../../common/endpoint/types';
import { WrapperPage } from '../../../../common/components/wrapper_page';
import { HeaderPage } from '../../../../common/components/header_page';
+import { AdvancedPolicyForms } from './policy_advanced';
export const PolicyDetails = React.memo(() => {
const dispatch = useDispatch<(action: AppAction) => void>();
@@ -69,6 +70,7 @@ export const PolicyDetails = React.memo(() => {
// Local state
const [showConfirm, setShowConfirm] = useState(false);
const [routeState, setRouteState] = useState();
+ const [showAdvancedPolicy, setShowAdvancedPolicy] = useState(false);
const policyName = policyItem?.name ?? '';
const hostListRouterPath = getEndpointListPath({ name: 'endpointList' });
@@ -128,6 +130,10 @@ export const PolicyDetails = React.memo(() => {
setShowConfirm(false);
}, []);
+ const handleAdvancedPolicyClick = useCallback(() => {
+ setShowAdvancedPolicy(!showAdvancedPolicy);
+ }, [showAdvancedPolicy]);
+
useEffect(() => {
if (!routeState && locationRouteState) {
setRouteState(locationRouteState);
@@ -245,6 +251,18 @@ export const PolicyDetails = React.memo(() => {
+
+
+
+
+
+
+
+ {showAdvancedPolicy && }
diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_forms/protections/malware.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_forms/protections/malware.tsx
index 6773ed6541927..215851fb28152 100644
--- a/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_forms/protections/malware.tsx
+++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_forms/protections/malware.tsx
@@ -19,6 +19,7 @@ import {
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
+import { cloneDeep } from 'lodash';
import { APP_ID } from '../../../../../../../common/constants';
import { SecurityPageName } from '../../../../../../app/types';
@@ -27,7 +28,6 @@ import { OS, MalwareProtectionOSes } from '../../../types';
import { ConfigForm } from '../config_form';
import { policyConfig } from '../../../store/policy_details/selectors';
import { usePolicyDetailsSelector } from '../../policy_hooks';
-import { clone } from '../../../models/policy_details_config';
import { LinkToApp } from '../../../../../../common/components/endpoint/link_to_app';
import { popupVersionsMap } from './popup_options_to_versions';
@@ -50,7 +50,7 @@ const ProtectionRadio = React.memo(({ id, label }: { id: ProtectionModes; label:
const handleRadioChange = useCallback(() => {
if (policyDetailsConfig) {
- const newPayload = clone(policyDetailsConfig);
+ const newPayload = cloneDeep(policyDetailsConfig);
for (const os of OSes) {
newPayload[os][protection].mode = id;
if (id === ProtectionModes.prevent) {
@@ -141,7 +141,7 @@ export const MalwareProtections = React.memo(() => {
const handleSwitchChange = useCallback(
(event) => {
if (policyDetailsConfig) {
- const newPayload = clone(policyDetailsConfig);
+ const newPayload = cloneDeep(policyDetailsConfig);
if (event.target.checked === false) {
for (const os of OSes) {
newPayload[os][protection].mode = ProtectionModes.off;
@@ -165,7 +165,7 @@ export const MalwareProtections = React.memo(() => {
const handleUserNotificationCheckbox = useCallback(
(event) => {
if (policyDetailsConfig) {
- const newPayload = clone(policyDetailsConfig);
+ const newPayload = cloneDeep(policyDetailsConfig);
for (const os of OSes) {
newPayload[os].popup[protection].enabled = event.target.checked;
}
From 5752b7a8ddd28d245bd5f2887b1d146fe99936aa Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Thu, 29 Oct 2020 14:21:36 -0400
Subject: [PATCH 43/73] Bump xml-crypto from 1.4.0 to 2.0.0 (#81859)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
---
x-pack/package.json | 2 +-
yarn.lock | 8 ++++----
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/x-pack/package.json b/x-pack/package.json
index ec4388c0b8b7d..ba464a21263d7 100644
--- a/x-pack/package.json
+++ b/x-pack/package.json
@@ -259,7 +259,7 @@
"venn.js": "0.2.20",
"vinyl-fs": "^3.0.3",
"whatwg-fetch": "^3.0.0",
- "xml-crypto": "^1.4.0",
+ "xml-crypto": "^2.0.0",
"yargs": "^15.4.1"
},
"dependencies": {
diff --git a/yarn.lock b/yarn.lock
index b2216537bbd7c..6b77b14f09d42 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -29247,10 +29247,10 @@ xhr@^2.0.1:
parse-headers "^2.0.0"
xtend "^4.0.0"
-xml-crypto@^1.4.0:
- version "1.4.0"
- resolved "https://registry.yarnpkg.com/xml-crypto/-/xml-crypto-1.4.0.tgz#de1cec8cd31cbd689cd90d3d6e8a27d4ae807de7"
- integrity sha512-K8FRdRxICVulK4WhiTUcJrRyAIJFPVOqxfurA3x/JlmXBTxy+SkEENF6GeRt7p/rB6WSOUS9g0gXNQw5n+407g==
+xml-crypto@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/xml-crypto/-/xml-crypto-2.0.0.tgz#54cd268ad9d31930afcf7092cbb664258ca9e826"
+ integrity sha512-/a04qr7RpONRZHOxROZ6iIHItdsQQjN3sj8lJkYDDss8tAkEaAs0VrFjb3tlhmS5snQru5lTs9/5ISSMdPDHlg==
dependencies:
xmldom "0.1.27"
xpath "0.0.27"
From e0b6b0ba5cabe78fb884e629144e4d088bdf92c6 Mon Sep 17 00:00:00 2001
From: Nick Partridge
Date: Thu, 29 Oct 2020 13:34:41 -0500
Subject: [PATCH 44/73] Vislib visualization renderer (#80744)
---
.../public/components/tag_cloud_chart.tsx | 4 +-
.../public/timelion_vis_renderer.tsx | 6 -
.../public/__snapshots__/pie_fn.test.ts.snap | 5 +-
.../public/__snapshots__/to_ast.test.ts.snap | 22 +
.../__snapshots__/to_ast_pie.test.ts.snap | 19 +
src/plugins/vis_type_vislib/public/area.ts | 19 +-
.../public/components/options/gauge/index.tsx | 4 +-
.../components/options/heatmap/index.tsx | 4 +-
.../public/components/options/index.tsx | 51 +
.../options/metrics_axes/index.test.tsx | 2 +-
.../components/options/metrics_axes/index.tsx | 4 +-
.../public/components/options/pie.tsx | 4 +-
.../components/options/point_series/index.ts | 4 +-
src/plugins/vis_type_vislib/public/gauge.ts | 11 +-
src/plugins/vis_type_vislib/public/goal.ts | 11 +-
src/plugins/vis_type_vislib/public/heatmap.ts | 20 +-
.../vis_type_vislib/public/histogram.ts | 19 +-
.../vis_type_vislib/public/horizontal_bar.ts | 19 +-
src/plugins/vis_type_vislib/public/index.scss | 2 +-
src/plugins/vis_type_vislib/public/line.ts | 19 +-
src/plugins/vis_type_vislib/public/pie.ts | 16 +-
src/plugins/vis_type_vislib/public/pie_fn.ts | 37 +-
src/plugins/vis_type_vislib/public/plugin.ts | 73 +-
.../public/sample_vis.test.mocks.ts | 3307 +++++++++++++++++
.../vis_type_vislib/public/services.ts | 5 -
.../vis_type_vislib/public/to_ast.test.ts | 60 +
src/plugins/vis_type_vislib/public/to_ast.ts | 103 +
.../options/index.ts => to_ast_esaggs.ts} | 26 +-
.../vis_type_vislib/public/to_ast_pie.test.ts | 60 +
.../vis_type_vislib/public/to_ast_pie.ts | 50 +
src/plugins/vis_type_vislib/public/types.ts | 6 +
.../vis_type_vislib/public/vis_controller.tsx | 172 +-
.../vis_type_vislib/public/vis_renderer.tsx | 61 +
.../public/vis_type_vislib_vis_fn.ts | 42 +-
.../public/vis_type_vislib_vis_types.ts | 27 +-
.../vis_type_vislib/public/vis_wrapper.tsx | 89 +
.../public/vislib/_vislib_vis_type.scss | 14 +-
.../vislib/components/legend/_legend.scss | 9 +-
.../vislib/components/legend/legend.test.tsx | 36 +-
.../vislib/components/legend/legend.tsx | 49 +-
.../helpers/point_series/_init_x_axis.ts | 4 +-
.../helpers/point_series/point_series.ts | 5 +-
.../public/vislib/lib/_handler.scss | 17 -
.../public/vislib/lib/_index.scss | 1 -
.../public/vislib/lib/dispatch.js | 4 -
.../public/vislib/lib/handler.js | 22 +-
.../public/vislib/lib/handler.test.js | 2 +-
.../public/vislib/lib/vis_config.js | 1 -
.../vis_type_vislib/public/vislib/vis.js | 13 +-
.../public/vislib/visualizations/_chart.js | 4 +-
.../vislib/visualizations/_vis_fixture.js | 17 +-
.../vislib/visualizations/gauge_chart.test.js | 4 +-
.../public/vislib/visualizations/pie_chart.js | 4 +-
.../vislib/visualizations/pie_chart.test.js | 8 +-
.../vislib/visualizations/point_series.js | 14 +-
.../visualizations/point_series/area_chart.js | 4 +-
.../point_series/area_chart.test.js | 4 +-
.../point_series/column_chart.js | 4 +-
.../point_series/column_chart.test.js | 16 +-
.../point_series/heatmap_chart.test.js | 4 +-
.../visualizations/point_series/line_chart.js | 4 +-
.../point_series/line_chart.test.js | 4 +-
.../public/components/_visualization.scss | 4 +-
src/plugins/visualizations/public/index.ts | 1 +
.../__snapshots__/build_pipeline.test.ts.snap | 2 -
.../public/legacy/build_pipeline.test.ts | 164 -
.../public/legacy/build_pipeline.ts | 96 -
src/plugins/visualizations/public/types.ts | 2 +-
.../page_objects/visualize_chart_page.ts | 2 +-
69 files changed, 4235 insertions(+), 687 deletions(-)
create mode 100644 src/plugins/vis_type_vislib/public/__snapshots__/to_ast.test.ts.snap
create mode 100644 src/plugins/vis_type_vislib/public/__snapshots__/to_ast_pie.test.ts.snap
create mode 100644 src/plugins/vis_type_vislib/public/components/options/index.tsx
create mode 100644 src/plugins/vis_type_vislib/public/sample_vis.test.mocks.ts
create mode 100644 src/plugins/vis_type_vislib/public/to_ast.test.ts
create mode 100644 src/plugins/vis_type_vislib/public/to_ast.ts
rename src/plugins/vis_type_vislib/public/{components/options/index.ts => to_ast_esaggs.ts} (51%)
create mode 100644 src/plugins/vis_type_vislib/public/to_ast_pie.test.ts
create mode 100644 src/plugins/vis_type_vislib/public/to_ast_pie.ts
create mode 100644 src/plugins/vis_type_vislib/public/vis_renderer.tsx
create mode 100644 src/plugins/vis_type_vislib/public/vis_wrapper.tsx
delete mode 100644 src/plugins/vis_type_vislib/public/vislib/lib/_handler.scss
diff --git a/src/plugins/vis_type_tagcloud/public/components/tag_cloud_chart.tsx b/src/plugins/vis_type_tagcloud/public/components/tag_cloud_chart.tsx
index cb0daa6d29382..a14328ac994f0 100644
--- a/src/plugins/vis_type_tagcloud/public/components/tag_cloud_chart.tsx
+++ b/src/plugins/vis_type_tagcloud/public/components/tag_cloud_chart.tsx
@@ -45,7 +45,9 @@ export const TagCloudChart = ({
const visController = useRef(null);
useEffect(() => {
- visController.current = new TagCloudVisualization(chartDiv.current, colors, fireEvent);
+ if (chartDiv.current) {
+ visController.current = new TagCloudVisualization(chartDiv.current, colors, fireEvent);
+ }
return () => {
visController.current.destroy();
visController.current = null;
diff --git a/src/plugins/vis_type_timelion/public/timelion_vis_renderer.tsx b/src/plugins/vis_type_timelion/public/timelion_vis_renderer.tsx
index 04579407105e8..2c914d3c5b662 100644
--- a/src/plugins/vis_type_timelion/public/timelion_vis_renderer.tsx
+++ b/src/plugins/vis_type_timelion/public/timelion_vis_renderer.tsx
@@ -42,12 +42,6 @@ export const getTimelionVisRenderer: (
const [seriesList] = visData.sheet;
const showNoResult = !seriesList || !seriesList.list.length;
- if (showNoResult) {
- // send the render complete event when there is no data to show
- // to notify that a chart is updated
- handlers.done();
- }
-
render(
diff --git a/src/plugins/vis_type_vislib/public/__snapshots__/pie_fn.test.ts.snap b/src/plugins/vis_type_vislib/public/__snapshots__/pie_fn.test.ts.snap
index 2cee55e4751c2..b64366c1ce0f3 100644
--- a/src/plugins/vis_type_vislib/public/__snapshots__/pie_fn.test.ts.snap
+++ b/src/plugins/vis_type_vislib/public/__snapshots__/pie_fn.test.ts.snap
@@ -2,12 +2,9 @@
exports[`interpreter/functions#pie returns an object with the correct structure 1`] = `
Object {
- "as": "visualization",
+ "as": "vislib_vis",
"type": "render",
"value": Object {
- "params": Object {
- "listenOnChange": true,
- },
"visConfig": Object {
"addLegend": true,
"addTooltip": true,
diff --git a/src/plugins/vis_type_vislib/public/__snapshots__/to_ast.test.ts.snap b/src/plugins/vis_type_vislib/public/__snapshots__/to_ast.test.ts.snap
new file mode 100644
index 0000000000000..c3ffc0dd08412
--- /dev/null
+++ b/src/plugins/vis_type_vislib/public/__snapshots__/to_ast.test.ts.snap
@@ -0,0 +1,22 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`vislib vis toExpressionAst function should match basic snapshot 1`] = `
+Object {
+ "addArgument": [Function],
+ "arguments": Object {
+ "type": Array [
+ "area",
+ ],
+ "visConfig": Array [
+ "{\\"type\\":\\"area\\",\\"grid\\":{\\"categoryLines\\":false,\\"style\\":{\\"color\\":\\"#eee\\"}},\\"categoryAxes\\":[{\\"id\\":\\"CategoryAxis-1\\",\\"type\\":\\"category\\",\\"position\\":\\"bottom\\",\\"show\\":true,\\"style\\":{},\\"scale\\":{\\"type\\":\\"linear\\"},\\"labels\\":{\\"show\\":true,\\"truncate\\":100},\\"title\\":{}}],\\"valueAxes\\":[{\\"id\\":\\"ValueAxis-1\\",\\"name\\":\\"LeftAxis-1\\",\\"type\\":\\"value\\",\\"position\\":\\"left\\",\\"show\\":true,\\"style\\":{},\\"scale\\":{\\"type\\":\\"linear\\",\\"mode\\":\\"normal\\"},\\"labels\\":{\\"show\\":true,\\"rotate\\":0,\\"filter\\":false,\\"truncate\\":100},\\"title\\":{\\"text\\":\\"Sum of total_quantity\\"}}],\\"seriesParams\\":[{\\"show\\":\\"true\\",\\"type\\":\\"area\\",\\"mode\\":\\"stacked\\",\\"data\\":{\\"label\\":\\"Sum of total_quantity\\",\\"id\\":\\"1\\"},\\"drawLinesBetweenPoints\\":true,\\"showCircles\\":true,\\"interpolate\\":\\"linear\\",\\"valueAxis\\":\\"ValueAxis-1\\"}],\\"addTooltip\\":true,\\"addLegend\\":true,\\"legendPosition\\":\\"top\\",\\"times\\":[],\\"addTimeMarker\\":false,\\"thresholdLine\\":{\\"show\\":false,\\"value\\":10,\\"width\\":1,\\"style\\":\\"full\\",\\"color\\":\\"#E7664C\\"},\\"labels\\":{},\\"dimensions\\":{\\"x\\":{\\"accessor\\":1,\\"format\\":{\\"id\\":\\"date\\",\\"params\\":{\\"pattern\\":\\"HH:mm:ss.SSS\\"}},\\"params\\":{}},\\"y\\":[{\\"accessor\\":0,\\"format\\":{\\"id\\":\\"number\\",\\"params\\":{\\"parsedUrl\\":{\\"origin\\":\\"http://localhost:5801\\",\\"pathname\\":\\"/app/visualize\\",\\"basePath\\":\\"\\"}}},\\"params\\":{}}],\\"series\\":[{\\"accessor\\":2,\\"format\\":{\\"id\\":\\"terms\\",\\"params\\":{\\"id\\":\\"string\\",\\"otherBucketLabel\\":\\"Other\\",\\"missingBucketLabel\\":\\"Missing\\",\\"parsedUrl\\":{\\"origin\\":\\"http://localhost:5801\\",\\"pathname\\":\\"/app/visualize\\",\\"basePath\\":\\"\\"}}},\\"params\\":{}}]}}",
+ ],
+ },
+ "getArgument": [Function],
+ "name": "vislib_vis",
+ "removeArgument": [Function],
+ "replaceArgument": [Function],
+ "toAst": [Function],
+ "toString": [Function],
+ "type": "expression_function_builder",
+}
+`;
diff --git a/src/plugins/vis_type_vislib/public/__snapshots__/to_ast_pie.test.ts.snap b/src/plugins/vis_type_vislib/public/__snapshots__/to_ast_pie.test.ts.snap
new file mode 100644
index 0000000000000..b8dc4b31747c4
--- /dev/null
+++ b/src/plugins/vis_type_vislib/public/__snapshots__/to_ast_pie.test.ts.snap
@@ -0,0 +1,19 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`vislib pie vis toExpressionAst function should match basic snapshot 1`] = `
+Object {
+ "addArgument": [Function],
+ "arguments": Object {
+ "visConfig": Array [
+ "{\\"type\\":\\"pie\\",\\"addTooltip\\":true,\\"addLegend\\":true,\\"legendPosition\\":\\"right\\",\\"isDonut\\":true,\\"labels\\":{\\"show\\":true,\\"values\\":true,\\"last_level\\":true,\\"truncate\\":100},\\"dimensions\\":{\\"metric\\":{\\"accessor\\":0,\\"format\\":{\\"id\\":\\"number\\"},\\"params\\":{}},\\"buckets\\":[{\\"accessor\\":1,\\"format\\":{\\"id\\":\\"terms\\",\\"params\\":{\\"id\\":\\"string\\",\\"otherBucketLabel\\":\\"Other\\",\\"missingBucketLabel\\":\\"Missing\\",\\"parsedUrl\\":{\\"origin\\":\\"http://localhost:5801\\",\\"pathname\\":\\"/app/visualize\\",\\"basePath\\":\\"\\"}}},\\"params\\":{}}]}}",
+ ],
+ },
+ "getArgument": [Function],
+ "name": "vislib_pie_vis",
+ "removeArgument": [Function],
+ "replaceArgument": [Function],
+ "toAst": [Function],
+ "toString": [Function],
+ "type": "expression_function_builder",
+}
+`;
diff --git a/src/plugins/vis_type_vislib/public/area.ts b/src/plugins/vis_type_vislib/public/area.ts
index ec90fbd1746a1..531958d6b3db3 100644
--- a/src/plugins/vis_type_vislib/public/area.ts
+++ b/src/plugins/vis_type_vislib/public/area.ts
@@ -37,22 +37,20 @@ import {
getConfigCollections,
} from './utils/collections';
import { getAreaOptionTabs, countLabel } from './utils/common_config';
-import { createVislibVisController } from './vis_controller';
-import { VisTypeVislibDependencies } from './plugin';
import { Rotates } from '../../charts/public';
-import { VIS_EVENT_TO_TRIGGER } from '../../../plugins/visualizations/public';
+import { BaseVisTypeOptions, VIS_EVENT_TO_TRIGGER } from '../../../plugins/visualizations/public';
+import { toExpressionAst } from './to_ast';
+import { BasicVislibParams } from './types';
-export const createAreaVisTypeDefinition = (deps: VisTypeVislibDependencies) => ({
+export const areaVisTypeDefinition: BaseVisTypeOptions = {
name: 'area',
title: i18n.translate('visTypeVislib.area.areaTitle', { defaultMessage: 'Area' }),
icon: 'visArea',
description: i18n.translate('visTypeVislib.area.areaDescription', {
defaultMessage: 'Emphasize the quantity beneath a line chart',
}),
- visualization: createVislibVisController(deps),
- getSupportedTriggers: () => {
- return [VIS_EVENT_TO_TRIGGER.filter, VIS_EVENT_TO_TRIGGER.brush];
- },
+ getSupportedTriggers: () => [VIS_EVENT_TO_TRIGGER.filter, VIS_EVENT_TO_TRIGGER.brush],
+ toExpressionAst,
visConfig: {
defaults: {
type: 'area',
@@ -131,9 +129,6 @@ export const createAreaVisTypeDefinition = (deps: VisTypeVislibDependencies) =>
labels: {},
},
},
- events: {
- brush: { disabled: false },
- },
editorConfig: {
collections: getConfigCollections(),
optionTabs: getAreaOptionTabs(),
@@ -190,4 +185,4 @@ export const createAreaVisTypeDefinition = (deps: VisTypeVislibDependencies) =>
},
]),
},
-});
+};
diff --git a/src/plugins/vis_type_vislib/public/components/options/gauge/index.tsx b/src/plugins/vis_type_vislib/public/components/options/gauge/index.tsx
index 6109b548f9412..911ee293f580e 100644
--- a/src/plugins/vis_type_vislib/public/components/options/gauge/index.tsx
+++ b/src/plugins/vis_type_vislib/public/components/options/gauge/index.tsx
@@ -60,4 +60,6 @@ function GaugeOptions(props: VisOptionsProps) {
);
}
-export { GaugeOptions };
+// default export required for React.Lazy
+// eslint-disable-next-line import/no-default-export
+export { GaugeOptions as default };
diff --git a/src/plugins/vis_type_vislib/public/components/options/heatmap/index.tsx b/src/plugins/vis_type_vislib/public/components/options/heatmap/index.tsx
index 7a89496d9441e..312cf60fda6b0 100644
--- a/src/plugins/vis_type_vislib/public/components/options/heatmap/index.tsx
+++ b/src/plugins/vis_type_vislib/public/components/options/heatmap/index.tsx
@@ -185,4 +185,6 @@ function HeatmapOptions(props: VisOptionsProps) {
);
}
-export { HeatmapOptions };
+// default export required for React.Lazy
+// eslint-disable-next-line import/no-default-export
+export { HeatmapOptions as default };
diff --git a/src/plugins/vis_type_vislib/public/components/options/index.tsx b/src/plugins/vis_type_vislib/public/components/options/index.tsx
new file mode 100644
index 0000000000000..18c41bf289b11
--- /dev/null
+++ b/src/plugins/vis_type_vislib/public/components/options/index.tsx
@@ -0,0 +1,51 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import React, { lazy } from 'react';
+
+import { VisOptionsProps } from 'src/plugins/vis_default_editor/public';
+import { ValidationVisOptionsProps } from '../common';
+import { GaugeVisParams } from '../../gauge';
+import { PieVisParams } from '../../pie';
+import { BasicVislibParams } from '../../types';
+import { HeatmapVisParams } from '../../heatmap';
+
+const GaugeOptionsLazy = lazy(() => import('./gauge'));
+const PieOptionsLazy = lazy(() => import('./pie'));
+const PointSeriesOptionsLazy = lazy(() => import('./point_series'));
+const HeatmapOptionsLazy = lazy(() => import('./heatmap'));
+const MetricsAxisOptionsLazy = lazy(() => import('./metrics_axes'));
+
+export const GaugeOptions = (props: VisOptionsProps) => (
+
+);
+
+export const PieOptions = (props: VisOptionsProps) => ;
+
+export const PointSeriesOptions = (props: ValidationVisOptionsProps) => (
+
+);
+
+export const HeatmapOptions = (props: VisOptionsProps) => (
+
+);
+
+export const MetricsAxisOptions = (props: ValidationVisOptionsProps) => (
+
+);
diff --git a/src/plugins/vis_type_vislib/public/components/options/metrics_axes/index.test.tsx b/src/plugins/vis_type_vislib/public/components/options/metrics_axes/index.test.tsx
index 0cc737f19e5c6..63881fea1ad88 100644
--- a/src/plugins/vis_type_vislib/public/components/options/metrics_axes/index.test.tsx
+++ b/src/plugins/vis_type_vislib/public/components/options/metrics_axes/index.test.tsx
@@ -21,7 +21,7 @@ import React from 'react';
import { mount, shallow } from 'enzyme';
import { IAggConfig, IAggType } from 'src/plugins/data/public';
-import { MetricsAxisOptions } from './index';
+import MetricsAxisOptions from './index';
import { BasicVislibParams, SeriesParam, ValueAxis } from '../../../types';
import { ValidationVisOptionsProps } from '../../common';
import { Positions } from '../../../utils/collections';
diff --git a/src/plugins/vis_type_vislib/public/components/options/metrics_axes/index.tsx b/src/plugins/vis_type_vislib/public/components/options/metrics_axes/index.tsx
index 18687404b9114..0862c47c35cff 100644
--- a/src/plugins/vis_type_vislib/public/components/options/metrics_axes/index.tsx
+++ b/src/plugins/vis_type_vislib/public/components/options/metrics_axes/index.tsx
@@ -325,4 +325,6 @@ function MetricsAxisOptions(props: ValidationVisOptionsProps)
) : null;
}
-export { MetricsAxisOptions };
+// default export required for React.Lazy
+// eslint-disable-next-line import/no-default-export
+export { MetricsAxisOptions as default };
diff --git a/src/plugins/vis_type_vislib/public/components/options/pie.tsx b/src/plugins/vis_type_vislib/public/components/options/pie.tsx
index 54ba307982967..30828bfc6a3ea 100644
--- a/src/plugins/vis_type_vislib/public/components/options/pie.tsx
+++ b/src/plugins/vis_type_vislib/public/components/options/pie.tsx
@@ -99,4 +99,6 @@ function PieOptions(props: VisOptionsProps) {
);
}
-export { PieOptions };
+// default export required for React.Lazy
+// eslint-disable-next-line import/no-default-export
+export { PieOptions as default };
diff --git a/src/plugins/vis_type_vislib/public/components/options/point_series/index.ts b/src/plugins/vis_type_vislib/public/components/options/point_series/index.ts
index fb94ec6743faa..937b92c950430 100644
--- a/src/plugins/vis_type_vislib/public/components/options/point_series/index.ts
+++ b/src/plugins/vis_type_vislib/public/components/options/point_series/index.ts
@@ -17,4 +17,6 @@
* under the License.
*/
-export { PointSeriesOptions } from './point_series';
+// default export required for React.Lazy
+// eslint-disable-next-line import/no-default-export
+export { PointSeriesOptions as default } from './point_series';
diff --git a/src/plugins/vis_type_vislib/public/gauge.ts b/src/plugins/vis_type_vislib/public/gauge.ts
index 561c45d26fa7f..86e3b8793d618 100644
--- a/src/plugins/vis_type_vislib/public/gauge.ts
+++ b/src/plugins/vis_type_vislib/public/gauge.ts
@@ -24,8 +24,9 @@ import { AggGroupNames } from '../../data/public';
import { GaugeOptions } from './components/options';
import { getGaugeCollections, Alignments, GaugeTypes } from './utils/collections';
import { ColorModes, ColorSchemas, ColorSchemaParams, Labels, Style } from '../../charts/public';
-import { createVislibVisController } from './vis_controller';
-import { VisTypeVislibDependencies } from './plugin';
+import { toExpressionAst } from './to_ast';
+import { BaseVisTypeOptions } from '../../visualizations/public';
+import { BasicVislibParams } from './types';
export interface Gauge extends ColorSchemaParams {
backStyle: 'Full';
@@ -55,7 +56,7 @@ export interface GaugeVisParams {
gauge: Gauge;
}
-export const createGaugeVisTypeDefinition = (deps: VisTypeVislibDependencies) => ({
+export const gaugeVisTypeDefinition: BaseVisTypeOptions = {
name: 'gauge',
title: i18n.translate('visTypeVislib.gauge.gaugeTitle', { defaultMessage: 'Gauge' }),
icon: 'visGauge',
@@ -63,6 +64,7 @@ export const createGaugeVisTypeDefinition = (deps: VisTypeVislibDependencies) =>
defaultMessage:
"Gauges indicate the status of a metric. Use it to show how a metric's value relates to reference threshold values.",
}),
+ toExpressionAst,
visConfig: {
defaults: {
type: 'gauge',
@@ -109,7 +111,6 @@ export const createGaugeVisTypeDefinition = (deps: VisTypeVislibDependencies) =>
},
},
},
- visualization: createVislibVisController(deps),
editorConfig: {
collections: getGaugeCollections(),
optionsTemplate: GaugeOptions,
@@ -145,4 +146,4 @@ export const createGaugeVisTypeDefinition = (deps: VisTypeVislibDependencies) =>
]),
},
useCustomNoDataScreen: true,
-});
+};
diff --git a/src/plugins/vis_type_vislib/public/goal.ts b/src/plugins/vis_type_vislib/public/goal.ts
index 5f74698938a0b..32574fb5b0a9c 100644
--- a/src/plugins/vis_type_vislib/public/goal.ts
+++ b/src/plugins/vis_type_vislib/public/goal.ts
@@ -21,20 +21,21 @@ import { i18n } from '@kbn/i18n';
import { GaugeOptions } from './components/options';
import { getGaugeCollections, GaugeTypes } from './utils/collections';
-import { createVislibVisController } from './vis_controller';
-import { VisTypeVislibDependencies } from './plugin';
import { ColorModes, ColorSchemas } from '../../charts/public';
import { AggGroupNames } from '../../data/public';
import { Schemas } from '../../vis_default_editor/public';
+import { toExpressionAst } from './to_ast';
+import { BaseVisTypeOptions } from '../../visualizations/public';
+import { BasicVislibParams } from './types';
-export const createGoalVisTypeDefinition = (deps: VisTypeVislibDependencies) => ({
+export const goalVisTypeDefinition: BaseVisTypeOptions = {
name: 'goal',
title: i18n.translate('visTypeVislib.goal.goalTitle', { defaultMessage: 'Goal' }),
icon: 'visGoal',
description: i18n.translate('visTypeVislib.goal.goalDescription', {
defaultMessage: 'A goal chart indicates how close you are to your final goal.',
}),
- visualization: createVislibVisController(deps),
+ toExpressionAst,
visConfig: {
defaults: {
addTooltip: true,
@@ -110,4 +111,4 @@ export const createGoalVisTypeDefinition = (deps: VisTypeVislibDependencies) =>
]),
},
useCustomNoDataScreen: true,
-});
+};
diff --git a/src/plugins/vis_type_vislib/public/heatmap.ts b/src/plugins/vis_type_vislib/public/heatmap.ts
index bd3d02029cb23..f970eddd645f5 100644
--- a/src/plugins/vis_type_vislib/public/heatmap.ts
+++ b/src/plugins/vis_type_vislib/public/heatmap.ts
@@ -23,12 +23,11 @@ import { RangeValues, Schemas } from '../../vis_default_editor/public';
import { AggGroupNames } from '../../data/public';
import { AxisTypes, getHeatmapCollections, Positions, ScaleTypes } from './utils/collections';
import { HeatmapOptions } from './components/options';
-import { createVislibVisController } from './vis_controller';
import { TimeMarker } from './vislib/visualizations/time_marker';
-import { CommonVislibParams, ValueAxis } from './types';
-import { VisTypeVislibDependencies } from './plugin';
+import { BasicVislibParams, CommonVislibParams, ValueAxis } from './types';
import { ColorSchemas, ColorSchemaParams } from '../../charts/public';
-import { VIS_EVENT_TO_TRIGGER } from '../../../plugins/visualizations/public';
+import { BaseVisTypeOptions, VIS_EVENT_TO_TRIGGER } from '../../../plugins/visualizations/public';
+import { toExpressionAst } from './to_ast';
export interface HeatmapVisParams extends CommonVislibParams, ColorSchemaParams {
type: 'heatmap';
@@ -42,17 +41,15 @@ export interface HeatmapVisParams extends CommonVislibParams, ColorSchemaParams
times: TimeMarker[];
}
-export const createHeatmapVisTypeDefinition = (deps: VisTypeVislibDependencies) => ({
+export const heatmapVisTypeDefinition: BaseVisTypeOptions = {
name: 'heatmap',
title: i18n.translate('visTypeVislib.heatmap.heatmapTitle', { defaultMessage: 'Heat Map' }),
icon: 'heatmap',
description: i18n.translate('visTypeVislib.heatmap.heatmapDescription', {
defaultMessage: 'Shade cells within a matrix',
}),
- getSupportedTriggers: () => {
- return [VIS_EVENT_TO_TRIGGER.filter];
- },
- visualization: createVislibVisController(deps),
+ getSupportedTriggers: () => [VIS_EVENT_TO_TRIGGER.filter],
+ toExpressionAst,
visConfig: {
defaults: {
type: 'heatmap',
@@ -86,9 +83,6 @@ export const createHeatmapVisTypeDefinition = (deps: VisTypeVislibDependencies)
],
},
},
- events: {
- brush: { disabled: false },
- },
editorConfig: {
collections: getHeatmapCollections(),
optionsTemplate: HeatmapOptions,
@@ -142,4 +136,4 @@ export const createHeatmapVisTypeDefinition = (deps: VisTypeVislibDependencies)
},
]),
},
-});
+};
diff --git a/src/plugins/vis_type_vislib/public/histogram.ts b/src/plugins/vis_type_vislib/public/histogram.ts
index 8aeeb4ec533ab..d5fb92f5c6a0c 100644
--- a/src/plugins/vis_type_vislib/public/histogram.ts
+++ b/src/plugins/vis_type_vislib/public/histogram.ts
@@ -36,12 +36,12 @@ import {
getConfigCollections,
} from './utils/collections';
import { getAreaOptionTabs, countLabel } from './utils/common_config';
-import { createVislibVisController } from './vis_controller';
-import { VisTypeVislibDependencies } from './plugin';
import { Rotates } from '../../charts/public';
-import { VIS_EVENT_TO_TRIGGER } from '../../../plugins/visualizations/public';
+import { BaseVisTypeOptions, VIS_EVENT_TO_TRIGGER } from '../../../plugins/visualizations/public';
+import { BasicVislibParams } from './types';
+import { toExpressionAst } from './to_ast';
-export const createHistogramVisTypeDefinition = (deps: VisTypeVislibDependencies) => ({
+export const histogramVisTypeDefinition: BaseVisTypeOptions = {
name: 'histogram',
title: i18n.translate('visTypeVislib.histogram.histogramTitle', {
defaultMessage: 'Vertical Bar',
@@ -50,10 +50,8 @@ export const createHistogramVisTypeDefinition = (deps: VisTypeVislibDependencies
description: i18n.translate('visTypeVislib.histogram.histogramDescription', {
defaultMessage: 'Assign a continuous variable to each axis',
}),
- visualization: createVislibVisController(deps),
- getSupportedTriggers: () => {
- return [VIS_EVENT_TO_TRIGGER.filter, VIS_EVENT_TO_TRIGGER.brush];
- },
+ getSupportedTriggers: () => [VIS_EVENT_TO_TRIGGER.filter, VIS_EVENT_TO_TRIGGER.brush],
+ toExpressionAst,
visConfig: {
defaults: {
type: 'histogram',
@@ -133,9 +131,6 @@ export const createHistogramVisTypeDefinition = (deps: VisTypeVislibDependencies
},
},
},
- events: {
- brush: { disabled: false },
- },
editorConfig: {
collections: getConfigCollections(),
optionTabs: getAreaOptionTabs(),
@@ -192,4 +187,4 @@ export const createHistogramVisTypeDefinition = (deps: VisTypeVislibDependencies
},
]),
},
-});
+};
diff --git a/src/plugins/vis_type_vislib/public/horizontal_bar.ts b/src/plugins/vis_type_vislib/public/horizontal_bar.ts
index 702581828e60d..f1a5365e5ae74 100644
--- a/src/plugins/vis_type_vislib/public/horizontal_bar.ts
+++ b/src/plugins/vis_type_vislib/public/horizontal_bar.ts
@@ -34,12 +34,12 @@ import {
getConfigCollections,
} from './utils/collections';
import { getAreaOptionTabs, countLabel } from './utils/common_config';
-import { createVislibVisController } from './vis_controller';
-import { VisTypeVislibDependencies } from './plugin';
import { Rotates } from '../../charts/public';
-import { VIS_EVENT_TO_TRIGGER } from '../../../plugins/visualizations/public';
+import { BaseVisTypeOptions, VIS_EVENT_TO_TRIGGER } from '../../../plugins/visualizations/public';
+import { BasicVislibParams } from './types';
+import { toExpressionAst } from './to_ast';
-export const createHorizontalBarVisTypeDefinition = (deps: VisTypeVislibDependencies) => ({
+export const horizontalBarVisTypeDefinition: BaseVisTypeOptions = {
name: 'horizontal_bar',
title: i18n.translate('visTypeVislib.horizontalBar.horizontalBarTitle', {
defaultMessage: 'Horizontal Bar',
@@ -48,10 +48,8 @@ export const createHorizontalBarVisTypeDefinition = (deps: VisTypeVislibDependen
description: i18n.translate('visTypeVislib.horizontalBar.horizontalBarDescription', {
defaultMessage: 'Assign a continuous variable to each axis',
}),
- visualization: createVislibVisController(deps),
- getSupportedTriggers: () => {
- return [VIS_EVENT_TO_TRIGGER.filter, VIS_EVENT_TO_TRIGGER.brush];
- },
+ getSupportedTriggers: () => [VIS_EVENT_TO_TRIGGER.filter, VIS_EVENT_TO_TRIGGER.brush],
+ toExpressionAst,
visConfig: {
defaults: {
type: 'histogram',
@@ -130,9 +128,6 @@ export const createHorizontalBarVisTypeDefinition = (deps: VisTypeVislibDependen
},
},
},
- events: {
- brush: { disabled: false },
- },
editorConfig: {
collections: getConfigCollections(),
optionTabs: getAreaOptionTabs(),
@@ -189,4 +184,4 @@ export const createHorizontalBarVisTypeDefinition = (deps: VisTypeVislibDependen
},
]),
},
-});
+};
diff --git a/src/plugins/vis_type_vislib/public/index.scss b/src/plugins/vis_type_vislib/public/index.scss
index 64445648ba84a..3c347aebde225 100644
--- a/src/plugins/vis_type_vislib/public/index.scss
+++ b/src/plugins/vis_type_vislib/public/index.scss
@@ -1 +1 @@
-@import './vislib/index'
+@import './vislib/index';
diff --git a/src/plugins/vis_type_vislib/public/line.ts b/src/plugins/vis_type_vislib/public/line.ts
index 6e9190229114b..a65b0bcf7e2bb 100644
--- a/src/plugins/vis_type_vislib/public/line.ts
+++ b/src/plugins/vis_type_vislib/public/line.ts
@@ -35,22 +35,20 @@ import {
getConfigCollections,
} from './utils/collections';
import { getAreaOptionTabs, countLabel } from './utils/common_config';
-import { createVislibVisController } from './vis_controller';
-import { VisTypeVislibDependencies } from './plugin';
import { Rotates } from '../../charts/public';
-import { VIS_EVENT_TO_TRIGGER } from '../../../plugins/visualizations/public';
+import { BaseVisTypeOptions, VIS_EVENT_TO_TRIGGER } from '../../../plugins/visualizations/public';
+import { toExpressionAst } from './to_ast';
+import { BasicVislibParams } from './types';
-export const createLineVisTypeDefinition = (deps: VisTypeVislibDependencies) => ({
+export const lineVisTypeDefinition: BaseVisTypeOptions = {
name: 'line',
title: i18n.translate('visTypeVislib.line.lineTitle', { defaultMessage: 'Line' }),
icon: 'visLine',
description: i18n.translate('visTypeVislib.line.lineDescription', {
defaultMessage: 'Emphasize trends',
}),
- visualization: createVislibVisController(deps),
- getSupportedTriggers: () => {
- return [VIS_EVENT_TO_TRIGGER.filter, VIS_EVENT_TO_TRIGGER.brush];
- },
+ getSupportedTriggers: () => [VIS_EVENT_TO_TRIGGER.filter, VIS_EVENT_TO_TRIGGER.brush],
+ toExpressionAst,
visConfig: {
defaults: {
type: 'line',
@@ -129,9 +127,6 @@ export const createLineVisTypeDefinition = (deps: VisTypeVislibDependencies) =>
},
},
},
- events: {
- brush: { disabled: false },
- },
editorConfig: {
collections: getConfigCollections(),
optionTabs: getAreaOptionTabs(),
@@ -182,4 +177,4 @@ export const createLineVisTypeDefinition = (deps: VisTypeVislibDependencies) =>
},
]),
},
-});
+};
diff --git a/src/plugins/vis_type_vislib/public/pie.ts b/src/plugins/vis_type_vislib/public/pie.ts
index 1e81dbdde3f68..58f7dd0df89e8 100644
--- a/src/plugins/vis_type_vislib/public/pie.ts
+++ b/src/plugins/vis_type_vislib/public/pie.ts
@@ -23,14 +23,12 @@ import { AggGroupNames } from '../../data/public';
import { Schemas } from '../../vis_default_editor/public';
import { PieOptions } from './components/options';
import { getPositions, Positions } from './utils/collections';
-import { createVislibVisController } from './vis_controller';
import { CommonVislibParams } from './types';
-import { VisTypeVislibDependencies } from './plugin';
-import { VIS_EVENT_TO_TRIGGER } from '../../../plugins/visualizations/public';
+import { BaseVisTypeOptions, VIS_EVENT_TO_TRIGGER } from '../../../plugins/visualizations/public';
+import { toExpressionAst } from './to_ast_pie';
export interface PieVisParams extends CommonVislibParams {
type: 'pie';
- addLegend: boolean;
isDonut: boolean;
labels: {
show: boolean;
@@ -40,17 +38,15 @@ export interface PieVisParams extends CommonVislibParams {
};
}
-export const createPieVisTypeDefinition = (deps: VisTypeVislibDependencies) => ({
+export const pieVisTypeDefinition: BaseVisTypeOptions = {
name: 'pie',
title: i18n.translate('visTypeVislib.pie.pieTitle', { defaultMessage: 'Pie' }),
icon: 'visPie',
description: i18n.translate('visTypeVislib.pie.pieDescription', {
defaultMessage: 'Compare parts of a whole',
}),
- visualization: createVislibVisController(deps),
- getSupportedTriggers: () => {
- return [VIS_EVENT_TO_TRIGGER.filter];
- },
+ getSupportedTriggers: () => [VIS_EVENT_TO_TRIGGER.filter],
+ toExpressionAst,
visConfig: {
defaults: {
type: 'pie',
@@ -108,4 +104,4 @@ export const createPieVisTypeDefinition = (deps: VisTypeVislibDependencies) => (
},
hierarchicalData: true,
responseHandler: 'vislib_slices',
-});
+};
diff --git a/src/plugins/vis_type_vislib/public/pie_fn.ts b/src/plugins/vis_type_vislib/public/pie_fn.ts
index bee200cbe30ee..c9da9e9bd9fab 100644
--- a/src/plugins/vis_type_vislib/public/pie_fn.ts
+++ b/src/plugins/vis_type_vislib/public/pie_fn.ts
@@ -18,27 +18,35 @@
*/
import { i18n } from '@kbn/i18n';
+
import { ExpressionFunctionDefinition, Datatable, Render } from '../../expressions/public';
+
// @ts-ignore
import { vislibSlicesResponseHandler } from './vislib/response_handler';
+import { PieVisParams } from './pie';
+import { vislibVisName } from './vis_type_vislib_vis_fn';
+
+export const vislibPieName = 'vislib_pie_vis';
interface Arguments {
visConfig: string;
}
-type VisParams = Required;
-
interface RenderValue {
- visConfig: VisParams;
+ visData: unknown;
+ visType: string;
+ visConfig: PieVisParams;
}
-export const createPieVisFn = (): ExpressionFunctionDefinition<
- 'kibana_pie',
+export type VisTypeVislibPieExpressionFunctionDefinition = ExpressionFunctionDefinition<
+ typeof vislibPieName,
Datatable,
Arguments,
Render
-> => ({
- name: 'kibana_pie',
+>;
+
+export const createPieVisFn = (): VisTypeVislibPieExpressionFunctionDefinition => ({
+ name: vislibPieName,
type: 'render',
inputTypes: ['datatable'],
help: i18n.translate('visTypeVislib.functions.pie.help', {
@@ -48,23 +56,20 @@ export const createPieVisFn = (): ExpressionFunctionDefinition<
visConfig: {
types: ['string'],
default: '"{}"',
- help: '',
+ help: 'vislib pie vis config',
},
},
fn(input, args) {
- const visConfig = JSON.parse(args.visConfig);
- const convertedData = vislibSlicesResponseHandler(input, visConfig.dimensions);
+ const visConfig = JSON.parse(args.visConfig) as PieVisParams;
+ const visData = vislibSlicesResponseHandler(input, visConfig.dimensions);
return {
type: 'render',
- as: 'visualization',
+ as: vislibVisName,
value: {
- visData: convertedData,
- visType: 'pie',
+ visData,
visConfig,
- params: {
- listenOnChange: true,
- },
+ visType: 'pie',
},
};
},
diff --git a/src/plugins/vis_type_vislib/public/plugin.ts b/src/plugins/vis_type_vislib/public/plugin.ts
index c6a6b6f82592b..f183042fd5201 100644
--- a/src/plugins/vis_type_vislib/public/plugin.ts
+++ b/src/plugins/vis_type_vislib/public/plugin.ts
@@ -17,40 +17,20 @@
* under the License.
*/
-import './index.scss';
-
-import {
- CoreSetup,
- CoreStart,
- Plugin,
- IUiSettingsClient,
- PluginInitializerContext,
-} from 'kibana/public';
+import { CoreSetup, CoreStart, Plugin, PluginInitializerContext } from 'kibana/public';
import { VisTypeXyPluginSetup } from 'src/plugins/vis_type_xy/public';
import { Plugin as ExpressionsPublicPlugin } from '../../expressions/public';
-import { VisualizationsSetup } from '../../visualizations/public';
+import { BaseVisTypeOptions, VisualizationsSetup } from '../../visualizations/public';
import { createVisTypeVislibVisFn } from './vis_type_vislib_vis_fn';
import { createPieVisFn } from './pie_fn';
-import {
- createHistogramVisTypeDefinition,
- createLineVisTypeDefinition,
- createPieVisTypeDefinition,
- createAreaVisTypeDefinition,
- createHeatmapVisTypeDefinition,
- createHorizontalBarVisTypeDefinition,
- createGaugeVisTypeDefinition,
- createGoalVisTypeDefinition,
-} from './vis_type_vislib_vis_types';
+import { visLibVisTypeDefinitions, pieVisTypeDefinition } from './vis_type_vislib_vis_types';
import { ChartsPluginSetup } from '../../charts/public';
import { DataPublicPluginStart } from '../../data/public';
-import { setFormatService, setDataActions, setKibanaLegacy } from './services';
import { KibanaLegacyStart } from '../../kibana_legacy/public';
-
-export interface VisTypeVislibDependencies {
- uiSettings: IUiSettingsClient;
- charts: ChartsPluginSetup;
-}
+import { setFormatService, setDataActions } from './services';
+import { getVislibVisRenderer } from './vis_renderer';
+import { BasicVislibParams } from './types';
/** @internal */
export interface VisTypeVislibPluginSetupDependencies {
@@ -66,54 +46,37 @@ export interface VisTypeVislibPluginStartDependencies {
kibanaLegacy: KibanaLegacyStart;
}
-type VisTypeVislibCoreSetup = CoreSetup;
+export type VisTypeVislibCoreSetup = CoreSetup;
/** @internal */
-export class VisTypeVislibPlugin implements Plugin {
+export class VisTypeVislibPlugin
+ implements
+ Plugin {
constructor(public initializerContext: PluginInitializerContext) {}
public async setup(
core: VisTypeVislibCoreSetup,
{ expressions, visualizations, charts, visTypeXy }: VisTypeVislibPluginSetupDependencies
) {
- const visualizationDependencies: Readonly = {
- uiSettings: core.uiSettings,
- charts,
- };
- const vislibTypes = [
- createHistogramVisTypeDefinition,
- createLineVisTypeDefinition,
- createPieVisTypeDefinition,
- createAreaVisTypeDefinition,
- createHeatmapVisTypeDefinition,
- createHorizontalBarVisTypeDefinition,
- createGaugeVisTypeDefinition,
- createGoalVisTypeDefinition,
- ];
- const vislibFns = [createVisTypeVislibVisFn(), createPieVisFn()];
-
// if visTypeXy plugin is disabled it's config will be undefined
if (!visTypeXy) {
- const convertedTypes: any[] = [];
+ const convertedTypes: Array> = [];
const convertedFns: any[] = [];
// Register legacy vislib types that have been converted
convertedFns.forEach(expressions.registerFunction);
- convertedTypes.forEach((vis) =>
- visualizations.createBaseVisualization(vis(visualizationDependencies))
- );
+ convertedTypes.forEach(visualizations.createBaseVisualization);
+ expressions.registerRenderer(getVislibVisRenderer(core, charts));
}
-
// Register non-converted types
- vislibFns.forEach(expressions.registerFunction);
- vislibTypes.forEach((vis) =>
- visualizations.createBaseVisualization(vis(visualizationDependencies))
- );
+ visLibVisTypeDefinitions.forEach(visualizations.createBaseVisualization);
+ visualizations.createBaseVisualization(pieVisTypeDefinition);
+ expressions.registerRenderer(getVislibVisRenderer(core, charts));
+ [createVisTypeVislibVisFn(), createPieVisFn()].forEach(expressions.registerFunction);
}
- public start(core: CoreStart, { data, kibanaLegacy }: VisTypeVislibPluginStartDependencies) {
+ public start(core: CoreStart, { data }: VisTypeVislibPluginStartDependencies) {
setFormatService(data.fieldFormats);
setDataActions(data.actions);
- setKibanaLegacy(kibanaLegacy);
}
}
diff --git a/src/plugins/vis_type_vislib/public/sample_vis.test.mocks.ts b/src/plugins/vis_type_vislib/public/sample_vis.test.mocks.ts
new file mode 100644
index 0000000000000..324e8e00f37fc
--- /dev/null
+++ b/src/plugins/vis_type_vislib/public/sample_vis.test.mocks.ts
@@ -0,0 +1,3307 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+export const samplePieVis = {
+ type: {
+ name: 'pie',
+ title: 'Pie',
+ description: 'Compare parts of a whole',
+ icon: 'visPie',
+ stage: 'production',
+ options: {
+ showTimePicker: true,
+ showQueryBar: true,
+ showFilterBar: true,
+ showIndexSelection: true,
+ hierarchicalData: false,
+ },
+ visConfig: {
+ defaults: {
+ type: 'pie',
+ addTooltip: true,
+ addLegend: true,
+ legendPosition: 'right',
+ isDonut: true,
+ labels: {
+ show: false,
+ values: true,
+ last_level: true,
+ truncate: 100,
+ },
+ },
+ },
+ editorConfig: {
+ collections: {
+ legendPositions: [
+ {
+ text: 'Top',
+ value: 'top',
+ },
+ {
+ text: 'Left',
+ value: 'left',
+ },
+ {
+ text: 'Right',
+ value: 'right',
+ },
+ {
+ text: 'Bottom',
+ value: 'bottom',
+ },
+ ],
+ },
+ schemas: {
+ all: [
+ {
+ group: 'metrics',
+ name: 'metric',
+ title: 'Slice size',
+ min: 1,
+ max: 1,
+ aggFilter: ['sum', 'count', 'cardinality', 'top_hits'],
+ defaults: [
+ {
+ schema: 'metric',
+ type: 'count',
+ },
+ ],
+ editor: false,
+ params: [],
+ },
+ {
+ group: 'buckets',
+ name: 'segment',
+ title: 'Split slices',
+ min: 0,
+ max: null,
+ aggFilter: ['!geohash_grid', '!geotile_grid', '!filter'],
+ editor: false,
+ params: [],
+ },
+ {
+ group: 'buckets',
+ name: 'split',
+ title: 'Split chart',
+ mustBeFirst: true,
+ min: 0,
+ max: 1,
+ aggFilter: ['!geohash_grid', '!geotile_grid', '!filter'],
+ params: [
+ {
+ name: 'row',
+ default: true,
+ },
+ ],
+ editor: false,
+ },
+ ],
+ buckets: [null, null],
+ metrics: [null],
+ },
+ },
+ hidden: false,
+ requestHandler: 'courier',
+ responseHandler: 'vislib_slices',
+ hierarchicalData: true,
+ useCustomNoDataScreen: false,
+ },
+ title: '[Flights] Airline Carrier',
+ description: '',
+ params: {
+ type: 'pie',
+ addTooltip: true,
+ addLegend: true,
+ legendPosition: 'right',
+ isDonut: true,
+ labels: {
+ show: true,
+ values: true,
+ last_level: true,
+ truncate: 100,
+ },
+ },
+ sessionState: {},
+ data: {
+ searchSource: {
+ id: 'data_source1',
+ requestStartHandlers: [],
+ inheritOptions: {},
+ history: [],
+ fields: {
+ filter: [],
+ query: {
+ query: '',
+ language: 'kuery',
+ },
+ index: {
+ id: 'd3d7af60-4c81-11e8-b3d7-01146121b73d',
+ title: 'kibana_sample_data_flights',
+ fieldFormatMap: {
+ AvgTicketPrice: {
+ id: 'number',
+ params: {
+ parsedUrl: {
+ origin: 'http://localhost:5801',
+ pathname: '/app/visualize',
+ basePath: '',
+ },
+ pattern: '$0,0.[00]',
+ },
+ },
+ hour_of_day: {
+ id: 'number',
+ params: {
+ pattern: '00',
+ },
+ },
+ },
+ fields: [
+ {
+ count: 0,
+ name: 'AvgTicketPrice',
+ type: 'number',
+ esTypes: ['float'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ count: 0,
+ name: 'Cancelled',
+ type: 'boolean',
+ esTypes: ['boolean'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ count: 0,
+ name: 'Carrier',
+ type: 'string',
+ esTypes: ['keyword'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ count: 0,
+ name: 'Dest',
+ type: 'string',
+ esTypes: ['keyword'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ count: 0,
+ name: 'DestAirportID',
+ type: 'string',
+ esTypes: ['keyword'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ count: 0,
+ name: 'DestCityName',
+ type: 'string',
+ esTypes: ['keyword'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ count: 0,
+ name: 'DestCountry',
+ type: 'string',
+ esTypes: ['keyword'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ count: 0,
+ name: 'DestLocation',
+ type: 'geo_point',
+ esTypes: ['geo_point'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ count: 0,
+ name: 'DestRegion',
+ type: 'string',
+ esTypes: ['keyword'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ count: 0,
+ name: 'DestWeather',
+ type: 'string',
+ esTypes: ['keyword'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ count: 0,
+ name: 'DistanceKilometers',
+ type: 'number',
+ esTypes: ['float'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ count: 0,
+ name: 'DistanceMiles',
+ type: 'number',
+ esTypes: ['float'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ count: 0,
+ name: 'FlightDelay',
+ type: 'boolean',
+ esTypes: ['boolean'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ count: 0,
+ name: 'FlightDelayMin',
+ type: 'number',
+ esTypes: ['integer'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ count: 0,
+ name: 'FlightDelayType',
+ type: 'string',
+ esTypes: ['keyword'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ count: 0,
+ name: 'FlightNum',
+ type: 'string',
+ esTypes: ['keyword'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ count: 0,
+ name: 'FlightTimeHour',
+ type: 'string',
+ esTypes: ['keyword'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ count: 0,
+ name: 'FlightTimeMin',
+ type: 'number',
+ esTypes: ['float'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ count: 0,
+ name: 'Origin',
+ type: 'string',
+ esTypes: ['keyword'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ count: 0,
+ name: 'OriginAirportID',
+ type: 'string',
+ esTypes: ['keyword'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ count: 0,
+ name: 'OriginCityName',
+ type: 'string',
+ esTypes: ['keyword'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ count: 0,
+ name: 'OriginCountry',
+ type: 'string',
+ esTypes: ['keyword'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ count: 0,
+ name: 'OriginLocation',
+ type: 'geo_point',
+ esTypes: ['geo_point'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ count: 0,
+ name: 'OriginRegion',
+ type: 'string',
+ esTypes: ['keyword'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ count: 0,
+ name: 'OriginWeather',
+ type: 'string',
+ esTypes: ['keyword'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ count: 0,
+ name: '_id',
+ type: 'string',
+ esTypes: ['_id'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: false,
+ },
+ {
+ count: 0,
+ name: '_index',
+ type: 'string',
+ esTypes: ['_index'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: false,
+ },
+ {
+ count: 0,
+ name: '_score',
+ type: 'number',
+ scripted: false,
+ searchable: false,
+ aggregatable: false,
+ readFromDocValues: false,
+ },
+ {
+ count: 0,
+ name: '_source',
+ type: '_source',
+ esTypes: ['_source'],
+ scripted: false,
+ searchable: false,
+ aggregatable: false,
+ readFromDocValues: false,
+ },
+ {
+ count: 0,
+ name: '_type',
+ type: 'string',
+ esTypes: ['_type'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: false,
+ },
+ {
+ count: 0,
+ name: 'dayOfWeek',
+ type: 'number',
+ esTypes: ['integer'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ count: 0,
+ name: 'timestamp',
+ type: 'date',
+ esTypes: ['date'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ count: 0,
+ script: "doc['timestamp'].value.hourOfDay",
+ lang: 'painless',
+ name: 'hour_of_day',
+ type: 'number',
+ scripted: true,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: false,
+ },
+ ],
+ timeFieldName: 'timestamp',
+ metaFields: ['_source', '_id', '_type', '_index', '_score'],
+ version: 'WzM1LDFd',
+ originalSavedObjectBody: {
+ title: 'kibana_sample_data_flights',
+ timeFieldName: 'timestamp',
+ fields:
+ '[{"count":0,"name":"AvgTicketPrice","type":"number","esTypes":["float"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true},{"count":0,"name":"Cancelled","type":"boolean","esTypes":["boolean"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true},{"count":0,"name":"Carrier","type":"string","esTypes":["keyword"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true},{"count":0,"name":"Dest","type":"string","esTypes":["keyword"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true},{"count":0,"name":"DestAirportID","type":"string","esTypes":["keyword"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true},{"count":0,"name":"DestCityName","type":"string","esTypes":["keyword"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true},{"count":0,"name":"DestCountry","type":"string","esTypes":["keyword"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true},{"count":0,"name":"DestLocation","type":"geo_point","esTypes":["geo_point"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true},{"count":0,"name":"DestRegion","type":"string","esTypes":["keyword"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true},{"count":0,"name":"DestWeather","type":"string","esTypes":["keyword"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true},{"count":0,"name":"DistanceKilometers","type":"number","esTypes":["float"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true},{"count":0,"name":"DistanceMiles","type":"number","esTypes":["float"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true},{"count":0,"name":"FlightDelay","type":"boolean","esTypes":["boolean"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true},{"count":0,"name":"FlightDelayMin","type":"number","esTypes":["integer"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true},{"count":0,"name":"FlightDelayType","type":"string","esTypes":["keyword"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true},{"count":0,"name":"FlightNum","type":"string","esTypes":["keyword"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true},{"count":0,"name":"FlightTimeHour","type":"string","esTypes":["keyword"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true},{"count":0,"name":"FlightTimeMin","type":"number","esTypes":["float"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true},{"count":0,"name":"Origin","type":"string","esTypes":["keyword"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true},{"count":0,"name":"OriginAirportID","type":"string","esTypes":["keyword"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true},{"count":0,"name":"OriginCityName","type":"string","esTypes":["keyword"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true},{"count":0,"name":"OriginCountry","type":"string","esTypes":["keyword"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true},{"count":0,"name":"OriginLocation","type":"geo_point","esTypes":["geo_point"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true},{"count":0,"name":"OriginRegion","type":"string","esTypes":["keyword"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true},{"count":0,"name":"OriginWeather","type":"string","esTypes":["keyword"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true},{"count":0,"name":"_id","type":"string","esTypes":["_id"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":false},{"count":0,"name":"_index","type":"string","esTypes":["_index"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":false},{"count":0,"name":"_score","type":"number","scripted":false,"searchable":false,"aggregatable":false,"readFromDocValues":false},{"count":0,"name":"_source","type":"_source","esTypes":["_source"],"scripted":false,"searchable":false,"aggregatable":false,"readFromDocValues":false},{"count":0,"name":"_type","type":"string","esTypes":["_type"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":false},{"count":0,"name":"dayOfWeek","type":"number","esTypes":["integer"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true},{"count":0,"name":"timestamp","type":"date","esTypes":["date"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true},{"count":0,"script":"doc[\'timestamp\'].value.hourOfDay","lang":"painless","name":"hour_of_day","type":"number","scripted":true,"searchable":true,"aggregatable":true,"readFromDocValues":false}]',
+ fieldFormatMap:
+ '{"AvgTicketPrice":{"id":"number","params":{"parsedUrl":{"origin":"http://localhost:5801","pathname":"/app/visualize","basePath":""},"pattern":"$0,0.[00]"}},"hour_of_day":{"id":"number","params":{"parsedUrl":{"origin":"http://localhost:5801","pathname":"/app/visualize","basePath":""},"pattern":"00"}}}',
+ },
+ shortDotsEnable: false,
+ fieldFormats: {
+ fieldFormats: {},
+ defaultMap: {
+ ip: {
+ id: 'ip',
+ params: {},
+ },
+ date: {
+ id: 'date',
+ params: {},
+ },
+ date_nanos: {
+ id: 'date_nanos',
+ params: {},
+ es: true,
+ },
+ number: {
+ id: 'number',
+ params: {},
+ },
+ boolean: {
+ id: 'boolean',
+ params: {},
+ },
+ _source: {
+ id: '_source',
+ params: {},
+ },
+ _default_: {
+ id: 'string',
+ params: {},
+ },
+ },
+ metaParamsOptions: {},
+ },
+ },
+ },
+ dependencies: {
+ legacy: {
+ loadingCount$: {
+ _isScalar: false,
+ observers: [
+ {
+ closed: false,
+ _parentOrParents: {
+ closed: false,
+ _parentOrParents: {
+ closed: false,
+ _parentOrParents: {
+ closed: false,
+ _parentOrParents: {
+ closed: false,
+ _parentOrParents: {
+ closed: false,
+ _parentOrParents: {
+ closed: false,
+ _parentOrParents: {
+ closed: false,
+ _parentOrParents: null,
+ _subscriptions: [null],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: true,
+ isStopped: false,
+ destination: {
+ closed: false,
+ _parentOrParents: null,
+ _subscriptions: null,
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: false,
+ destination: {
+ closed: true,
+ },
+ _context: {},
+ },
+ },
+ _subscriptions: [null],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: true,
+ isStopped: false,
+ count: 1,
+ },
+ _subscriptions: [null],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: true,
+ isStopped: false,
+ hasPrev: true,
+ prev: 0,
+ },
+ _subscriptions: [null],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: false,
+ parent: {
+ closed: true,
+ _parentOrParents: null,
+ _subscriptions: null,
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: true,
+ isStopped: true,
+ concurrent: 1,
+ hasCompleted: true,
+ buffer: [],
+ active: 1,
+ index: 2,
+ },
+ },
+ _subscriptions: [null],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: false,
+ parent: {
+ closed: true,
+ _parentOrParents: null,
+ _subscriptions: null,
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: true,
+ concurrent: 1,
+ hasCompleted: true,
+ buffer: [
+ {
+ _isScalar: false,
+ },
+ ],
+ active: 1,
+ index: 1,
+ },
+ },
+ _subscriptions: [
+ {
+ closed: false,
+ _subscriptions: [
+ {
+ closed: false,
+ _subscriptions: null,
+ subject: {
+ _isScalar: false,
+ observers: [
+ {
+ closed: false,
+ _parentOrParents: {
+ closed: false,
+ _parentOrParents: {
+ closed: false,
+ _parentOrParents: {
+ closed: false,
+ _parentOrParents: {
+ closed: false,
+ _parentOrParents: {
+ closed: false,
+ _parentOrParents: {
+ closed: false,
+ _parentOrParents: null,
+ _subscriptions: [null],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: true,
+ isStopped: false,
+ destination: {
+ closed: false,
+ _parentOrParents: null,
+ _subscriptions: null,
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: false,
+ _context: {},
+ },
+ },
+ _subscriptions: [null],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: true,
+ isStopped: false,
+ count: 13,
+ },
+ _subscriptions: [null],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: true,
+ isStopped: false,
+ hasPrev: true,
+ prev: 0,
+ },
+ _subscriptions: [null],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: false,
+ parent: {
+ closed: true,
+ _parentOrParents: null,
+ _subscriptions: null,
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: true,
+ isStopped: true,
+ concurrent: 1,
+ hasCompleted: true,
+ buffer: [],
+ active: 1,
+ index: 2,
+ },
+ },
+ _subscriptions: [null],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: false,
+ parent: {
+ closed: true,
+ _parentOrParents: null,
+ _subscriptions: null,
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: true,
+ concurrent: 1,
+ hasCompleted: true,
+ buffer: [
+ {
+ _isScalar: false,
+ },
+ ],
+ active: 1,
+ index: 1,
+ },
+ },
+ _subscriptions: [
+ null,
+ {
+ closed: false,
+ _subscriptions: [
+ {
+ closed: false,
+ _subscriptions: [
+ {
+ closed: false,
+ _subscriptions: null,
+ subject: {
+ _isScalar: false,
+ observers: [null],
+ closed: false,
+ isStopped: false,
+ hasError: false,
+ thrownError: null,
+ _value: 0,
+ },
+ },
+ ],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: false,
+ hasKey: true,
+ key: 0,
+ },
+ ],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: false,
+ },
+ ],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: false,
+ seenValue: false,
+ },
+ _subscriptions: [
+ {
+ closed: false,
+ _subscriptions: null,
+ },
+ ],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: false,
+ },
+ {
+ closed: false,
+ _parentOrParents: {
+ closed: false,
+ _parentOrParents: {
+ closed: false,
+ _parentOrParents: {
+ closed: false,
+ _parentOrParents: {
+ closed: false,
+ _parentOrParents: {
+ closed: false,
+ _parentOrParents: {
+ closed: false,
+ _parentOrParents: null,
+ _subscriptions: [null],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: true,
+ isStopped: false,
+ destination: {
+ closed: false,
+ _parentOrParents: null,
+ _subscriptions: null,
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: false,
+ _context: {},
+ },
+ },
+ _subscriptions: [null],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: true,
+ isStopped: false,
+ count: 1,
+ },
+ _subscriptions: [null],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: true,
+ isStopped: false,
+ hasPrev: true,
+ prev: 0,
+ },
+ _subscriptions: [null],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: false,
+ parent: {
+ closed: true,
+ _parentOrParents: null,
+ _subscriptions: null,
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: true,
+ isStopped: true,
+ concurrent: 1,
+ hasCompleted: true,
+ buffer: [],
+ active: 1,
+ index: 2,
+ },
+ },
+ _subscriptions: [null],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: false,
+ parent: {
+ closed: true,
+ _parentOrParents: null,
+ _subscriptions: null,
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: true,
+ concurrent: 1,
+ hasCompleted: true,
+ buffer: [
+ {
+ _isScalar: false,
+ },
+ ],
+ active: 1,
+ index: 1,
+ },
+ },
+ _subscriptions: [
+ null,
+ {
+ closed: false,
+ _subscriptions: [
+ {
+ closed: false,
+ _subscriptions: [
+ {
+ closed: false,
+ _subscriptions: null,
+ subject: {
+ _isScalar: false,
+ observers: [null],
+ closed: false,
+ isStopped: false,
+ hasError: false,
+ thrownError: null,
+ _value: 0,
+ },
+ },
+ ],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: false,
+ hasKey: true,
+ key: 0,
+ },
+ ],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: false,
+ },
+ ],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: false,
+ seenValue: false,
+ },
+ _subscriptions: [
+ {
+ closed: false,
+ _subscriptions: null,
+ },
+ ],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: false,
+ },
+ {
+ closed: false,
+ _parentOrParents: {
+ closed: false,
+ _parentOrParents: {
+ closed: false,
+ _parentOrParents: {
+ closed: false,
+ _parentOrParents: {
+ closed: false,
+ _parentOrParents: {
+ closed: false,
+ _parentOrParents: {
+ closed: false,
+ _parentOrParents: null,
+ _subscriptions: [null],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: true,
+ isStopped: false,
+ destination: {
+ closed: false,
+ _parentOrParents: null,
+ _subscriptions: null,
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: false,
+ _context: {},
+ },
+ },
+ _subscriptions: [null],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: true,
+ isStopped: false,
+ count: 1,
+ },
+ _subscriptions: [null],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: true,
+ isStopped: false,
+ hasPrev: true,
+ prev: 0,
+ },
+ _subscriptions: [null],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: false,
+ parent: {
+ closed: true,
+ _parentOrParents: null,
+ _subscriptions: null,
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: true,
+ isStopped: true,
+ concurrent: 1,
+ hasCompleted: true,
+ buffer: [],
+ active: 1,
+ index: 2,
+ },
+ },
+ _subscriptions: [null],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: false,
+ parent: {
+ closed: true,
+ _parentOrParents: null,
+ _subscriptions: null,
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: true,
+ concurrent: 1,
+ hasCompleted: true,
+ buffer: [
+ {
+ _isScalar: false,
+ },
+ ],
+ active: 1,
+ index: 1,
+ },
+ },
+ _subscriptions: [
+ null,
+ {
+ closed: false,
+ _subscriptions: [
+ {
+ closed: false,
+ _subscriptions: [
+ {
+ closed: false,
+ _subscriptions: null,
+ subject: {
+ _isScalar: false,
+ observers: [null],
+ closed: false,
+ isStopped: false,
+ hasError: false,
+ thrownError: null,
+ _value: 0,
+ },
+ },
+ ],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: false,
+ hasKey: true,
+ key: 0,
+ },
+ ],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: false,
+ },
+ ],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: false,
+ seenValue: false,
+ },
+ _subscriptions: [
+ {
+ closed: false,
+ _subscriptions: null,
+ },
+ ],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: false,
+ },
+ {
+ closed: false,
+ _parentOrParents: {
+ closed: false,
+ _parentOrParents: {
+ closed: false,
+ _parentOrParents: {
+ closed: false,
+ _parentOrParents: {
+ closed: false,
+ _parentOrParents: {
+ closed: false,
+ _parentOrParents: {
+ closed: false,
+ _parentOrParents: null,
+ _subscriptions: [null],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: true,
+ isStopped: false,
+ destination: {
+ closed: false,
+ _parentOrParents: null,
+ _subscriptions: null,
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: false,
+ _context: {},
+ },
+ },
+ _subscriptions: [null],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: true,
+ isStopped: false,
+ count: 3,
+ },
+ _subscriptions: [null],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: true,
+ isStopped: false,
+ hasPrev: true,
+ prev: 0,
+ },
+ _subscriptions: [null],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: false,
+ parent: {
+ closed: true,
+ _parentOrParents: null,
+ _subscriptions: null,
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: true,
+ isStopped: true,
+ concurrent: 1,
+ hasCompleted: true,
+ buffer: [],
+ active: 1,
+ index: 2,
+ },
+ },
+ _subscriptions: [null],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: false,
+ parent: {
+ closed: true,
+ _parentOrParents: null,
+ _subscriptions: null,
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: true,
+ concurrent: 1,
+ hasCompleted: true,
+ buffer: [
+ {
+ _isScalar: false,
+ },
+ ],
+ active: 1,
+ index: 1,
+ },
+ },
+ _subscriptions: [
+ null,
+ {
+ closed: false,
+ _subscriptions: [
+ {
+ closed: false,
+ _subscriptions: [
+ {
+ closed: false,
+ _subscriptions: null,
+ subject: {
+ _isScalar: false,
+ observers: [null],
+ closed: false,
+ isStopped: false,
+ hasError: false,
+ thrownError: null,
+ _value: 0,
+ },
+ },
+ ],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: false,
+ hasKey: true,
+ key: 0,
+ },
+ ],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: false,
+ },
+ ],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: false,
+ seenValue: false,
+ },
+ _subscriptions: [
+ {
+ closed: false,
+ _subscriptions: null,
+ },
+ ],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: false,
+ },
+ null,
+ ],
+ closed: false,
+ isStopped: false,
+ hasError: false,
+ thrownError: null,
+ },
+ },
+ ],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: false,
+ },
+ null,
+ ],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: false,
+ seenValue: false,
+ },
+ _subscriptions: [null],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: false,
+ },
+ _subscriptions: [
+ {
+ closed: false,
+ _subscriptions: null,
+ },
+ ],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: false,
+ hasKey: true,
+ key: 0,
+ },
+ ],
+ closed: false,
+ isStopped: false,
+ hasError: false,
+ thrownError: null,
+ _value: 0,
+ },
+ },
+ },
+ },
+ aggs: {
+ typesRegistry: {},
+ getResponseAggs: () => [
+ {
+ id: '1',
+ enabled: true,
+ type: 'count',
+ params: {},
+ schema: 'metric',
+ toSerializedFieldFormat: () => ({
+ id: 'number',
+ }),
+ },
+ {
+ id: '2',
+ enabled: true,
+ type: 'terms',
+ params: {
+ field: 'Carrier',
+ orderBy: '1',
+ order: 'desc',
+ size: 5,
+ otherBucket: false,
+ otherBucketLabel: 'Other',
+ missingBucket: false,
+ missingBucketLabel: 'Missing',
+ },
+ schema: 'segment',
+ toSerializedFieldFormat: () => ({
+ id: 'terms',
+ params: {
+ id: 'string',
+ otherBucketLabel: 'Other',
+ missingBucketLabel: 'Missing',
+ parsedUrl: {
+ origin: 'http://localhost:5801',
+ pathname: '/app/visualize',
+ basePath: '',
+ },
+ },
+ }),
+ },
+ ],
+ },
+ },
+ isHierarchical: () => true,
+ uiState: {
+ vis: {
+ legendOpen: false,
+ },
+ },
+};
+
+export const sampleAreaVis = {
+ type: {
+ name: 'area',
+ title: 'Area',
+ description: 'Emphasize the quantity beneath a line chart',
+ icon: 'visArea',
+ stage: 'production',
+ options: {
+ showTimePicker: true,
+ showQueryBar: true,
+ showFilterBar: true,
+ showIndexSelection: true,
+ hierarchicalData: false,
+ },
+ visConfig: {
+ defaults: {
+ type: 'area',
+ grid: {
+ categoryLines: false,
+ },
+ categoryAxes: [
+ {
+ id: 'CategoryAxis-1',
+ type: 'category',
+ position: 'bottom',
+ show: true,
+ style: {},
+ scale: {
+ type: 'linear',
+ },
+ labels: {
+ show: true,
+ filter: true,
+ truncate: 100,
+ },
+ title: {},
+ },
+ ],
+ valueAxes: [
+ {
+ id: 'ValueAxis-1',
+ name: 'LeftAxis-1',
+ type: 'value',
+ position: 'left',
+ show: true,
+ style: {},
+ scale: {
+ type: 'linear',
+ mode: 'normal',
+ },
+ labels: {
+ show: true,
+ rotate: 0,
+ filter: false,
+ truncate: 100,
+ },
+ title: {
+ text: 'Count',
+ },
+ },
+ ],
+ seriesParams: [
+ {
+ show: true,
+ type: 'area',
+ mode: 'stacked',
+ data: {
+ label: 'Count',
+ id: '1',
+ },
+ drawLinesBetweenPoints: true,
+ lineWidth: 2,
+ showCircles: true,
+ interpolate: 'linear',
+ valueAxis: 'ValueAxis-1',
+ },
+ ],
+ addTooltip: true,
+ addLegend: true,
+ legendPosition: 'right',
+ times: [],
+ addTimeMarker: false,
+ thresholdLine: {
+ show: false,
+ value: 10,
+ width: 1,
+ style: 'full',
+ color: '#E7664C',
+ },
+ labels: {},
+ },
+ },
+ editorConfig: {
+ collections: {
+ legendPositions: [
+ {
+ text: 'Top',
+ value: 'top',
+ },
+ {
+ text: 'Left',
+ value: 'left',
+ },
+ {
+ text: 'Right',
+ value: 'right',
+ },
+ {
+ text: 'Bottom',
+ value: 'bottom',
+ },
+ ],
+ positions: [
+ {
+ text: 'Top',
+ value: 'top',
+ },
+ {
+ text: 'Left',
+ value: 'left',
+ },
+ {
+ text: 'Right',
+ value: 'right',
+ },
+ {
+ text: 'Bottom',
+ value: 'bottom',
+ },
+ ],
+ chartTypes: [
+ {
+ text: 'Line',
+ value: 'line',
+ },
+ {
+ text: 'Area',
+ value: 'area',
+ },
+ {
+ text: 'Bar',
+ value: 'histogram',
+ },
+ ],
+ axisModes: [
+ {
+ text: 'Normal',
+ value: 'normal',
+ },
+ {
+ text: 'Percentage',
+ value: 'percentage',
+ },
+ {
+ text: 'Wiggle',
+ value: 'wiggle',
+ },
+ {
+ text: 'Silhouette',
+ value: 'silhouette',
+ },
+ ],
+ scaleTypes: [
+ {
+ text: 'Linear',
+ value: 'linear',
+ },
+ {
+ text: 'Log',
+ value: 'log',
+ },
+ {
+ text: 'Square root',
+ value: 'square root',
+ },
+ ],
+ chartModes: [
+ {
+ text: 'Normal',
+ value: 'normal',
+ },
+ {
+ text: 'Stacked',
+ value: 'stacked',
+ },
+ ],
+ interpolationModes: [
+ {
+ text: 'Straight',
+ value: 'linear',
+ },
+ {
+ text: 'Smoothed',
+ value: 'cardinal',
+ },
+ {
+ text: 'Stepped',
+ value: 'step-after',
+ },
+ ],
+ thresholdLineStyles: [
+ {
+ value: 'full',
+ text: 'Full',
+ },
+ {
+ value: 'dashed',
+ text: 'Dashed',
+ },
+ {
+ value: 'dot-dashed',
+ text: 'Dot-dashed',
+ },
+ ],
+ },
+ optionTabs: [
+ {
+ name: 'advanced',
+ title: 'Metrics & axes',
+ },
+ {
+ name: 'options',
+ title: 'Panel settings',
+ },
+ ],
+ schemas: {
+ all: [
+ {
+ group: 'metrics',
+ name: 'metric',
+ title: 'Y-axis',
+ aggFilter: ['!geo_centroid', '!geo_bounds'],
+ min: 1,
+ defaults: [
+ {
+ schema: 'metric',
+ type: 'count',
+ },
+ ],
+ max: null,
+ editor: false,
+ params: [],
+ },
+ {
+ group: 'metrics',
+ name: 'radius',
+ title: 'Dot size',
+ min: 0,
+ max: 1,
+ aggFilter: ['count', 'avg', 'sum', 'min', 'max', 'cardinality'],
+ editor: false,
+ params: [],
+ },
+ {
+ group: 'buckets',
+ name: 'segment',
+ title: 'X-axis',
+ min: 0,
+ max: 1,
+ aggFilter: ['!geohash_grid', '!geotile_grid', '!filter'],
+ editor: false,
+ params: [],
+ },
+ {
+ group: 'buckets',
+ name: 'group',
+ title: 'Split series',
+ min: 0,
+ max: 3,
+ aggFilter: ['!geohash_grid', '!geotile_grid', '!filter'],
+ editor: false,
+ params: [],
+ },
+ {
+ group: 'buckets',
+ name: 'split',
+ title: 'Split chart',
+ min: 0,
+ max: 1,
+ aggFilter: ['!geohash_grid', '!geotile_grid', '!filter'],
+ params: [
+ {
+ name: 'row',
+ default: true,
+ },
+ ],
+ editor: false,
+ },
+ ],
+ buckets: [null, null, null],
+ metrics: [null, null],
+ },
+ },
+ hidden: false,
+ requestHandler: 'courier',
+ responseHandler: 'none',
+ hierarchicalData: false,
+ useCustomNoDataScreen: false,
+ },
+ title: '[eCommerce] Sales by Category',
+ description: '',
+ params: {
+ type: 'area',
+ grid: {
+ categoryLines: false,
+ style: {
+ color: '#eee',
+ },
+ },
+ categoryAxes: [
+ {
+ id: 'CategoryAxis-1',
+ type: 'category',
+ position: 'bottom',
+ show: true,
+ style: {},
+ scale: {
+ type: 'linear',
+ },
+ labels: {
+ show: true,
+ truncate: 100,
+ },
+ title: {},
+ },
+ ],
+ valueAxes: [
+ {
+ id: 'ValueAxis-1',
+ name: 'LeftAxis-1',
+ type: 'value',
+ position: 'left',
+ show: true,
+ style: {},
+ scale: {
+ type: 'linear',
+ mode: 'normal',
+ },
+ labels: {
+ show: true,
+ rotate: 0,
+ filter: false,
+ truncate: 100,
+ },
+ title: {
+ text: 'Sum of total_quantity',
+ },
+ },
+ ],
+ seriesParams: [
+ {
+ show: 'true',
+ type: 'area',
+ mode: 'stacked',
+ data: {
+ label: 'Sum of total_quantity',
+ id: '1',
+ },
+ drawLinesBetweenPoints: true,
+ showCircles: true,
+ interpolate: 'linear',
+ valueAxis: 'ValueAxis-1',
+ },
+ ],
+ addTooltip: true,
+ addLegend: true,
+ legendPosition: 'top',
+ times: [],
+ addTimeMarker: false,
+ thresholdLine: {
+ show: false,
+ value: 10,
+ width: 1,
+ style: 'full',
+ color: '#E7664C',
+ },
+ labels: {},
+ dimensions: {
+ x: {
+ accessor: 0,
+ format: {
+ id: 'date',
+ params: {
+ pattern: 'YYYY-MM-DD HH:mm',
+ },
+ },
+ params: {
+ date: true,
+ interval: 43200000,
+ format: 'YYYY-MM-DD HH:mm',
+ bounds: {
+ min: '2020-09-30T12:41:13.795Z',
+ max: '2020-10-15T17:00:00.000Z',
+ },
+ },
+ label: 'order_date per 12 hours',
+ aggType: 'date_histogram',
+ },
+ y: [
+ {
+ accessor: 2,
+ format: {
+ id: 'number',
+ params: {
+ parsedUrl: {
+ origin: 'http://localhost:5801',
+ pathname: '/app/visualize',
+ basePath: '',
+ },
+ },
+ },
+ params: {},
+ label: 'Sum of total_quantity',
+ aggType: 'sum',
+ },
+ ],
+ series: [
+ {
+ accessor: 1,
+ format: {
+ id: 'terms',
+ params: {
+ id: 'string',
+ otherBucketLabel: 'Other',
+ missingBucketLabel: 'Missing',
+ },
+ },
+ params: {},
+ label: 'category.keyword: Descending',
+ aggType: 'terms',
+ },
+ ],
+ },
+ },
+ sessionState: {},
+ data: {
+ searchSource: {
+ id: 'data_source1',
+ requestStartHandlers: [],
+ inheritOptions: {},
+ history: [],
+ fields: {
+ query: {
+ query: '',
+ language: 'kuery',
+ },
+ filter: [],
+ index: {
+ id: 'ff959d40-b880-11e8-a6d9-e546fe2bba5f',
+ title: 'kibana_sample_data_ecommerce',
+ fieldFormatMap: {
+ taxful_total_price: {
+ id: 'number',
+ params: {
+ pattern: '$0,0.[00]',
+ },
+ },
+ },
+ fields: [
+ {
+ count: 0,
+ name: '_id',
+ type: 'string',
+ esTypes: ['_id'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: false,
+ },
+ {
+ count: 0,
+ name: '_index',
+ type: 'string',
+ esTypes: ['_index'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: false,
+ },
+ {
+ count: 0,
+ name: '_score',
+ type: 'number',
+ scripted: false,
+ searchable: false,
+ aggregatable: false,
+ readFromDocValues: false,
+ },
+ {
+ count: 0,
+ name: '_source',
+ type: '_source',
+ esTypes: ['_source'],
+ scripted: false,
+ searchable: false,
+ aggregatable: false,
+ readFromDocValues: false,
+ },
+ {
+ count: 0,
+ name: '_type',
+ type: 'string',
+ esTypes: ['_type'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: false,
+ },
+ {
+ count: 0,
+ name: 'category',
+ type: 'string',
+ esTypes: ['text'],
+ scripted: false,
+ searchable: true,
+ aggregatable: false,
+ readFromDocValues: false,
+ },
+ {
+ count: 0,
+ name: 'category.keyword',
+ type: 'string',
+ esTypes: ['keyword'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ subType: {
+ multi: {
+ parent: 'category',
+ },
+ },
+ },
+ {
+ count: 0,
+ name: 'currency',
+ type: 'string',
+ esTypes: ['keyword'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ count: 0,
+ name: 'customer_birth_date',
+ type: 'date',
+ esTypes: ['date'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ count: 0,
+ name: 'customer_first_name',
+ type: 'string',
+ esTypes: ['text'],
+ scripted: false,
+ searchable: true,
+ aggregatable: false,
+ readFromDocValues: false,
+ },
+ {
+ count: 0,
+ name: 'customer_first_name.keyword',
+ type: 'string',
+ esTypes: ['keyword'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ subType: {
+ multi: {
+ parent: 'customer_first_name',
+ },
+ },
+ },
+ {
+ count: 0,
+ name: 'customer_full_name',
+ type: 'string',
+ esTypes: ['text'],
+ scripted: false,
+ searchable: true,
+ aggregatable: false,
+ readFromDocValues: false,
+ },
+ {
+ count: 0,
+ name: 'customer_full_name.keyword',
+ type: 'string',
+ esTypes: ['keyword'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ subType: {
+ multi: {
+ parent: 'customer_full_name',
+ },
+ },
+ },
+ {
+ count: 0,
+ name: 'customer_gender',
+ type: 'string',
+ esTypes: ['keyword'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ count: 0,
+ name: 'customer_id',
+ type: 'string',
+ esTypes: ['keyword'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ count: 0,
+ name: 'customer_last_name',
+ type: 'string',
+ esTypes: ['text'],
+ scripted: false,
+ searchable: true,
+ aggregatable: false,
+ readFromDocValues: false,
+ },
+ {
+ count: 0,
+ name: 'customer_last_name.keyword',
+ type: 'string',
+ esTypes: ['keyword'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ subType: {
+ multi: {
+ parent: 'customer_last_name',
+ },
+ },
+ },
+ {
+ count: 0,
+ name: 'customer_phone',
+ type: 'string',
+ esTypes: ['keyword'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ count: 0,
+ name: 'day_of_week',
+ type: 'string',
+ esTypes: ['keyword'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ count: 0,
+ name: 'day_of_week_i',
+ type: 'number',
+ esTypes: ['integer'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ count: 0,
+ name: 'email',
+ type: 'string',
+ esTypes: ['keyword'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ count: 0,
+ name: 'event.dataset',
+ type: 'string',
+ esTypes: ['keyword'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ count: 0,
+ name: 'geoip.city_name',
+ type: 'string',
+ esTypes: ['keyword'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ count: 0,
+ name: 'geoip.continent_name',
+ type: 'string',
+ esTypes: ['keyword'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ count: 0,
+ name: 'geoip.country_iso_code',
+ type: 'string',
+ esTypes: ['keyword'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ count: 0,
+ name: 'geoip.location',
+ type: 'geo_point',
+ esTypes: ['geo_point'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ count: 0,
+ name: 'geoip.region_name',
+ type: 'string',
+ esTypes: ['keyword'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ count: 0,
+ name: 'manufacturer',
+ type: 'string',
+ esTypes: ['text'],
+ scripted: false,
+ searchable: true,
+ aggregatable: false,
+ readFromDocValues: false,
+ },
+ {
+ count: 0,
+ name: 'manufacturer.keyword',
+ type: 'string',
+ esTypes: ['keyword'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ subType: {
+ multi: {
+ parent: 'manufacturer',
+ },
+ },
+ },
+ {
+ count: 0,
+ name: 'order_date',
+ type: 'date',
+ esTypes: ['date'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ count: 0,
+ name: 'order_id',
+ type: 'string',
+ esTypes: ['keyword'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ count: 0,
+ name: 'products._id',
+ type: 'string',
+ esTypes: ['text'],
+ scripted: false,
+ searchable: true,
+ aggregatable: false,
+ readFromDocValues: false,
+ },
+ {
+ count: 0,
+ name: 'products._id.keyword',
+ type: 'string',
+ esTypes: ['keyword'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ subType: {
+ multi: {
+ parent: 'products._id',
+ },
+ },
+ },
+ {
+ count: 0,
+ name: 'products.base_price',
+ type: 'number',
+ esTypes: ['half_float'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ count: 0,
+ name: 'products.base_unit_price',
+ type: 'number',
+ esTypes: ['half_float'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ count: 0,
+ name: 'products.category',
+ type: 'string',
+ esTypes: ['text'],
+ scripted: false,
+ searchable: true,
+ aggregatable: false,
+ readFromDocValues: false,
+ },
+ {
+ count: 0,
+ name: 'products.category.keyword',
+ type: 'string',
+ esTypes: ['keyword'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ subType: {
+ multi: {
+ parent: 'products.category',
+ },
+ },
+ },
+ {
+ count: 0,
+ name: 'products.created_on',
+ type: 'date',
+ esTypes: ['date'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ count: 0,
+ name: 'products.discount_amount',
+ type: 'number',
+ esTypes: ['half_float'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ count: 0,
+ name: 'products.discount_percentage',
+ type: 'number',
+ esTypes: ['half_float'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ count: 0,
+ name: 'products.manufacturer',
+ type: 'string',
+ esTypes: ['text'],
+ scripted: false,
+ searchable: true,
+ aggregatable: false,
+ readFromDocValues: false,
+ },
+ {
+ count: 0,
+ name: 'products.manufacturer.keyword',
+ type: 'string',
+ esTypes: ['keyword'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ subType: {
+ multi: {
+ parent: 'products.manufacturer',
+ },
+ },
+ },
+ {
+ count: 0,
+ name: 'products.min_price',
+ type: 'number',
+ esTypes: ['half_float'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ count: 0,
+ name: 'products.price',
+ type: 'number',
+ esTypes: ['half_float'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ count: 0,
+ name: 'products.product_id',
+ type: 'number',
+ esTypes: ['long'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ count: 0,
+ name: 'products.product_name',
+ type: 'string',
+ esTypes: ['text'],
+ scripted: false,
+ searchable: true,
+ aggregatable: false,
+ readFromDocValues: false,
+ },
+ {
+ count: 0,
+ name: 'products.product_name.keyword',
+ type: 'string',
+ esTypes: ['keyword'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ subType: {
+ multi: {
+ parent: 'products.product_name',
+ },
+ },
+ },
+ {
+ count: 0,
+ name: 'products.quantity',
+ type: 'number',
+ esTypes: ['integer'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ count: 0,
+ name: 'products.sku',
+ type: 'string',
+ esTypes: ['keyword'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ count: 0,
+ name: 'products.tax_amount',
+ type: 'number',
+ esTypes: ['half_float'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ count: 0,
+ name: 'products.taxful_price',
+ type: 'number',
+ esTypes: ['half_float'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ count: 0,
+ name: 'products.taxless_price',
+ type: 'number',
+ esTypes: ['half_float'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ count: 0,
+ name: 'products.unit_discount_amount',
+ type: 'number',
+ esTypes: ['half_float'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ count: 0,
+ name: 'sku',
+ type: 'string',
+ esTypes: ['keyword'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ count: 0,
+ name: 'taxful_total_price',
+ type: 'number',
+ esTypes: ['half_float'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ count: 0,
+ name: 'taxless_total_price',
+ type: 'number',
+ esTypes: ['half_float'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ count: 0,
+ name: 'total_quantity',
+ type: 'number',
+ esTypes: ['integer'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ count: 0,
+ name: 'total_unique_products',
+ type: 'number',
+ esTypes: ['integer'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ count: 0,
+ name: 'type',
+ type: 'string',
+ esTypes: ['keyword'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ {
+ count: 0,
+ name: 'user',
+ type: 'string',
+ esTypes: ['keyword'],
+ scripted: false,
+ searchable: true,
+ aggregatable: true,
+ readFromDocValues: true,
+ },
+ ],
+ timeFieldName: 'order_date',
+ metaFields: ['_source', '_id', '_type', '_index', '_score'],
+ version: 'WzEzLDFd',
+ originalSavedObjectBody: {
+ title: 'kibana_sample_data_ecommerce',
+ timeFieldName: 'order_date',
+ fields:
+ '[{"count":0,"name":"_id","type":"string","esTypes":["_id"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":false},{"count":0,"name":"_index","type":"string","esTypes":["_index"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":false},{"count":0,"name":"_score","type":"number","scripted":false,"searchable":false,"aggregatable":false,"readFromDocValues":false},{"count":0,"name":"_source","type":"_source","esTypes":["_source"],"scripted":false,"searchable":false,"aggregatable":false,"readFromDocValues":false},{"count":0,"name":"_type","type":"string","esTypes":["_type"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":false},{"count":0,"name":"category","type":"string","esTypes":["text"],"scripted":false,"searchable":true,"aggregatable":false,"readFromDocValues":false},{"count":0,"name":"category.keyword","type":"string","esTypes":["keyword"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true,"subType":{"multi":{"parent":"category"}}},{"count":0,"name":"currency","type":"string","esTypes":["keyword"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true},{"count":0,"name":"customer_birth_date","type":"date","esTypes":["date"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true},{"count":0,"name":"customer_first_name","type":"string","esTypes":["text"],"scripted":false,"searchable":true,"aggregatable":false,"readFromDocValues":false},{"count":0,"name":"customer_first_name.keyword","type":"string","esTypes":["keyword"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true,"subType":{"multi":{"parent":"customer_first_name"}}},{"count":0,"name":"customer_full_name","type":"string","esTypes":["text"],"scripted":false,"searchable":true,"aggregatable":false,"readFromDocValues":false},{"count":0,"name":"customer_full_name.keyword","type":"string","esTypes":["keyword"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true,"subType":{"multi":{"parent":"customer_full_name"}}},{"count":0,"name":"customer_gender","type":"string","esTypes":["keyword"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true},{"count":0,"name":"customer_id","type":"string","esTypes":["keyword"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true},{"count":0,"name":"customer_last_name","type":"string","esTypes":["text"],"scripted":false,"searchable":true,"aggregatable":false,"readFromDocValues":false},{"count":0,"name":"customer_last_name.keyword","type":"string","esTypes":["keyword"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true,"subType":{"multi":{"parent":"customer_last_name"}}},{"count":0,"name":"customer_phone","type":"string","esTypes":["keyword"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true},{"count":0,"name":"day_of_week","type":"string","esTypes":["keyword"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true},{"count":0,"name":"day_of_week_i","type":"number","esTypes":["integer"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true},{"count":0,"name":"email","type":"string","esTypes":["keyword"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true},{"count":0,"name":"event.dataset","type":"string","esTypes":["keyword"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true},{"count":0,"name":"geoip.city_name","type":"string","esTypes":["keyword"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true},{"count":0,"name":"geoip.continent_name","type":"string","esTypes":["keyword"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true},{"count":0,"name":"geoip.country_iso_code","type":"string","esTypes":["keyword"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true},{"count":0,"name":"geoip.location","type":"geo_point","esTypes":["geo_point"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true},{"count":0,"name":"geoip.region_name","type":"string","esTypes":["keyword"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true},{"count":0,"name":"manufacturer","type":"string","esTypes":["text"],"scripted":false,"searchable":true,"aggregatable":false,"readFromDocValues":false},{"count":0,"name":"manufacturer.keyword","type":"string","esTypes":["keyword"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true,"subType":{"multi":{"parent":"manufacturer"}}},{"count":0,"name":"order_date","type":"date","esTypes":["date"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true},{"count":0,"name":"order_id","type":"string","esTypes":["keyword"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true},{"count":0,"name":"products._id","type":"string","esTypes":["text"],"scripted":false,"searchable":true,"aggregatable":false,"readFromDocValues":false},{"count":0,"name":"products._id.keyword","type":"string","esTypes":["keyword"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true,"subType":{"multi":{"parent":"products._id"}}},{"count":0,"name":"products.base_price","type":"number","esTypes":["half_float"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true},{"count":0,"name":"products.base_unit_price","type":"number","esTypes":["half_float"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true},{"count":0,"name":"products.category","type":"string","esTypes":["text"],"scripted":false,"searchable":true,"aggregatable":false,"readFromDocValues":false},{"count":0,"name":"products.category.keyword","type":"string","esTypes":["keyword"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true,"subType":{"multi":{"parent":"products.category"}}},{"count":0,"name":"products.created_on","type":"date","esTypes":["date"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true},{"count":0,"name":"products.discount_amount","type":"number","esTypes":["half_float"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true},{"count":0,"name":"products.discount_percentage","type":"number","esTypes":["half_float"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true},{"count":0,"name":"products.manufacturer","type":"string","esTypes":["text"],"scripted":false,"searchable":true,"aggregatable":false,"readFromDocValues":false},{"count":0,"name":"products.manufacturer.keyword","type":"string","esTypes":["keyword"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true,"subType":{"multi":{"parent":"products.manufacturer"}}},{"count":0,"name":"products.min_price","type":"number","esTypes":["half_float"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true},{"count":0,"name":"products.price","type":"number","esTypes":["half_float"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true},{"count":0,"name":"products.product_id","type":"number","esTypes":["long"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true},{"count":0,"name":"products.product_name","type":"string","esTypes":["text"],"scripted":false,"searchable":true,"aggregatable":false,"readFromDocValues":false},{"count":0,"name":"products.product_name.keyword","type":"string","esTypes":["keyword"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true,"subType":{"multi":{"parent":"products.product_name"}}},{"count":0,"name":"products.quantity","type":"number","esTypes":["integer"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true},{"count":0,"name":"products.sku","type":"string","esTypes":["keyword"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true},{"count":0,"name":"products.tax_amount","type":"number","esTypes":["half_float"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true},{"count":0,"name":"products.taxful_price","type":"number","esTypes":["half_float"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true},{"count":0,"name":"products.taxless_price","type":"number","esTypes":["half_float"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true},{"count":0,"name":"products.unit_discount_amount","type":"number","esTypes":["half_float"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true},{"count":0,"name":"sku","type":"string","esTypes":["keyword"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true},{"count":0,"name":"taxful_total_price","type":"number","esTypes":["half_float"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true},{"count":0,"name":"taxless_total_price","type":"number","esTypes":["half_float"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true},{"count":0,"name":"total_quantity","type":"number","esTypes":["integer"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true},{"count":0,"name":"total_unique_products","type":"number","esTypes":["integer"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true},{"count":0,"name":"type","type":"string","esTypes":["keyword"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true},{"count":0,"name":"user","type":"string","esTypes":["keyword"],"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true}]',
+ fieldFormatMap:
+ '{"taxful_total_price":{"id":"number","params":{"parsedUrl":{"origin":"http://localhost:5801","pathname":"/app/visualize","basePath":""},"pattern":"$0,0.[00]"}}}',
+ },
+ shortDotsEnable: false,
+ fieldFormats: {
+ fieldFormats: {},
+ defaultMap: {
+ ip: {
+ id: 'ip',
+ params: {},
+ },
+ date: {
+ id: 'date',
+ params: {},
+ },
+ date_nanos: {
+ id: 'date_nanos',
+ params: {},
+ es: true,
+ },
+ number: {
+ id: 'number',
+ params: {},
+ },
+ boolean: {
+ id: 'boolean',
+ params: {},
+ },
+ _source: {
+ id: '_source',
+ params: {},
+ },
+ _default_: {
+ id: 'string',
+ params: {},
+ },
+ },
+ metaParamsOptions: {},
+ },
+ },
+ },
+ dependencies: {
+ legacy: {
+ loadingCount$: {
+ _isScalar: false,
+ observers: [
+ {
+ closed: false,
+ _parentOrParents: {
+ closed: false,
+ _parentOrParents: {
+ closed: false,
+ _parentOrParents: {
+ closed: false,
+ _parentOrParents: {
+ closed: false,
+ _parentOrParents: {
+ closed: false,
+ _parentOrParents: {
+ closed: false,
+ _parentOrParents: {
+ closed: false,
+ _parentOrParents: null,
+ _subscriptions: [null],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: true,
+ isStopped: false,
+ destination: {
+ closed: false,
+ _parentOrParents: null,
+ _subscriptions: null,
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: false,
+ destination: {
+ closed: true,
+ },
+ _context: {},
+ },
+ },
+ _subscriptions: [null],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: true,
+ isStopped: false,
+ count: 1,
+ },
+ _subscriptions: [null],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: true,
+ isStopped: false,
+ hasPrev: true,
+ prev: 0,
+ },
+ _subscriptions: [null],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: false,
+ parent: {
+ closed: true,
+ _parentOrParents: null,
+ _subscriptions: null,
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: true,
+ isStopped: true,
+ concurrent: 1,
+ hasCompleted: true,
+ buffer: [],
+ active: 1,
+ index: 2,
+ },
+ },
+ _subscriptions: [null],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: false,
+ parent: {
+ closed: true,
+ _parentOrParents: null,
+ _subscriptions: null,
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: true,
+ concurrent: 1,
+ hasCompleted: true,
+ buffer: [
+ {
+ _isScalar: false,
+ },
+ ],
+ active: 1,
+ index: 1,
+ },
+ },
+ _subscriptions: [
+ {
+ closed: false,
+ _subscriptions: [
+ {
+ closed: false,
+ _subscriptions: null,
+ subject: {
+ _isScalar: false,
+ observers: [
+ {
+ closed: false,
+ _parentOrParents: {
+ closed: false,
+ _parentOrParents: {
+ closed: false,
+ _parentOrParents: {
+ closed: false,
+ _parentOrParents: {
+ closed: false,
+ _parentOrParents: {
+ closed: false,
+ _parentOrParents: {
+ closed: false,
+ _parentOrParents: null,
+ _subscriptions: [null],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: true,
+ isStopped: false,
+ destination: {
+ closed: false,
+ _parentOrParents: null,
+ _subscriptions: null,
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: false,
+ _context: {},
+ },
+ },
+ _subscriptions: [null],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: true,
+ isStopped: false,
+ count: 13,
+ },
+ _subscriptions: [null],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: true,
+ isStopped: false,
+ hasPrev: true,
+ prev: 0,
+ },
+ _subscriptions: [null],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: false,
+ parent: {
+ closed: true,
+ _parentOrParents: null,
+ _subscriptions: null,
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: true,
+ isStopped: true,
+ concurrent: 1,
+ hasCompleted: true,
+ buffer: [],
+ active: 1,
+ index: 2,
+ },
+ },
+ _subscriptions: [null],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: false,
+ parent: {
+ closed: true,
+ _parentOrParents: null,
+ _subscriptions: null,
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: true,
+ concurrent: 1,
+ hasCompleted: true,
+ buffer: [
+ {
+ _isScalar: false,
+ },
+ ],
+ active: 1,
+ index: 1,
+ },
+ },
+ _subscriptions: [
+ null,
+ {
+ closed: false,
+ _subscriptions: [
+ {
+ closed: false,
+ _subscriptions: [
+ {
+ closed: false,
+ _subscriptions: null,
+ subject: {
+ _isScalar: false,
+ observers: [null],
+ closed: false,
+ isStopped: false,
+ hasError: false,
+ thrownError: null,
+ _value: 0,
+ },
+ },
+ ],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: false,
+ hasKey: true,
+ key: 0,
+ },
+ ],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: false,
+ },
+ ],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: false,
+ seenValue: false,
+ },
+ _subscriptions: [
+ {
+ closed: false,
+ _subscriptions: null,
+ },
+ ],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: false,
+ },
+ {
+ closed: false,
+ _parentOrParents: {
+ closed: false,
+ _parentOrParents: {
+ closed: false,
+ _parentOrParents: {
+ closed: false,
+ _parentOrParents: {
+ closed: false,
+ _parentOrParents: {
+ closed: false,
+ _parentOrParents: {
+ closed: false,
+ _parentOrParents: null,
+ _subscriptions: [null],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: true,
+ isStopped: false,
+ destination: {
+ closed: false,
+ _parentOrParents: null,
+ _subscriptions: null,
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: false,
+ _context: {},
+ },
+ },
+ _subscriptions: [null],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: true,
+ isStopped: false,
+ count: 1,
+ },
+ _subscriptions: [null],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: true,
+ isStopped: false,
+ hasPrev: true,
+ prev: 0,
+ },
+ _subscriptions: [null],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: false,
+ parent: {
+ closed: true,
+ _parentOrParents: null,
+ _subscriptions: null,
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: true,
+ isStopped: true,
+ concurrent: 1,
+ hasCompleted: true,
+ buffer: [],
+ active: 1,
+ index: 2,
+ },
+ },
+ _subscriptions: [null],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: false,
+ parent: {
+ closed: true,
+ _parentOrParents: null,
+ _subscriptions: null,
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: true,
+ concurrent: 1,
+ hasCompleted: true,
+ buffer: [
+ {
+ _isScalar: false,
+ },
+ ],
+ active: 1,
+ index: 1,
+ },
+ },
+ _subscriptions: [
+ null,
+ {
+ closed: false,
+ _subscriptions: [
+ {
+ closed: false,
+ _subscriptions: [
+ {
+ closed: false,
+ _subscriptions: null,
+ subject: {
+ _isScalar: false,
+ observers: [null],
+ closed: false,
+ isStopped: false,
+ hasError: false,
+ thrownError: null,
+ _value: 0,
+ },
+ },
+ ],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: false,
+ hasKey: true,
+ key: 0,
+ },
+ ],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: false,
+ },
+ ],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: false,
+ seenValue: false,
+ },
+ _subscriptions: [
+ {
+ closed: false,
+ _subscriptions: null,
+ },
+ ],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: false,
+ },
+ {
+ closed: false,
+ _parentOrParents: {
+ closed: false,
+ _parentOrParents: {
+ closed: false,
+ _parentOrParents: {
+ closed: false,
+ _parentOrParents: {
+ closed: false,
+ _parentOrParents: {
+ closed: false,
+ _parentOrParents: {
+ closed: false,
+ _parentOrParents: null,
+ _subscriptions: [null],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: true,
+ isStopped: false,
+ destination: {
+ closed: false,
+ _parentOrParents: null,
+ _subscriptions: null,
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: false,
+ _context: {},
+ },
+ },
+ _subscriptions: [null],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: true,
+ isStopped: false,
+ count: 1,
+ },
+ _subscriptions: [null],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: true,
+ isStopped: false,
+ hasPrev: true,
+ prev: 0,
+ },
+ _subscriptions: [null],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: false,
+ parent: {
+ closed: true,
+ _parentOrParents: null,
+ _subscriptions: null,
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: true,
+ isStopped: true,
+ concurrent: 1,
+ hasCompleted: true,
+ buffer: [],
+ active: 1,
+ index: 2,
+ },
+ },
+ _subscriptions: [null],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: false,
+ parent: {
+ closed: true,
+ _parentOrParents: null,
+ _subscriptions: null,
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: true,
+ concurrent: 1,
+ hasCompleted: true,
+ buffer: [
+ {
+ _isScalar: false,
+ },
+ ],
+ active: 1,
+ index: 1,
+ },
+ },
+ _subscriptions: [
+ null,
+ {
+ closed: false,
+ _subscriptions: [
+ {
+ closed: false,
+ _subscriptions: [
+ {
+ closed: false,
+ _subscriptions: null,
+ subject: {
+ _isScalar: false,
+ observers: [null],
+ closed: false,
+ isStopped: false,
+ hasError: false,
+ thrownError: null,
+ _value: 0,
+ },
+ },
+ ],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: false,
+ hasKey: true,
+ key: 0,
+ },
+ ],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: false,
+ },
+ ],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: false,
+ seenValue: false,
+ },
+ _subscriptions: [
+ {
+ closed: false,
+ _subscriptions: null,
+ },
+ ],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: false,
+ },
+ {
+ closed: false,
+ _parentOrParents: {
+ closed: false,
+ _parentOrParents: {
+ closed: false,
+ _parentOrParents: {
+ closed: false,
+ _parentOrParents: {
+ closed: false,
+ _parentOrParents: {
+ closed: false,
+ _parentOrParents: {
+ closed: false,
+ _parentOrParents: null,
+ _subscriptions: [null],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: true,
+ isStopped: false,
+ destination: {
+ closed: false,
+ _parentOrParents: null,
+ _subscriptions: null,
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: false,
+ _context: {},
+ },
+ },
+ _subscriptions: [null],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: true,
+ isStopped: false,
+ count: 3,
+ },
+ _subscriptions: [null],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: true,
+ isStopped: false,
+ hasPrev: true,
+ prev: 0,
+ },
+ _subscriptions: [null],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: false,
+ parent: {
+ closed: true,
+ _parentOrParents: null,
+ _subscriptions: null,
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: true,
+ isStopped: true,
+ concurrent: 1,
+ hasCompleted: true,
+ buffer: [],
+ active: 1,
+ index: 2,
+ },
+ },
+ _subscriptions: [null],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: false,
+ parent: {
+ closed: true,
+ _parentOrParents: null,
+ _subscriptions: null,
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: true,
+ concurrent: 1,
+ hasCompleted: true,
+ buffer: [
+ {
+ _isScalar: false,
+ },
+ ],
+ active: 1,
+ index: 1,
+ },
+ },
+ _subscriptions: [
+ null,
+ {
+ closed: false,
+ _subscriptions: [
+ {
+ closed: false,
+ _subscriptions: [
+ {
+ closed: false,
+ _subscriptions: null,
+ subject: {
+ _isScalar: false,
+ observers: [null],
+ closed: false,
+ isStopped: false,
+ hasError: false,
+ thrownError: null,
+ _value: 0,
+ },
+ },
+ ],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: false,
+ hasKey: true,
+ key: 0,
+ },
+ ],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: false,
+ },
+ ],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: false,
+ seenValue: false,
+ },
+ _subscriptions: [
+ {
+ closed: false,
+ _subscriptions: null,
+ },
+ ],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: false,
+ },
+ null,
+ ],
+ closed: false,
+ isStopped: false,
+ hasError: false,
+ thrownError: null,
+ },
+ },
+ ],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: false,
+ },
+ null,
+ ],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: false,
+ seenValue: false,
+ },
+ _subscriptions: [null],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: false,
+ },
+ _subscriptions: [
+ {
+ closed: false,
+ _subscriptions: null,
+ },
+ ],
+ syncErrorValue: null,
+ syncErrorThrown: false,
+ syncErrorThrowable: false,
+ isStopped: false,
+ hasKey: true,
+ key: 0,
+ },
+ ],
+ closed: false,
+ isStopped: false,
+ hasError: false,
+ thrownError: null,
+ _value: 0,
+ },
+ },
+ },
+ },
+ aggs: {
+ typesRegistry: {},
+ getResponseAggs: () => [
+ {
+ id: '1',
+ enabled: true,
+ type: 'sum',
+ params: {
+ field: 'total_quantity',
+ },
+ schema: 'metric',
+ toSerializedFieldFormat: () => ({
+ id: 'number',
+ params: {
+ parsedUrl: {
+ origin: 'http://localhost:5801',
+ pathname: '/app/visualize',
+ basePath: '',
+ },
+ },
+ }),
+ },
+ {
+ id: '2',
+ enabled: true,
+ type: 'date_histogram',
+ params: {
+ field: 'order_date',
+ timeRange: {
+ from: '2020-09-30T12:41:13.795Z',
+ to: '2020-10-15T17:00:00.000Z',
+ },
+ useNormalizedEsInterval: true,
+ scaleMetricValues: false,
+ interval: 'auto',
+ drop_partials: false,
+ min_doc_count: 1,
+ extended_bounds: {},
+ },
+ schema: 'segment',
+ toSerializedFieldFormat: () => ({
+ id: 'date',
+ params: { pattern: 'HH:mm:ss.SSS' },
+ }),
+ },
+ {
+ id: '3',
+ enabled: true,
+ type: 'terms',
+ params: {
+ field: 'category.keyword',
+ orderBy: '1',
+ order: 'desc',
+ size: 5,
+ otherBucket: false,
+ otherBucketLabel: 'Other',
+ missingBucket: false,
+ missingBucketLabel: 'Missing',
+ },
+ schema: 'group',
+ toSerializedFieldFormat: () => ({
+ id: 'terms',
+ params: {
+ id: 'string',
+ otherBucketLabel: 'Other',
+ missingBucketLabel: 'Missing',
+ parsedUrl: {
+ origin: 'http://localhost:5801',
+ pathname: '/app/visualize',
+ basePath: '',
+ },
+ },
+ }),
+ },
+ ],
+ },
+ },
+ isHierarchical: () => false,
+ uiState: {},
+};
diff --git a/src/plugins/vis_type_vislib/public/services.ts b/src/plugins/vis_type_vislib/public/services.ts
index 7257b98f2e9f5..633fae9c7f2a6 100644
--- a/src/plugins/vis_type_vislib/public/services.ts
+++ b/src/plugins/vis_type_vislib/public/services.ts
@@ -19,7 +19,6 @@
import { createGetterSetter } from '../../kibana_utils/public';
import { DataPublicPluginStart } from '../../data/public';
-import { KibanaLegacyStart } from '../../kibana_legacy/public';
export const [getDataActions, setDataActions] = createGetterSetter<
DataPublicPluginStart['actions']
@@ -28,7 +27,3 @@ export const [getDataActions, setDataActions] = createGetterSetter<
export const [getFormatService, setFormatService] = createGetterSetter<
DataPublicPluginStart['fieldFormats']
>('vislib data.fieldFormats');
-
-export const [getKibanaLegacy, setKibanaLegacy] = createGetterSetter(
- 'vislib kibanalegacy'
-);
diff --git a/src/plugins/vis_type_vislib/public/to_ast.test.ts b/src/plugins/vis_type_vislib/public/to_ast.test.ts
new file mode 100644
index 0000000000000..48d3dfe254d0b
--- /dev/null
+++ b/src/plugins/vis_type_vislib/public/to_ast.test.ts
@@ -0,0 +1,60 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { Vis } from '../../visualizations/public';
+import { buildExpression } from '../../expressions/public';
+
+import { BasicVislibParams } from './types';
+import { toExpressionAst } from './to_ast';
+import { sampleAreaVis } from './sample_vis.test.mocks';
+
+jest.mock('../../expressions/public', () => ({
+ ...(jest.requireActual('../../expressions/public') as any),
+ buildExpression: jest.fn().mockImplementation(() => ({
+ toAst: () => ({
+ type: 'expression',
+ chain: [],
+ }),
+ })),
+}));
+
+jest.mock('./to_ast_esaggs', () => ({
+ getEsaggsFn: jest.fn(),
+}));
+
+describe('vislib vis toExpressionAst function', () => {
+ let vis: Vis;
+
+ const params = {
+ timefilter: {},
+ timeRange: {},
+ abortSignal: {},
+ } as any;
+
+ beforeEach(() => {
+ vis = sampleAreaVis as any;
+ });
+
+ it('should match basic snapshot', () => {
+ toExpressionAst(vis, params);
+ const [, builtExpression] = (buildExpression as jest.Mock).mock.calls[0][0];
+
+ expect(builtExpression).toMatchSnapshot();
+ });
+});
diff --git a/src/plugins/vis_type_vislib/public/to_ast.ts b/src/plugins/vis_type_vislib/public/to_ast.ts
new file mode 100644
index 0000000000000..7cd55ccd32ebc
--- /dev/null
+++ b/src/plugins/vis_type_vislib/public/to_ast.ts
@@ -0,0 +1,103 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import moment from 'moment';
+
+import { VisToExpressionAst, getVisSchemas } from '../../visualizations/public';
+import { buildExpression, buildExpressionFunction } from '../../expressions/public';
+
+import { vislibVisName, VisTypeVislibExpressionFunctionDefinition } from './vis_type_vislib_vis_fn';
+import { BasicVislibParams } from './types';
+import {
+ DateHistogramParams,
+ Dimensions,
+ HistogramParams,
+} from './vislib/helpers/point_series/point_series';
+import { getEsaggsFn } from './to_ast_esaggs';
+
+export const toExpressionAst: VisToExpressionAst = async (vis, params) => {
+ const schemas = getVisSchemas(vis, params);
+ const dimensions: Dimensions = {
+ x: schemas.segment ? schemas.segment[0] : null,
+ y: schemas.metric,
+ z: schemas.radius,
+ width: schemas.width,
+ series: schemas.group,
+ splitRow: schemas.split_row,
+ splitColumn: schemas.split_column,
+ };
+
+ const responseAggs = vis.data.aggs?.getResponseAggs() ?? [];
+
+ if (dimensions.x) {
+ const xAgg = responseAggs[dimensions.x.accessor] as any;
+ if (xAgg.type.name === 'date_histogram') {
+ (dimensions.x.params as DateHistogramParams).date = true;
+ const { esUnit, esValue } = xAgg.buckets.getInterval();
+ (dimensions.x.params as DateHistogramParams).intervalESUnit = esUnit;
+ (dimensions.x.params as DateHistogramParams).intervalESValue = esValue;
+ (dimensions.x.params as DateHistogramParams).interval = moment
+ .duration(esValue, esUnit)
+ .asMilliseconds();
+ (dimensions.x.params as DateHistogramParams).format = xAgg.buckets.getScaledDateFormat();
+ (dimensions.x.params as DateHistogramParams).bounds = xAgg.buckets.getBounds();
+ } else if (xAgg.type.name === 'histogram') {
+ const intervalParam = xAgg.type.paramByName('interval');
+ const output = { params: {} as any };
+ await intervalParam.modifyAggConfigOnSearchRequestStart(xAgg, vis.data.searchSource, {
+ abortSignal: params.abortSignal,
+ });
+ intervalParam.write(xAgg, output);
+ (dimensions.x.params as HistogramParams).interval = output.params.interval;
+ }
+ }
+
+ const visConfig = { ...vis.params };
+
+ (dimensions.y || []).forEach((yDimension) => {
+ const yAgg = responseAggs.filter(({ enabled }) => enabled)[yDimension.accessor];
+ const seriesParam = (visConfig.seriesParams || []).find((param) => param.data.id === yAgg.id);
+ if (seriesParam) {
+ const usedValueAxis = (visConfig.valueAxes || []).find(
+ (valueAxis) => valueAxis.id === seriesParam.valueAxis
+ );
+ if (usedValueAxis?.scale.mode === 'percentage') {
+ yDimension.format = { id: 'percent' };
+ }
+ }
+ if (visConfig?.gauge?.percentageMode === true) {
+ yDimension.format = { id: 'percent' };
+ }
+ });
+
+ visConfig.dimensions = dimensions;
+
+ const configStr = JSON.stringify(visConfig).replace(/\\/g, `\\\\`).replace(/'/g, `\\'`);
+ const visTypeXy = buildExpressionFunction(
+ vislibVisName,
+ {
+ type: vis.type.name,
+ visConfig: configStr,
+ }
+ );
+
+ const ast = buildExpression([getEsaggsFn(vis), visTypeXy]);
+
+ return ast.toAst();
+};
diff --git a/src/plugins/vis_type_vislib/public/components/options/index.ts b/src/plugins/vis_type_vislib/public/to_ast_esaggs.ts
similarity index 51%
rename from src/plugins/vis_type_vislib/public/components/options/index.ts
rename to src/plugins/vis_type_vislib/public/to_ast_esaggs.ts
index 57afbd4818ae4..a7312c9d36cbb 100644
--- a/src/plugins/vis_type_vislib/public/components/options/index.ts
+++ b/src/plugins/vis_type_vislib/public/to_ast_esaggs.ts
@@ -17,8 +17,24 @@
* under the License.
*/
-export { GaugeOptions } from './gauge';
-export { PieOptions } from './pie';
-export { PointSeriesOptions } from './point_series';
-export { HeatmapOptions } from './heatmap';
-export { MetricsAxisOptions } from './metrics_axes';
+import { Vis } from '../../visualizations/public';
+import { buildExpressionFunction } from '../../expressions/public';
+import { EsaggsExpressionFunctionDefinition } from '../../data/public';
+
+import { PieVisParams } from './pie';
+import { BasicVislibParams } from './types';
+
+/**
+ * Get esaggs expressions function
+ * TODO: replace this with vis.data.aggs!.toExpressionAst();
+ * @param vis
+ */
+export function getEsaggsFn(vis: Vis | Vis