diff --git a/.backportrc.json b/.backportrc.json
index 0894909d2aac4..87bc3a1be583b 100644
--- a/.backportrc.json
+++ b/.backportrc.json
@@ -25,7 +25,7 @@
],
"targetPRLabels": ["backport"],
"branchLabelMapping": {
- "^v7.8.0$": "7.x",
+ "^v7.9.0$": "7.x",
"^v(\\d+).(\\d+).\\d+$": "$1.$2"
}
}
diff --git a/docs/development/core/server/kibana-plugin-core-server.savedobjectsmigrationlogger.error.md b/docs/development/core/server/kibana-plugin-core-server.savedobjectsmigrationlogger.error.md
new file mode 100644
index 0000000000000..7536cd2b07ae6
--- /dev/null
+++ b/docs/development/core/server/kibana-plugin-core-server.savedobjectsmigrationlogger.error.md
@@ -0,0 +1,11 @@
+
+
+[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [SavedObjectsMigrationLogger](./kibana-plugin-core-server.savedobjectsmigrationlogger.md) > [error](./kibana-plugin-core-server.savedobjectsmigrationlogger.error.md)
+
+## SavedObjectsMigrationLogger.error property
+
+Signature:
+
+```typescript
+error: (msg: string, meta: LogMeta) => void;
+```
diff --git a/docs/development/core/server/kibana-plugin-core-server.savedobjectsmigrationlogger.md b/docs/development/core/server/kibana-plugin-core-server.savedobjectsmigrationlogger.md
index 066643516b213..1b691ee8cb16d 100644
--- a/docs/development/core/server/kibana-plugin-core-server.savedobjectsmigrationlogger.md
+++ b/docs/development/core/server/kibana-plugin-core-server.savedobjectsmigrationlogger.md
@@ -16,6 +16,7 @@ export interface SavedObjectsMigrationLogger
| Property | Type | Description |
| --- | --- | --- |
| [debug](./kibana-plugin-core-server.savedobjectsmigrationlogger.debug.md) | (msg: string) => void
| |
+| [error](./kibana-plugin-core-server.savedobjectsmigrationlogger.error.md) | (msg: string, meta: LogMeta) => void
| |
| [info](./kibana-plugin-core-server.savedobjectsmigrationlogger.info.md) | (msg: string) => void
| |
| [warn](./kibana-plugin-core-server.savedobjectsmigrationlogger.warn.md) | (msg: string) => void
| |
| [warning](./kibana-plugin-core-server.savedobjectsmigrationlogger.warning.md) | (msg: string) => void
| |
diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.iindexpattern.gettimefield.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.iindexpattern.gettimefield.md
new file mode 100644
index 0000000000000..a4d6abcf86a94
--- /dev/null
+++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.iindexpattern.gettimefield.md
@@ -0,0 +1,15 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [IIndexPattern](./kibana-plugin-plugins-data-server.iindexpattern.md) > [getTimeField](./kibana-plugin-plugins-data-server.iindexpattern.gettimefield.md)
+
+## IIndexPattern.getTimeField() method
+
+Signature:
+
+```typescript
+getTimeField?(): IFieldType | undefined;
+```
+Returns:
+
+`IFieldType | undefined`
+
diff --git a/src/core/server/saved_objects/migrations/core/document_migrator.test.ts b/src/core/server/saved_objects/migrations/core/document_migrator.test.ts
index 3ec478e3ca28d..bd10520ca1c57 100644
--- a/src/core/server/saved_objects/migrations/core/document_migrator.test.ts
+++ b/src/core/server/saved_objects/migrations/core/document_migrator.test.ts
@@ -293,7 +293,7 @@ describe('DocumentMigrator', () => {
migrationVersion: { dog: '10.2.0' },
})
).toThrow(
- /Document "smelly" has property "dog" which belongs to a more recent version of Kibana \(10\.2\.0\)/i
+ /Document "smelly" has property "dog" which belongs to a more recent version of Kibana \[10\.2\.0\]\. The last known version is \[undefined\]/i
);
});
@@ -315,7 +315,7 @@ describe('DocumentMigrator', () => {
migrationVersion: { dawg: '1.2.4' },
})
).toThrow(
- /Document "fleabag" has property "dawg" which belongs to a more recent version of Kibana \(1\.2\.4\)/i
+ /Document "fleabag" has property "dawg" which belongs to a more recent version of Kibana \[1\.2\.4\]\. The last known version is \[1\.2\.3\]/i
);
});
diff --git a/src/core/server/saved_objects/migrations/core/document_migrator.ts b/src/core/server/saved_objects/migrations/core/document_migrator.ts
index 4ddb2b070d3ac..07c1da5586107 100644
--- a/src/core/server/saved_objects/migrations/core/document_migrator.ts
+++ b/src/core/server/saved_objects/migrations/core/document_migrator.ts
@@ -350,7 +350,7 @@ function nextUnmigratedProp(doc: SavedObjectUnsanitizedDoc, migrations: ActiveMi
if (docVersion && (!latestVersion || Semver.gt(docVersion, latestVersion))) {
throw Boom.badData(
`Document "${doc.id}" has property "${p}" which belongs to a more recent` +
- ` version of Kibana (${docVersion}).`,
+ ` version of Kibana [${docVersion}]. The last known version is [${latestVersion}]`,
doc
);
}
diff --git a/src/core/server/saved_objects/migrations/core/index_migrator.ts b/src/core/server/saved_objects/migrations/core/index_migrator.ts
index c75fa68572c71..ef2a8870d78d0 100644
--- a/src/core/server/saved_objects/migrations/core/index_migrator.ts
+++ b/src/core/server/saved_objects/migrations/core/index_migrator.ts
@@ -195,7 +195,7 @@ async function migrateSourceToDest(context: Context) {
await Index.write(
callCluster,
dest.indexName,
- migrateRawDocs(serializer, documentMigrator.migrate, docs)
+ migrateRawDocs(serializer, documentMigrator.migrate, docs, log)
);
}
}
diff --git a/src/core/server/saved_objects/migrations/core/migrate_raw_docs.test.ts b/src/core/server/saved_objects/migrations/core/migrate_raw_docs.test.ts
index 89f3fde384848..e55b72be2436d 100644
--- a/src/core/server/saved_objects/migrations/core/migrate_raw_docs.test.ts
+++ b/src/core/server/saved_objects/migrations/core/migrate_raw_docs.test.ts
@@ -21,6 +21,7 @@ import _ from 'lodash';
import { SavedObjectTypeRegistry } from '../../saved_objects_type_registry';
import { SavedObjectsSerializer } from '../../serialization';
import { migrateRawDocs } from './migrate_raw_docs';
+import { createSavedObjectsMigrationLoggerMock } from '../../migrations/mocks';
describe('migrateRawDocs', () => {
test('converts raw docs to saved objects', async () => {
@@ -31,7 +32,8 @@ describe('migrateRawDocs', () => {
[
{ _id: 'a:b', _source: { type: 'a', a: { name: 'AAA' } } },
{ _id: 'c:d', _source: { type: 'c', c: { name: 'DDD' } } },
- ]
+ ],
+ createSavedObjectsMigrationLoggerMock()
);
expect(result).toEqual([
@@ -48,7 +50,8 @@ describe('migrateRawDocs', () => {
expect(transform).toHaveBeenCalled();
});
- test('passes invalid docs through untouched', async () => {
+ test('passes invalid docs through untouched and logs error', async () => {
+ const logger = createSavedObjectsMigrationLoggerMock();
const transform = jest.fn((doc: any) =>
_.set(_.cloneDeep(doc), 'attributes.name', 'TADA')
);
@@ -58,7 +61,8 @@ describe('migrateRawDocs', () => {
[
{ _id: 'foo:b', _source: { type: 'a', a: { name: 'AAA' } } },
{ _id: 'c:d', _source: { type: 'c', c: { name: 'DDD' } } },
- ]
+ ],
+ logger
);
expect(result).toEqual([
@@ -82,5 +86,7 @@ describe('migrateRawDocs', () => {
},
],
]);
+
+ expect(logger.error).toBeCalledTimes(1);
});
});
diff --git a/src/core/server/saved_objects/migrations/core/migrate_raw_docs.ts b/src/core/server/saved_objects/migrations/core/migrate_raw_docs.ts
index 5fe15f40db8ec..49acea82e1c8a 100644
--- a/src/core/server/saved_objects/migrations/core/migrate_raw_docs.ts
+++ b/src/core/server/saved_objects/migrations/core/migrate_raw_docs.ts
@@ -23,6 +23,7 @@
import { SavedObjectsRawDoc, SavedObjectsSerializer } from '../../serialization';
import { TransformFn } from './document_migrator';
+import { SavedObjectsMigrationLogger } from '.';
/**
* Applies the specified migration function to every saved object document in the list
@@ -35,7 +36,8 @@ import { TransformFn } from './document_migrator';
export function migrateRawDocs(
serializer: SavedObjectsSerializer,
migrateDoc: TransformFn,
- rawDocs: SavedObjectsRawDoc[]
+ rawDocs: SavedObjectsRawDoc[],
+ log: SavedObjectsMigrationLogger
): SavedObjectsRawDoc[] {
return rawDocs.map(raw => {
if (serializer.isRawSavedObject(raw)) {
@@ -47,6 +49,10 @@ export function migrateRawDocs(
});
}
+ log.error(
+ `Error: Unable to migrate the corrupt Saved Object document ${raw._id}. To prevent Kibana from performing a migration on every restart, please delete or fix this document by ensuring that the namespace and type in the document's id matches the values in the namespace and type fields.`,
+ { rawDocument: raw }
+ );
return raw;
});
}
diff --git a/src/core/server/saved_objects/migrations/core/migration_coordinator.test.ts b/src/core/server/saved_objects/migrations/core/migration_coordinator.test.ts
index 800edaeaa5885..3f2c31a7c0e5c 100644
--- a/src/core/server/saved_objects/migrations/core/migration_coordinator.test.ts
+++ b/src/core/server/saved_objects/migrations/core/migration_coordinator.test.ts
@@ -19,14 +19,10 @@
import _ from 'lodash';
import { coordinateMigration } from './migration_coordinator';
+import { createSavedObjectsMigrationLoggerMock } from '../mocks';
describe('coordinateMigration', () => {
- const log = {
- debug: jest.fn(),
- warning: jest.fn(),
- warn: jest.fn(),
- info: jest.fn(),
- };
+ const log = createSavedObjectsMigrationLoggerMock();
test('waits for isMigrated, if there is an index conflict', async () => {
const pollInterval = 1;
diff --git a/src/core/server/saved_objects/migrations/core/migration_logger.ts b/src/core/server/saved_objects/migrations/core/migration_logger.ts
index 9dfb3abc8e72d..00ed8bf0b73fc 100644
--- a/src/core/server/saved_objects/migrations/core/migration_logger.ts
+++ b/src/core/server/saved_objects/migrations/core/migration_logger.ts
@@ -17,7 +17,7 @@
* under the License.
*/
-import { Logger } from 'src/core/server/logging';
+import { Logger, LogMeta } from '../../../logging';
/*
* This file provides a helper class for ensuring that all logging
@@ -35,6 +35,7 @@ export interface SavedObjectsMigrationLogger {
*/
warning: (msg: string) => void;
warn: (msg: string) => void;
+ error: (msg: string, meta: LogMeta) => void;
}
export class MigrationLogger implements SavedObjectsMigrationLogger {
@@ -48,4 +49,5 @@ export class MigrationLogger implements SavedObjectsMigrationLogger {
public debug = (msg: string) => this.logger.debug(msg);
public warning = (msg: string) => this.logger.warn(msg);
public warn = (msg: string) => this.logger.warn(msg);
+ public error = (msg: string, meta: LogMeta) => this.logger.error(msg, meta);
}
diff --git a/src/core/server/saved_objects/migrations/kibana/kibana_migrator.ts b/src/core/server/saved_objects/migrations/kibana/kibana_migrator.ts
index dafd6c5341196..7d9ff9bed6d72 100644
--- a/src/core/server/saved_objects/migrations/kibana/kibana_migrator.ts
+++ b/src/core/server/saved_objects/migrations/kibana/kibana_migrator.ts
@@ -22,9 +22,9 @@
* (the shape of the mappings and documents in the index).
*/
-import { Logger } from 'src/core/server/logging';
import { KibanaConfigType } from 'src/core/server/kibana_config';
import { BehaviorSubject } from 'rxjs';
+import { Logger } from '../../../logging';
import { IndexMapping, SavedObjectsTypeMappingDefinitions } from '../../mappings';
import { SavedObjectUnsanitizedDoc, SavedObjectsSerializer } from '../../serialization';
import { docValidator, PropertyValidators } from '../../validation';
diff --git a/src/core/server/saved_objects/migrations/mocks.ts b/src/core/server/saved_objects/migrations/mocks.ts
index 76a890d26bfa0..50a7191393472 100644
--- a/src/core/server/saved_objects/migrations/mocks.ts
+++ b/src/core/server/saved_objects/migrations/mocks.ts
@@ -20,12 +20,13 @@
import { SavedObjectMigrationContext } from './types';
import { SavedObjectsMigrationLogger } from './core';
-const createLoggerMock = (): jest.Mocked => {
+export const createSavedObjectsMigrationLoggerMock = (): jest.Mocked => {
const mock = {
debug: jest.fn(),
info: jest.fn(),
warning: jest.fn(),
warn: jest.fn(),
+ error: jest.fn(),
};
return mock;
@@ -33,7 +34,7 @@ const createLoggerMock = (): jest.Mocked => {
const createContextMock = (): jest.Mocked => {
const mock = {
- log: createLoggerMock(),
+ log: createSavedObjectsMigrationLoggerMock(),
};
return mock;
};
diff --git a/src/core/server/server.api.md b/src/core/server/server.api.md
index bd6046b5ec281..e4234689c25e8 100644
--- a/src/core/server/server.api.md
+++ b/src/core/server/server.api.md
@@ -91,7 +91,6 @@ import { IngestGetPipelineParams } from 'elasticsearch';
import { IngestPutPipelineParams } from 'elasticsearch';
import { IngestSimulateParams } from 'elasticsearch';
import { KibanaConfigType } from 'src/core/server/kibana_config';
-import { Logger as Logger_2 } from 'src/core/server/logging';
import { MGetParams } from 'elasticsearch';
import { MGetResponse } from 'elasticsearch';
import { MSearchParams } from 'elasticsearch';
@@ -2169,6 +2168,8 @@ export interface SavedObjectsMigrationLogger {
// (undocumented)
debug: (msg: string) => void;
// (undocumented)
+ error: (msg: string, meta: LogMeta) => void;
+ // (undocumented)
info: (msg: string) => void;
// (undocumented)
warn: (msg: string) => void;
diff --git a/src/legacy/ui/public/new_platform/new_platform.test.ts b/src/legacy/ui/public/new_platform/new_platform.test.ts
index 1629aac588a61..21e7b559f71f5 100644
--- a/src/legacy/ui/public/new_platform/new_platform.test.ts
+++ b/src/legacy/ui/public/new_platform/new_platform.test.ts
@@ -22,6 +22,7 @@ jest.mock('history');
import { setRootControllerMock, historyMock } from './new_platform.test.mocks';
import { legacyAppRegister, __reset__, __setup__, __start__ } from './new_platform';
import { coreMock } from '../../../../core/public/mocks';
+import { AppMount } from '../../../../core/public';
describe('ui/new_platform', () => {
describe('legacyAppRegister', () => {
@@ -33,7 +34,7 @@ describe('ui/new_platform', () => {
const registerApp = () => {
const unmountMock = jest.fn();
- const mountMock = jest.fn(() => unmountMock);
+ const mountMock = jest.fn, Parameters>(() => unmountMock);
legacyAppRegister({
id: 'test',
title: 'Test',
@@ -62,13 +63,25 @@ describe('ui/new_platform', () => {
controller(scopeMock, elementMock);
expect(mountMock).toHaveBeenCalledWith({
- element: elementMock[0],
+ element: expect.any(HTMLElement),
appBasePath: '/test/base/path/app/test',
onAppLeave: expect.any(Function),
history: historyMock,
});
});
+ test('app is mounted in new div inside containing element', () => {
+ const { mountMock } = registerApp();
+ const controller = setRootControllerMock.mock.calls[0][1];
+ const scopeMock = { $on: jest.fn() };
+ const elementMock = [document.createElement('div')];
+
+ controller(scopeMock, elementMock);
+
+ const { element } = mountMock.mock.calls[0][0];
+ expect(element.parentElement).toEqual(elementMock[0]);
+ });
+
test('controller calls deprecated context app.mount when invoked', () => {
const unmountMock = jest.fn();
// Two arguments changes how this is called.
@@ -84,7 +97,7 @@ describe('ui/new_platform', () => {
controller(scopeMock, elementMock);
expect(mountMock).toHaveBeenCalledWith(expect.any(Object), {
- element: elementMock[0],
+ element: expect.any(HTMLElement),
appBasePath: '/test/base/path/app/test',
onAppLeave: expect.any(Function),
history: historyMock,
diff --git a/src/legacy/ui/public/new_platform/new_platform.ts b/src/legacy/ui/public/new_platform/new_platform.ts
index a15c7cce5511d..1eb46e1a43895 100644
--- a/src/legacy/ui/public/new_platform/new_platform.ts
+++ b/src/legacy/ui/public/new_platform/new_platform.ts
@@ -176,7 +176,8 @@ export const legacyAppRegister = (app: App) => {
legacyAppRegistered = true;
require('ui/chrome').setRootController(app.id, ($scope: IScope, $element: JQLite) => {
- const element = $element[0];
+ const element = document.createElement('div');
+ $element[0].appendChild(element);
// Root controller cannot return a Promise so use an internal async function and call it immediately
(async () => {
diff --git a/src/plugins/dashboard/public/index.ts b/src/plugins/dashboard/public/index.ts
index 44733499cdcba..e093342f95735 100644
--- a/src/plugins/dashboard/public/index.ts
+++ b/src/plugins/dashboard/public/index.ts
@@ -31,7 +31,7 @@ export {
} from './application';
export { DashboardConstants, createDashboardEditUrl } from './dashboard_constants';
-export { DashboardStart } from './plugin';
+export { DashboardStart, DashboardUrlGenerator } from './plugin';
export { DASHBOARD_APP_URL_GENERATOR } from './url_generator';
export function plugin(initializerContext: PluginInitializerContext) {
diff --git a/src/plugins/dashboard/public/plugin.tsx b/src/plugins/dashboard/public/plugin.tsx
index b28822120b31e..894440cfa9cbb 100644
--- a/src/plugins/dashboard/public/plugin.tsx
+++ b/src/plugins/dashboard/public/plugin.tsx
@@ -42,7 +42,11 @@ import {
DataPublicPluginSetup,
esFilters,
} from '../../../plugins/data/public';
-import { SharePluginSetup, SharePluginStart } from '../../../plugins/share/public';
+import {
+ SharePluginSetup,
+ SharePluginStart,
+ UrlGeneratorContract,
+} from '../../../plugins/share/public';
import { UiActionsSetup, UiActionsStart } from '../../../plugins/ui_actions/public';
import { Start as InspectorStartContract } from '../../../plugins/inspector/public';
@@ -77,7 +81,7 @@ import {
import {
DashboardAppLinkGeneratorState,
DASHBOARD_APP_URL_GENERATOR,
- createDirectAccessDashboardLinkGenerator,
+ createDashboardUrlGenerator,
} from './url_generator';
import { createSavedDashboardLoader } from './saved_dashboards';
import { DashboardConstants } from './dashboard_constants';
@@ -89,6 +93,8 @@ declare module '../../share/public' {
}
}
+export type DashboardUrlGenerator = UrlGeneratorContract;
+
interface SetupDependencies {
data: DataPublicPluginSetup;
embeddable: EmbeddableSetup;
@@ -111,8 +117,10 @@ interface StartDependencies {
}
export type Setup = void;
+
export interface DashboardStart {
getSavedDashboardLoader: () => SavedObjectLoader;
+ dashboardUrlGenerator?: DashboardUrlGenerator;
}
declare module '../../../plugins/ui_actions/public' {
@@ -130,6 +138,8 @@ export class DashboardPlugin
private appStateUpdater = new BehaviorSubject(() => ({}));
private stopUrlTracking: (() => void) | undefined = undefined;
+ private dashboardUrlGenerator?: DashboardUrlGenerator;
+
public setup(
core: CoreSetup,
{ share, uiActions, embeddable, home, kibanaLegacy, data, usageCollection }: SetupDependencies
@@ -140,8 +150,8 @@ export class DashboardPlugin
const startServices = core.getStartServices();
if (share) {
- share.urlGenerators.registerUrlGenerator(
- createDirectAccessDashboardLinkGenerator(async () => {
+ this.dashboardUrlGenerator = share.urlGenerators.registerUrlGenerator(
+ createDashboardUrlGenerator(async () => {
const [coreStart, , selfStart] = await startServices;
return {
appBasePath: coreStart.application.getUrlForApp('dashboard'),
@@ -325,6 +335,7 @@ export class DashboardPlugin
});
return {
getSavedDashboardLoader: () => savedDashboardLoader,
+ dashboardUrlGenerator: this.dashboardUrlGenerator,
};
}
diff --git a/src/plugins/dashboard/public/url_generator.test.ts b/src/plugins/dashboard/public/url_generator.test.ts
index 248a3f991d6cb..68d447c4a1336 100644
--- a/src/plugins/dashboard/public/url_generator.test.ts
+++ b/src/plugins/dashboard/public/url_generator.test.ts
@@ -17,7 +17,7 @@
* under the License.
*/
-import { createDirectAccessDashboardLinkGenerator } from './url_generator';
+import { createDashboardUrlGenerator } from './url_generator';
import { hashedItemStore } from '../../kibana_utils/public';
// eslint-disable-next-line
import { mockStorage } from '../../kibana_utils/public/storage/hashed_item_store/mock';
@@ -55,7 +55,7 @@ describe('dashboard url generator', () => {
});
test('creates a link to a saved dashboard', async () => {
- const generator = createDirectAccessDashboardLinkGenerator(() =>
+ const generator = createDashboardUrlGenerator(() =>
Promise.resolve({
appBasePath: APP_BASE_PATH,
useHashedUrl: false,
@@ -67,7 +67,7 @@ describe('dashboard url generator', () => {
});
test('creates a link with global time range set up', async () => {
- const generator = createDirectAccessDashboardLinkGenerator(() =>
+ const generator = createDashboardUrlGenerator(() =>
Promise.resolve({
appBasePath: APP_BASE_PATH,
useHashedUrl: false,
@@ -83,7 +83,7 @@ describe('dashboard url generator', () => {
});
test('creates a link with filters, time range, refresh interval and query to a saved object', async () => {
- const generator = createDirectAccessDashboardLinkGenerator(() =>
+ const generator = createDashboardUrlGenerator(() =>
Promise.resolve({
appBasePath: APP_BASE_PATH,
useHashedUrl: false,
@@ -123,7 +123,7 @@ describe('dashboard url generator', () => {
});
test('if no useHash setting is given, uses the one was start services', async () => {
- const generator = createDirectAccessDashboardLinkGenerator(() =>
+ const generator = createDashboardUrlGenerator(() =>
Promise.resolve({
appBasePath: APP_BASE_PATH,
useHashedUrl: true,
@@ -137,7 +137,7 @@ describe('dashboard url generator', () => {
});
test('can override a false useHash ui setting', async () => {
- const generator = createDirectAccessDashboardLinkGenerator(() =>
+ const generator = createDashboardUrlGenerator(() =>
Promise.resolve({
appBasePath: APP_BASE_PATH,
useHashedUrl: false,
@@ -152,7 +152,7 @@ describe('dashboard url generator', () => {
});
test('can override a true useHash ui setting', async () => {
- const generator = createDirectAccessDashboardLinkGenerator(() =>
+ const generator = createDashboardUrlGenerator(() =>
Promise.resolve({
appBasePath: APP_BASE_PATH,
useHashedUrl: true,
@@ -195,7 +195,7 @@ describe('dashboard url generator', () => {
};
test('attaches filters from destination dashboard', async () => {
- const generator = createDirectAccessDashboardLinkGenerator(() =>
+ const generator = createDashboardUrlGenerator(() =>
Promise.resolve({
appBasePath: APP_BASE_PATH,
useHashedUrl: false,
@@ -224,7 +224,7 @@ describe('dashboard url generator', () => {
});
test("doesn't fail if can't retrieve filters from destination dashboard", async () => {
- const generator = createDirectAccessDashboardLinkGenerator(() =>
+ const generator = createDashboardUrlGenerator(() =>
Promise.resolve({
appBasePath: APP_BASE_PATH,
useHashedUrl: false,
@@ -246,7 +246,7 @@ describe('dashboard url generator', () => {
});
test('can enforce empty filters', async () => {
- const generator = createDirectAccessDashboardLinkGenerator(() =>
+ const generator = createDashboardUrlGenerator(() =>
Promise.resolve({
appBasePath: APP_BASE_PATH,
useHashedUrl: false,
@@ -270,7 +270,7 @@ describe('dashboard url generator', () => {
});
test('no filters in result url if no filters applied', async () => {
- const generator = createDirectAccessDashboardLinkGenerator(() =>
+ const generator = createDashboardUrlGenerator(() =>
Promise.resolve({
appBasePath: APP_BASE_PATH,
useHashedUrl: false,
@@ -288,7 +288,7 @@ describe('dashboard url generator', () => {
});
test('can turn off preserving filters', async () => {
- const generator = createDirectAccessDashboardLinkGenerator(() =>
+ const generator = createDashboardUrlGenerator(() =>
Promise.resolve({
appBasePath: APP_BASE_PATH,
useHashedUrl: false,
diff --git a/src/plugins/dashboard/public/url_generator.ts b/src/plugins/dashboard/public/url_generator.ts
index 6f121ceb2d373..9d66f2df65777 100644
--- a/src/plugins/dashboard/public/url_generator.ts
+++ b/src/plugins/dashboard/public/url_generator.ts
@@ -75,7 +75,7 @@ export type DashboardAppLinkGeneratorState = UrlGeneratorState<{
preserveSavedFilters?: boolean;
}>;
-export const createDirectAccessDashboardLinkGenerator = (
+export const createDashboardUrlGenerator = (
getStartServices: () => Promise<{
appBasePath: string;
useHashedUrl: boolean;
diff --git a/src/plugins/data/server/server.api.md b/src/plugins/data/server/server.api.md
index df4ba23244b4d..1f4076aa12bde 100644
--- a/src/plugins/data/server/server.api.md
+++ b/src/plugins/data/server/server.api.md
@@ -93,8 +93,7 @@ import { IngestGetPipelineParams } from 'elasticsearch';
import { IngestPutPipelineParams } from 'elasticsearch';
import { IngestSimulateParams } from 'elasticsearch';
import { KibanaConfigType as KibanaConfigType_2 } from 'src/core/server/kibana_config';
-import { Logger as Logger_2 } from 'src/core/server/logging';
-import { Logger as Logger_3 } from 'kibana/server';
+import { Logger as Logger_2 } from 'kibana/server';
import { MGetParams } from 'elasticsearch';
import { MGetResponse } from 'elasticsearch';
import moment from 'moment';
diff --git a/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/add_panel_flyout.test.tsx b/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/add_panel_flyout.test.tsx
index 282b0f05891e0..3894d6fbed382 100644
--- a/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/add_panel_flyout.test.tsx
+++ b/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/add_panel_flyout.test.tsx
@@ -18,6 +18,7 @@
*/
import * as React from 'react';
+import { EuiFlyout } from '@elastic/eui';
import { AddPanelFlyout } from './add_panel_flyout';
import {
ContactCardEmbeddableFactory,
@@ -75,6 +76,9 @@ test('createNewEmbeddable() add embeddable to container', async () => {
/>
) as ReactWrapper;
+ // https://github.com/elastic/kibana/issues/64789
+ expect(component.exists(EuiFlyout)).toBe(false);
+
expect(Object.values(container.getInput().panels).length).toBe(0);
component.instance().createNewEmbeddable(CONTACT_CARD_EMBEDDABLE);
await new Promise(r => setTimeout(r, 1));
diff --git a/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/add_panel_flyout.tsx b/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/add_panel_flyout.tsx
index 5bf3f69a95c30..4c23916675e8f 100644
--- a/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/add_panel_flyout.tsx
+++ b/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/add_panel_flyout.tsx
@@ -21,13 +21,7 @@ import { FormattedMessage } from '@kbn/i18n/react';
import React, { ReactElement } from 'react';
import { CoreSetup } from 'src/core/public';
-import {
- EuiContextMenuItem,
- EuiFlyout,
- EuiFlyoutBody,
- EuiFlyoutHeader,
- EuiTitle,
-} from '@elastic/eui';
+import { EuiContextMenuItem, EuiFlyoutBody, EuiFlyoutHeader, EuiTitle } from '@elastic/eui';
import { EmbeddableStart } from 'src/plugins/embeddable/public';
import { IContainer } from '../../../../containers';
@@ -152,7 +146,7 @@ export class AddPanelFlyout extends React.Component {
);
return (
-
+ <>
@@ -161,7 +155,7 @@ export class AddPanelFlyout extends React.Component {
{savedObjectsFinder}
-
+ >
);
}
}
diff --git a/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/open_add_panel_flyout.tsx b/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/open_add_panel_flyout.tsx
index a452e07b51577..867092b78ef7a 100644
--- a/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/open_add_panel_flyout.tsx
+++ b/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/open_add_panel_flyout.tsx
@@ -55,7 +55,8 @@ export async function openAddPanelFlyout(options: {
/>
),
{
- 'data-test-subj': 'addPanelFlyout',
+ 'data-test-subj': 'dashboardAddPanel',
+ ownFocus: true,
}
);
}
diff --git a/src/plugins/share/public/url_generators/url_generator_service.test.ts b/src/plugins/share/public/url_generators/url_generator_service.test.ts
index 4a377db033762..d256dcf5f7aa0 100644
--- a/src/plugins/share/public/url_generators/url_generator_service.test.ts
+++ b/src/plugins/share/public/url_generators/url_generator_service.test.ts
@@ -30,11 +30,11 @@ test('Asking for a generator that does not exist throws an error', () => {
});
test('Registering and retrieving a generator', async () => {
- setup.registerUrlGenerator({
+ const generator = setup.registerUrlGenerator({
id: 'TEST_GENERATOR',
createUrl: () => Promise.resolve('myurl'),
});
- const generator = start.getUrlGenerator('TEST_GENERATOR');
+
expect(generator).toMatchInlineSnapshot(`
Object {
"createUrl": [Function],
@@ -47,6 +47,20 @@ test('Registering and retrieving a generator', async () => {
new Error('You cannot call migrate on a non-deprecated generator.')
);
expect(await generator.createUrl({})).toBe('myurl');
+
+ const retrievedGenerator = start.getUrlGenerator('TEST_GENERATOR');
+ expect(retrievedGenerator).toMatchInlineSnapshot(`
+ Object {
+ "createUrl": [Function],
+ "id": "TEST_GENERATOR",
+ "isDeprecated": false,
+ "migrate": [Function],
+ }
+ `);
+ await expect(generator.migrate({})).rejects.toEqual(
+ new Error('You cannot call migrate on a non-deprecated generator.')
+ );
+ expect(await generator.createUrl({})).toBe('myurl');
});
test('Registering a generator with a createUrl function that is deprecated throws an error', () => {
diff --git a/src/plugins/share/public/url_generators/url_generator_service.ts b/src/plugins/share/public/url_generators/url_generator_service.ts
index 332750671cee3..13c1b94acdd07 100644
--- a/src/plugins/share/public/url_generators/url_generator_service.ts
+++ b/src/plugins/share/public/url_generators/url_generator_service.ts
@@ -28,7 +28,9 @@ export interface UrlGeneratorsStart {
}
export interface UrlGeneratorsSetup {
- registerUrlGenerator: (generator: UrlGeneratorsDefinition) => void;
+ registerUrlGenerator: (
+ generator: UrlGeneratorsDefinition
+ ) => UrlGeneratorContract;
}
export class UrlGeneratorsService implements Plugin {
@@ -43,10 +45,9 @@ export class UrlGeneratorsService implements Plugin(
generatorOptions: UrlGeneratorsDefinition
) => {
- this.urlGenerators.set(
- generatorOptions.id,
- new UrlGeneratorInternal(generatorOptions, this.getUrlGenerator)
- );
+ const generator = new UrlGeneratorInternal(generatorOptions, this.getUrlGenerator);
+ this.urlGenerators.set(generatorOptions.id, generator);
+ return generator.getPublicContract();
},
};
return setup;
diff --git a/src/plugins/vis_type_table/public/components/table_vis_options.tsx b/src/plugins/vis_type_table/public/components/table_vis_options.tsx
index 68348d5ef1060..837d478535936 100644
--- a/src/plugins/vis_type_table/public/components/table_vis_options.tsx
+++ b/src/plugins/vis_type_table/public/components/table_vis_options.tsx
@@ -147,5 +147,6 @@ function TableOptions({
);
}
-
-export { TableOptions };
+// default export required for React.Lazy
+// eslint-disable-next-line import/no-default-export
+export { TableOptions as default };
diff --git a/src/plugins/vis_type_table/public/components/table_vis_options_lazy.tsx b/src/plugins/vis_type_table/public/components/table_vis_options_lazy.tsx
new file mode 100644
index 0000000000000..ca273aa771ef1
--- /dev/null
+++ b/src/plugins/vis_type_table/public/components/table_vis_options_lazy.tsx
@@ -0,0 +1,30 @@
+/*
+ * 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, Suspense } from 'react';
+import { EuiLoadingSpinner } from '@elastic/eui';
+import { VisOptionsProps } from 'src/plugins/vis_default_editor/public';
+import { TableVisParams } from '../types';
+
+const TableOptionsComponent = lazy(() => import('./table_vis_options'));
+
+export const TableOptions = (props: VisOptionsProps) => (
+ }>
+
+
+);
diff --git a/src/plugins/vis_type_table/public/table_vis_type.ts b/src/plugins/vis_type_table/public/table_vis_type.ts
index 26e5ac8cfd71a..c3bc72497007e 100644
--- a/src/plugins/vis_type_table/public/table_vis_type.ts
+++ b/src/plugins/vis_type_table/public/table_vis_type.ts
@@ -24,7 +24,7 @@ import { Vis } from '../../visualizations/public';
import { tableVisResponseHandler } from './table_vis_response_handler';
// @ts-ignore
import tableVisTemplate from './table_vis.html';
-import { TableOptions } from './components/table_vis_options';
+import { TableOptions } from './components/table_vis_options_lazy';
import { getTableVisualizationControllerClass } from './vis_controller';
export function getTableVisTypeDefinition(core: CoreSetup, context: PluginInitializerContext) {
diff --git a/x-pack/plugins/dashboard_enhanced/public/plugin.ts b/x-pack/plugins/dashboard_enhanced/public/plugin.ts
index 772e032289bce..c258a4148f84a 100644
--- a/x-pack/plugins/dashboard_enhanced/public/plugin.ts
+++ b/x-pack/plugins/dashboard_enhanced/public/plugin.ts
@@ -11,6 +11,7 @@ import { DashboardDrilldownsService } from './services';
import { DataPublicPluginStart } from '../../../../src/plugins/data/public';
import { AdvancedUiActionsSetup, AdvancedUiActionsStart } from '../../advanced_ui_actions/public';
import { DrilldownsSetup, DrilldownsStart } from '../../drilldowns/public';
+import { DashboardStart } from '../../../../src/plugins/dashboard/public';
export interface SetupDependencies {
advancedUiActions: AdvancedUiActionsSetup;
@@ -25,6 +26,7 @@ export interface StartDependencies {
drilldowns: DrilldownsStart;
embeddable: EmbeddableStart;
share: SharePluginStart;
+ dashboard: DashboardStart;
}
// eslint-disable-next-line
diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_drilldowns_services.ts b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_drilldowns_services.ts
index 0161836b2c5b9..f5926cd6961c2 100644
--- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_drilldowns_services.ts
+++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_drilldowns_services.ts
@@ -44,6 +44,12 @@ export class DashboardDrilldownsService {
{ advancedUiActions: uiActions }: SetupDependencies
) {
const start = createStartServicesGetter(core.getStartServices);
+ const getDashboardUrlGenerator = () => {
+ const urlGenerator = start().plugins.dashboard.dashboardUrlGenerator;
+ if (!urlGenerator)
+ throw new Error('dashboardUrlGenerator is required for dashboard to dashboard drilldown');
+ return urlGenerator;
+ };
const actionFlyoutCreateDrilldown = new FlyoutCreateDrilldownAction({ start });
uiActions.addTriggerAction(CONTEXT_MENU_TRIGGER, actionFlyoutCreateDrilldown);
@@ -51,7 +57,10 @@ export class DashboardDrilldownsService {
const actionFlyoutEditDrilldown = new FlyoutEditDrilldownAction({ start });
uiActions.addTriggerAction(CONTEXT_MENU_TRIGGER, actionFlyoutEditDrilldown);
- const dashboardToDashboardDrilldown = new DashboardToDashboardDrilldown({ start });
+ const dashboardToDashboardDrilldown = new DashboardToDashboardDrilldown({
+ start,
+ getDashboardUrlGenerator,
+ });
uiActions.registerDrilldown(dashboardToDashboardDrilldown);
}
}
diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.test.tsx b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.test.tsx
index 18ee95cb57b3b..d8465562f9302 100644
--- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.test.tsx
+++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.test.tsx
@@ -5,8 +5,7 @@
*/
import { DashboardToDashboardDrilldown } from './drilldown';
-import { UrlGeneratorContract } from '../../../../../../../src/plugins/share/public';
-import { savedObjectsServiceMock } from '../../../../../../../src/core/public/mocks';
+import { savedObjectsServiceMock, coreMock } from '../../../../../../../src/core/public/mocks';
import { dataPluginMock } from '../../../../../../../src/plugins/data/public/mocks';
import { ActionContext, Config } from './types';
import {
@@ -19,15 +18,16 @@ import {
import { esFilters } from '../../../../../../../src/plugins/data/public';
// convenient to use real implementation here.
-import { createDirectAccessDashboardLinkGenerator } from '../../../../../../../src/plugins/dashboard/public/url_generator';
+import { createDashboardUrlGenerator } from '../../../../../../../src/plugins/dashboard/public/url_generator';
+import { UrlGeneratorsService } from '../../../../../../../src/plugins/share/public/url_generators';
import { VisualizeEmbeddableContract } from '../../../../../../../src/plugins/visualizations/public';
import {
RangeSelectTriggerContext,
ValueClickTriggerContext,
} from '../../../../../../../src/plugins/embeddable/public';
+import { StartDependencies } from '../../../plugin';
import { SavedObjectLoader } from '../../../../../../../src/plugins/saved_objects/public';
import { StartServicesGetter } from '../../../../../../../src/plugins/kibana_utils/public/core';
-import { StartDependencies } from '../../../plugin';
describe('.isConfigValid()', () => {
const drilldown = new DashboardToDashboardDrilldown({} as any);
@@ -105,23 +105,19 @@ describe('.execute() & getHref', () => {
data: {
actions: dataPluginActions,
},
- share: {
- urlGenerators: {
- getUrlGenerator: () =>
- createDirectAccessDashboardLinkGenerator(() =>
- Promise.resolve({
- appBasePath: 'test',
- useHashedUrl: false,
- savedDashboardLoader: ({} as unknown) as SavedObjectLoader,
- })
- ) as UrlGeneratorContract,
- },
- },
},
self: {},
- })) as unknown) as StartServicesGetter<
- Pick
- >,
+ })) as unknown) as StartServicesGetter>,
+ getDashboardUrlGenerator: () =>
+ new UrlGeneratorsService().setup(coreMock.createSetup()).registerUrlGenerator(
+ createDashboardUrlGenerator(() =>
+ Promise.resolve({
+ appBasePath: 'test',
+ useHashedUrl: false,
+ savedDashboardLoader: ({} as unknown) as SavedObjectLoader,
+ })
+ )
+ ),
});
const selectRangeFiltersSpy = jest
.spyOn(dataPluginActions, 'createFiltersFromRangeSelectAction')
diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx
index 848e77384f7f0..6d83b8443a828 100644
--- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx
+++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx
@@ -6,7 +6,7 @@
import React from 'react';
import { reactToUiComponent } from '../../../../../../../src/plugins/kibana_react/public';
-import { DASHBOARD_APP_URL_GENERATOR } from '../../../../../../../src/plugins/dashboard/public';
+import { DashboardUrlGenerator } from '../../../../../../../src/plugins/dashboard/public';
import { ActionContext, Config } from './types';
import { CollectConfigContainer } from './components';
import { DASHBOARD_TO_DASHBOARD_DRILLDOWN } from './constants';
@@ -22,7 +22,8 @@ import { StartServicesGetter } from '../../../../../../../src/plugins/kibana_uti
import { StartDependencies } from '../../../plugin';
export interface Params {
- start: StartServicesGetter>;
+ start: StartServicesGetter>;
+ getDashboardUrlGenerator: () => DashboardUrlGenerator;
}
export class DashboardToDashboardDrilldown
@@ -142,9 +143,7 @@ export class DashboardToDashboardDrilldown
}
}
- const { plugins } = this.params.start();
-
- return plugins.share.urlGenerators.getUrlGenerator(DASHBOARD_APP_URL_GENERATOR).createUrl({
+ return this.params.getDashboardUrlGenerator().createUrl({
dashboardId: config.dashboardId,
query: config.useCurrentFilters ? query : undefined,
timeRange,
diff --git a/x-pack/plugins/drilldowns/public/components/connected_flyout_manage_drilldowns/connected_flyout_manage_drilldowns.tsx b/x-pack/plugins/drilldowns/public/components/connected_flyout_manage_drilldowns/connected_flyout_manage_drilldowns.tsx
index 0d4a67e325e4d..5ebda079a15bf 100644
--- a/x-pack/plugins/drilldowns/public/components/connected_flyout_manage_drilldowns/connected_flyout_manage_drilldowns.tsx
+++ b/x-pack/plugins/drilldowns/public/components/connected_flyout_manage_drilldowns/connected_flyout_manage_drilldowns.tsx
@@ -289,8 +289,8 @@ function useDrilldownsStateManager(
await run(async () => {
await actionManager.createEvent(action, selectedTriggers);
notifications.toasts.addSuccess({
- title: toastDrilldownCreated.title,
- text: toastDrilldownCreated.text(action.name),
+ title: toastDrilldownCreated.title(action.name),
+ text: toastDrilldownCreated.text,
});
});
}
@@ -303,8 +303,8 @@ function useDrilldownsStateManager(
await run(async () => {
await actionManager.updateEvent(drilldownId, action, selectedTriggers);
notifications.toasts.addSuccess({
- title: toastDrilldownEdited.title,
- text: toastDrilldownEdited.text(action.name),
+ title: toastDrilldownEdited.title(action.name),
+ text: toastDrilldownEdited.text,
});
});
}
@@ -320,8 +320,8 @@ function useDrilldownsStateManager(
text: toastDrilldownDeleted.text,
}
: {
- title: toastDrilldownsDeleted.title,
- text: toastDrilldownsDeleted.text(drilldownIds.length),
+ title: toastDrilldownsDeleted.title(drilldownIds.length),
+ text: toastDrilldownsDeleted.text,
}
);
});
diff --git a/x-pack/plugins/drilldowns/public/components/connected_flyout_manage_drilldowns/i18n.ts b/x-pack/plugins/drilldowns/public/components/connected_flyout_manage_drilldowns/i18n.ts
index 31384860786ef..851439eccbe7e 100644
--- a/x-pack/plugins/drilldowns/public/components/connected_flyout_manage_drilldowns/i18n.ts
+++ b/x-pack/plugins/drilldowns/public/components/connected_flyout_manage_drilldowns/i18n.ts
@@ -7,35 +7,41 @@
import { i18n } from '@kbn/i18n';
export const toastDrilldownCreated = {
- title: i18n.translate(
- 'xpack.drilldowns.components.flyoutDrilldownWizard.toast.drilldownCreatedTitle',
+ title: (drilldownName: string) =>
+ i18n.translate(
+ 'xpack.drilldowns.components.flyoutDrilldownWizard.toast.drilldownCreatedTitle',
+ {
+ defaultMessage: 'Drilldown "{drilldownName}" created',
+ values: {
+ drilldownName,
+ },
+ }
+ ),
+ text: i18n.translate(
+ 'xpack.drilldowns.components.flyoutDrilldownWizard.toast.drilldownCreatedText',
{
- defaultMessage: 'Drilldown created',
+ // TODO: remove `Save your dashboard before testing.` part
+ // when drilldowns are used not only in dashboard
+ // or after https://github.com/elastic/kibana/issues/65179 implemented
+ defaultMessage: 'Save your dashboard before testing.',
}
),
- text: (drilldownName: string) =>
- i18n.translate('xpack.drilldowns.components.flyoutDrilldownWizard.toast.drilldownCreatedText', {
- defaultMessage: 'You created "{drilldownName}". Save dashboard before testing.',
- values: {
- drilldownName,
- },
- }),
};
export const toastDrilldownEdited = {
- title: i18n.translate(
- 'xpack.drilldowns.components.flyoutDrilldownWizard.toast.drilldownEditedTitle',
- {
- defaultMessage: 'Drilldown edited',
- }
- ),
- text: (drilldownName: string) =>
- i18n.translate('xpack.drilldowns.components.flyoutDrilldownWizard.toast.drilldownEditedText', {
- defaultMessage: 'You edited "{drilldownName}". Save dashboard before testing.',
+ title: (drilldownName: string) =>
+ i18n.translate('xpack.drilldowns.components.flyoutDrilldownWizard.toast.drilldownEditedTitle', {
+ defaultMessage: 'Drilldown "{drilldownName}" updated',
values: {
drilldownName,
},
}),
+ text: i18n.translate(
+ 'xpack.drilldowns.components.flyoutDrilldownWizard.toast.drilldownEditedText',
+ {
+ defaultMessage: 'Save your dashboard before testing.',
+ }
+ ),
};
export const toastDrilldownDeleted = {
@@ -48,28 +54,26 @@ export const toastDrilldownDeleted = {
text: i18n.translate(
'xpack.drilldowns.components.flyoutDrilldownWizard.toast.drilldownDeletedText',
{
- defaultMessage: 'You deleted a drilldown.',
+ defaultMessage: 'Save your dashboard before testing.',
}
),
};
export const toastDrilldownsDeleted = {
- title: i18n.translate(
- 'xpack.drilldowns.components.flyoutDrilldownWizard.toast.drilldownsDeletedTitle',
- {
- defaultMessage: 'Drilldowns deleted',
- }
- ),
- text: (n: number) =>
+ title: (n: number) =>
i18n.translate(
- 'xpack.drilldowns.components.flyoutDrilldownWizard.toast.drilldownsDeletedText',
+ 'xpack.drilldowns.components.flyoutDrilldownWizard.toast.drilldownsDeletedTitle',
{
- defaultMessage: 'You deleted {n} drilldowns',
- values: {
- n,
- },
+ defaultMessage: '{n} drilldowns deleted',
+ values: { n },
}
),
+ text: i18n.translate(
+ 'xpack.drilldowns.components.flyoutDrilldownWizard.toast.drilldownsDeletedText',
+ {
+ defaultMessage: 'Save your dashboard before testing.',
+ }
+ ),
};
export const toastDrilldownsCRUDError = i18n.translate(
@@ -79,10 +83,3 @@ export const toastDrilldownsCRUDError = i18n.translate(
description: 'Title for generic error toast when persisting drilldown updates failed',
}
);
-
-export const toastDrilldownsFetchError = i18n.translate(
- 'xpack.drilldowns.components.flyoutDrilldownWizard.toast.drilldownsFetchErrorTitle',
- {
- defaultMessage: 'Error fetching drilldowns',
- }
-);
diff --git a/x-pack/plugins/drilldowns/public/components/drilldown_hello_bar/i18n.ts b/x-pack/plugins/drilldowns/public/components/drilldown_hello_bar/i18n.ts
index 63dc95dabc0fb..622376c5b40ad 100644
--- a/x-pack/plugins/drilldowns/public/components/drilldown_hello_bar/i18n.ts
+++ b/x-pack/plugins/drilldowns/public/components/drilldown_hello_bar/i18n.ts
@@ -10,7 +10,7 @@ export const txtHelpText = i18n.translate(
'xpack.drilldowns.components.DrilldownHelloBar.helpText',
{
defaultMessage:
- 'Drilldowns provide the ability to define a new behavior when interacting with a panel. You can add multiple options or simply override the default filtering behavior.',
+ 'Drilldowns enable you to define new behaviors for interacting with panels. You can add multiple actions and override the default filter.',
}
);
diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/components/package_list_grid.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/components/package_list_grid.tsx
index 818b365d5be12..2f06d1d8703c2 100644
--- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/components/package_list_grid.tsx
+++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/components/package_list_grid.tsx
@@ -13,6 +13,7 @@ import {
// @ts-ignore
EuiSearchBar,
EuiText,
+ Query,
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
@@ -35,9 +36,28 @@ export function PackageListGrid({
list,
showInstalledBadge,
}: ListProps) {
+ const initialQuery = EuiSearchBar.Query.MATCH_ALL;
+
+ const [query, setQuery] = useState(initialQuery);
const [searchTerm, setSearchTerm] = useState('');
const localSearchRef = useLocalSearch(list);
+ const onQueryChange = ({
+ // eslint-disable-next-line no-shadow
+ query,
+ queryText: userInput,
+ error,
+ }: {
+ query: Query | null;
+ queryText: string;
+ error: { message: string } | null;
+ }) => {
+ if (!error) {
+ setQuery(query);
+ setSearchTerm(userInput);
+ }
+ };
+
const controlsContent = ;
let gridContent: JSX.Element;
@@ -59,16 +79,14 @@ export function PackageListGrid({
{controlsContent}
{
- setSearchTerm(userInput);
- }}
+ onChange={onQueryChange}
/>
{gridContent}
diff --git a/x-pack/plugins/ingest_manager/server/routes/enrollment_api_key/handler.ts b/x-pack/plugins/ingest_manager/server/routes/enrollment_api_key/handler.ts
index 9d3eb5360dbe3..94fc6de609613 100644
--- a/x-pack/plugins/ingest_manager/server/routes/enrollment_api_key/handler.ts
+++ b/x-pack/plugins/ingest_manager/server/routes/enrollment_api_key/handler.ts
@@ -58,6 +58,12 @@ export const postEnrollmentApiKeyHandler: RequestHandler<
return response.ok({ body });
} catch (e) {
+ if (e.isBoom) {
+ return response.customError({
+ statusCode: e.output.statusCode,
+ body: { message: e.message },
+ });
+ }
return response.customError({
statusCode: 500,
body: { message: e.message },
diff --git a/x-pack/plugins/ingest_manager/server/services/api_keys/enrollment_api_key.ts b/x-pack/plugins/ingest_manager/server/services/api_keys/enrollment_api_key.ts
index 1ac812c3380cd..3b003f47eb6f9 100644
--- a/x-pack/plugins/ingest_manager/server/services/api_keys/enrollment_api_key.ts
+++ b/x-pack/plugins/ingest_manager/server/services/api_keys/enrollment_api_key.ts
@@ -5,6 +5,7 @@
*/
import uuid from 'uuid';
+import Boom from 'boom';
import { SavedObjectsClientContract, SavedObject } from 'src/core/server';
import { EnrollmentAPIKey, EnrollmentAPIKeySOAttributes } from '../../types';
import { ENROLLMENT_API_KEYS_SAVED_OBJECT_TYPE } from '../../constants';
@@ -106,6 +107,9 @@ export async function generateEnrollmentAPIKey(
) {
const id = uuid.v4();
const { name: providedKeyName } = data;
+ if (data.configId) {
+ await validateConfigId(soClient, data.configId);
+ }
const configId = data.configId ?? (await agentConfigService.getDefaultAgentConfigId(soClient));
const name = providedKeyName ? `${providedKeyName} (${id})` : id;
const key = await createAPIKey(soClient, name, {
@@ -143,6 +147,17 @@ export async function generateEnrollmentAPIKey(
return getEnrollmentAPIKey(soClient, so.id);
}
+async function validateConfigId(soClient: SavedObjectsClientContract, configId: string) {
+ try {
+ await agentConfigService.get(soClient, configId);
+ } catch (e) {
+ if (e.isBoom && e.output.statusCode === 404) {
+ throw Boom.badRequest(`Agent config ${configId} does not exist`);
+ }
+ throw e;
+ }
+}
+
function savedObjectToEnrollmentApiKey({
error,
attributes,
diff --git a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/create_watch_flyout/create_watch_service.js b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/create_watch_flyout/create_watch_service.js
index 29e89022a5502..2a65ee06f2c2c 100644
--- a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/create_watch_flyout/create_watch_service.js
+++ b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/create_watch_flyout/create_watch_service.js
@@ -157,6 +157,7 @@ class CreateWatchService {
id,
type: 'json',
isNew: false, // Set to false, as we want to allow watches to be overwritten.
+ isActive: true,
watch,
},
};
diff --git a/x-pack/plugins/ml/server/models/job_validation/job_validation.test.ts b/x-pack/plugins/ml/server/models/job_validation/job_validation.test.ts
index ca127f43d08af..d907677855c12 100644
--- a/x-pack/plugins/ml/server/models/job_validation/job_validation.test.ts
+++ b/x-pack/plugins/ml/server/models/job_validation/job_validation.test.ts
@@ -14,6 +14,13 @@ const callWithRequest: APICaller = (method: string) => {
if (method === 'fieldCaps') {
resolve({ fields: [] });
return;
+ } else if (method === 'ml.info') {
+ resolve({
+ limits: {
+ effective_max_model_memory_limit: '100MB',
+ max_model_memory_limit: '1GB',
+ },
+ });
}
resolve({});
}) as Promise;
@@ -291,7 +298,7 @@ describe('ML - validateJob', () => {
});
// Failing https://github.com/elastic/kibana/issues/65865
- it.skip('basic validation passes, extended checks return some messages', () => {
+ it('basic validation passes, extended checks return some messages', () => {
const payload = getBasicPayload();
return validateJob(callWithRequest, payload).then(messages => {
const ids = messages.map(m => m.id);
@@ -305,7 +312,7 @@ describe('ML - validateJob', () => {
});
// Failing https://github.com/elastic/kibana/issues/65866
- it.skip('categorization job using mlcategory passes aggregatable field check', () => {
+ it('categorization job using mlcategory passes aggregatable field check', () => {
const payload: any = {
job: {
job_id: 'categorization_test',
@@ -372,7 +379,7 @@ describe('ML - validateJob', () => {
});
// Failing https://github.com/elastic/kibana/issues/65867
- it.skip('script field not reported as non aggregatable', () => {
+ it('script field not reported as non aggregatable', () => {
const payload: any = {
job: {
job_id: 'categorization_test',
diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.tsx
index 3440bb28b2468..8511ab468ca80 100644
--- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.tsx
+++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.tsx
@@ -127,26 +127,27 @@ export const AlertDetails: React.FunctionComponent = ({
defaultMessage="Edit"
/>
-
-
-
+ {editFlyoutVisible && (
+
+ setEditFlyoutVisibility(false)}
+ />
+
+ )}
) : null}
diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_edit.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_edit.test.tsx
index 722db146a54ce..4d8801d8b7484 100644
--- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_edit.test.tsx
+++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_edit.test.tsx
@@ -131,11 +131,7 @@ describe('alert_edit', () => {
capabilities: deps!.capabilities,
}}
>
- {}}
- initialAlert={alert}
- />
+ {}} initialAlert={alert} />
);
diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_edit.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_edit.tsx
index 00bc9874face1..747464d2212f4 100644
--- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_edit.tsx
+++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_edit.tsx
@@ -31,15 +31,10 @@ import { PLUGIN } from '../../constants/plugin';
interface AlertEditProps {
initialAlert: Alert;
- editFlyoutVisible: boolean;
- setEditFlyoutVisibility: React.Dispatch>;
+ onClose(): void;
}
-export const AlertEdit = ({
- initialAlert,
- editFlyoutVisible,
- setEditFlyoutVisibility,
-}: AlertEditProps) => {
+export const AlertEdit = ({ initialAlert, onClose }: AlertEditProps) => {
const [{ alert }, dispatch] = useReducer(alertReducer, { alert: initialAlert });
const [isSaving, setIsSaving] = useState(false);
const [hasActionsDisabled, setHasActionsDisabled] = useState(false);
@@ -57,14 +52,10 @@ export const AlertEdit = ({
} = useAlertsContext();
const closeFlyout = useCallback(() => {
- setEditFlyoutVisibility(false);
+ onClose();
setAlert('alert', initialAlert);
// eslint-disable-next-line react-hooks/exhaustive-deps
- }, [setEditFlyoutVisibility]);
-
- if (!editFlyoutVisible) {
- return null;
- }
+ }, [onClose]);
const alertType = alertTypeRegistry.get(alert.alertTypeId);
diff --git a/x-pack/plugins/uptime/common/translations.ts b/x-pack/plugins/uptime/common/translations.ts
new file mode 100644
index 0000000000000..678fe7cb1f984
--- /dev/null
+++ b/x-pack/plugins/uptime/common/translations.ts
@@ -0,0 +1,14 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { i18n } from '@kbn/i18n';
+
+export const VALUE_MUST_BE_GREATER_THEN_ZEO = i18n.translate(
+ 'xpack.uptime.settings.invalid.error',
+ {
+ defaultMessage: 'Value must be greater than 0.',
+ }
+);
diff --git a/x-pack/plugins/uptime/public/components/settings/certificate_form.tsx b/x-pack/plugins/uptime/public/components/settings/certificate_form.tsx
index 5bfd26f7c6401..8200e8292cd98 100644
--- a/x-pack/plugins/uptime/public/components/settings/certificate_form.tsx
+++ b/x-pack/plugins/uptime/public/components/settings/certificate_form.tsx
@@ -59,7 +59,7 @@ export const CertificateExpirationForm: React.FC = ({
>
= ({
}}
/>
}
- isInvalid={!!fieldErrors?.certificatesThresholds?.expirationThresholdError}
+ isInvalid={!!fieldErrors?.expirationThresholdError}
label={
= ({
= ({
= ({
}}
/>
}
- isInvalid={!!fieldErrors?.certificatesThresholds?.ageThresholdError}
+ isInvalid={!!fieldErrors?.ageThresholdError}
label={
= ({
+ onChange={({ currentTarget: { value } }) =>
onChange({
- certAgeThreshold: Number(e.currentTarget.value),
+ certAgeThreshold: Number(value),
})
}
/>
diff --git a/x-pack/plugins/uptime/public/pages/settings.tsx b/x-pack/plugins/uptime/public/pages/settings.tsx
index 7ed9cf4444343..d018567ae1104 100644
--- a/x-pack/plugins/uptime/public/pages/settings.tsx
+++ b/x-pack/plugins/uptime/public/pages/settings.tsx
@@ -32,13 +32,12 @@ import {
OnFieldChangeType,
} from '../components/settings/certificate_form';
import * as Translations from './translations';
+import { VALUE_MUST_BE_GREATER_THEN_ZEO } from '../../common/translations';
interface SettingsPageFieldErrors {
- heartbeatIndices: 'May not be blank' | '';
- certificatesThresholds: {
- expirationThresholdError: string | null;
- ageThresholdError: string | null;
- } | null;
+ heartbeatIndices: string | '';
+ expirationThresholdError?: string;
+ ageThresholdError?: string;
}
export interface SettingsFormProps {
@@ -49,22 +48,28 @@ export interface SettingsFormProps {
isDisabled: boolean;
}
+const isValidCertVal = (val: string | number) => {
+ if (val === '') {
+ return Translations.BLANK_STR;
+ }
+ if (val === 0) {
+ return VALUE_MUST_BE_GREATER_THEN_ZEO;
+ }
+};
+
const getFieldErrors = (formFields: DynamicSettings | null): SettingsPageFieldErrors | null => {
if (formFields) {
- const blankStr = 'May not be blank';
const { certAgeThreshold, certExpirationThreshold, heartbeatIndices } = formFields;
- const heartbeatIndErr = heartbeatIndices.match(/^\S+$/) ? '' : blankStr;
- const expirationThresholdError = certExpirationThreshold ? null : blankStr;
- const ageThresholdError = certAgeThreshold ? null : blankStr;
+
+ const indError = heartbeatIndices.match(/^\S+$/) ? '' : Translations.BLANK_STR;
+
+ const expError = isValidCertVal(certExpirationThreshold);
+ const ageError = isValidCertVal(certAgeThreshold);
+
return {
- heartbeatIndices: heartbeatIndErr,
- certificatesThresholds:
- expirationThresholdError || ageThresholdError
- ? {
- expirationThresholdError,
- ageThresholdError,
- }
- : null,
+ heartbeatIndices: indError,
+ expirationThresholdError: expError,
+ ageThresholdError: ageError,
};
}
return null;
diff --git a/x-pack/plugins/uptime/public/pages/translations.ts b/x-pack/plugins/uptime/public/pages/translations.ts
index 74fb2eeb1416b..8ed5503235884 100644
--- a/x-pack/plugins/uptime/public/pages/translations.ts
+++ b/x-pack/plugins/uptime/public/pages/translations.ts
@@ -36,3 +36,7 @@ export const settings = {
defaultMessage: 'Return to overview',
}),
};
+
+export const BLANK_STR = i18n.translate('xpack.uptime.settings.blank.error', {
+ defaultMessage: 'May not be blank.',
+});
diff --git a/x-pack/plugins/uptime/server/rest_api/dynamic_settings.ts b/x-pack/plugins/uptime/server/rest_api/dynamic_settings.ts
index 31833a25ee8ac..c7d532d932aa6 100644
--- a/x-pack/plugins/uptime/server/rest_api/dynamic_settings.ts
+++ b/x-pack/plugins/uptime/server/rest_api/dynamic_settings.ts
@@ -11,6 +11,7 @@ import { UMServerLibs } from '../lib/lib';
import { DynamicSettings, DynamicSettingsType } from '../../common/runtime_types';
import { UMRestApiRouteFactory } from '.';
import { savedObjectsAdapter } from '../lib/saved_objects';
+import { VALUE_MUST_BE_GREATER_THEN_ZEO } from '../../common/translations';
export const createGetDynamicSettingsRoute: UMRestApiRouteFactory = (libs: UMServerLibs) => ({
method: 'GET',
@@ -23,19 +24,35 @@ export const createGetDynamicSettingsRoute: UMRestApiRouteFactory = (libs: UMSer
},
});
+const validateCertsValues = (settings: DynamicSettings) => {
+ const errors: any = {};
+ if (settings.certAgeThreshold <= 0) {
+ errors.certAgeThreshold = VALUE_MUST_BE_GREATER_THEN_ZEO;
+ }
+ if (settings.certExpirationThreshold <= 0) {
+ errors.certExpirationThreshold = VALUE_MUST_BE_GREATER_THEN_ZEO;
+ }
+ if (errors.certAgeThreshold || errors.certExpirationThreshold) {
+ return errors;
+ }
+};
+
export const createPostDynamicSettingsRoute: UMRestApiRouteFactory = (libs: UMServerLibs) => ({
method: 'POST',
path: '/api/uptime/dynamic_settings',
validate: {
- body: schema.object({}, { unknowns: 'allow' }),
+ body: schema.object({
+ heartbeatIndices: schema.string(),
+ certAgeThreshold: schema.number(),
+ certExpirationThreshold: schema.number(),
+ }),
},
writeAccess: true,
- options: {
- tags: ['access:uptime-write'],
- },
handler: async ({ savedObjectsClient }, _context, request, response): Promise => {
const decoded = DynamicSettingsType.decode(request.body);
- if (isRight(decoded)) {
+ const certThresholdErrors = validateCertsValues(request.body as DynamicSettings);
+
+ if (isRight(decoded) && !certThresholdErrors) {
const newSettings: DynamicSettings = decoded.right;
await savedObjectsAdapter.setUptimeDynamicSettings(savedObjectsClient, newSettings);
@@ -47,7 +64,7 @@ export const createPostDynamicSettingsRoute: UMRestApiRouteFactory = (libs: UMSe
} else {
const error = PathReporter.report(decoded).join(', ');
return response.badRequest({
- body: error,
+ body: JSON.stringify(certThresholdErrors) || error,
});
}
},
diff --git a/x-pack/test/api_integration/apis/fleet/enrollment_api_keys/crud.ts b/x-pack/test/api_integration/apis/fleet/enrollment_api_keys/crud.ts
index 602ec6ca9d9e4..9d0629a7b32e2 100644
--- a/x-pack/test/api_integration/apis/fleet/enrollment_api_keys/crud.ts
+++ b/x-pack/test/api_integration/apis/fleet/enrollment_api_keys/crud.ts
@@ -25,6 +25,7 @@ export default function(providerContext: FtrProviderContext) {
after(async () => {
await esArchiver.unload('fleet/agents');
});
+
describe('GET /fleet/enrollment-api-keys', async () => {
it('should list existing api keys', async () => {
const { body: apiResponse } = await supertest
@@ -54,7 +55,7 @@ export default function(providerContext: FtrProviderContext) {
.post(`/api/ingest_manager/fleet/enrollment-api-keys`)
.set('kbn-xsrf', 'xxx')
.send({
- config_id: 'policy1',
+ config_id: 'config1',
})
.expect(200);
keyId = apiResponse.item.id;
@@ -89,12 +90,22 @@ export default function(providerContext: FtrProviderContext) {
.expect(400);
});
- it('should allow to create an enrollment api key with a policy', async () => {
+ it('should not allow to create an enrollment api key for a non existing agent config', async () => {
+ await supertest
+ .post(`/api/ingest_manager/fleet/enrollment-api-keys`)
+ .set('kbn-xsrf', 'xxx')
+ .send({
+ config_id: 'idonotexistsconfig',
+ })
+ .expect(400);
+ });
+
+ it('should allow to create an enrollment api key with an agent config', async () => {
const { body: apiResponse } = await supertest
.post(`/api/ingest_manager/fleet/enrollment-api-keys`)
.set('kbn-xsrf', 'xxx')
.send({
- config_id: 'policy1',
+ config_id: 'config1',
})
.expect(200);
@@ -107,7 +118,7 @@ export default function(providerContext: FtrProviderContext) {
.post(`/api/ingest_manager/fleet/enrollment-api-keys`)
.set('kbn-xsrf', 'xxx')
.send({
- config_id: 'policy1',
+ config_id: 'config1',
})
.expect(200);
expect(apiResponse.success).to.eql(true);
diff --git a/x-pack/test/api_integration/apis/ml/anomaly_detectors/get.ts b/x-pack/test/api_integration/apis/ml/anomaly_detectors/get.ts
new file mode 100644
index 0000000000000..255afecde74cb
--- /dev/null
+++ b/x-pack/test/api_integration/apis/ml/anomaly_detectors/get.ts
@@ -0,0 +1,222 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import expect from '@kbn/expect';
+import { FtrProviderContext } from '../../../ftr_provider_context';
+import { USER } from '../../../../functional/services/machine_learning/security_common';
+
+const COMMON_HEADERS = {
+ 'kbn-xsrf': 'some-xsrf-token',
+};
+
+export default ({ getService }: FtrProviderContext) => {
+ const esArchiver = getService('esArchiver');
+ const supertest = getService('supertestWithoutAuth');
+ const ml = getService('ml');
+
+ const jobId = `fq_single_${Date.now()}`;
+
+ async function createJobs() {
+ const mockJobConfigs = [
+ {
+ job_id: `${jobId}_1`,
+ description:
+ 'Single metric job based on the farequote dataset with 30m bucketspan and mean(responsetime)',
+ groups: ['automated', 'farequote', 'single-metric'],
+ analysis_config: {
+ bucket_span: '30m',
+ detectors: [{ function: 'mean', field_name: 'responsetime' }],
+ influencers: [],
+ summary_count_field_name: 'doc_count',
+ },
+ data_description: { time_field: '@timestamp' },
+ analysis_limits: { model_memory_limit: '11MB' },
+ model_plot_config: { enabled: true },
+ },
+ {
+ job_id: `${jobId}_2`,
+ description:
+ 'Another single metric job based on the farequote dataset with 30m bucketspan and mean(responsetime)',
+ groups: ['automated', 'farequote', 'single-metric'],
+ analysis_config: {
+ bucket_span: '30m',
+ detectors: [{ function: 'mean', field_name: 'responsetime' }],
+ influencers: [],
+ summary_count_field_name: 'doc_count',
+ },
+ data_description: { time_field: '@timestamp' },
+ analysis_limits: { model_memory_limit: '11MB' },
+ model_plot_config: { enabled: false },
+ },
+ ];
+
+ for (const jobConfig of mockJobConfigs) {
+ await ml.api.createAnomalyDetectionJob(jobConfig);
+ }
+ }
+
+ describe('GET anomaly_detectors', () => {
+ before(async () => {
+ await esArchiver.loadIfNeeded('ml/farequote');
+ await ml.testResources.setKibanaTimeZoneToUTC();
+
+ await createJobs();
+ });
+
+ after(async () => {
+ await ml.api.cleanMlIndices();
+ });
+
+ describe('GetAnomalyDetectors', () => {
+ it('should fetch all anomaly detector jobs', async () => {
+ const { body } = await supertest
+ .get(`/api/ml/anomaly_detectors`)
+ .auth(USER.ML_VIEWER, ml.securityCommon.getPasswordForUser(USER.ML_VIEWER))
+ .set(COMMON_HEADERS)
+ .expect(200);
+
+ expect(body.count).to.eql(2);
+ expect(body.jobs.length).to.eql(2);
+ expect(body.jobs[0].job_id).to.eql(`${jobId}_1`);
+ expect(body.jobs[1].job_id).to.eql(`${jobId}_2`);
+ });
+
+ it('should not allow to retrieve jobs for the user without required permissions', async () => {
+ const { body } = await supertest
+ .get(`/api/ml/anomaly_detectors`)
+ .auth(USER.ML_UNAUTHORIZED, ml.securityCommon.getPasswordForUser(USER.ML_UNAUTHORIZED))
+ .set(COMMON_HEADERS)
+ .expect(404);
+
+ expect(body.error).to.eql('Not Found');
+ expect(body.message).to.eql('Not Found');
+ });
+ });
+
+ describe('GetAnomalyDetectorsById', () => {
+ it('should fetch single anomaly detector job by id', async () => {
+ const { body } = await supertest
+ .get(`/api/ml/anomaly_detectors/${jobId}_1`)
+ .auth(USER.ML_VIEWER, ml.securityCommon.getPasswordForUser(USER.ML_VIEWER))
+ .set(COMMON_HEADERS)
+ .expect(200);
+
+ expect(body.count).to.eql(1);
+ expect(body.jobs.length).to.eql(1);
+ expect(body.jobs[0].job_id).to.eql(`${jobId}_1`);
+ });
+
+ it('should fetch anomaly detector jobs based on provided ids', async () => {
+ const { body } = await supertest
+ .get(`/api/ml/anomaly_detectors/${jobId}_1,${jobId}_2`)
+ .auth(USER.ML_VIEWER, ml.securityCommon.getPasswordForUser(USER.ML_VIEWER))
+ .set(COMMON_HEADERS)
+ .expect(200);
+
+ expect(body.count).to.eql(2);
+ expect(body.jobs.length).to.eql(2);
+ expect(body.jobs[0].job_id).to.eql(`${jobId}_1`);
+ expect(body.jobs[1].job_id).to.eql(`${jobId}_2`);
+ });
+
+ it('should not allow to retrieve a job for the user without required permissions', async () => {
+ const { body } = await supertest
+ .get(`/api/ml/anomaly_detectors/${jobId}_1`)
+ .auth(USER.ML_UNAUTHORIZED, ml.securityCommon.getPasswordForUser(USER.ML_UNAUTHORIZED))
+ .set(COMMON_HEADERS)
+ .expect(404);
+
+ expect(body.error).to.eql('Not Found');
+ expect(body.message).to.eql('Not Found');
+ });
+ });
+
+ describe('GetAnomalyDetectorsStats', () => {
+ it('should fetch jobs stats', async () => {
+ const { body } = await supertest
+ .get(`/api/ml/anomaly_detectors/_stats`)
+ .auth(USER.ML_VIEWER, ml.securityCommon.getPasswordForUser(USER.ML_VIEWER))
+ .set(COMMON_HEADERS)
+ .expect(200);
+
+ expect(body.count).to.eql(2);
+ expect(body.jobs.length).to.eql(2);
+ expect(body.jobs[0].job_id).to.eql(`${jobId}_1`);
+ expect(body.jobs[0]).to.keys(
+ 'timing_stats',
+ 'state',
+ 'forecasts_stats',
+ 'model_size_stats',
+ 'data_counts'
+ );
+ expect(body.jobs[1].job_id).to.eql(`${jobId}_2`);
+ });
+
+ it('should not allow to retrieve jobs stats for the user without required permissions', async () => {
+ const { body } = await supertest
+ .get(`/api/ml/anomaly_detectors/_stats`)
+ .auth(USER.ML_UNAUTHORIZED, ml.securityCommon.getPasswordForUser(USER.ML_UNAUTHORIZED))
+ .set(COMMON_HEADERS)
+ .expect(404);
+
+ expect(body.error).to.eql('Not Found');
+ expect(body.message).to.eql('Not Found');
+ });
+ });
+
+ describe('GetAnomalyDetectorsStatsById', () => {
+ it('should fetch single job stats', async () => {
+ const { body } = await supertest
+ .get(`/api/ml/anomaly_detectors/${jobId}_1/_stats`)
+ .auth(USER.ML_VIEWER, ml.securityCommon.getPasswordForUser(USER.ML_VIEWER))
+ .set(COMMON_HEADERS)
+ .expect(200);
+
+ expect(body.count).to.eql(1);
+ expect(body.jobs.length).to.eql(1);
+ expect(body.jobs[0].job_id).to.eql(`${jobId}_1`);
+ expect(body.jobs[0]).to.keys(
+ 'timing_stats',
+ 'state',
+ 'forecasts_stats',
+ 'model_size_stats',
+ 'data_counts'
+ );
+ });
+
+ it('should fetch multiple jobs stats based on provided ids', async () => {
+ const { body } = await supertest
+ .get(`/api/ml/anomaly_detectors/${jobId}_1,${jobId}_2/_stats`)
+ .auth(USER.ML_VIEWER, ml.securityCommon.getPasswordForUser(USER.ML_VIEWER))
+ .set(COMMON_HEADERS)
+ .expect(200);
+
+ expect(body.count).to.eql(2);
+ expect(body.jobs.length).to.eql(2);
+ expect(body.jobs[0].job_id).to.eql(`${jobId}_1`);
+ expect(body.jobs[0]).to.keys(
+ 'timing_stats',
+ 'state',
+ 'forecasts_stats',
+ 'model_size_stats',
+ 'data_counts'
+ );
+ expect(body.jobs[1].job_id).to.eql(`${jobId}_2`);
+ });
+
+ it('should not allow to retrieve a job stats for the user without required permissions', async () => {
+ const { body } = await supertest
+ .get(`/api/ml/anomaly_detectors/${jobId}_1/_stats`)
+ .auth(USER.ML_UNAUTHORIZED, ml.securityCommon.getPasswordForUser(USER.ML_UNAUTHORIZED))
+ .set(COMMON_HEADERS)
+ .expect(404);
+
+ expect(body.error).to.eql('Not Found');
+ expect(body.message).to.eql('Not Found');
+ });
+ });
+ });
+};
diff --git a/x-pack/test/api_integration/apis/ml/anomaly_detectors/index.ts b/x-pack/test/api_integration/apis/ml/anomaly_detectors/index.ts
index fb8acaf5c3ae9..3985cd39e4d1c 100644
--- a/x-pack/test/api_integration/apis/ml/anomaly_detectors/index.ts
+++ b/x-pack/test/api_integration/apis/ml/anomaly_detectors/index.ts
@@ -8,5 +8,6 @@ import { FtrProviderContext } from '../../../ftr_provider_context';
export default function({ loadTestFile }: FtrProviderContext) {
describe('anomaly detectors', function() {
loadTestFile(require.resolve('./create'));
+ loadTestFile(require.resolve('./get'));
});
}
diff --git a/x-pack/test/api_integration/apis/ml/index.ts b/x-pack/test/api_integration/apis/ml/index.ts
index 58356637c63ac..df99b125e6adb 100644
--- a/x-pack/test/api_integration/apis/ml/index.ts
+++ b/x-pack/test/api_integration/apis/ml/index.ts
@@ -37,5 +37,6 @@ export default function({ getService, loadTestFile }: FtrProviderContext) {
loadTestFile(require.resolve('./fields_service'));
loadTestFile(require.resolve('./job_validation'));
loadTestFile(require.resolve('./jobs'));
+ loadTestFile(require.resolve('./results'));
});
}
diff --git a/x-pack/test/api_integration/apis/ml/results/get_anomalies_table_data.ts b/x-pack/test/api_integration/apis/ml/results/get_anomalies_table_data.ts
new file mode 100644
index 0000000000000..9f34a3c639562
--- /dev/null
+++ b/x-pack/test/api_integration/apis/ml/results/get_anomalies_table_data.ts
@@ -0,0 +1,136 @@
+/*
+ * 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 { USER } from '../../../../functional/services/machine_learning/security_common';
+import { FtrProviderContext } from '../../../ftr_provider_context';
+import { Datafeed, Job } from '../../../../../plugins/ml/common/types/anomaly_detection_jobs';
+
+// eslint-disable-next-line import/no-default-export
+export default ({ getService }: FtrProviderContext) => {
+ const esArchiver = getService('esArchiver');
+ const supertest = getService('supertestWithoutAuth');
+ const ml = getService('ml');
+
+ const COMMON_HEADERS = {
+ 'kbn-xsrf': 'some-xsrf-token',
+ };
+
+ const JOB_CONFIG: Job = {
+ job_id: `fq_multi_1_ae`,
+ description:
+ 'mean/min/max(responsetime) partition=airline on farequote dataset with 1h bucket span',
+ groups: ['farequote', 'automated', 'multi-metric'],
+ analysis_config: {
+ bucket_span: '1h',
+ influencers: ['airline'],
+ detectors: [
+ { function: 'mean', field_name: 'responsetime', partition_field_name: 'airline' },
+ { function: 'min', field_name: 'responsetime', partition_field_name: 'airline' },
+ { function: 'max', field_name: 'responsetime', partition_field_name: 'airline' },
+ ],
+ },
+ data_description: { time_field: '@timestamp' },
+ analysis_limits: { model_memory_limit: '20mb' },
+ model_plot_config: { enabled: true },
+ };
+
+ const DATAFEED_CONFIG: Datafeed = {
+ datafeed_id: 'datafeed-fq_multi_1_se',
+ indices: ['ft_farequote'],
+ job_id: 'fq_multi_1_ae',
+ query: { bool: { must: [{ match_all: {} }] } },
+ };
+
+ async function createMockJobs() {
+ await ml.api.createAndRunAnomalyDetectionLookbackJob(JOB_CONFIG, DATAFEED_CONFIG);
+ }
+
+ describe('GetAnomaliesTableData', () => {
+ before(async () => {
+ await esArchiver.loadIfNeeded('ml/farequote');
+ await ml.testResources.setKibanaTimeZoneToUTC();
+ await createMockJobs();
+ });
+
+ after(async () => {
+ await ml.api.cleanMlIndices();
+ });
+
+ it('should fetch anomalies table data', async () => {
+ const requestBody = {
+ jobIds: [JOB_CONFIG.job_id],
+ criteriaFields: [{ fieldName: 'detector_index', fieldValue: 0 }],
+ influencers: [],
+ aggregationInterval: 'auto',
+ threshold: 0,
+ earliestMs: 1454889600000, // February 8, 2016 12:00:00 AM GMT
+ latestMs: 1454976000000, // February 9, 2016 12:00:00 AM GMT
+ dateFormatTz: 'UTC',
+ maxRecords: 500,
+ };
+
+ const { body } = await supertest
+ .post(`/api/ml/results/anomalies_table_data`)
+ .auth(USER.ML_VIEWER, ml.securityCommon.getPasswordForUser(USER.ML_VIEWER))
+ .set(COMMON_HEADERS)
+ .send(requestBody)
+ .expect(200);
+
+ expect(body.interval).to.eql('hour');
+ expect(body.anomalies.length).to.eql(12);
+ });
+
+ it('should validate request body', async () => {
+ const requestBody = {
+ // missing jobIds
+ criteriaFields: [{ fieldName: 'detector_index', fieldValue: 0 }],
+ influencers: [],
+ aggregationInterval: 'auto',
+ threshold: 0,
+ // invalid earliest and latest instead of earliestMs and latestMs
+ earliest: 1454889600000, // February 8, 2016 12:00:00 AM GMT
+ latest: 1454976000000, // February 9, 2016 12:00:00 AM GMT
+ dateFormatTz: 'UTC',
+ maxRecords: 500,
+ };
+
+ const { body } = await supertest
+ .post(`/api/ml/results/anomalies_table_data`)
+ .auth(USER.ML_VIEWER, ml.securityCommon.getPasswordForUser(USER.ML_VIEWER))
+ .set(COMMON_HEADERS)
+ .send(requestBody)
+ .expect(400);
+
+ expect(body.error).to.eql('Bad Request');
+ expect(body.message).to.eql(
+ '[request body.jobIds]: expected value of type [array] but got [undefined]'
+ );
+ });
+
+ it('should not allow fetching of anomalies table data without required permissions', async () => {
+ const requestBody = {
+ jobIds: [JOB_CONFIG.job_id],
+ criteriaFields: [{ fieldName: 'detector_index', fieldValue: 0 }],
+ influencers: [],
+ aggregationInterval: 'auto',
+ threshold: 0,
+ earliestMs: 1454889600000, // February 8, 2016 12:00:00 AM GMT
+ latestMs: 1454976000000, // February 9, 2016 12:00:00 AM GMT
+ dateFormatTz: 'UTC',
+ maxRecords: 500,
+ };
+ const { body } = await supertest
+ .post(`/api/ml/results/anomalies_table_data`)
+ .auth(USER.ML_UNAUTHORIZED, ml.securityCommon.getPasswordForUser(USER.ML_UNAUTHORIZED))
+ .set(COMMON_HEADERS)
+ .send(requestBody)
+ .expect(404);
+
+ expect(body.error).to.eql('Not Found');
+ expect(body.message).to.eql('Not Found');
+ });
+ });
+};
diff --git a/x-pack/test/api_integration/apis/ml/results/index.ts b/x-pack/test/api_integration/apis/ml/results/index.ts
new file mode 100644
index 0000000000000..80197e6a32ad9
--- /dev/null
+++ b/x-pack/test/api_integration/apis/ml/results/index.ts
@@ -0,0 +1,12 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+import { FtrProviderContext } from '../../../ftr_provider_context';
+
+export default function({ loadTestFile }: FtrProviderContext) {
+ describe('ResultsService', () => {
+ loadTestFile(require.resolve('./get_anomalies_table_data'));
+ });
+}
diff --git a/x-pack/test/functional/apps/dashboard/_async_dashboard.ts b/x-pack/test/functional/apps/dashboard/_async_dashboard.ts
index 2c8abda999ddd..82641db457aea 100644
--- a/x-pack/test/functional/apps/dashboard/_async_dashboard.ts
+++ b/x-pack/test/functional/apps/dashboard/_async_dashboard.ts
@@ -9,6 +9,7 @@ import { FtrProviderContext } from '../../ftr_provider_context';
export default function({ getService, getPageObjects }: FtrProviderContext) {
const retry = getService('retry');
+ const browser = getService('browser');
const kibanaServer = getService('kibanaServer');
const log = getService('log');
const pieChart = getService('pieChart');
@@ -93,6 +94,9 @@ export default function({ getService, getPageObjects }: FtrProviderContext) {
]`;
await kibanaServer.uiSettings.update({ 'timepicker:quickRanges': SAMPLE_DATA_RANGE });
+ // refresh page to make sure ui settings update is picked up
+ await browser.refresh();
+ await PageObjects.header.waitUntilLoadingHasFinished();
await appMenu.clickLink('Discover');
await PageObjects.discover.selectIndexPattern('kibana_sample_data_flights');
await PageObjects.timePicker.setCommonlyUsedTime('sample_data range');
@@ -104,6 +108,7 @@ export default function({ getService, getPageObjects }: FtrProviderContext) {
after(async () => {
await PageObjects.common.navigateToUrl('home', 'tutorial_directory/sampleData');
+ await PageObjects.header.waitUntilLoadingHasFinished();
await PageObjects.home.removeSampleDataSet('flights');
const isInstalled = await PageObjects.home.isSampleDataSetInstalled('flights');
expect(isInstalled).to.be(false);
diff --git a/x-pack/test/functional/es_archives/fleet/agents/data.json b/x-pack/test/functional/es_archives/fleet/agents/data.json
index d22e3cd3fecdd..1739f583b2e87 100644
--- a/x-pack/test/functional/es_archives/fleet/agents/data.json
+++ b/x-pack/test/functional/es_archives/fleet/agents/data.json
@@ -199,3 +199,30 @@
}
}
}
+
+{
+ "type": "doc",
+ "value": {
+ "id": "ingest-agent-configs:config1",
+ "index": ".kibana",
+ "source": {
+ "type": "ingest-agent-configs",
+ "ingest-agent-configs": {
+ "name": "Test config",
+ "namespace": "default",
+ "description": "Config 1",
+ "status": "active",
+ "datasources": [],
+ "is_default": true,
+ "monitoring_enabled": [
+ "logs",
+ "metrics"
+ ],
+ "revision": 2,
+ "updated_on": "2020-05-07T19:34:42.533Z",
+ "updated_by": "system",
+ "id": "config1"
+ }
+ }
+ }
+}
diff --git a/x-pack/test/functional/es_archives/fleet/agents/mappings.json b/x-pack/test/functional/es_archives/fleet/agents/mappings.json
index 409cc3c689eaf..15e5a5524107b 100644
--- a/x-pack/test/functional/es_archives/fleet/agents/mappings.json
+++ b/x-pack/test/functional/es_archives/fleet/agents/mappings.json
@@ -9,39 +9,42 @@
"dynamic": "strict",
"_meta": {
"migrationMappingPropertyHashes": {
- "ingest-outputs": "aee9782e0d500b867859650a36280165",
"ml-telemetry": "257fd1d4b4fdbb9cb4b8a3b27da201e9",
"visualization": "52d7a13ad68a150c4525b292d23e12cc",
"references": "7997cf5a56cc02bdc9c93361bde732b0",
"graph-workspace": "cd7ba1330e6682e9cc00b78850874be1",
+ "epm-packages": "92b4b1899b887b090d01c033f3118a85",
"type": "2f4316de49999235636386fe51dc06c1",
- "infrastructure-ui-source": "ddc0ecb18383f6b26101a2fadb2dab0c",
"space": "c5ca8acafa0beaa4d08d014a97b6bc6b",
+ "infrastructure-ui-source": "ddc0ecb18383f6b26101a2fadb2dab0c",
+ "ingest_manager_settings": "c5b0749b4ab03c582efd4c14cb8f132c",
"application_usage_totals": "c897e4310c5f24b07caaff3db53ae2c1",
"action": "6e96ac5e648f57523879661ea72525b7",
- "agent_configs": "38abaf89513877745c359e7700c0c66a",
"dashboard": "d00f614b29a80360e1190193fd333bab",
- "metrics-explorer-view": "53c5365793677328df0ccb6138bf3cdd",
- "siem-detection-engine-rule-actions": "90eee2e4635260f4be0a1da8f5bc0aa0",
- "fleet-agent-events": "3231653fafe4ef3196fe3b32ab774bf2",
+ "metrics-explorer-view": "428e319af3e822c80a84cf87123ca35c",
+ "siem-detection-engine-rule-actions": "6569b288c169539db10cb262bf79de18",
"query": "11aaeb7f5f7fa5bb43f25e18ce26e7d9",
"file-upload-telemetry": "0ed4d3e1983d1217a30982630897092e",
"application_usage_transactional": "965839e75f809fefe04f92dc4d99722a",
"action_task_params": "a9d49f184ee89641044be0ca2950fa3a",
+ "fleet-agent-events": "3231653fafe4ef3196fe3b32ab774bf2",
+ "ingest-datasources": "2346514df03316001d56ed4c8d46fa94",
"apm-indices": "9bb9b2bf1fa636ed8619cbab5ce6a1dd",
- "inventory-view": "9ecce5b58867403613d82fe496470b34",
- "fleet-enrollment-api-keys": "28b91e20b105b6f928e2012600085d8f",
- "upgrade-assistant-reindex-operation": "a53a20fe086b72c9a86da3cc12dad8a6",
+ "inventory-view": "5299b67717e96502c77babf1c16fd4d3",
+ "upgrade-assistant-reindex-operation": "296a89039fc4260292be36b1b005d8f2",
"cases-comments": "c2061fb929f585df57425102fa928b4b",
+ "fleet-enrollment-api-keys": "28b91e20b105b6f928e2012600085d8f",
"canvas-element": "7390014e1091044523666d97247392fc",
- "datasources": "d4bc0c252b2b5683ff21ea32d00acffc",
+ "ingest-outputs": "0e57221778a7153c8292edf154099036",
"telemetry": "36a616f7026dfa617d6655df850fe16d",
"upgrade-assistant-telemetry": "56702cec857e0a9dacfb696655b4ff7b",
"lens-ui-telemetry": "509bfa5978586998e05f9e303c07a327",
+ "namespaces": "2f4316de49999235636386fe51dc06c1",
"server": "ec97f1c5da1a19609a60874e5af1100c",
"siem-ui-timeline-note": "8874706eedc49059d4cf0f5094559084",
"lens": "21c3ea0763beb1ecb0162529706b88c5",
"sample-data-telemetry": "7d3cfeb915303c9641c59681967ffeb4",
+ "fleet-agent-actions": "e520c855577170c24481be05c3ae14ec",
"search": "181661168bbadd1eff5902361e2a0d5c",
"updated_at": "00da57df13e94e9d98437d13ace4bfe0",
"cases-configure": "42711cbb311976c0687853f4c1354572",
@@ -49,23 +52,22 @@
"alert": "7b44fba6773e37c806ce290ea9b7024e",
"siem-detection-engine-rule-status": "ae783f41c6937db6b7a2ef5c93a9e9b0",
"map": "23d7aa4a720d4938ccde3983f87bd58d",
- "uptime-dynamic-settings": "b6289473c8985c79b6c47eebc19a0ca5",
- "epm-packages": "75d12cd13c867fd713d7dfb27366bc20",
+ "uptime-dynamic-settings": "fcdb453a30092f022f2642db29523d80",
+ "cases": "32aa96a6d3855ddda53010ae2048ac22",
"apm-telemetry": "3525d7c22c42bc80f5e6e9cb3f2b26a2",
- "cases": "08b8b110dbca273d37e8aef131ecab61",
- "siem-ui-timeline": "ac8020190f5950dd3250b6499144e7fb",
+ "siem-ui-timeline": "f2d929253ecd06ffbac78b4047f45a86",
"kql-telemetry": "d12a98a6f19a2d273696597547e064ee",
"ui-metric": "0d409297dc5ebe1e3a1da691c6ee32e3",
- "url": "c7f66a0df8b1b52f17c28c4adb111105",
- "fleet-agents": "c3eeb7b9d97176f15f6d126370ab23c7",
+ "ingest-agent-configs": "f4bdc17427437537ca1754d5d5057ad5",
+ "url": "b675c3be8d76ecf029294d51dc7ec65d",
"migrationVersion": "4a1746014a75ade3a714e1db5763276f",
"index-pattern": "66eccb05066c5a89924f48a9e9736499",
- "maps-telemetry": "268da3a48066123fc5baf35abaa55014",
+ "fleet-agents": "864760267df6c970f629bd4458506c53",
+ "maps-telemetry": "bfd39d88aadadb4be597ea984d433dbe",
"namespace": "2f4316de49999235636386fe51dc06c1",
"cases-user-actions": "32277330ec6b721abe3b846cfd939a71",
- "fleet-agent-actions": "ed270b46812f0fa1439366c428a2cf17",
- "siem-ui-timeline-pinned-event": "20638091112f0e14f0e443d512301c29",
"timelion-sheet": "9a2a2748877c7a7b582fef201ab1d4cf",
+ "siem-ui-timeline-pinned-event": "20638091112f0e14f0e443d512301c29",
"config": "ae24d22d5986d04124cc6568f771066f",
"tsvb-validation-telemetry": "3a37ef6c8700ae6fc97d5c7da00e9215"
}
@@ -107,145 +109,6 @@
}
}
},
- "fleet-agent-actions": {
- "properties": {
- "agent_id": {
- "type": "keyword"
- },
- "created_at": {
- "type": "date"
- },
- "data": {
- "type": "flattened"
- },
- "sent_at": {
- "type": "date"
- },
- "type": {
- "type": "keyword"
- }
- }
- },
- "agent_configs": {
- "properties": {
- "datasources": {
- "type": "keyword"
- },
- "description": {
- "type": "text"
- },
- "id": {
- "type": "keyword"
- },
- "is_default": {
- "type": "boolean"
- },
- "name": {
- "type": "text"
- },
- "namespace": {
- "type": "keyword"
- },
- "revision": {
- "type": "integer"
- },
- "status": {
- "type": "keyword"
- },
- "updated_by": {
- "type": "keyword"
- },
- "updated_on": {
- "type": "keyword"
- }
- }
- },
- "fleet-agent-events": {
- "properties": {
- "action_id": {
- "type": "keyword"
- },
- "agent_id": {
- "type": "keyword"
- },
- "config_id": {
- "type": "keyword"
- },
- "data": {
- "type": "text"
- },
- "message": {
- "type": "text"
- },
- "payload": {
- "type": "text"
- },
- "stream_id": {
- "type": "keyword"
- },
- "subtype": {
- "type": "keyword"
- },
- "timestamp": {
- "type": "date"
- },
- "type": {
- "type": "keyword"
- }
- }
- },
- "fleet-agents": {
- "properties": {
- "access_api_key_id": {
- "type": "keyword"
- },
- "active": {
- "type": "boolean"
- },
- "config_id": {
- "type": "keyword"
- },
- "config_newest_revision": {
- "type": "integer"
- },
- "config_revision": {
- "type": "integer"
- },
- "current_error_events": {
- "type": "text"
- },
- "default_api_key": {
- "type": "keyword"
- },
- "enrolled_at": {
- "type": "date"
- },
- "last_checkin": {
- "type": "date"
- },
- "last_updated": {
- "type": "date"
- },
- "local_metadata": {
- "type": "flattened"
- },
- "shared_id": {
- "type": "keyword"
- },
- "type": {
- "type": "keyword"
- },
- "updated_at": {
- "type": "date"
- },
- "user_provided_metadata": {
- "type": "flattened"
- },
- "version": {
- "type": "keyword"
- }
- }
- },
"alert": {
"properties": {
"actions": {
@@ -1355,6 +1218,9 @@
}
}
},
+ "connector_id": {
+ "type": "keyword"
+ },
"created_at": {
"type": "date"
},
@@ -1630,137 +1496,180 @@
}
}
},
- "datasources": {
+ "epm-packages": {
"properties": {
- "config_id": {
- "type": "keyword"
- },
- "description": {
- "type": "text"
- },
- "enabled": {
- "type": "boolean"
+ "es_index_patterns": {
+ "type": "object",
+ "dynamic": "false"
},
- "inputs": {
+ "installed": {
"type": "nested",
"properties": {
- "config": {
- "type": "flattened"
- },
- "enabled": {
- "type": "boolean"
- },
- "processors": {
+ "id": {
"type": "keyword"
},
- "streams": {
- "type": "nested",
- "properties": {
- "config": {
- "type": "flattened"
- },
- "dataset": {
- "type": "keyword"
- },
- "enabled": {
- "type": "boolean"
- },
- "id": {
- "type": "keyword"
- },
- "processors": {
- "type": "keyword"
- }
- }
- },
"type": {
"type": "keyword"
}
}
},
+ "internal": {
+ "type": "boolean"
+ },
"name": {
"type": "keyword"
},
- "namespace": {
- "type": "keyword"
+ "removable": {
+ "type": "boolean"
},
- "output_id": {
+ "version": {
"type": "keyword"
- },
- "package": {
- "properties": {
- "name": {
- "type": "keyword"
- },
- "title": {
- "type": "keyword"
- },
- "version": {
- "type": "keyword"
- }
- }
- },
- "revision": {
- "type": "integer"
}
}
},
- "fleet-enrollment-api-keys": {
+ "file-upload-telemetry": {
"properties": {
- "active": {
- "type": "boolean"
- },
- "api_key": {
- "type": "binary"
- },
- "api_key_id": {
- "type": "keyword"
- },
- "config_id": {
+ "filesUploadedTotalCount": {
+ "type": "long"
+ }
+ }
+ },
+ "fleet-agent-actions": {
+ "properties": {
+ "agent_id": {
"type": "keyword"
},
"created_at": {
"type": "date"
},
- "expire_at": {
- "type": "date"
+ "data": {
+ "type": "binary"
},
- "name": {
- "type": "keyword"
+ "sent_at": {
+ "type": "date"
},
"type": {
"type": "keyword"
- },
- "updated_at": {
- "type": "date"
}
}
},
- "epm-packages": {
+ "fleet-agent-events": {
"properties": {
- "installed": {
- "type": "nested",
- "properties": {
- "id": {
- "type": "keyword"
- },
- "type": {
- "type": "keyword"
- }
- }
- },
- "name": {
+ "action_id": {
+ "type": "keyword"
+ },
+ "agent_id": {
+ "type": "keyword"
+ },
+ "config_id": {
+ "type": "keyword"
+ },
+ "data": {
+ "type": "text"
+ },
+ "message": {
+ "type": "text"
+ },
+ "payload": {
+ "type": "text"
+ },
+ "stream_id": {
+ "type": "keyword"
+ },
+ "subtype": {
+ "type": "keyword"
+ },
+ "timestamp": {
+ "type": "date"
+ },
+ "type": {
+ "type": "keyword"
+ }
+ }
+ },
+ "fleet-agents": {
+ "properties": {
+ "access_api_key_id": {
+ "type": "keyword"
+ },
+ "active": {
+ "type": "boolean"
+ },
+ "config_id": {
+ "type": "keyword"
+ },
+ "config_newest_revision": {
+ "type": "integer"
+ },
+ "config_revision": {
+ "type": "integer"
+ },
+ "current_error_events": {
+ "type": "text"
+ },
+ "default_api_key": {
+ "type": "keyword"
+ },
+ "default_api_key_id": {
+ "type": "keyword"
+ },
+ "enrolled_at": {
+ "type": "date"
+ },
+ "last_checkin": {
+ "type": "date"
+ },
+ "last_updated": {
+ "type": "date"
+ },
+ "local_metadata": {
+ "type": "flattened"
+ },
+ "shared_id": {
"type": "keyword"
},
+ "type": {
+ "type": "keyword"
+ },
+ "updated_at": {
+ "type": "date"
+ },
+ "user_provided_metadata": {
+ "type": "flattened"
+ },
"version": {
"type": "keyword"
}
}
},
- "file-upload-telemetry": {
+ "fleet-enrollment-api-keys": {
"properties": {
- "filesUploadedTotalCount": {
- "type": "long"
+ "active": {
+ "type": "boolean"
+ },
+ "api_key": {
+ "type": "binary"
+ },
+ "api_key_id": {
+ "type": "keyword"
+ },
+ "config_id": {
+ "type": "keyword"
+ },
+ "created_at": {
+ "type": "date"
+ },
+ "expire_at": {
+ "type": "date"
+ },
+ "name": {
+ "type": "keyword"
+ },
+ "type": {
+ "type": "keyword"
+ },
+ "updated_at": {
+ "type": "date"
}
}
},
@@ -1888,8 +1797,176 @@
}
}
},
+ "ingest-agent-configs": {
+ "properties": {
+ "datasources": {
+ "type": "keyword"
+ },
+ "description": {
+ "type": "text"
+ },
+ "id": {
+ "type": "keyword"
+ },
+ "is_default": {
+ "type": "boolean"
+ },
+ "monitoring_enabled": {
+ "type": "keyword"
+ },
+ "name": {
+ "type": "text"
+ },
+ "namespace": {
+ "type": "keyword"
+ },
+ "revision": {
+ "type": "integer"
+ },
+ "status": {
+ "type": "keyword"
+ },
+ "updated_by": {
+ "type": "keyword"
+ },
+ "updated_on": {
+ "type": "keyword"
+ }
+ }
+ },
+ "ingest-datasources": {
+ "properties": {
+ "config_id": {
+ "type": "keyword"
+ },
+ "description": {
+ "type": "text"
+ },
+ "enabled": {
+ "type": "boolean"
+ },
+ "inputs": {
+ "type": "nested",
+ "properties": {
+ "config": {
+ "type": "flattened"
+ },
+ "enabled": {
+ "type": "boolean"
+ },
+ "processors": {
+ "type": "keyword"
+ },
+ "streams": {
+ "type": "nested",
+ "properties": {
+ "agent_stream": {
+ "type": "flattened"
+ },
+ "config": {
+ "type": "flattened"
+ },
+ "dataset": {
+ "type": "keyword"
+ },
+ "enabled": {
+ "type": "boolean"
+ },
+ "id": {
+ "type": "keyword"
+ },
+ "processors": {
+ "type": "keyword"
+ },
+ "vars": {
+ "type": "flattened"
+ }
+ }
+ },
+ "type": {
+ "type": "keyword"
+ },
+ "vars": {
+ "type": "flattened"
+ }
+ }
+ },
+ "name": {
+ "type": "keyword"
+ },
+ "namespace": {
+ "type": "keyword"
+ },
+ "output_id": {
+ "type": "keyword"
+ },
+ "package": {
+ "properties": {
+ "name": {
+ "type": "keyword"
+ },
+ "title": {
+ "type": "keyword"
+ },
+ "version": {
+ "type": "keyword"
+ }
+ }
+ },
+ "revision": {
+ "type": "integer"
+ }
+ }
+ },
+ "ingest-outputs": {
+ "properties": {
+ "ca_sha256": {
+ "type": "keyword"
+ },
+ "config": {
+ "type": "flattened"
+ },
+ "fleet_enroll_password": {
+ "type": "binary"
+ },
+ "fleet_enroll_username": {
+ "type": "binary"
+ },
+ "hosts": {
+ "type": "keyword"
+ },
+ "is_default": {
+ "type": "boolean"
+ },
+ "name": {
+ "type": "keyword"
+ },
+ "type": {
+ "type": "keyword"
+ }
+ }
+ },
+ "ingest_manager_settings": {
+ "properties": {
+ "agent_auto_upgrade": {
+ "type": "keyword"
+ },
+ "kibana_ca_sha256": {
+ "type": "keyword"
+ },
+ "kibana_url": {
+ "type": "keyword"
+ },
+ "package_auto_upgrade": {
+ "type": "keyword"
+ }
+ }
+ },
"inventory-view": {
"properties": {
+ "accountId": {
+ "type": "keyword"
+ },
"autoBounds": {
"type": "boolean"
},
@@ -1983,8 +2060,11 @@
"nodeType": {
"type": "keyword"
},
+ "region": {
+ "type": "keyword"
+ },
"time": {
- "type": "integer"
+ "type": "long"
},
"view": {
"type": "keyword"
@@ -2102,6 +2182,12 @@
"indexPatternsWithGeoFieldCount": {
"type": "long"
},
+ "indexPatternsWithGeoPointFieldCount": {
+ "type": "long"
+ },
+ "indexPatternsWithGeoShapeFieldCount": {
+ "type": "long"
+ },
"mapsTotalCount": {
"type": "long"
},
@@ -2156,6 +2242,9 @@
"filterQuery": {
"type": "keyword"
},
+ "forceInterval": {
+ "type": "boolean"
+ },
"groupBy": {
"type": "keyword"
},
@@ -2211,36 +2300,8 @@
"namespace": {
"type": "keyword"
},
- "ingest-outputs": {
- "properties": {
- "api_key": {
- "type": "keyword"
- },
- "ca_sha256": {
- "type": "keyword"
- },
- "config": {
- "type": "flattened"
- },
- "fleet_enroll_password": {
- "type": "binary"
- },
- "fleet_enroll_username": {
- "type": "binary"
- },
- "hosts": {
- "type": "keyword"
- },
- "is_default": {
- "type": "boolean"
- },
- "name": {
- "type": "keyword"
- },
- "type": {
- "type": "keyword"
- }
- }
+ "namespaces": {
+ "type": "keyword"
},
"query": {
"properties": {
@@ -2346,7 +2407,7 @@
},
"params": {
"type": "object",
- "dynamic": "true"
+ "enabled": false
}
}
},
@@ -2647,6 +2708,15 @@
}
}
},
+ "templateTimelineId": {
+ "type": "text"
+ },
+ "templateTimelineVersion": {
+ "type": "integer"
+ },
+ "timelineType": {
+ "type": "keyword"
+ },
"title": {
"type": "text"
},
@@ -2827,11 +2897,48 @@
"type": "date"
},
"upgrade-assistant-reindex-operation": {
- "dynamic": "true",
"properties": {
+ "errorMessage": {
+ "type": "keyword"
+ },
"indexName": {
"type": "keyword"
},
+ "lastCompletedStep": {
+ "type": "integer"
+ },
+ "locked": {
+ "type": "date"
+ },
+ "newIndexName": {
+ "type": "keyword"
+ },
+ "reindexOptions": {
+ "properties": {
+ "openAndClose": {
+ "type": "boolean"
+ },
+ "queueSettings": {
+ "properties": {
+ "queuedAt": {
+ "type": "long"
+ },
+ "startedAt": {
+ "type": "long"
+ }
+ }
+ }
+ }
+ },
+ "reindexTaskId": {
+ "type": "keyword"
+ },
+ "reindexTaskPercComplete": {
+ "type": "float"
+ },
+ "runningReindexCount": {
+ "type": "integer"
+ },
"status": {
"type": "integer"
}
@@ -2891,6 +2998,12 @@
},
"uptime-dynamic-settings": {
"properties": {
+ "certAgeThreshold": {
+ "type": "long"
+ },
+ "certExpirationThreshold": {
+ "type": "long"
+ },
"heartbeatIndices": {
"type": "keyword"
}
@@ -2911,8 +3024,7 @@
"type": "text",
"fields": {
"keyword": {
- "type": "keyword",
- "ignore_above": 2048
+ "type": "keyword"
}
}
}