{
/**
* Create and register a new locator.
*
- * @param urlGenerator Definition of the new locator.
+ * @param locatorDefinition Definition of the new locator.
*/
create(locatorDefinition: LocatorDefinition
): LocatorPublic
;
diff --git a/src/plugins/share/public/index.ts b/src/plugins/share/public/index.ts
index 86d29f6ad84cf..c4c097f992538 100644
--- a/src/plugins/share/public/index.ts
+++ b/src/plugins/share/public/index.ts
@@ -12,8 +12,6 @@ export { CSV_QUOTE_VALUES_SETTING, CSV_SEPARATOR_SETTING } from '../common/const
export type { LocatorDefinition, LocatorPublic, KibanaLocation } from '../common/url_service';
-export type { UrlGeneratorStateMapping } from './url_generators/url_generator_definition';
-
export type { SharePluginSetup, SharePluginStart } from './plugin';
export type {
@@ -25,14 +23,6 @@ export type {
BrowserUrlService,
} from './types';
-export type {
- UrlGeneratorId,
- UrlGeneratorState,
- UrlGeneratorsDefinition,
- UrlGeneratorContract,
-} from './url_generators';
-export { UrlGeneratorsService } from './url_generators';
-
export type { RedirectOptions } from '../common/url_service';
export { useLocatorUrl } from '../common/url_service/locators/use_locator_url';
diff --git a/src/plugins/share/public/mocks.ts b/src/plugins/share/public/mocks.ts
index 066767b87fcea..7406dbb12f883 100644
--- a/src/plugins/share/public/mocks.ts
+++ b/src/plugins/share/public/mocks.ts
@@ -39,9 +39,6 @@ const url = new UrlService {
const setupContract: Setup = {
register: jest.fn(),
- urlGenerators: {
- registerUrlGenerator: jest.fn(),
- },
url,
navigate: jest.fn(),
setAnonymousAccessServiceProvider: jest.fn(),
@@ -52,9 +49,6 @@ const createSetupContract = (): Setup => {
const createStartContract = (): Start => {
const startContract: Start = {
url,
- urlGenerators: {
- getUrlGenerator: jest.fn(),
- },
toggleShareContextMenu: jest.fn(),
navigate: jest.fn(),
};
diff --git a/src/plugins/share/public/plugin.ts b/src/plugins/share/public/plugin.ts
index ce9eeb5c2da33..5a7ff7b12cdd2 100644
--- a/src/plugins/share/public/plugin.ts
+++ b/src/plugins/share/public/plugin.ts
@@ -11,11 +11,6 @@ import './index.scss';
import type { CoreSetup, CoreStart, Plugin, PluginInitializerContext } from 'src/core/public';
import { ShareMenuManager, ShareMenuManagerStart } from './services';
import { ShareMenuRegistry, ShareMenuRegistrySetup } from './services';
-import {
- UrlGeneratorsService,
- UrlGeneratorsSetup,
- UrlGeneratorsStart,
-} from './url_generators/url_generator_service';
import { UrlService } from '../common/url_service';
import { RedirectManager } from './url_service';
import type { RedirectOptions } from '../common/url_service/locators/redirect';
@@ -31,13 +26,6 @@ import type { BrowserUrlService } from './types';
/** @public */
export type SharePluginSetup = ShareMenuRegistrySetup & {
- /**
- * @deprecated
- *
- * URL Generators are deprecated use UrlService instead.
- */
- urlGenerators: UrlGeneratorsSetup;
-
/**
* Utilities to work with URL locators and short URLs.
*/
@@ -57,13 +45,6 @@ export type SharePluginSetup = ShareMenuRegistrySetup & {
/** @public */
export type SharePluginStart = ShareMenuManagerStart & {
- /**
- * @deprecated
- *
- * URL Generators are deprecated use UrlService instead.
- */
- urlGenerators: UrlGeneratorsStart;
-
/**
* Utilities to work with URL locators and short URLs.
*/
@@ -79,7 +60,6 @@ export type SharePluginStart = ShareMenuManagerStart & {
export class SharePlugin implements Plugin {
private readonly shareMenuRegistry = new ShareMenuRegistry();
private readonly shareContextMenu = new ShareMenuManager();
- private readonly urlGeneratorsService = new UrlGeneratorsService();
private redirectManager?: RedirectManager;
private url?: BrowserUrlService;
@@ -128,7 +108,6 @@ export class SharePlugin implements Plugin {
return {
...this.shareMenuRegistry.setup(),
- urlGenerators: this.urlGeneratorsService.setup(core),
url: this.url,
navigate: (options: RedirectOptions) => this.redirectManager!.navigate(options),
setAnonymousAccessServiceProvider: (provider: () => AnonymousAccessServiceContract) => {
@@ -150,7 +129,6 @@ export class SharePlugin implements Plugin {
return {
...sharingContextMenuStart,
- urlGenerators: this.urlGeneratorsService.start(core),
url: this.url!,
navigate: (options: RedirectOptions) => this.redirectManager!.navigate(options),
};
diff --git a/src/plugins/share/public/url_generators/README.md b/src/plugins/share/public/url_generators/README.md
deleted file mode 100644
index f948354aad959..0000000000000
--- a/src/plugins/share/public/url_generators/README.md
+++ /dev/null
@@ -1,120 +0,0 @@
-# URL Generators are deprecated
-
-__Below is documentation of URL Generators, which are now deprecated and will be removed in favor of URL locators in 7.14.__
-
----
-
-## URL Generator Services
-
-Developers who maintain pages in Kibana that other developers may want to link to
-can register a direct access link generator. This provides backward compatibility support
-so the developer of the app/page has a way to change their url structure without
-breaking users of this system. If users were to generate the urls on their own,
-using string concatenation, those links may break often.
-
-Owners: Kibana App Arch team.
-
-## Producer Usage
-
-If you are registering a new generator, don't forget to add a mapping of id to state
-
-```ts
-declare module '../../share/public' {
- export interface UrlGeneratorStateMapping {
- [MY_GENERATOR]: MyState;
- }
-}
-```
-
-### Migration
-
-Once your generator is released, you should *never* change the `MyState` type, nor the value of `MY_GENERATOR`.
-Instead, register a new generator id, with the new state type, and add a migration function to convert to it.
-
-To avoid having to refactor many run time usages of the old id, change the _value_ of the generator id, but not
-the name itself. For example:
-
-Initial release:
-```ts
-export const MY_GENERATOR = 'MY_GENERATOR';
-export const MyState {
- foo: string;
-}
-export interface UrlGeneratorStateMapping {
- [MY_GENERATOR]: UrlGeneratorState;
-}
-```
-
-Second release:
-```ts
- // Value stays the same here! This is important.
- export const MY_LEGACY_GENERATOR_V1 = 'MY_GENERATOR';
- // Always point the const `MY_GENERATOR` to the most
- // recent version of the state to avoid a large refactor.
- export const MY_GENERATOR = 'MY_GENERATOR_V2';
-
- // Same here, the mapping stays the same, but the names change.
- export const MyLegacyState {
- foo: string;
- }
- // New type, old name!
- export const MyState {
- bar: string;
- }
- export interface UrlGeneratorStateMapping {
- [MY_LEGACY_GENERATOR_V1]: UrlGeneratorState;
- [MY_GENERATOR]: UrlGeneratorState;
- }
-```
-
-### Examples
-
-Working examples of registered link generators can be found in `examples/url_generator_examples` folder. Run these
-examples via
-
-```
-yarn start --run-examples
-```
-
-## Consumer Usage
-
-Consumers of this service can use the ids and state to create URL strings:
-
-```ts
- const { id, state } = getLinkData();
- const generator = urlGeneratorPluginStart.getLinkGenerator(id);
- if (generator.isDeprecated) {
- // Consumers have a few options here.
-
- // If the consumer constrols the persisted data, they can migrate this data and
- // update it. Something like this:
- const { id: newId, state: newState } = await generator.migrate(state);
- replaceLegacyData({ oldId: id, newId, newState });
-
- // If the consumer does not control the persisted data store, they can warn the
- // user that they are using a deprecated id and should update the data on their
- // own.
- alert(`This data is deprecated, please generate new URL data.`);
-
- // They can also choose to do nothing. Calling `createUrl` will internally migrate this
- // data. Depending on the cost, we may choose to keep support for deprecated generators
- // along for a long time, using telemetry to make this decision. However another
- // consideration is how many migrations are taking place and whether this is creating a
- // performance issue.
- }
- const link = await generator.createUrl(savedLink.state);
-```
-
-**As a consumer, you should not persist the url string!**
-
-As soon as you do, you have lost your migration options. Instead you should store the id
-and the state object. This will let you recreate the migrated url later.
-
-### Examples
-
-Working examples of consuming registered link generators can be found in `examples/url_generator_explorer` folder. Run these
-via
-
-```
-yarn start --run-examples
-```
diff --git a/src/plugins/share/public/url_generators/url_generator_definition.ts b/src/plugins/share/public/url_generators/url_generator_definition.ts
deleted file mode 100644
index 32fe51a16d197..0000000000000
--- a/src/plugins/share/public/url_generators/url_generator_definition.ts
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License
- * 2.0 and the Server Side Public License, v 1; you may not use this file except
- * in compliance with, at your election, the Elastic License 2.0 or the Server
- * Side Public License, v 1.
- */
-
-export type UrlGeneratorId = string;
-
-export interface UrlGeneratorState<
- S extends {},
- I extends string | undefined = undefined,
- MS extends {} | undefined = undefined
-> {
- State: S;
- MigratedId?: I;
- MigratedState?: MS;
-}
-
-export interface UrlGeneratorStateMapping {
- // The `any` here is quite unfortunate. Using `object` actually gives no type errors in my IDE
- // but running `node scripts/type_check` will cause an error:
- // examples/url_generators_examples/public/url_generator.ts:77:66 -
- // error TS2339: Property 'name' does not exist on type 'object'. However it's correctly
- // typed when I edit that file.
- [key: string]: UrlGeneratorState;
-}
-
-export interface UrlGeneratorsDefinition {
- id: Id;
- createUrl?: (state: UrlGeneratorStateMapping[Id]['State']) => Promise;
- isDeprecated?: boolean;
- migrate?: (state: UrlGeneratorStateMapping[Id]['State']) => Promise<{
- state: UrlGeneratorStateMapping[Id]['MigratedState'];
- id: UrlGeneratorStateMapping[Id]['MigratedId'];
- }>;
-}
diff --git a/src/plugins/share/public/url_generators/url_generator_internal.ts b/src/plugins/share/public/url_generators/url_generator_internal.ts
deleted file mode 100644
index 7f7dc0f63f87b..0000000000000
--- a/src/plugins/share/public/url_generators/url_generator_internal.ts
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License
- * 2.0 and the Server Side Public License, v 1; you may not use this file except
- * in compliance with, at your election, the Elastic License 2.0 or the Server
- * Side Public License, v 1.
- */
-
-import { i18n } from '@kbn/i18n';
-import { UrlGeneratorsStart } from './url_generator_service';
-import {
- UrlGeneratorStateMapping,
- UrlGeneratorId,
- UrlGeneratorsDefinition,
-} from './url_generator_definition';
-import { UrlGeneratorContract } from './url_generator_contract';
-
-export class UrlGeneratorInternal {
- constructor(
- private spec: UrlGeneratorsDefinition,
- private getGenerator: UrlGeneratorsStart['getUrlGenerator']
- ) {
- if (spec.isDeprecated && !spec.migrate) {
- throw new Error(
- i18n.translate('share.urlGenerators.error.noMigrationFnProvided', {
- defaultMessage:
- 'If the access link generator is marked as deprecated, you must provide a migration function.',
- })
- );
- }
-
- if (!spec.isDeprecated && spec.migrate) {
- throw new Error(
- i18n.translate('share.urlGenerators.error.migrationFnGivenNotDeprecated', {
- defaultMessage:
- 'If you provide a migration function, you must mark this generator as deprecated',
- })
- );
- }
-
- if (!spec.createUrl && !spec.isDeprecated) {
- throw new Error(
- i18n.translate('share.urlGenerators.error.noCreateUrlFnProvided', {
- defaultMessage:
- 'This generator is not marked as deprecated. Please provide a createUrl fn.',
- })
- );
- }
-
- if (spec.createUrl && spec.isDeprecated) {
- throw new Error(
- i18n.translate('share.urlGenerators.error.createUrlFnProvided', {
- defaultMessage: 'This generator is marked as deprecated. Do not supply a createUrl fn.',
- })
- );
- }
- }
-
- getPublicContract(): UrlGeneratorContract {
- return {
- id: this.spec.id,
- createUrl: async (state: UrlGeneratorStateMapping[Id]['State']) => {
- if (this.spec.migrate && !this.spec.createUrl) {
- const { id, state: newState } = await this.spec.migrate(state);
-
- // eslint-disable-next-line
- console.warn(`URL generator is deprecated and may not work in future versions. Please migrate your data.`);
-
- return this.getGenerator(id!).createUrl(newState!);
- }
-
- return this.spec.createUrl!(state);
- },
- isDeprecated: !!this.spec.isDeprecated,
- };
- }
-}
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
deleted file mode 100644
index c07aa3f915b2e..0000000000000
--- a/src/plugins/share/public/url_generators/url_generator_service.test.ts
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License
- * 2.0 and the Server Side Public License, v 1; you may not use this file except
- * in compliance with, at your election, the Elastic License 2.0 or the Server
- * Side Public License, v 1.
- */
-
-import { UrlGeneratorsService } from './url_generator_service';
-import { coreMock } from '../../../../core/public/mocks';
-
-const service = new UrlGeneratorsService();
-
-const setup = service.setup(coreMock.createSetup());
-const start = service.start(coreMock.createStart());
-
-test('Asking for a generator that does not exist throws an error', () => {
- expect(() => start.getUrlGenerator('noexist')).toThrowError();
-});
-
-test('Registering and retrieving a generator', async () => {
- const generator = setup.registerUrlGenerator({
- id: 'TEST_GENERATOR',
- createUrl: () => Promise.resolve('myurl'),
- });
-
- expect(generator).toMatchInlineSnapshot(`
- Object {
- "createUrl": [Function],
- "id": "TEST_GENERATOR",
- "isDeprecated": false,
- }
- `);
- expect(await generator.createUrl({})).toBe('myurl');
-
- const retrievedGenerator = start.getUrlGenerator('TEST_GENERATOR');
- expect(retrievedGenerator).toMatchInlineSnapshot(`
- Object {
- "createUrl": [Function],
- "id": "TEST_GENERATOR",
- "isDeprecated": false,
- }
- `);
- expect(await generator.createUrl({})).toBe('myurl');
-});
-
-test('Registering a generator with a createUrl function that is deprecated throws an error', () => {
- expect(() =>
- setup.registerUrlGenerator({
- id: 'TEST_GENERATOR',
- migrate: () => Promise.resolve({ id: '', state: {} }),
- createUrl: () => Promise.resolve('myurl'),
- isDeprecated: true,
- })
- ).toThrowError(
- new Error('This generator is marked as deprecated. Do not supply a createUrl fn.')
- );
-});
-
-test('Registering a deprecated generator with no migration function throws an error', () => {
- expect(() =>
- setup.registerUrlGenerator({
- id: 'TEST_GENERATOR',
- isDeprecated: true,
- })
- ).toThrowError(
- new Error(
- 'If the access link generator is marked as deprecated, you must provide a migration function.'
- )
- );
-});
-
-test('Registering a generator with no functions throws an error', () => {
- expect(() =>
- setup.registerUrlGenerator({
- id: 'TEST_GENERATOR',
- })
- ).toThrowError(
- new Error('This generator is not marked as deprecated. Please provide a createUrl fn.')
- );
-});
-
-test('Registering a generator with a migrate function that is not deprecated throws an error', () => {
- expect(() =>
- setup.registerUrlGenerator({
- id: 'TEST_GENERATOR',
- migrate: () => Promise.resolve({ id: '', state: {} }),
- isDeprecated: false,
- })
- ).toThrowError(
- new Error('If you provide a migration function, you must mark this generator as deprecated')
- );
-});
-
-test('Registering a generator with a migrate function and a createUrl fn throws an error', () => {
- expect(() =>
- setup.registerUrlGenerator({
- id: 'TEST_GENERATOR',
- createUrl: () => Promise.resolve('myurl'),
- migrate: () => Promise.resolve({ id: '', state: {} }),
- })
- ).toThrowError();
-});
-
-test('Generator returns migrated url', async () => {
- setup.registerUrlGenerator({
- id: 'v1',
- migrate: (state: { bar: string }) => Promise.resolve({ id: 'v2', state: { foo: state.bar } }),
- isDeprecated: true,
- });
- setup.registerUrlGenerator({
- id: 'v2',
- createUrl: (state: { foo: string }) => Promise.resolve(`www.${state.foo}.com`),
- isDeprecated: false,
- });
-
- const generator = start.getUrlGenerator('v1');
- expect(generator.isDeprecated).toBe(true);
- expect(await generator.createUrl({ bar: 'hi' })).toEqual('www.hi.com');
-});
diff --git a/src/plugins/share/public/url_generators/url_generator_service.ts b/src/plugins/share/public/url_generators/url_generator_service.ts
deleted file mode 100644
index 5a8e7a1b5c17a..0000000000000
--- a/src/plugins/share/public/url_generators/url_generator_service.ts
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License
- * 2.0 and the Server Side Public License, v 1; you may not use this file except
- * in compliance with, at your election, the Elastic License 2.0 or the Server
- * Side Public License, v 1.
- */
-
-import { CoreSetup, CoreStart, Plugin } from 'src/core/public';
-import { i18n } from '@kbn/i18n';
-import { UrlGeneratorId, UrlGeneratorsDefinition } from './url_generator_definition';
-import { UrlGeneratorInternal } from './url_generator_internal';
-import { UrlGeneratorContract } from './url_generator_contract';
-
-export interface UrlGeneratorsStart {
- /**
- * @deprecated
- *
- * URL Generators are deprecated, use URL locators in UrlService instead.
- */
- getUrlGenerator: (urlGeneratorId: T) => UrlGeneratorContract;
-}
-
-export interface UrlGeneratorsSetup {
- /**
- * @deprecated
- *
- * URL Generators are deprecated, use URL locators in UrlService instead.
- */
- registerUrlGenerator: (
- generator: UrlGeneratorsDefinition
- ) => UrlGeneratorContract;
-}
-
-export class UrlGeneratorsService implements Plugin {
- // Unfortunate use of any here, but I haven't figured out how to type this any better without
- // getting warnings.
- private urlGenerators: Map> = new Map();
-
- constructor() {}
-
- public setup(core: CoreSetup) {
- const setup: UrlGeneratorsSetup = {
- registerUrlGenerator: (
- generatorOptions: UrlGeneratorsDefinition
- ) => {
- const generator = new UrlGeneratorInternal(generatorOptions, this.getUrlGenerator);
- this.urlGenerators.set(generatorOptions.id, generator);
- return generator.getPublicContract();
- },
- };
- return setup;
- }
-
- public start(core: CoreStart) {
- const start: UrlGeneratorsStart = {
- getUrlGenerator: this.getUrlGenerator,
- };
- return start;
- }
-
- public stop() {}
-
- private readonly getUrlGenerator = (id: UrlGeneratorId) => {
- const generator = this.urlGenerators.get(id);
- if (!generator) {
- throw new Error(
- i18n.translate('share.urlGenerators.errors.noGeneratorWithId', {
- defaultMessage: 'No generator found with id {id}',
- values: { id },
- })
- );
- }
- return generator.getPublicContract();
- };
-}
diff --git a/src/plugins/shared_ux/public/components/exit_full_screen_button/exit_full_screen_button.tsx b/src/plugins/shared_ux/public/components/exit_full_screen_button/exit_full_screen_button.tsx
index eb941593bdf1a..1f0b2f43a6b25 100644
--- a/src/plugins/shared_ux/public/components/exit_full_screen_button/exit_full_screen_button.tsx
+++ b/src/plugins/shared_ux/public/components/exit_full_screen_button/exit_full_screen_button.tsx
@@ -25,8 +25,10 @@ export interface Props {
/**
* A service-enabled component that provides Kibana-specific functionality to the `ExitFullScreenButton`
- * component. Use of this component requires both the `EuiTheme` context as well as the Shared UX
- * `ServicesProvider`.
+ * component.
+ *
+ * Use of this component requires both the `EuiTheme` context as well as either a configured Shared UX
+ * `ServicesProvider` or the `ServicesContext` provided by the Shared UX public plugin contract.
*
* See shared-ux/public/services for information.
*/
diff --git a/src/plugins/shared_ux/public/components/exit_full_screen_button/index.ts b/src/plugins/shared_ux/public/components/exit_full_screen_button/index.ts
index 0baf60d8499ca..66ffe2976d786 100644
--- a/src/plugins/shared_ux/public/components/exit_full_screen_button/index.ts
+++ b/src/plugins/shared_ux/public/components/exit_full_screen_button/index.ts
@@ -5,13 +5,5 @@
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
-/* eslint-disable import/no-default-export */
-import { ExitFullScreenButton } from './exit_full_screen_button';
export { ExitFullScreenButton } from './exit_full_screen_button';
-
-/**
- * Exporting the ExitFullScreenButton component as a default export so it can be
- * loaded by React.lazy.
- */
-export default ExitFullScreenButton;
diff --git a/src/plugins/shared_ux/public/components/index.ts b/src/plugins/shared_ux/public/components/index.ts
index f3c25ca023e8d..3c5e4424f99f5 100644
--- a/src/plugins/shared_ux/public/components/index.ts
+++ b/src/plugins/shared_ux/public/components/index.ts
@@ -13,7 +13,11 @@ import { withSuspense } from './utility';
* The Lazily-loaded `ExitFullScreenButton` component. Consumers should use `React.Suspennse` or the
* `withSuspense` HOC to load this component.
*/
-export const LazyExitFullScreenButton = React.lazy(() => import('./exit_full_screen_button'));
+export const LazyExitFullScreenButton = React.lazy(() =>
+ import('./exit_full_screen_button').then(({ ExitFullScreenButton }) => ({
+ default: ExitFullScreenButton,
+ }))
+);
/**
* A `ExitFullScreenButton` component that is wrapped by the `withSuspense` HOC. This component can
diff --git a/src/plugins/shared_ux/public/services/index.tsx b/src/plugins/shared_ux/public/services/index.tsx
index acc8b9294d1df..0677f3ef0ca84 100644
--- a/src/plugins/shared_ux/public/services/index.tsx
+++ b/src/plugins/shared_ux/public/services/index.tsx
@@ -27,8 +27,11 @@ const ServicesContext = createContext(servicesFactory());
/**
* The `React.Context` Provider component for the `SharedUXServices` context. Any
- * plugin or environemnt that consumes SharedUX components needs to wrap their React
+ * plugin or environment that consumes SharedUX components needs to wrap their React
* tree with this provider.
+ *
+ * Within a plugin, you can use the `ServicesContext` provided by the SharedUX plugin start
+ * lifeycle method.
*/
export const ServicesProvider: FC = ({ children, ...services }) => (
{children}
diff --git a/src/plugins/vis_types/timeseries/public/metrics_type.ts b/src/plugins/vis_types/timeseries/public/metrics_type.ts
index ff613c0eadb06..0c5b365938058 100644
--- a/src/plugins/vis_types/timeseries/public/metrics_type.ts
+++ b/src/plugins/vis_types/timeseries/public/metrics_type.ts
@@ -26,7 +26,6 @@ import {
} from '../../../visualizations/public';
import { getDataStart } from './services';
import type { TimeseriesVisDefaultParams, TimeseriesVisParams } from './types';
-import { triggerTSVBtoLensConfiguration } from './trigger_action';
import type { IndexPatternValue, Panel } from '../common/types';
import { RequestAdapter } from '../../../inspector/public';
@@ -169,6 +168,8 @@ export const metricsVisDefinition: VisTypeDefinition<
return [];
},
navigateToLens: async (params?: VisParams) => {
+ const { triggerTSVBtoLensConfiguration } = await import('./trigger_action');
+
const triggerConfiguration = params
? await triggerTSVBtoLensConfiguration(params as Panel)
: null;
diff --git a/src/plugins/vis_types/timeseries/public/trigger_action/get_series.test.ts b/src/plugins/vis_types/timeseries/public/trigger_action/get_series.test.ts
index 7410c95677cff..3b01aeebb2dcf 100644
--- a/src/plugins/vis_types/timeseries/public/trigger_action/get_series.test.ts
+++ b/src/plugins/vis_types/timeseries/public/trigger_action/get_series.test.ts
@@ -84,6 +84,32 @@ describe('getSeries', () => {
]);
});
+ test('should return the correct formula config for a positive only function', () => {
+ const metric = [
+ {
+ field: 'day_of_week_i',
+ id: '123456',
+ type: 'max',
+ },
+ {
+ id: '891011',
+ type: 'positive_only',
+ field: '123456',
+ },
+ ] as Metric[];
+ const config = getSeries(metric);
+ expect(config).toStrictEqual([
+ {
+ agg: 'formula',
+ fieldName: 'document',
+ isFullReference: true,
+ params: {
+ formula: 'clamp(max(day_of_week_i), 0, max(day_of_week_i))',
+ },
+ },
+ ]);
+ });
+
test('should return the correct config for the cumulative sum on count', () => {
const metric = [
{
@@ -299,6 +325,42 @@ describe('getSeries', () => {
]);
});
+ test('should return the correct formula config for a top_hit size 1 aggregation', () => {
+ const metric = [
+ {
+ id: '12345',
+ type: 'top_hit',
+ field: 'day_of_week_i',
+ size: 1,
+ order_by: 'timestamp',
+ },
+ ] as Metric[];
+ const config = getSeries(metric);
+ expect(config).toStrictEqual([
+ {
+ agg: 'last_value',
+ fieldName: 'day_of_week_i',
+ isFullReference: false,
+ params: {
+ sortField: 'timestamp',
+ },
+ },
+ ]);
+ });
+
+ test('should return null for a top_hit size >1 aggregation', () => {
+ const metric = [
+ {
+ id: '12345',
+ type: 'top_hit',
+ field: 'day_of_week_i',
+ size: 2,
+ },
+ ] as Metric[];
+ const config = getSeries(metric);
+ expect(config).toBeNull();
+ });
+
test('should return the correct formula for the math aggregation with percentiles as variables', () => {
const metric = [
{
diff --git a/src/plugins/vis_types/timeseries/public/trigger_action/get_series.ts b/src/plugins/vis_types/timeseries/public/trigger_action/get_series.ts
index eed1594300b92..5e7d39f3085f6 100644
--- a/src/plugins/vis_types/timeseries/public/trigger_action/get_series.ts
+++ b/src/plugins/vis_types/timeseries/public/trigger_action/get_series.ts
@@ -57,6 +57,15 @@ export const getSeries = (metrics: Metric[]): VisualizeEditorLayersContext['metr
continue;
}
const currentMetric = metrics[layerMetricIdx];
+ // We can only support top_hit with size 1
+ if (
+ (currentMetric.type === 'top_hit' &&
+ currentMetric?.size &&
+ Number(currentMetric?.size) !== 1) ||
+ currentMetric?.order === 'asc'
+ ) {
+ return null;
+ }
// should treat percentiles differently
if (currentMetric.type === 'percentile') {
@@ -125,6 +134,14 @@ export const getSeries = (metrics: Metric[]): VisualizeEditorLayersContext['metr
}
break;
}
+ case 'positive_only': {
+ const formula = getSiblingPipelineSeriesFormula(aggregation, metrics[metricIdx], metrics);
+ if (!formula) {
+ return null;
+ }
+ metricsArray = getFormulaSeries(formula) as VisualizeEditorLayersContext['metrics'];
+ break;
+ }
case 'avg_bucket':
case 'max_bucket':
case 'min_bucket':
@@ -144,6 +161,29 @@ export const getSeries = (metrics: Metric[]): VisualizeEditorLayersContext['metr
metricsArray = getFormulaSeries(formula);
break;
}
+ case 'top_hit': {
+ const currentMetric = metrics[metricIdx];
+ // We can only support top_hit with size 1
+ if (
+ (currentMetric?.size && Number(currentMetric?.size) !== 1) ||
+ currentMetric?.order === 'asc'
+ ) {
+ return null;
+ }
+ const timeScale = getTimeScale(currentMetric);
+ metricsArray = [
+ {
+ agg: aggregationMap.name,
+ isFullReference: aggregationMap.isFullReference,
+ fieldName: fieldName ?? 'document',
+ params: {
+ ...(timeScale && { timeScale }),
+ ...(currentMetric?.order_by && { sortField: currentMetric?.order_by }),
+ },
+ },
+ ];
+ break;
+ }
default: {
const timeScale = getTimeScale(metrics[metricIdx]);
metricsArray = [
diff --git a/src/plugins/vis_types/timeseries/public/trigger_action/metrics_helpers.ts b/src/plugins/vis_types/timeseries/public/trigger_action/metrics_helpers.ts
index 07140c9fdd9d1..dc9457ac1fafc 100644
--- a/src/plugins/vis_types/timeseries/public/trigger_action/metrics_helpers.ts
+++ b/src/plugins/vis_types/timeseries/public/trigger_action/metrics_helpers.ts
@@ -192,20 +192,31 @@ export const getSiblingPipelineSeriesFormula = (
return null;
}
const aggregationMap = SUPPORTED_METRICS[aggregation];
- const subMetricField = subFunctionMetric.field;
+ const subMetricField = subFunctionMetric.type !== 'count' ? subFunctionMetric.field : '';
// support nested aggs with formula
const additionalSubFunction = metrics.find((metric) => metric.id === subMetricField);
let formula = `${aggregationMap.name}(`;
+ let minMax = '';
if (additionalSubFunction) {
const additionalPipelineAggMap = SUPPORTED_METRICS[additionalSubFunction.type];
if (!additionalPipelineAggMap) {
return null;
}
+ const additionalSubFunctionField =
+ additionalSubFunction.type !== 'count' ? additionalSubFunction.field : '';
+ if (currentMetric.type === 'positive_only') {
+ minMax = `, 0, ${pipelineAggMap.name}(${additionalPipelineAggMap.name}(${
+ additionalSubFunctionField ?? ''
+ }))`;
+ }
formula += `${pipelineAggMap.name}(${additionalPipelineAggMap.name}(${
- additionalSubFunction.field ?? ''
- })))`;
+ additionalSubFunctionField ?? ''
+ }))${minMax})`;
} else {
- formula += `${pipelineAggMap.name}(${subFunctionMetric.field ?? ''}))`;
+ if (currentMetric.type === 'positive_only') {
+ minMax = `, 0, ${pipelineAggMap.name}(${subMetricField ?? ''})`;
+ }
+ formula += `${pipelineAggMap.name}(${subMetricField ?? ''})${minMax})`;
}
return formula;
};
@@ -262,7 +273,8 @@ export const getFormulaEquivalent = (
case 'avg_bucket':
case 'max_bucket':
case 'min_bucket':
- case 'sum_bucket': {
+ case 'sum_bucket':
+ case 'positive_only': {
return getSiblingPipelineSeriesFormula(currentMetric.type, currentMetric, metrics);
}
case 'count': {
diff --git a/src/plugins/vis_types/timeseries/public/trigger_action/supported_metrics.ts b/src/plugins/vis_types/timeseries/public/trigger_action/supported_metrics.ts
index b3d58d81105ab..354b60c31854a 100644
--- a/src/plugins/vis_types/timeseries/public/trigger_action/supported_metrics.ts
+++ b/src/plugins/vis_types/timeseries/public/trigger_action/supported_metrics.ts
@@ -80,8 +80,16 @@ export const SUPPORTED_METRICS: { [key: string]: AggOptions } = {
name: 'filter_ratio',
isFullReference: false,
},
+ top_hit: {
+ name: 'last_value',
+ isFullReference: false,
+ },
math: {
name: 'formula',
isFullReference: true,
},
+ positive_only: {
+ name: 'clamp',
+ isFullReference: true,
+ },
};
diff --git a/src/plugins/vis_types/vega/public/components/vega_vis_component.tsx b/src/plugins/vis_types/vega/public/components/vega_vis_component.tsx
index 66cb87d0d6138..f9b6f3c0e36df 100644
--- a/src/plugins/vis_types/vega/public/components/vega_vis_component.tsx
+++ b/src/plugins/vis_types/vega/public/components/vega_vis_component.tsx
@@ -6,8 +6,8 @@
* Side Public License, v 1.
*/
-import React, { useEffect, useCallback, useRef } from 'react';
-import { EuiResizeObserver } from '@elastic/eui';
+import React, { useEffect, useRef, useMemo, useCallback } from 'react';
+import { EuiResizeObserver, EuiResizeObserverProps } from '@elastic/eui';
import { throttle } from 'lodash';
import type { IInterpreterRenderHandlers, RenderMode } from 'src/plugins/expressions';
@@ -27,6 +27,8 @@ interface VegaVisComponentProps {
type VegaVisController = InstanceType>;
+const THROTTLE_INTERVAL = 300;
+
export const VegaVisComponent = ({
visData,
fireEvent,
@@ -35,6 +37,7 @@ export const VegaVisComponent = ({
renderMode,
}: VegaVisComponentProps) => {
const chartDiv = useRef(null);
+ const renderCompleted = useRef(false);
const visController = useRef(null);
useEffect(() => {
@@ -42,7 +45,6 @@ export const VegaVisComponent = ({
const VegaVis = createVegaVisualization(deps, renderMode);
visController.current = new VegaVis(chartDiv.current, fireEvent);
}
-
return () => {
visController.current?.destroy();
visController.current = null;
@@ -50,23 +52,40 @@ export const VegaVisComponent = ({
}, [deps, fireEvent, renderMode]);
useEffect(() => {
+ const asyncRender = async (visCtrl: VegaVisController) => {
+ await visCtrl.render(visData);
+ renderCompleted.current = true;
+ renderComplete();
+ };
+
if (visController.current) {
- visController.current.render(visData).then(renderComplete);
+ asyncRender(visController.current);
}
- }, [visData, renderComplete]);
+ }, [renderComplete, visData]);
+
+ const resizeChart = useMemo(
+ () =>
+ throttle(
+ (dimensions) => {
+ visController.current?.resize(dimensions);
+ },
+ THROTTLE_INTERVAL,
+ { leading: false, trailing: true }
+ ),
+ []
+ );
- /* eslint-disable-next-line react-hooks/exhaustive-deps */
- const updateChartSize = useCallback(
- throttle(() => {
- if (visController.current) {
- visController.current.render(visData).then(renderComplete);
+ const onContainerResize: EuiResizeObserverProps['onResize'] = useCallback(
+ (dimensions) => {
+ if (renderCompleted.current) {
+ resizeChart(dimensions);
}
- }, 300),
- [renderComplete, visData]
+ },
+ [resizeChart]
);
return (
-
+
{(resizeRef) => (
diff --git a/src/plugins/vis_types/vega/public/vega_view/vega_base_view.d.ts b/src/plugins/vis_types/vega/public/vega_view/vega_base_view.d.ts
index a1d79394de4eb..1ddd2849e3f39 100644
--- a/src/plugins/vis_types/vega/public/vega_view/vega_base_view.d.ts
+++ b/src/plugins/vis_types/vega/public/vega_view/vega_base_view.d.ts
@@ -34,6 +34,7 @@ export class VegaBaseView {
_addDestroyHandler(handler: Function): void;
destroy(): Promise
;
+ resize(dimensions?: { height: number; width: number }): Promise;
_$container: any;
_$controls: any;
diff --git a/src/plugins/vis_types/vega/public/vega_view/vega_base_view.js b/src/plugins/vis_types/vega/public/vega_view/vega_base_view.js
index 25cfcdb4dde04..c6ec924f07d9d 100644
--- a/src/plugins/vis_types/vega/public/vega_view/vega_base_view.js
+++ b/src/plugins/vis_types/vega/public/vega_view/vega_base_view.js
@@ -262,16 +262,19 @@ export class VegaBaseView {
}
}
- resize() {
+ async resize(dimensions) {
if (this._parser.useResize && this._view) {
- this.updateVegaSize(this._view);
- return this._view.runAsync();
+ this.updateVegaSize(this._view, dimensions);
+ await this._view.runAsync();
+
+ // The derived class should create this method
+ this.onViewContainerResize?.();
}
}
- updateVegaSize(view) {
- const width = Math.floor(Math.max(0, this._$container.width()));
- const height = Math.floor(Math.max(0, this._$container.height()));
+ updateVegaSize(view, dimensions) {
+ const width = Math.floor(Math.max(0, dimensions?.width ?? this._$container.width()));
+ const height = Math.floor(Math.max(0, dimensions?.height ?? this._$container.height()));
if (view.width() !== width || view.height() !== height) {
view.width(width).height(height);
diff --git a/src/plugins/vis_types/vega/public/vega_view/vega_map_view/view.ts b/src/plugins/vis_types/vega/public/vega_view/vega_map_view/view.ts
index be68abaebc638..fe8d85a011442 100644
--- a/src/plugins/vis_types/vega/public/vega_view/vega_map_view/view.ts
+++ b/src/plugins/vis_types/vega/public/vega_view/vega_map_view/view.ts
@@ -46,6 +46,8 @@ async function updateVegaView(mapBoxInstance: Map, vegaView: View) {
}
export class VegaMapView extends VegaBaseView {
+ private mapBoxInstance?: Map;
+
private get shouldShowZoomControl() {
return Boolean(this._parser.mapConfig.zoomControl);
}
@@ -139,6 +141,7 @@ export class VegaMapView extends VegaBaseView {
};
mapBoxInstance.once('load', initMapComponents);
+ this.mapBoxInstance = mapBoxInstance;
});
}
@@ -193,4 +196,8 @@ export class VegaMapView extends VegaBaseView {
await this.initMapContainer(vegaView);
}
+
+ protected async onViewContainerResize() {
+ this.mapBoxInstance?.resize();
+ }
}
diff --git a/src/plugins/vis_types/vega/public/vega_vis_renderer.tsx b/src/plugins/vis_types/vega/public/vega_vis_renderer.tsx
index a7bab7f0f0860..ac36c9f2d20e1 100644
--- a/src/plugins/vis_types/vega/public/vega_vis_renderer.tsx
+++ b/src/plugins/vis_types/vega/public/vega_vis_renderer.tsx
@@ -27,7 +27,6 @@ export const getVegaVisRenderer: (
handlers.onDestroy(() => {
unmountComponentAtNode(domNode);
});
-
render(
diff --git a/src/plugins/vis_types/vega/public/vega_visualization.ts b/src/plugins/vis_types/vega/public/vega_visualization.ts
index f9a18067e6886..49e6355a7109d 100644
--- a/src/plugins/vis_types/vega/public/vega_visualization.ts
+++ b/src/plugins/vis_types/vega/public/vega_visualization.ts
@@ -16,6 +16,7 @@ import { createVegaStateRestorer } from './lib/vega_state_restorer';
type VegaVisType = new (el: HTMLDivElement, fireEvent: IInterpreterRenderHandlers['event']) => {
render(visData: VegaParser): Promise;
+ resize(dimensions?: { height: number; width: number }): Promise;
destroy(): void;
};
@@ -97,6 +98,10 @@ export const createVegaVisualization = (
}
}
+ async resize(dimensions?: { height: number; width: number }) {
+ return this.vegaView?.resize(dimensions);
+ }
+
destroy() {
this.vegaStateRestorer.clear();
this.vegaView?.destroy();
diff --git a/src/plugins/visualizations/public/embeddable/visualize_embeddable.tsx b/src/plugins/visualizations/public/embeddable/visualize_embeddable.tsx
index 24b451533532f..efc3bbf8314f8 100644
--- a/src/plugins/visualizations/public/embeddable/visualize_embeddable.tsx
+++ b/src/plugins/visualizations/public/embeddable/visualize_embeddable.tsx
@@ -401,7 +401,7 @@ export class VisualizeEmbeddable
const parentContext = this.parent?.getInput().executionContext;
const child: KibanaExecutionContext = {
type: 'visualization',
- name: this.vis.type.title,
+ name: this.vis.type.name,
id: this.vis.id ?? 'an_unsaved_vis',
description: this.vis.title || this.input.title || this.vis.type.name,
url: this.output.editUrl,
diff --git a/test/functional/apps/context/_date_nanos.ts b/test/functional/apps/context/_date_nanos.ts
index 6b7b28a4c7690..84793150b3edc 100644
--- a/test/functional/apps/context/_date_nanos.ts
+++ b/test/functional/apps/context/_date_nanos.ts
@@ -24,16 +24,20 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
before(async function () {
await security.testUser.setRoles(['kibana_admin', 'kibana_date_nanos']);
await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/date_nanos');
+ await kibanaServer.savedObjects.clean({ types: ['search', 'index-pattern'] });
+ await kibanaServer.importExport.load('test/functional/fixtures/kbn_archiver/date_nanos');
await kibanaServer.uiSettings.replace({ defaultIndex: TEST_INDEX_PATTERN });
await kibanaServer.uiSettings.update({
'context:defaultSize': `${TEST_DEFAULT_CONTEXT_SIZE}`,
'context:step': `${TEST_STEP_SIZE}`,
+ 'doc_table:legacy': true,
});
});
after(async function unloadMakelogs() {
await security.testUser.restoreDefaults();
await esArchiver.unload('test/functional/fixtures/es_archiver/date_nanos');
+ await kibanaServer.savedObjects.clean({ types: ['search', 'index-pattern'] });
});
it('displays predessors - anchor - successors in right order ', async function () {
diff --git a/test/functional/apps/context/_date_nanos_custom_timestamp.ts b/test/functional/apps/context/_date_nanos_custom_timestamp.ts
index 43714804a1912..1c9417968f8ab 100644
--- a/test/functional/apps/context/_date_nanos_custom_timestamp.ts
+++ b/test/functional/apps/context/_date_nanos_custom_timestamp.ts
@@ -24,10 +24,15 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
before(async function () {
await security.testUser.setRoles(['kibana_admin', 'kibana_date_nanos_custom']);
await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/date_nanos_custom');
+ await kibanaServer.savedObjects.clean({ types: ['search', 'index-pattern'] });
+ await kibanaServer.importExport.load(
+ 'test/functional/fixtures/kbn_archiver/date_nanos_custom'
+ );
await kibanaServer.uiSettings.replace({ defaultIndex: TEST_INDEX_PATTERN });
await kibanaServer.uiSettings.update({
'context:defaultSize': `${TEST_DEFAULT_CONTEXT_SIZE}`,
'context:step': `${TEST_STEP_SIZE}`,
+ 'doc_table:legacy': true,
});
});
@@ -45,6 +50,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
after(async function () {
await security.testUser.restoreDefaults();
await esArchiver.unload('test/functional/fixtures/es_archiver/date_nanos_custom');
+ await kibanaServer.savedObjects.clean({ types: ['search', 'index-pattern'] });
});
});
}
diff --git a/test/functional/apps/context/_filters.ts b/test/functional/apps/context/_filters.ts
index d07cf802b7ebb..103d08f8f6a95 100644
--- a/test/functional/apps/context/_filters.ts
+++ b/test/functional/apps/context/_filters.ts
@@ -18,10 +18,19 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
const docTable = getService('docTable');
const filterBar = getService('filterBar');
const retry = getService('retry');
+ const kibanaServer = getService('kibanaServer');
const PageObjects = getPageObjects(['common', 'context']);
describe('context filters', function contextSize() {
+ before(async function () {
+ await kibanaServer.uiSettings.update({ 'doc_table:legacy': true });
+ });
+
+ after(async function () {
+ await kibanaServer.uiSettings.replace({});
+ });
+
beforeEach(async function () {
await PageObjects.context.navigateTo(TEST_INDEX_PATTERN, TEST_ANCHOR_ID, {
columns: TEST_COLUMN_NAMES,
diff --git a/test/functional/apps/context/_size.ts b/test/functional/apps/context/_size.ts
index 52b16d2b9abe5..10f7b125c46b5 100644
--- a/test/functional/apps/context/_size.ts
+++ b/test/functional/apps/context/_size.ts
@@ -28,6 +28,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
await kibanaServer.uiSettings.update({
'context:defaultSize': `${TEST_DEFAULT_CONTEXT_SIZE}`,
'context:step': `${TEST_STEP_SIZE}`,
+ 'doc_table:legacy': true,
});
await PageObjects.context.navigateTo(TEST_INDEX_PATTERN, TEST_ANCHOR_ID);
});
diff --git a/test/functional/apps/dashboard/dashboard_time_picker.ts b/test/functional/apps/dashboard/dashboard_time_picker.ts
index 8a25f941be70f..6f876185fd8dd 100644
--- a/test/functional/apps/dashboard/dashboard_time_picker.ts
+++ b/test/functional/apps/dashboard/dashboard_time_picker.ts
@@ -68,8 +68,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
);
await dashboardExpect.docTableFieldCount(0);
} else {
- const initialRows = await dataGrid.getDocTableRows();
- expect(initialRows.length).to.above(10);
+ const docCount = await dataGrid.getDocCount();
+ expect(docCount).to.above(10);
// Set to time range with no data
await PageObjects.timePicker.setAbsoluteRange(
diff --git a/test/functional/apps/dashboard/saved_search_embeddable.ts b/test/functional/apps/dashboard/saved_search_embeddable.ts
index ce1033fa02075..b08dc43210d26 100644
--- a/test/functional/apps/dashboard/saved_search_embeddable.ts
+++ b/test/functional/apps/dashboard/saved_search_embeddable.ts
@@ -48,7 +48,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
const marks = $('mark')
.toArray()
.map((mark) => $(mark).text());
- expect(marks.length).to.above(10);
+ expect(marks.length).to.above(0);
});
it('removing a filter removes highlights', async function () {
diff --git a/test/functional/apps/discover/_date_nanos.ts b/test/functional/apps/discover/_date_nanos.ts
index 81327d0744bfe..dcabb3dac0585 100644
--- a/test/functional/apps/discover/_date_nanos.ts
+++ b/test/functional/apps/discover/_date_nanos.ts
@@ -21,6 +21,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
describe('date_nanos', function () {
before(async function () {
await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/date_nanos');
+ await kibanaServer.savedObjects.clean({ types: ['search', 'index-pattern'] });
+ await kibanaServer.importExport.load('test/functional/fixtures/kbn_archiver/date_nanos');
await kibanaServer.uiSettings.replace({ defaultIndex: 'date-nanos' });
await security.testUser.setRoles(['kibana_admin', 'kibana_date_nanos']);
await PageObjects.common.navigateToApp('discover');
@@ -30,6 +32,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
after(async function unloadMakelogs() {
await security.testUser.restoreDefaults();
await esArchiver.unload('test/functional/fixtures/es_archiver/date_nanos');
+ await kibanaServer.savedObjects.clean({ types: ['search', 'index-pattern'] });
});
it('should show a timestamp with nanoseconds in the first result row', async function () {
diff --git a/test/functional/apps/discover/_date_nanos_mixed.ts b/test/functional/apps/discover/_date_nanos_mixed.ts
index 7d4104c3ac344..5cd72a67f36b1 100644
--- a/test/functional/apps/discover/_date_nanos_mixed.ts
+++ b/test/functional/apps/discover/_date_nanos_mixed.ts
@@ -21,6 +21,10 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
describe('date_nanos_mixed', function () {
before(async function () {
await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/date_nanos_mixed');
+ await kibanaServer.savedObjects.clean({ types: ['search', 'index-pattern'] });
+ await kibanaServer.importExport.load(
+ 'test/functional/fixtures/kbn_archiver/date_nanos_mixed'
+ );
await kibanaServer.uiSettings.replace({ defaultIndex: 'timestamp-*' });
await security.testUser.setRoles(['kibana_admin', 'kibana_date_nanos_mixed']);
await PageObjects.common.navigateToApp('discover');
@@ -30,6 +34,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
after(async () => {
await security.testUser.restoreDefaults();
esArchiver.unload('test/functional/fixtures/es_archiver/date_nanos_mixed');
+ await kibanaServer.savedObjects.clean({ types: ['search', 'index-pattern'] });
});
it('shows a list of records of indices with date & date_nanos fields in the right order', async function () {
diff --git a/test/functional/apps/discover/_discover_fields_api.ts b/test/functional/apps/discover/_discover_fields_api.ts
index 700c865031cd6..fb3ee3b9858d3 100644
--- a/test/functional/apps/discover/_discover_fields_api.ts
+++ b/test/functional/apps/discover/_discover_fields_api.ts
@@ -11,7 +11,6 @@ import { FtrProviderContext } from './ftr_provider_context';
export default function ({ getService, getPageObjects }: FtrProviderContext) {
const log = getService('log');
- const docTable = getService('docTable');
const retry = getService('retry');
const esArchiver = getService('esArchiver');
const kibanaServer = getService('kibanaServer');
@@ -19,6 +18,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
const defaultSettings = {
defaultIndex: 'logstash-*',
'discover:searchFieldsFromSource': false,
+ 'doc_table:legacy': true,
};
describe('discover uses fields API test', function describeIndexTests() {
before(async function () {
@@ -27,13 +27,12 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
await kibanaServer.importExport.load('test/functional/fixtures/kbn_archiver/discover.json');
await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/logstash_functional');
await kibanaServer.uiSettings.replace(defaultSettings);
- log.debug('discover');
await PageObjects.common.navigateToApp('discover');
await PageObjects.timePicker.setDefaultAbsoluteRange();
});
after(async () => {
- await kibanaServer.uiSettings.replace({ 'discover:searchFieldsFromSource': true });
+ await kibanaServer.uiSettings.replace({});
});
it('should correctly display documents', async function () {
@@ -61,8 +60,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
});
it('displays _source viewer in doc viewer', async function () {
- await docTable.clickRowToggle({ rowIndex: 0 });
-
+ await PageObjects.discover.clickDocTableRowToggle(0);
await PageObjects.discover.isShowingDocViewer();
await PageObjects.discover.clickDocViewerTab(1);
await PageObjects.discover.expectSourceViewerToExist();
diff --git a/test/functional/apps/discover/_errors.ts b/test/functional/apps/discover/_errors.ts
index b252cbf5f0824..327f39ee0dec4 100644
--- a/test/functional/apps/discover/_errors.ts
+++ b/test/functional/apps/discover/_errors.ts
@@ -11,6 +11,7 @@ import { FtrProviderContext } from '../../ftr_provider_context';
export default function ({ getService, getPageObjects }: FtrProviderContext) {
const esArchiver = getService('esArchiver');
+ const kibanaServer = getService('kibanaServer');
const toasts = getService('toasts');
const testSubjects = getService('testSubjects');
const PageObjects = getPageObjects(['common', 'header', 'discover', 'timePicker']);
@@ -18,13 +19,16 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
describe('errors', function describeIndexTests() {
before(async function () {
await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/logstash_functional');
- await esArchiver.load('test/functional/fixtures/es_archiver/invalid_scripted_field');
+ await kibanaServer.savedObjects.clean({ types: ['search', 'index-pattern'] });
+ await kibanaServer.importExport.load(
+ 'test/functional/fixtures/kbn_archiver/invalid_scripted_field'
+ );
await PageObjects.timePicker.setDefaultAbsoluteRangeViaUiSettings();
await PageObjects.common.navigateToApp('discover');
});
after(async function () {
- await esArchiver.load('test/functional/fixtures/es_archiver/empty_kibana');
+ await kibanaServer.savedObjects.clean({ types: ['search', 'index-pattern'] });
});
describe('invalid scripted field error', () => {
diff --git a/test/functional/apps/discover/_indexpattern_with_unmapped_fields.ts b/test/functional/apps/discover/_indexpattern_with_unmapped_fields.ts
index 2a1e60db541e8..c3982ba72824b 100644
--- a/test/functional/apps/discover/_indexpattern_with_unmapped_fields.ts
+++ b/test/functional/apps/discover/_indexpattern_with_unmapped_fields.ts
@@ -19,6 +19,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
describe('index pattern with unmapped fields', () => {
before(async () => {
await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/unmapped_fields');
+ await kibanaServer.savedObjects.clean({ types: ['search', 'index-pattern'] });
+ await kibanaServer.importExport.load('test/functional/fixtures/kbn_archiver/unmapped_fields');
await security.testUser.setRoles(['kibana_admin', 'test-index-unmapped-fields']);
const fromTime = 'Jan 20, 2021 @ 00:00:00.000';
const toTime = 'Jan 25, 2021 @ 00:00:00.000';
@@ -35,6 +37,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
after(async () => {
await esArchiver.unload('test/functional/fixtures/es_archiver/unmapped_fields');
+ await kibanaServer.savedObjects.clean({ types: ['search', 'index-pattern'] });
await kibanaServer.uiSettings.unset('defaultIndex');
await kibanaServer.uiSettings.unset('discover:searchFieldsFromSource');
await kibanaServer.uiSettings.unset('timepicker:timeDefaults');
diff --git a/test/functional/apps/discover/_indexpattern_without_timefield.ts b/test/functional/apps/discover/_indexpattern_without_timefield.ts
index 6d6e1af7b2fbc..2d5892fa6e6ca 100644
--- a/test/functional/apps/discover/_indexpattern_without_timefield.ts
+++ b/test/functional/apps/discover/_indexpattern_without_timefield.ts
@@ -23,6 +23,10 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
await esArchiver.loadIfNeeded(
'test/functional/fixtures/es_archiver/index_pattern_without_timefield'
);
+ await kibanaServer.savedObjects.clean({ types: ['search', 'index-pattern'] });
+ await kibanaServer.importExport.load(
+ 'test/functional/fixtures/kbn_archiver/index_pattern_without_timefield'
+ );
await kibanaServer.uiSettings.replace({
defaultIndex: 'without-timefield',
'timepicker:timeDefaults': '{ "from": "2019-01-18T19:37:13.000Z", "to": "now"}',
@@ -37,6 +41,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
await esArchiver.unload(
'test/functional/fixtures/es_archiver/index_pattern_without_timefield'
);
+ await kibanaServer.savedObjects.clean({ types: ['search', 'index-pattern'] });
});
it('should not display a timepicker', async () => {
diff --git a/test/functional/apps/management/_scripted_fields_filter.js b/test/functional/apps/management/_scripted_fields_filter.js
index 6a7d414becfe7..117b8747c5a0a 100644
--- a/test/functional/apps/management/_scripted_fields_filter.js
+++ b/test/functional/apps/management/_scripted_fields_filter.js
@@ -16,7 +16,8 @@ export default function ({ getService, getPageObjects }) {
const esArchiver = getService('esArchiver');
const PageObjects = getPageObjects(['settings']);
- describe('filter scripted fields', function describeIndexTests() {
+ // FLAKY: https://github.com/elastic/kibana/issues/126027
+ describe.skip('filter scripted fields', function describeIndexTests() {
before(async function () {
// delete .kibana index and then wait for Kibana to re-create it
await browser.setWindowSize(1200, 800);
diff --git a/test/functional/fixtures/es_archiver/date_nanos/data.json b/test/functional/fixtures/es_archiver/date_nanos/data.json
index 60feed23ee149..1638b6dd4190b 100644
--- a/test/functional/fixtures/es_archiver/date_nanos/data.json
+++ b/test/functional/fixtures/es_archiver/date_nanos/data.json
@@ -1,47 +1,3 @@
-{
- "type": "doc",
- "value": {
- "id": "index-pattern:date-nanos",
- "index": ".kibana",
- "source": {
- "index-pattern": {
- "fields": "[{\"name\":\"referer\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"agent\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:image:width\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"xss.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"headings.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:description\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"meta.user.lastname\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.article:tag.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"geo.dest\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.twitter:image\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.article:section.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"utc_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.twitter:card\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"meta.char\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"clientip\",\"type\":\"ip\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:image:height\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"host\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"machine.ram\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"links\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"id\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@tags.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"phpmemory\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.twitter:card.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"ip\",\"type\":\"ip\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:image\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.article:modified_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"index\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.url\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:site_name.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"request.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.article:tag\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"agent.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"spaces\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:site.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"headings\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"_source\",\"type\":\"_source\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"relatedContent.og:image.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"request\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"index.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"extension\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"memory\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"_index\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"relatedContent.twitter:site\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:description\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:url\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"geo.coordinates\",\"type\":\"geo_point\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.url.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"meta.related\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:title.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:title.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"response.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@message.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"machine.os\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.article:section\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:url.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"xss\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"links.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:title\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"geo.srcdest\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"url.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"extension.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"machine.os.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@tags\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"host.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:type.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"geo.src\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"spaces.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:image:height.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"url\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:description.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:site_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:title\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"@message\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:image.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@timestamp\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"bytes\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"response\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"meta.user.firstname\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:image:width.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:description.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.article:published_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"_id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"_type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"_score\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false}]",
- "timeFieldName": "@timestamp",
- "title": "date-nanos",
- "fieldFormatMap": "{\"@timestamp\":{\"id\":\"date_nanos\"}}"
- },
- "type": "index-pattern"
- }
- }
-}
-
-{
- "type": "doc",
- "value": {
- "id": "search:ab12e3c0-f231-11e6-9486-733b1ac9221a",
- "index": ".kibana",
- "source": {
- "search": {
- "columns": [
- "_source"
- ],
- "description": "A Saved Search Description",
- "hits": 0,
- "kibanaSavedObjectMeta": {
- "searchSourceJSON": "{\n \"index\": \"date-nanos\",\n \"highlightAll\": true,\n \"filter\": [],\n \"query\": {\n \"query_string\": {\n \"query\": \"*\",\n \"analyze_wildcard\": true\n }\n }\n}"
- },
- "sort": [
- "@timestamp",
- "desc"
- ],
- "title": "A Saved Search",
- "version": 1
- },
- "type": "search"
- }
- }
-}
-
{
"type": "doc",
"value": {
diff --git a/test/functional/fixtures/es_archiver/date_nanos_custom/data.json b/test/functional/fixtures/es_archiver/date_nanos_custom/data.json
index 73cba70a8b93d..10b0db8beda72 100644
--- a/test/functional/fixtures/es_archiver/date_nanos_custom/data.json
+++ b/test/functional/fixtures/es_archiver/date_nanos_custom/data.json
@@ -1,22 +1,3 @@
-{
- "type": "doc",
- "value": {
- "id": "index-pattern:date_nanos_custom_timestamp",
- "index": ".kibana",
- "source": {
- "index-pattern": {
- "fields": "[{\"name\":\"_id\",\"type\":\"string\",\"esTypes\":[\"_id\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"name\":\"_index\",\"type\":\"string\",\"esTypes\":[\"_index\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"name\":\"_score\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":false,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"_source\",\"type\":\"_source\",\"esTypes\":[\"_source\"],\"count\":0,\"scripted\":false,\"searchable\":false,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"_type\",\"type\":\"string\",\"esTypes\":[\"_type\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"name\":\"test\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"test.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"test\"}}},{\"name\":\"timestamp\",\"type\":\"date\",\"esTypes\":[\"date_nanos\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true}]",
- "timeFieldName": "timestamp",
- "title": "date_nanos_custom_timestamp"
- },
- "references": [
- ],
- "type": "index-pattern",
- "updated_at": "2020-01-09T21:43:20.283Z"
- }
- }
-}
-
{
"type": "doc",
"value": {
diff --git a/test/functional/fixtures/es_archiver/date_nanos_mixed/data.json b/test/functional/fixtures/es_archiver/date_nanos_mixed/data.json
index abde15e2b08c4..d49a6fa2f2412 100644
--- a/test/functional/fixtures/es_archiver/date_nanos_mixed/data.json
+++ b/test/functional/fixtures/es_archiver/date_nanos_mixed/data.json
@@ -1,51 +1,3 @@
-{
- "type": "doc",
- "value": {
- "id": "index-pattern:timestamp-*",
- "index": ".kibana",
- "source": {
- "index-pattern": {
- "fields": "[{\"name\":\"_id\",\"type\":\"string\",\"esTypes\":[\"_id\"],\"count\":1,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"name\":\"_index\",\"type\":\"string\",\"esTypes\":[\"_index\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"name\":\"_score\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":false,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"_source\",\"type\":\"_source\",\"esTypes\":[\"_source\"],\"count\":0,\"scripted\":false,\"searchable\":false,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"_type\",\"type\":\"string\",\"esTypes\":[\"_type\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"name\":\"timestamp\",\"type\":\"date\",\"esTypes\":[\"date\",\"date_nanos\"],\"count\":2,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true}]",
- "timeFieldName": "timestamp",
- "title": "timestamp-*",
- "fieldFormatMap": "{\"timestamp\":{\"id\":\"date_nanos\"}}"
- },
- "type": "index-pattern"
- },
- "type": "_doc"
- }
-}
-
-{
- "type": "doc",
- "value": {
- "id": "search:82116b30-d407-11e9-8004-932185690e7b",
- "index": ".kibana",
- "source": {
- "search": {
- "columns": [
- "_source"
- ],
- "description": "",
- "hits": 0,
- "kibanaSavedObjectMeta": {
- "searchSourceJSON": "{\"highlightAll\":true,\"version\":true,\"query\":{\"language\":\"kuery\",\"query\":\"\"},\"filter\":[{\"$state\":{\"store\":\"appState\"},\"meta\":{\"alias\":null,\"disabled\":false,\"key\":\"number\",\"negate\":false,\"params\":{\"query\":123},\"type\":\"phrase\",\"value\":\"123\",\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index\"},\"query\":{\"match\":{\"number\":{\"query\":123,\"type\":\"phrase\"}}}}],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"
- },
- "sort": [
- [
- "@timestamp",
- "desc"
- ]
- ],
- "title": "New Saved Search",
- "version": 1
- },
- "type": "search"
- },
- "type": "_doc"
- }
-}
-
{
"type": "doc",
"value": {
diff --git a/test/functional/fixtures/es_archiver/index_pattern_without_timefield/data.json b/test/functional/fixtures/es_archiver/index_pattern_without_timefield/data.json
index 0888079ec7c52..9998cb3a71732 100644
--- a/test/functional/fixtures/es_archiver/index_pattern_without_timefield/data.json
+++ b/test/functional/fixtures/es_archiver/index_pattern_without_timefield/data.json
@@ -1,18 +1,3 @@
-{
- "type": "doc",
- "value": {
- "id": "index-pattern:without-timefield",
- "index": ".kibana",
- "source": {
- "index-pattern": {
- "fields": "[]",
- "title": "without-timefield"
- },
- "type": "index-pattern"
- }
- }
-}
-
{
"type": "doc",
"value": {
diff --git a/test/functional/fixtures/es_archiver/invalid_scripted_field/data.json.gz b/test/functional/fixtures/es_archiver/invalid_scripted_field/data.json.gz
deleted file mode 100644
index 380dd6049179a..0000000000000
Binary files a/test/functional/fixtures/es_archiver/invalid_scripted_field/data.json.gz and /dev/null differ
diff --git a/test/functional/fixtures/es_archiver/invalid_scripted_field/mappings.json b/test/functional/fixtures/es_archiver/invalid_scripted_field/mappings.json
deleted file mode 100644
index 0d41e0ce86c14..0000000000000
--- a/test/functional/fixtures/es_archiver/invalid_scripted_field/mappings.json
+++ /dev/null
@@ -1,212 +0,0 @@
-{
- "type": "index",
- "value": {
- "aliases": {
- ".kibana": {}
- },
- "index": ".kibana_1",
- "mappings": {
- "dynamic": "strict",
- "properties": {
- "config": {
- "dynamic": "true",
- "properties": {
- "buildNum": {
- "type": "keyword"
- },
- "defaultIndex": {
- "fields": {
- "keyword": {
- "ignore_above": 256,
- "type": "keyword"
- }
- },
- "type": "text"
- }
- }
- },
- "dashboard": {
- "properties": {
- "description": {
- "type": "text"
- },
- "hits": {
- "type": "integer"
- },
- "kibanaSavedObjectMeta": {
- "properties": {
- "searchSourceJSON": {
- "type": "text"
- }
- }
- },
- "optionsJSON": {
- "type": "text"
- },
- "panelsJSON": {
- "type": "text"
- },
- "refreshInterval": {
- "properties": {
- "display": {
- "type": "keyword"
- },
- "pause": {
- "type": "boolean"
- },
- "section": {
- "type": "integer"
- },
- "value": {
- "type": "integer"
- }
- }
- },
- "timeFrom": {
- "type": "keyword"
- },
- "timeRestore": {
- "type": "boolean"
- },
- "timeTo": {
- "type": "keyword"
- },
- "title": {
- "type": "text"
- },
- "uiStateJSON": {
- "type": "text"
- },
- "version": {
- "type": "integer"
- }
- }
- },
- "index-pattern": {
- "properties": {
- "fieldFormatMap": {
- "type": "text"
- },
- "fields": {
- "type": "text"
- },
- "intervalName": {
- "type": "keyword"
- },
- "notExpandable": {
- "type": "boolean"
- },
- "sourceFilters": {
- "type": "text"
- },
- "timeFieldName": {
- "type": "keyword"
- },
- "title": {
- "type": "text"
- }
- }
- },
- "search": {
- "properties": {
- "columns": {
- "type": "keyword"
- },
- "description": {
- "type": "text"
- },
- "hits": {
- "type": "integer"
- },
- "kibanaSavedObjectMeta": {
- "properties": {
- "searchSourceJSON": {
- "type": "text"
- }
- }
- },
- "sort": {
- "type": "keyword"
- },
- "title": {
- "type": "text"
- },
- "version": {
- "type": "integer"
- }
- }
- },
- "server": {
- "properties": {
- "uuid": {
- "type": "keyword"
- }
- }
- },
- "type": {
- "type": "keyword"
- },
- "updated_at": {
- "type": "date"
- },
- "url": {
- "properties": {
- "accessCount": {
- "type": "long"
- },
- "accessDate": {
- "type": "date"
- },
- "createDate": {
- "type": "date"
- },
- "url": {
- "fields": {
- "keyword": {
- "ignore_above": 2048,
- "type": "keyword"
- }
- },
- "type": "text"
- }
- }
- },
- "visualization": {
- "properties": {
- "description": {
- "type": "text"
- },
- "kibanaSavedObjectMeta": {
- "properties": {
- "searchSourceJSON": {
- "type": "text"
- }
- }
- },
- "savedSearchId": {
- "type": "keyword"
- },
- "title": {
- "type": "text"
- },
- "uiStateJSON": {
- "type": "text"
- },
- "version": {
- "type": "integer"
- },
- "visState": {
- "type": "text"
- }
- }
- }
- }
- },
- "settings": {
- "index": {
- "number_of_replicas": "0",
- "number_of_shards": "1"
- }
- }
- }
-}
\ No newline at end of file
diff --git a/test/functional/fixtures/es_archiver/mgmt/data.json.gz b/test/functional/fixtures/es_archiver/mgmt/data.json.gz
deleted file mode 100644
index c230ff8ff7e39..0000000000000
Binary files a/test/functional/fixtures/es_archiver/mgmt/data.json.gz and /dev/null differ
diff --git a/test/functional/fixtures/es_archiver/mgmt/mappings.json b/test/functional/fixtures/es_archiver/mgmt/mappings.json
deleted file mode 100644
index f4962f9c47668..0000000000000
--- a/test/functional/fixtures/es_archiver/mgmt/mappings.json
+++ /dev/null
@@ -1,242 +0,0 @@
-{
- "type": "index",
- "value": {
- "aliases": {
- ".kibana": {}
- },
- "index": ".kibana_1",
- "mappings": {
- "dynamic": "strict",
- "properties": {
- "config": {
- "dynamic": "true",
- "properties": {
- "buildNum": {
- "type": "keyword"
- },
- "defaultIndex": {
- "fields": {
- "keyword": {
- "ignore_above": 256,
- "type": "keyword"
- }
- },
- "type": "text"
- }
- }
- },
- "dashboard": {
- "properties": {
- "description": {
- "type": "text"
- },
- "hits": {
- "type": "integer"
- },
- "kibanaSavedObjectMeta": {
- "properties": {
- "searchSourceJSON": {
- "type": "text"
- }
- }
- },
- "optionsJSON": {
- "type": "text"
- },
- "panelsJSON": {
- "type": "text"
- },
- "refreshInterval": {
- "properties": {
- "display": {
- "type": "keyword"
- },
- "pause": {
- "type": "boolean"
- },
- "section": {
- "type": "integer"
- },
- "value": {
- "type": "integer"
- }
- }
- },
- "timeFrom": {
- "type": "keyword"
- },
- "timeRestore": {
- "type": "boolean"
- },
- "timeTo": {
- "type": "keyword"
- },
- "title": {
- "type": "text"
- },
- "uiStateJSON": {
- "type": "text"
- },
- "version": {
- "type": "integer"
- }
- }
- },
- "graph-workspace": {
- "properties": {
- "description": {
- "type": "text"
- },
- "kibanaSavedObjectMeta": {
- "properties": {
- "searchSourceJSON": {
- "type": "text"
- }
- }
- },
- "numLinks": {
- "type": "integer"
- },
- "numVertices": {
- "type": "integer"
- },
- "title": {
- "type": "text"
- },
- "version": {
- "type": "integer"
- },
- "wsState": {
- "type": "text"
- }
- }
- },
- "index-pattern": {
- "properties": {
- "fieldFormatMap": {
- "type": "text"
- },
- "fields": {
- "type": "text"
- },
- "intervalName": {
- "type": "keyword"
- },
- "notExpandable": {
- "type": "boolean"
- },
- "sourceFilters": {
- "type": "text"
- },
- "timeFieldName": {
- "type": "keyword"
- },
- "title": {
- "type": "text"
- }
- }
- },
- "search": {
- "properties": {
- "columns": {
- "type": "keyword"
- },
- "description": {
- "type": "text"
- },
- "hits": {
- "type": "integer"
- },
- "kibanaSavedObjectMeta": {
- "properties": {
- "searchSourceJSON": {
- "type": "text"
- }
- }
- },
- "sort": {
- "type": "keyword"
- },
- "title": {
- "type": "text"
- },
- "version": {
- "type": "integer"
- }
- }
- },
- "server": {
- "properties": {
- "uuid": {
- "type": "keyword"
- }
- }
- },
- "type": {
- "type": "keyword"
- },
- "updated_at": {
- "type": "date"
- },
- "url": {
- "properties": {
- "accessCount": {
- "type": "long"
- },
- "accessDate": {
- "type": "date"
- },
- "createDate": {
- "type": "date"
- },
- "url": {
- "fields": {
- "keyword": {
- "ignore_above": 2048,
- "type": "keyword"
- }
- },
- "type": "text"
- }
- }
- },
- "visualization": {
- "properties": {
- "description": {
- "type": "text"
- },
- "kibanaSavedObjectMeta": {
- "properties": {
- "searchSourceJSON": {
- "type": "text"
- }
- }
- },
- "savedSearchId": {
- "type": "keyword"
- },
- "title": {
- "type": "text"
- },
- "uiStateJSON": {
- "type": "text"
- },
- "version": {
- "type": "integer"
- },
- "visState": {
- "type": "text"
- }
- }
- }
- }
- },
- "settings": {
- "index": {
- "auto_expand_replicas": "0-1",
- "number_of_replicas": "0",
- "number_of_shards": "1"
- }
- }
- }
-}
\ No newline at end of file
diff --git a/test/functional/fixtures/es_archiver/unmapped_fields/data.json b/test/functional/fixtures/es_archiver/unmapped_fields/data.json
index 10c33280696b1..d23a5b83eb2c6 100644
--- a/test/functional/fixtures/es_archiver/unmapped_fields/data.json
+++ b/test/functional/fixtures/es_archiver/unmapped_fields/data.json
@@ -1,48 +1,3 @@
-{
- "type": "doc",
- "value": {
- "id": "search:cd43f5c2-h761-13f6-9486-733b1ac9221a",
- "index": ".kibana",
- "source": {
- "search": {
- "columns": [
- "_source"
- ],
- "description": "Existing Saved Search",
- "hits": 4,
- "kibanaSavedObjectMeta": {
- "searchSourceJSON": "{\n \"index\": \"test-index-unmapped-fields\",\n \"highlightAll\": true,\n \"filter\": [],\n \"query\": {\n \"query_string\": {\n \"query\": \"*\",\n \"analyze_wildcard\": true\n }\n }\n}"
- },
- "sort": [
- "@timestamp",
- "desc"
- ],
- "title": "Existing Saved Search",
- "version": 1
- },
- "type": "search"
- }
- }
-}
-
-{
- "type": "doc",
- "value": {
- "id": "index-pattern:test-index-unmapped-fields",
- "index": ".kibana",
- "source": {
- "index-pattern": {
- "fields": "[{\"name\":\"_id\",\"type\":\"string\",\"esTypes\":[\"_id\"],\"count\":1,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"name\":\"_index\",\"type\":\"string\",\"esTypes\":[\"_index\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"name\":\"_score\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":false,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"_source\",\"type\":\"_source\",\"esTypes\":[\"_source\"],\"count\":0,\"scripted\":false,\"searchable\":false,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"_type\",\"type\":\"string\",\"esTypes\":[\"_type\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"name\":\"timestamp\",\"type\":\"date\",\"esTypes\":[\"date\"],\"count\":4,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true}]",
- "timeFieldName": "timestamp",
- "title": "test-index-unmapped-fields",
- "fieldFormatMap": "{\"timestamp\":{\"id\":\"date\"}}"
- },
- "type": "index-pattern"
- },
- "type": "_doc"
- }
-}
-
{
"type": "doc",
"value": {
diff --git a/test/functional/fixtures/es_archiver/visualize_embedding/data.json.gz b/test/functional/fixtures/es_archiver/visualize_embedding/data.json.gz
deleted file mode 100644
index 95b32f0ee11e5..0000000000000
Binary files a/test/functional/fixtures/es_archiver/visualize_embedding/data.json.gz and /dev/null differ
diff --git a/test/functional/fixtures/es_archiver/visualize_embedding/mappings.json b/test/functional/fixtures/es_archiver/visualize_embedding/mappings.json
deleted file mode 100644
index 451369d85acd8..0000000000000
--- a/test/functional/fixtures/es_archiver/visualize_embedding/mappings.json
+++ /dev/null
@@ -1,205 +0,0 @@
-{
- "type": "index",
- "value": {
- "aliases": {
- ".kibana": {}
- },
- "index": ".kibana_1",
- "mappings": {
- "properties": {
- "config": {
- "dynamic": "true",
- "properties": {
- "buildNum": {
- "type": "keyword"
- }
- }
- },
- "dashboard": {
- "dynamic": "strict",
- "properties": {
- "description": {
- "type": "text"
- },
- "hits": {
- "type": "integer"
- },
- "kibanaSavedObjectMeta": {
- "properties": {
- "searchSourceJSON": {
- "type": "text"
- }
- }
- },
- "optionsJSON": {
- "type": "text"
- },
- "panelsJSON": {
- "type": "text"
- },
- "refreshInterval": {
- "properties": {
- "display": {
- "type": "keyword"
- },
- "pause": {
- "type": "boolean"
- },
- "section": {
- "type": "integer"
- },
- "value": {
- "type": "integer"
- }
- }
- },
- "timeFrom": {
- "type": "keyword"
- },
- "timeRestore": {
- "type": "boolean"
- },
- "timeTo": {
- "type": "keyword"
- },
- "title": {
- "type": "text"
- },
- "uiStateJSON": {
- "type": "text"
- },
- "version": {
- "type": "integer"
- }
- }
- },
- "index-pattern": {
- "dynamic": "strict",
- "properties": {
- "fieldFormatMap": {
- "type": "text"
- },
- "fields": {
- "type": "text"
- },
- "intervalName": {
- "type": "keyword"
- },
- "notExpandable": {
- "type": "boolean"
- },
- "sourceFilters": {
- "type": "text"
- },
- "timeFieldName": {
- "type": "keyword"
- },
- "title": {
- "type": "text"
- }
- }
- },
- "search": {
- "dynamic": "strict",
- "properties": {
- "columns": {
- "type": "keyword"
- },
- "description": {
- "type": "text"
- },
- "hits": {
- "type": "integer"
- },
- "kibanaSavedObjectMeta": {
- "properties": {
- "searchSourceJSON": {
- "type": "text"
- }
- }
- },
- "sort": {
- "type": "keyword"
- },
- "title": {
- "type": "text"
- },
- "version": {
- "type": "integer"
- }
- }
- },
- "server": {
- "dynamic": "strict",
- "properties": {
- "uuid": {
- "type": "keyword"
- }
- }
- },
- "type": {
- "type": "keyword"
- },
- "url": {
- "dynamic": "strict",
- "properties": {
- "accessCount": {
- "type": "long"
- },
- "accessDate": {
- "type": "date"
- },
- "createDate": {
- "type": "date"
- },
- "url": {
- "fields": {
- "keyword": {
- "ignore_above": 2048,
- "type": "keyword"
- }
- },
- "type": "text"
- }
- }
- },
- "visualization": {
- "dynamic": "strict",
- "properties": {
- "description": {
- "type": "text"
- },
- "kibanaSavedObjectMeta": {
- "properties": {
- "searchSourceJSON": {
- "type": "text"
- }
- }
- },
- "savedSearchId": {
- "type": "keyword"
- },
- "title": {
- "type": "text"
- },
- "uiStateJSON": {
- "type": "text"
- },
- "version": {
- "type": "integer"
- },
- "visState": {
- "type": "text"
- }
- }
- }
- }
- },
- "settings": {
- "index": {
- "number_of_replicas": "1",
- "number_of_shards": "1"
- }
- }
- }
-}
\ No newline at end of file
diff --git a/test/functional/fixtures/es_archiver/visualize_source-filters/data.json.gz b/test/functional/fixtures/es_archiver/visualize_source-filters/data.json.gz
deleted file mode 100644
index c8d1c98790e59..0000000000000
Binary files a/test/functional/fixtures/es_archiver/visualize_source-filters/data.json.gz and /dev/null differ
diff --git a/test/functional/fixtures/es_archiver/visualize_source-filters/mappings.json b/test/functional/fixtures/es_archiver/visualize_source-filters/mappings.json
deleted file mode 100644
index 451369d85acd8..0000000000000
--- a/test/functional/fixtures/es_archiver/visualize_source-filters/mappings.json
+++ /dev/null
@@ -1,205 +0,0 @@
-{
- "type": "index",
- "value": {
- "aliases": {
- ".kibana": {}
- },
- "index": ".kibana_1",
- "mappings": {
- "properties": {
- "config": {
- "dynamic": "true",
- "properties": {
- "buildNum": {
- "type": "keyword"
- }
- }
- },
- "dashboard": {
- "dynamic": "strict",
- "properties": {
- "description": {
- "type": "text"
- },
- "hits": {
- "type": "integer"
- },
- "kibanaSavedObjectMeta": {
- "properties": {
- "searchSourceJSON": {
- "type": "text"
- }
- }
- },
- "optionsJSON": {
- "type": "text"
- },
- "panelsJSON": {
- "type": "text"
- },
- "refreshInterval": {
- "properties": {
- "display": {
- "type": "keyword"
- },
- "pause": {
- "type": "boolean"
- },
- "section": {
- "type": "integer"
- },
- "value": {
- "type": "integer"
- }
- }
- },
- "timeFrom": {
- "type": "keyword"
- },
- "timeRestore": {
- "type": "boolean"
- },
- "timeTo": {
- "type": "keyword"
- },
- "title": {
- "type": "text"
- },
- "uiStateJSON": {
- "type": "text"
- },
- "version": {
- "type": "integer"
- }
- }
- },
- "index-pattern": {
- "dynamic": "strict",
- "properties": {
- "fieldFormatMap": {
- "type": "text"
- },
- "fields": {
- "type": "text"
- },
- "intervalName": {
- "type": "keyword"
- },
- "notExpandable": {
- "type": "boolean"
- },
- "sourceFilters": {
- "type": "text"
- },
- "timeFieldName": {
- "type": "keyword"
- },
- "title": {
- "type": "text"
- }
- }
- },
- "search": {
- "dynamic": "strict",
- "properties": {
- "columns": {
- "type": "keyword"
- },
- "description": {
- "type": "text"
- },
- "hits": {
- "type": "integer"
- },
- "kibanaSavedObjectMeta": {
- "properties": {
- "searchSourceJSON": {
- "type": "text"
- }
- }
- },
- "sort": {
- "type": "keyword"
- },
- "title": {
- "type": "text"
- },
- "version": {
- "type": "integer"
- }
- }
- },
- "server": {
- "dynamic": "strict",
- "properties": {
- "uuid": {
- "type": "keyword"
- }
- }
- },
- "type": {
- "type": "keyword"
- },
- "url": {
- "dynamic": "strict",
- "properties": {
- "accessCount": {
- "type": "long"
- },
- "accessDate": {
- "type": "date"
- },
- "createDate": {
- "type": "date"
- },
- "url": {
- "fields": {
- "keyword": {
- "ignore_above": 2048,
- "type": "keyword"
- }
- },
- "type": "text"
- }
- }
- },
- "visualization": {
- "dynamic": "strict",
- "properties": {
- "description": {
- "type": "text"
- },
- "kibanaSavedObjectMeta": {
- "properties": {
- "searchSourceJSON": {
- "type": "text"
- }
- }
- },
- "savedSearchId": {
- "type": "keyword"
- },
- "title": {
- "type": "text"
- },
- "uiStateJSON": {
- "type": "text"
- },
- "version": {
- "type": "integer"
- },
- "visState": {
- "type": "text"
- }
- }
- }
- }
- },
- "settings": {
- "index": {
- "number_of_replicas": "1",
- "number_of_shards": "1"
- }
- }
- }
-}
\ No newline at end of file
diff --git a/test/functional/fixtures/es_archiver/visualize_source_filters/data.json.gz b/test/functional/fixtures/es_archiver/visualize_source_filters/data.json.gz
deleted file mode 100644
index 238ffe3b76241..0000000000000
Binary files a/test/functional/fixtures/es_archiver/visualize_source_filters/data.json.gz and /dev/null differ
diff --git a/test/functional/fixtures/es_archiver/visualize_source_filters/mappings.json b/test/functional/fixtures/es_archiver/visualize_source_filters/mappings.json
deleted file mode 100644
index ec6a9ce7f13a1..0000000000000
--- a/test/functional/fixtures/es_archiver/visualize_source_filters/mappings.json
+++ /dev/null
@@ -1,223 +0,0 @@
-{
- "type": "index",
- "value": {
- "aliases": {
- ".kibana": {}
- },
- "index": ".kibana_1",
- "mappings": {
- "properties": {
- "config": {
- "dynamic": "true",
- "properties": {
- "buildNum": {
- "type": "keyword"
- },
- "dateFormat:tz": {
- "fields": {
- "keyword": {
- "ignore_above": 256,
- "type": "keyword"
- }
- },
- "type": "text"
- },
- "defaultIndex": {
- "fields": {
- "keyword": {
- "ignore_above": 256,
- "type": "keyword"
- }
- },
- "type": "text"
- }
- }
- },
- "dashboard": {
- "dynamic": "strict",
- "properties": {
- "description": {
- "type": "text"
- },
- "hits": {
- "type": "integer"
- },
- "kibanaSavedObjectMeta": {
- "properties": {
- "searchSourceJSON": {
- "type": "text"
- }
- }
- },
- "optionsJSON": {
- "type": "text"
- },
- "panelsJSON": {
- "type": "text"
- },
- "refreshInterval": {
- "properties": {
- "display": {
- "type": "keyword"
- },
- "pause": {
- "type": "boolean"
- },
- "section": {
- "type": "integer"
- },
- "value": {
- "type": "integer"
- }
- }
- },
- "timeFrom": {
- "type": "keyword"
- },
- "timeRestore": {
- "type": "boolean"
- },
- "timeTo": {
- "type": "keyword"
- },
- "title": {
- "type": "text"
- },
- "uiStateJSON": {
- "type": "text"
- },
- "version": {
- "type": "integer"
- }
- }
- },
- "index-pattern": {
- "dynamic": "strict",
- "properties": {
- "fieldFormatMap": {
- "type": "text"
- },
- "fields": {
- "type": "text"
- },
- "intervalName": {
- "type": "keyword"
- },
- "notExpandable": {
- "type": "boolean"
- },
- "sourceFilters": {
- "type": "text"
- },
- "timeFieldName": {
- "type": "keyword"
- },
- "title": {
- "type": "text"
- }
- }
- },
- "search": {
- "dynamic": "strict",
- "properties": {
- "columns": {
- "type": "keyword"
- },
- "description": {
- "type": "text"
- },
- "hits": {
- "type": "integer"
- },
- "kibanaSavedObjectMeta": {
- "properties": {
- "searchSourceJSON": {
- "type": "text"
- }
- }
- },
- "sort": {
- "type": "keyword"
- },
- "title": {
- "type": "text"
- },
- "version": {
- "type": "integer"
- }
- }
- },
- "server": {
- "dynamic": "strict",
- "properties": {
- "uuid": {
- "type": "keyword"
- }
- }
- },
- "type": {
- "type": "keyword"
- },
- "url": {
- "dynamic": "strict",
- "properties": {
- "accessCount": {
- "type": "long"
- },
- "accessDate": {
- "type": "date"
- },
- "createDate": {
- "type": "date"
- },
- "url": {
- "fields": {
- "keyword": {
- "ignore_above": 2048,
- "type": "keyword"
- }
- },
- "type": "text"
- }
- }
- },
- "visualization": {
- "dynamic": "strict",
- "properties": {
- "description": {
- "type": "text"
- },
- "kibanaSavedObjectMeta": {
- "properties": {
- "searchSourceJSON": {
- "type": "text"
- }
- }
- },
- "savedSearchId": {
- "type": "keyword"
- },
- "title": {
- "type": "text"
- },
- "uiStateJSON": {
- "type": "text"
- },
- "version": {
- "type": "integer"
- },
- "visState": {
- "type": "text"
- }
- }
- }
- }
- },
- "settings": {
- "index": {
- "number_of_replicas": "1",
- "number_of_shards": "1"
- }
- }
- }
-}
\ No newline at end of file
diff --git a/test/functional/fixtures/kbn_archiver/date_nanos.json b/test/functional/fixtures/kbn_archiver/date_nanos.json
new file mode 100644
index 0000000000000..249f364887620
--- /dev/null
+++ b/test/functional/fixtures/kbn_archiver/date_nanos.json
@@ -0,0 +1,51 @@
+{
+ "attributes": {
+ "fieldFormatMap": "{\"@timestamp\":{\"id\":\"date_nanos\"}}",
+ "fields": "[{\"name\":\"referer\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"agent\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:image:width\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"xss.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"headings.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:description\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"meta.user.lastname\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.article:tag.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"geo.dest\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.twitter:image\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.article:section.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"utc_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.twitter:card\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"meta.char\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"clientip\",\"type\":\"ip\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:image:height\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"host\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"machine.ram\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"links\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"id\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@tags.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"phpmemory\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.twitter:card.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"ip\",\"type\":\"ip\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:image\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.article:modified_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"index\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.url\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:site_name.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"request.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.article:tag\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"agent.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"spaces\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:site.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"headings\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"_source\",\"type\":\"_source\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"relatedContent.og:image.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"request\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"index.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"extension\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"memory\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"_index\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"relatedContent.twitter:site\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:description\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:url\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"geo.coordinates\",\"type\":\"geo_point\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.url.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"meta.related\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:title.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:title.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"response.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@message.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"machine.os\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.article:section\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:url.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"xss\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"links.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:title\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"geo.srcdest\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"url.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"extension.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"machine.os.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@tags\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"host.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:type.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"geo.src\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"spaces.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:image:height.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"url\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:description.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:site_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:title\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"@message\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:image.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@timestamp\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"bytes\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"response\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"meta.user.firstname\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:image:width.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:description.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.article:published_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"_id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"_type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"_score\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false}]",
+ "timeFieldName": "@timestamp",
+ "title": "date-nanos"
+ },
+ "coreMigrationVersion": "7.17.1",
+ "id": "date-nanos",
+ "migrationVersion": {
+ "index-pattern": "7.11.0"
+ },
+ "references": [],
+ "type": "index-pattern",
+ "version": "WzM2LDJd"
+}
+
+{
+ "attributes": {
+ "columns": [
+ "_source"
+ ],
+ "description": "A Saved Search Description",
+ "hits": 0,
+ "kibanaSavedObjectMeta": {
+ "searchSourceJSON": "{\"highlightAll\":true,\"filter\":[],\"query\":{\"query_string\":{\"query\":\"*\",\"analyze_wildcard\":true}},\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"
+ },
+ "sort": [
+ [
+ "@timestamp",
+ "desc"
+ ]
+ ],
+ "title": "A Saved Search",
+ "version": 1
+ },
+ "coreMigrationVersion": "7.17.1",
+ "id": "ab12e3c0-f231-11e6-9486-733b1ac9221a",
+ "migrationVersion": {
+ "search": "7.9.3"
+ },
+ "references": [
+ {
+ "id": "date-nanos",
+ "name": "kibanaSavedObjectMeta.searchSourceJSON.index",
+ "type": "index-pattern"
+ }
+ ],
+ "type": "search",
+ "version": "WzM3LDJd"
+}
\ No newline at end of file
diff --git a/test/functional/fixtures/kbn_archiver/date_nanos_custom.json b/test/functional/fixtures/kbn_archiver/date_nanos_custom.json
new file mode 100644
index 0000000000000..b789407a0ba88
--- /dev/null
+++ b/test/functional/fixtures/kbn_archiver/date_nanos_custom.json
@@ -0,0 +1,68 @@
+{
+ "attributes": {
+ "fieldFormatMap": "{\"@timestamp\":{\"id\":\"date_nanos\"}}",
+ "fields": "[{\"name\":\"referer\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"agent\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:image:width\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"xss.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"headings.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:description\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"meta.user.lastname\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.article:tag.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"geo.dest\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.twitter:image\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.article:section.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"utc_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.twitter:card\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"meta.char\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"clientip\",\"type\":\"ip\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:image:height\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"host\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"machine.ram\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"links\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"id\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@tags.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"phpmemory\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.twitter:card.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"ip\",\"type\":\"ip\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:image\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.article:modified_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"index\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.url\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:site_name.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"request.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.article:tag\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"agent.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"spaces\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:site.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"headings\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"_source\",\"type\":\"_source\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"relatedContent.og:image.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"request\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"index.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"extension\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"memory\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"_index\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"relatedContent.twitter:site\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:description\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:url\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"geo.coordinates\",\"type\":\"geo_point\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.url.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"meta.related\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:title.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:title.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"response.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@message.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"machine.os\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.article:section\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:url.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"xss\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"links.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:title\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"geo.srcdest\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"url.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"extension.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"machine.os.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@tags\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"host.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:type.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"geo.src\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"spaces.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:image:height.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"url\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:description.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:site_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:title\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"@message\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:image.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@timestamp\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"bytes\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"response\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"meta.user.firstname\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:image:width.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:description.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.article:published_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"_id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"_type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"_score\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false}]",
+ "timeFieldName": "@timestamp",
+ "title": "date-nanos"
+ },
+ "coreMigrationVersion": "7.17.1",
+ "id": "date-nanos",
+ "migrationVersion": {
+ "index-pattern": "7.11.0"
+ },
+ "references": [],
+ "type": "index-pattern",
+ "version": "WzQyLDJd"
+}
+
+{
+ "attributes": {
+ "columns": [
+ "_source"
+ ],
+ "description": "A Saved Search Description",
+ "hits": 0,
+ "kibanaSavedObjectMeta": {
+ "searchSourceJSON": "{\"highlightAll\":true,\"filter\":[],\"query\":{\"query_string\":{\"query\":\"*\",\"analyze_wildcard\":true}},\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"
+ },
+ "sort": [
+ [
+ "@timestamp",
+ "desc"
+ ]
+ ],
+ "title": "A Saved Search",
+ "version": 1
+ },
+ "coreMigrationVersion": "7.17.1",
+ "id": "ab12e3c0-f231-11e6-9486-733b1ac9221a",
+ "migrationVersion": {
+ "search": "7.9.3"
+ },
+ "references": [
+ {
+ "id": "date-nanos",
+ "name": "kibanaSavedObjectMeta.searchSourceJSON.index",
+ "type": "index-pattern"
+ }
+ ],
+ "type": "search",
+ "version": "WzQzLDJd"
+}
+
+{
+ "attributes": {
+ "fields": "[{\"name\":\"_id\",\"type\":\"string\",\"esTypes\":[\"_id\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"name\":\"_index\",\"type\":\"string\",\"esTypes\":[\"_index\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"name\":\"_score\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":false,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"_source\",\"type\":\"_source\",\"esTypes\":[\"_source\"],\"count\":0,\"scripted\":false,\"searchable\":false,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"_type\",\"type\":\"string\",\"esTypes\":[\"_type\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"name\":\"test\",\"type\":\"string\",\"esTypes\":[\"text\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"test.keyword\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true,\"subType\":{\"multi\":{\"parent\":\"test\"}}},{\"name\":\"timestamp\",\"type\":\"date\",\"esTypes\":[\"date_nanos\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true}]",
+ "timeFieldName": "timestamp",
+ "title": "date_nanos_custom_timestamp"
+ },
+ "coreMigrationVersion": "7.17.1",
+ "id": "date_nanos_custom_timestamp",
+ "migrationVersion": {
+ "index-pattern": "7.11.0"
+ },
+ "references": [],
+ "type": "index-pattern",
+ "updated_at": "2020-01-09T21:43:20.283Z",
+ "version": "WzQ1LDJd"
+}
\ No newline at end of file
diff --git a/test/functional/fixtures/kbn_archiver/date_nanos_mixed.json b/test/functional/fixtures/kbn_archiver/date_nanos_mixed.json
new file mode 100644
index 0000000000000..6d528a382753f
--- /dev/null
+++ b/test/functional/fixtures/kbn_archiver/date_nanos_mixed.json
@@ -0,0 +1,16 @@
+{
+ "attributes": {
+ "fieldFormatMap": "{\"timestamp\":{\"id\":\"date_nanos\"}}",
+ "fields": "[{\"name\":\"_id\",\"type\":\"string\",\"esTypes\":[\"_id\"],\"count\":1,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"name\":\"_index\",\"type\":\"string\",\"esTypes\":[\"_index\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"name\":\"_score\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":false,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"_source\",\"type\":\"_source\",\"esTypes\":[\"_source\"],\"count\":0,\"scripted\":false,\"searchable\":false,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"_type\",\"type\":\"string\",\"esTypes\":[\"_type\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"name\":\"timestamp\",\"type\":\"date\",\"esTypes\":[\"date\",\"date_nanos\"],\"count\":2,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true}]",
+ "timeFieldName": "timestamp",
+ "title": "timestamp-*"
+ },
+ "coreMigrationVersion": "7.17.1",
+ "id": "timestamp-*",
+ "migrationVersion": {
+ "index-pattern": "7.11.0"
+ },
+ "references": [],
+ "type": "index-pattern",
+ "version": "WzU2LDJd"
+}
\ No newline at end of file
diff --git a/test/functional/fixtures/kbn_archiver/index_pattern_without_timefield.json b/test/functional/fixtures/kbn_archiver/index_pattern_without_timefield.json
new file mode 100644
index 0000000000000..d5906dc8a2e99
--- /dev/null
+++ b/test/functional/fixtures/kbn_archiver/index_pattern_without_timefield.json
@@ -0,0 +1,30 @@
+{
+ "attributes": {
+ "fields": "[]",
+ "timeFieldName": "@timestamp",
+ "title": "with-timefield"
+ },
+ "coreMigrationVersion": "7.17.1",
+ "id": "with-timefield",
+ "migrationVersion": {
+ "index-pattern": "7.11.0"
+ },
+ "references": [],
+ "type": "index-pattern",
+ "version": "WzEzLDJd"
+}
+
+{
+ "attributes": {
+ "fields": "[]",
+ "title": "without-timefield"
+ },
+ "coreMigrationVersion": "7.17.1",
+ "id": "without-timefield",
+ "migrationVersion": {
+ "index-pattern": "7.11.0"
+ },
+ "references": [],
+ "type": "index-pattern",
+ "version": "WzEyLDJd"
+}
\ No newline at end of file
diff --git a/test/functional/fixtures/kbn_archiver/invalid_scripted_field.json b/test/functional/fixtures/kbn_archiver/invalid_scripted_field.json
new file mode 100644
index 0000000000000..23abe20855e3e
--- /dev/null
+++ b/test/functional/fixtures/kbn_archiver/invalid_scripted_field.json
@@ -0,0 +1,16 @@
+{
+ "attributes": {
+ "fields": "[{\"name\":\"@message\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"@message.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"@tags\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"@tags.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"@timestamp\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"_id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"name\":\"_index\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"name\":\"_score\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":false,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"_source\",\"type\":\"_source\",\"count\":0,\"scripted\":false,\"searchable\":false,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"_type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"name\":\"agent\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"agent.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"bytes\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"clientip\",\"type\":\"ip\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"extension\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"extension.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"geo.coordinates\",\"type\":\"geo_point\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"geo.dest\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"geo.src\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"geo.srcdest\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"headings\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"headings.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"host.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"id\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"index\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"index.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"ip\",\"type\":\"ip\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"links\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"links.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"machine.os\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"machine.os.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"machine.ram\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"memory\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"meta.char\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"meta.related\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"meta.user.firstname\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"meta.user.lastname\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"phpmemory\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"referer\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"relatedContent.article:modified_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"relatedContent.article:published_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"relatedContent.article:section\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"relatedContent.article:section.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"relatedContent.article:tag\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"relatedContent.article:tag.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"relatedContent.og:description\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"relatedContent.og:description.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"relatedContent.og:image\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"relatedContent.og:image.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"relatedContent.og:image:height\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"relatedContent.og:image:height.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"relatedContent.og:image:width\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"relatedContent.og:image:width.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"relatedContent.og:site_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"relatedContent.og:site_name.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"relatedContent.og:title\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"relatedContent.og:title.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"relatedContent.og:type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"relatedContent.og:type.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"relatedContent.og:url\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"relatedContent.og:url.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"relatedContent.twitter:card\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"relatedContent.twitter:card.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"relatedContent.twitter:description\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"relatedContent.twitter:description.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"relatedContent.twitter:image\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"relatedContent.twitter:image.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"relatedContent.twitter:site\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"relatedContent.twitter:site.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"relatedContent.twitter:title\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"relatedContent.twitter:title.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"relatedContent.url\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"relatedContent.url.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"request\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"request.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"response\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"response.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"spaces\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"spaces.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"url\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"url.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"utc_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"xss\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"xss.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"invalid_scripted_field\",\"type\":\"number\",\"count\":0,\"scripted\":true,\"script\":\"invalid\",\"lang\":\"painless\",\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false}]",
+ "timeFieldName": "@timestamp",
+ "title": "log*"
+ },
+ "coreMigrationVersion": "7.17.1",
+ "id": "18ea0c30-2d77-11e8-93f2-6f8a391f33ef",
+ "migrationVersion": {
+ "index-pattern": "7.11.0"
+ },
+ "references": [],
+ "type": "index-pattern",
+ "updated_at": "2018-03-22T02:17:11.427Z",
+ "version": "WzMsMl0="
+}
\ No newline at end of file
diff --git a/test/functional/fixtures/kbn_archiver/unmapped_fields.json b/test/functional/fixtures/kbn_archiver/unmapped_fields.json
new file mode 100644
index 0000000000000..aa1e464af5377
--- /dev/null
+++ b/test/functional/fixtures/kbn_archiver/unmapped_fields.json
@@ -0,0 +1,51 @@
+{
+ "attributes": {
+ "fieldFormatMap": "{\"timestamp\":{\"id\":\"date\"}}",
+ "fields": "[{\"name\":\"_id\",\"type\":\"string\",\"esTypes\":[\"_id\"],\"count\":1,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"name\":\"_index\",\"type\":\"string\",\"esTypes\":[\"_index\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"name\":\"_score\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":false,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"_source\",\"type\":\"_source\",\"esTypes\":[\"_source\"],\"count\":0,\"scripted\":false,\"searchable\":false,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"_type\",\"type\":\"string\",\"esTypes\":[\"_type\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"name\":\"timestamp\",\"type\":\"date\",\"esTypes\":[\"date\"],\"count\":4,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true}]",
+ "timeFieldName": "timestamp",
+ "title": "test-index-unmapped-fields"
+ },
+ "coreMigrationVersion": "7.17.1",
+ "id": "test-index-unmapped-fields",
+ "migrationVersion": {
+ "index-pattern": "7.11.0"
+ },
+ "references": [],
+ "type": "index-pattern",
+ "version": "WzEzLDJd"
+}
+
+{
+ "attributes": {
+ "columns": [
+ "_source"
+ ],
+ "description": "Existing Saved Search",
+ "hits": 4,
+ "kibanaSavedObjectMeta": {
+ "searchSourceJSON": "{\"highlightAll\":true,\"filter\":[],\"query\":{\"query_string\":{\"query\":\"*\",\"analyze_wildcard\":true}},\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"
+ },
+ "sort": [
+ [
+ "@timestamp",
+ "desc"
+ ]
+ ],
+ "title": "Existing Saved Search",
+ "version": 1
+ },
+ "coreMigrationVersion": "7.17.1",
+ "id": "cd43f5c2-h761-13f6-9486-733b1ac9221a",
+ "migrationVersion": {
+ "search": "7.9.3"
+ },
+ "references": [
+ {
+ "id": "test-index-unmapped-fields",
+ "name": "kibanaSavedObjectMeta.searchSourceJSON.index",
+ "type": "index-pattern"
+ }
+ ],
+ "type": "search",
+ "version": "WzEyLDJd"
+}
\ No newline at end of file
diff --git a/test/functional/page_objects/discover_page.ts b/test/functional/page_objects/discover_page.ts
index effacb30bdc89..1583903be4991 100644
--- a/test/functional/page_objects/discover_page.ts
+++ b/test/functional/page_objects/discover_page.ts
@@ -240,7 +240,7 @@ export class DiscoverPageObject extends FtrService {
}
public async useLegacyTable() {
- return (await this.kibanaServer.uiSettings.get('doc_table:legacy')) !== false;
+ return (await this.kibanaServer.uiSettings.get('doc_table:legacy')) === true;
}
public async getDocTableIndex(index: number) {
@@ -276,6 +276,11 @@ export class DiscoverPageObject extends FtrService {
return result[usedCellIdx];
}
+ public async clickDocTableRowToggle(rowIndex: number = 0) {
+ const docTable = await this.getDocTable();
+ await docTable.clickRowToggle({ rowIndex });
+ }
+
public async skipToEndOfDocTable() {
// add the focus to the button to make it appear
const skipButton = await this.testSubjects.find('discoverSkipTableButton');
diff --git a/test/functional/services/dashboard/expectations.ts b/test/functional/services/dashboard/expectations.ts
index 75f60b1448eea..c56e7c1eae27e 100644
--- a/test/functional/services/dashboard/expectations.ts
+++ b/test/functional/services/dashboard/expectations.ts
@@ -226,11 +226,20 @@ export class DashboardExpectService extends FtrService {
async savedSearchRowCount(expectedMinCount: number) {
this.log.debug(`DashboardExpect.savedSearchRowCount(${expectedMinCount})`);
await this.retry.try(async () => {
- const savedSearchRows = await this.testSubjects.findAll(
- 'docTableExpandToggleColumn',
- this.findTimeout
- );
- expect(savedSearchRows.length).to.be.above(expectedMinCount);
+ const gridExists = await this.find.existsByCssSelector('[data-document-number]');
+ if (gridExists) {
+ const grid = await this.find.byCssSelector('[data-document-number]');
+ // in this case it's the document explorer
+ const docNr = Number(await grid.getAttribute('data-document-number'));
+ expect(docNr).to.be.above(expectedMinCount);
+ } else {
+ // in this case it's the classic table
+ const savedSearchRows = await this.testSubjects.findAll(
+ 'docTableExpandToggleColumn',
+ this.findTimeout
+ );
+ expect(savedSearchRows.length).to.be.above(expectedMinCount);
+ }
});
}
diff --git a/test/functional/services/inspector.ts b/test/functional/services/inspector.ts
index 753d9b7b0b85e..b8dec2a2092fb 100644
--- a/test/functional/services/inspector.ts
+++ b/test/functional/services/inspector.ts
@@ -195,8 +195,12 @@ export class InspectorService extends FtrService {
*/
public async openInspectorView(viewId: string): Promise {
this.log.debug(`Open Inspector view ${viewId}`);
- await this.testSubjects.click('inspectorViewChooser');
- await this.testSubjects.click(viewId);
+ await this.retry.try(async () => {
+ await this.testSubjects.click('inspectorViewChooser');
+ // check whether popover menu opens, if not, fail and retry opening
+ await this.testSubjects.existOrFail(viewId, { timeout: 2000 });
+ await this.testSubjects.click(viewId);
+ });
}
/**
diff --git a/x-pack/examples/ui_actions_enhanced_examples/public/drilldowns/dashboard_to_discover_drilldown/drilldown.tsx b/x-pack/examples/ui_actions_enhanced_examples/public/drilldowns/dashboard_to_discover_drilldown/drilldown.tsx
index 91fb8552beed8..4635d4694ed1e 100644
--- a/x-pack/examples/ui_actions_enhanced_examples/public/drilldowns/dashboard_to_discover_drilldown/drilldown.tsx
+++ b/x-pack/examples/ui_actions_enhanced_examples/public/drilldowns/dashboard_to_discover_drilldown/drilldown.tsx
@@ -65,9 +65,9 @@ export class DashboardToDiscoverDrilldown
};
private readonly getPath = async (config: Config, context: ActionContext): Promise => {
- const { urlGenerator } = this.params.start().plugins.discover;
+ const { locator } = this.params.start().plugins.discover;
- if (!urlGenerator) throw new Error('Discover URL generator not available.');
+ if (!locator) throw new Error('Discover locator not available.');
let indexPatternId =
!!config.customIndexPattern && !!config.indexPatternId ? config.indexPatternId : '';
@@ -79,7 +79,7 @@ export class DashboardToDiscoverDrilldown
}
}
- return await urlGenerator.createUrl({
+ return await locator.getUrl({
indexPatternId,
});
};
diff --git a/x-pack/plugins/alerting/README.md b/x-pack/plugins/alerting/README.md
index bc917fbf43bc4..8fdfe77776b4e 100644
--- a/x-pack/plugins/alerting/README.md
+++ b/x-pack/plugins/alerting/README.md
@@ -19,6 +19,7 @@ Table of Contents
- [Methods](#methods)
- [Executor](#executor)
- [Action variables](#action-variables)
+ - [Recovered Alerts](#recovered-alerts)
- [Licensing](#licensing)
- [Documentation](#documentation)
- [Tests](#tests)
@@ -100,6 +101,7 @@ The following table describes the properties of the `options` object.
|isExportable|Whether the rule type is exportable from the Saved Objects Management UI.|boolean|
|defaultScheduleInterval|The default interval that will show up in the UI when creating a rule of this rule type.|boolean|
|minimumScheduleInterval|The minimum interval that will be allowed for all rules of this rule type.|boolean|
+|doesSetRecoveryContext|Whether the rule type will set context variables for recovered alerts. Defaults to `false`. If this is set to true, context variables are made available for the recovery action group and executors will be provided with the ability to set recovery context.|boolean|
### Executor
@@ -170,6 +172,35 @@ This function should take the rule type params as input and extract out any save
This function should take the rule type params (with saved object references) and the saved object references array as input and inject the saved object ID in place of any saved object references in the rule type params. Note that any error thrown within this function will be propagated.
+
+## Recovered Alerts
+The Alerting framework automatically determines which alerts are recovered by comparing the active alerts from the previous rule execution to the active alerts in the current rule execution. Alerts that were active previously but not active currently are considered `recovered`. If any actions were specified on the Recovery action group for the rule, they will be scheduled at the end of the execution cycle.
+
+Because this determination occurs after rule type executors have completed execution, the framework provides a mechanism for rule type executors to set contextual information for recovered alerts that can be templated and used inside recovery actions. In order to use this mechanism, the rule type must set the `doesSetRecoveryContext` flag to `true` during rule type registration.
+
+Then, the following code would be added within a rule type executor. As you can see, when the rule type is finished creating and scheduling actions for active alerts, it should call `done()` on the alertFactory. This will give the executor access to the list recovered alerts for this execution cycle, for which it can iterate and set context.
+
+```
+// Create and schedule actions for active alerts
+for (const i = 0; i < 5; ++i) {
+ alertFactory
+ .create('server_1')
+ .scheduleActions('default', {
+ server: 'server_1',
+ });
+}
+
+// Call done() to gain access to recovery utils
+// If `doesSetRecoveryContext` is set to `false`, getRecoveredAlerts() returns an empty list
+const { getRecoveredAlerts } = alertsFactory.done();
+
+for (const alert of getRecoveredAlerts()) {
+ const alertId = alert.getId();
+ alert.setContext({
+ server:
+ })
+}
+```
## Licensing
Currently most rule types are free features. But some rule types are subscription features, such as the tracking containment rule.
@@ -743,6 +774,7 @@ This factory returns an instance of `Alert`. The `Alert` class has the following
|scheduleActions(actionGroup, context)|Call this to schedule the execution of actions. The actionGroup is a string `id` that relates to the group of alert `actions` to execute and the context will be used for templating purposes. `scheduleActions` or `scheduleActionsWithSubGroup` should only be called once per alert.|
|scheduleActionsWithSubGroup(actionGroup, subgroup, context)|Call this to schedule the execution of actions within a subgroup. The actionGroup is a string `id` that relates to the group of alert `actions` to execute, the `subgroup` is a dynamic string that denotes a subgroup within the actionGroup and the context will be used for templating purposes. `scheduleActions` or `scheduleActionsWithSubGroup` should only be called once per alert.|
|replaceState(state)|Used to replace the current state of the alert. This doesn't work like React, the entire state must be provided. Use this feature as you see fit. The state that is set will persist between rule executions whenever you re-create an alert with the same id. The alert state will be erased when `scheduleActions` or `scheduleActionsWithSubGroup` aren't called during an execution.|
+|setContext(context)|Call this to set the context for this alert that is used for templating purposes.
### When should I use `scheduleActions` and `scheduleActionsWithSubGroup`?
The `scheduleActions` or `scheduleActionsWithSubGroup` methods are both used to achieve the same thing: schedule actions to be run under a specific action group.
@@ -758,13 +790,16 @@ Action Subgroups are dynamic, and can be defined on the fly.
This approach enables users to specify actions under specific action groups, but they can't specify actions that are specific to subgroups.
As subgroups fall under action groups, we will schedule the actions specified for the action group, but the subgroup allows the RuleType implementer to reuse the same action group for multiple different active subgroups.
+### When should I use `setContext`?
+`setContext` is intended to be used for setting context for recovered alerts. While rule type executors make the determination as to which alerts are active for an execution, the Alerting Framework automatically determines which alerts are recovered for an execution. `setContext` empowers rule type executors to provide additional contextual information for these recovered alerts that will be templated into actions.
+
## Templating Actions
There needs to be a way to map rule context into action parameters. For this, we started off by adding template support. Any string within the `params` of a rule saved object's `actions` will be processed as a template and can inject context or state values.
When an alert executes, the first argument is the `group` of actions to execute and the second is the context the rule exposes to templates. We iterate through each action parameter attributes recursively and render templates if they are a string. Templates have access to the following "variables":
-- `context` - provided by context argument of `.scheduleActions(...)` and `.scheduleActionsWithSubGroup(...)` on an alert.
+- `context` - provided by context argument of `.scheduleActions(...)`, `.scheduleActionsWithSubGroup(...)` and `setContext(...)` on an alert.
- `state` - the alert's `state` provided by the most recent `replaceState` call on an alert.
- `alertId` - the id of the rule
- `alertInstanceId` - the alert id
diff --git a/x-pack/plugins/alerting/common/rule_type.ts b/x-pack/plugins/alerting/common/rule_type.ts
index 6f5f00e8f4073..eb24e29f552b9 100644
--- a/x-pack/plugins/alerting/common/rule_type.ts
+++ b/x-pack/plugins/alerting/common/rule_type.ts
@@ -37,6 +37,7 @@ export interface RuleType<
ruleTaskTimeout?: string;
defaultScheduleInterval?: string;
minimumScheduleInterval?: string;
+ doesSetRecoveryContext?: boolean;
enabledInLicense: boolean;
authorizedConsumers: Record;
}
diff --git a/x-pack/plugins/alerting/server/alert/alert.test.ts b/x-pack/plugins/alerting/server/alert/alert.test.ts
index 83b82de904703..eae1b18164b0f 100644
--- a/x-pack/plugins/alerting/server/alert/alert.test.ts
+++ b/x-pack/plugins/alerting/server/alert/alert.test.ts
@@ -17,14 +17,21 @@ beforeAll(() => {
beforeEach(() => clock.reset());
afterAll(() => clock.restore());
+describe('getId()', () => {
+ test('correctly sets id in constructor', () => {
+ const alert = new Alert('1');
+ expect(alert.getId()).toEqual('1');
+ });
+});
+
describe('hasScheduledActions()', () => {
test('defaults to false', () => {
- const alert = new Alert();
+ const alert = new Alert('1');
expect(alert.hasScheduledActions()).toEqual(false);
});
test('returns true when scheduleActions is called', () => {
- const alert = new Alert();
+ const alert = new Alert('1');
alert.scheduleActions('default');
expect(alert.hasScheduledActions()).toEqual(true);
});
@@ -32,7 +39,7 @@ describe('hasScheduledActions()', () => {
describe('isThrottled', () => {
test(`should throttle when group didn't change and throttle period is still active`, () => {
- const alert = new Alert({
+ const alert = new Alert('1', {
meta: {
lastScheduledActions: {
date: new Date(),
@@ -46,7 +53,7 @@ describe('isThrottled', () => {
});
test(`shouldn't throttle when group didn't change and throttle period expired`, () => {
- const alert = new Alert({
+ const alert = new Alert('1', {
meta: {
lastScheduledActions: {
date: new Date(),
@@ -60,7 +67,7 @@ describe('isThrottled', () => {
});
test(`shouldn't throttle when group changes`, () => {
- const alert = new Alert({
+ const alert = new Alert('1', {
meta: {
lastScheduledActions: {
date: new Date(),
@@ -76,12 +83,12 @@ describe('isThrottled', () => {
describe('scheduledActionGroupOrSubgroupHasChanged()', () => {
test('should be false if no last scheduled and nothing scheduled', () => {
- const alert = new Alert();
+ const alert = new Alert('1');
expect(alert.scheduledActionGroupOrSubgroupHasChanged()).toEqual(false);
});
test('should be false if group does not change', () => {
- const alert = new Alert({
+ const alert = new Alert('1', {
meta: {
lastScheduledActions: {
date: new Date(),
@@ -94,7 +101,7 @@ describe('scheduledActionGroupOrSubgroupHasChanged()', () => {
});
test('should be false if group and subgroup does not change', () => {
- const alert = new Alert({
+ const alert = new Alert('1', {
meta: {
lastScheduledActions: {
date: new Date(),
@@ -108,7 +115,7 @@ describe('scheduledActionGroupOrSubgroupHasChanged()', () => {
});
test('should be false if group does not change and subgroup goes from undefined to defined', () => {
- const alert = new Alert({
+ const alert = new Alert('1', {
meta: {
lastScheduledActions: {
date: new Date(),
@@ -121,7 +128,7 @@ describe('scheduledActionGroupOrSubgroupHasChanged()', () => {
});
test('should be false if group does not change and subgroup goes from defined to undefined', () => {
- const alert = new Alert({
+ const alert = new Alert('1', {
meta: {
lastScheduledActions: {
date: new Date(),
@@ -135,13 +142,13 @@ describe('scheduledActionGroupOrSubgroupHasChanged()', () => {
});
test('should be true if no last scheduled and has scheduled action', () => {
- const alert = new Alert();
+ const alert = new Alert('1');
alert.scheduleActions('default');
expect(alert.scheduledActionGroupOrSubgroupHasChanged()).toEqual(true);
});
test('should be true if group does change', () => {
- const alert = new Alert({
+ const alert = new Alert('1', {
meta: {
lastScheduledActions: {
date: new Date(),
@@ -154,7 +161,7 @@ describe('scheduledActionGroupOrSubgroupHasChanged()', () => {
});
test('should be true if group does change and subgroup does change', () => {
- const alert = new Alert({
+ const alert = new Alert('1', {
meta: {
lastScheduledActions: {
date: new Date(),
@@ -168,7 +175,7 @@ describe('scheduledActionGroupOrSubgroupHasChanged()', () => {
});
test('should be true if group does not change and subgroup does change', () => {
- const alert = new Alert({
+ const alert = new Alert('1', {
meta: {
lastScheduledActions: {
date: new Date(),
@@ -184,14 +191,14 @@ describe('scheduledActionGroupOrSubgroupHasChanged()', () => {
describe('getScheduledActionOptions()', () => {
test('defaults to undefined', () => {
- const alert = new Alert();
+ const alert = new Alert('1');
expect(alert.getScheduledActionOptions()).toBeUndefined();
});
});
describe('unscheduleActions()', () => {
test('makes hasScheduledActions() return false', () => {
- const alert = new Alert();
+ const alert = new Alert('1');
alert.scheduleActions('default');
expect(alert.hasScheduledActions()).toEqual(true);
alert.unscheduleActions();
@@ -199,7 +206,7 @@ describe('unscheduleActions()', () => {
});
test('makes getScheduledActionOptions() return undefined', () => {
- const alert = new Alert();
+ const alert = new Alert('1');
alert.scheduleActions('default');
expect(alert.getScheduledActionOptions()).toEqual({
actionGroup: 'default',
@@ -214,7 +221,7 @@ describe('unscheduleActions()', () => {
describe('getState()', () => {
test('returns state passed to constructor', () => {
const state = { foo: true };
- const alert = new Alert({
+ const alert = new Alert('1', {
state,
});
expect(alert.getState()).toEqual(state);
@@ -223,7 +230,7 @@ describe('getState()', () => {
describe('scheduleActions()', () => {
test('makes hasScheduledActions() return true', () => {
- const alert = new Alert({
+ const alert = new Alert('1', {
state: { foo: true },
meta: {
lastScheduledActions: {
@@ -237,7 +244,7 @@ describe('scheduleActions()', () => {
});
test('makes isThrottled() return true when throttled', () => {
- const alert = new Alert({
+ const alert = new Alert('1', {
state: { foo: true },
meta: {
lastScheduledActions: {
@@ -251,7 +258,7 @@ describe('scheduleActions()', () => {
});
test('make isThrottled() return false when throttled expired', () => {
- const alert = new Alert({
+ const alert = new Alert('1', {
state: { foo: true },
meta: {
lastScheduledActions: {
@@ -266,7 +273,7 @@ describe('scheduleActions()', () => {
});
test('makes getScheduledActionOptions() return given options', () => {
- const alert = new Alert({
+ const alert = new Alert('1', {
state: { foo: true },
meta: {},
});
@@ -279,7 +286,7 @@ describe('scheduleActions()', () => {
});
test('cannot schdule for execution twice', () => {
- const alert = new Alert();
+ const alert = new Alert('1');
alert.scheduleActions('default', { field: true });
expect(() =>
alert.scheduleActions('default', { field: false })
@@ -291,7 +298,7 @@ describe('scheduleActions()', () => {
describe('scheduleActionsWithSubGroup()', () => {
test('makes hasScheduledActions() return true', () => {
- const alert = new Alert({
+ const alert = new Alert('1', {
state: { foo: true },
meta: {
lastScheduledActions: {
@@ -307,7 +314,7 @@ describe('scheduleActionsWithSubGroup()', () => {
});
test('makes isThrottled() return true when throttled and subgroup is the same', () => {
- const alert = new Alert({
+ const alert = new Alert('1', {
state: { foo: true },
meta: {
lastScheduledActions: {
@@ -324,7 +331,7 @@ describe('scheduleActionsWithSubGroup()', () => {
});
test('makes isThrottled() return true when throttled and last schedule had no subgroup', () => {
- const alert = new Alert({
+ const alert = new Alert('1', {
state: { foo: true },
meta: {
lastScheduledActions: {
@@ -340,7 +347,7 @@ describe('scheduleActionsWithSubGroup()', () => {
});
test('makes isThrottled() return false when throttled and subgroup is the different', () => {
- const alert = new Alert({
+ const alert = new Alert('1', {
state: { foo: true },
meta: {
lastScheduledActions: {
@@ -357,7 +364,7 @@ describe('scheduleActionsWithSubGroup()', () => {
});
test('make isThrottled() return false when throttled expired', () => {
- const alert = new Alert({
+ const alert = new Alert('1', {
state: { foo: true },
meta: {
lastScheduledActions: {
@@ -374,7 +381,7 @@ describe('scheduleActionsWithSubGroup()', () => {
});
test('makes getScheduledActionOptions() return given options', () => {
- const alert = new Alert({
+ const alert = new Alert('1', {
state: { foo: true },
meta: {},
});
@@ -390,7 +397,7 @@ describe('scheduleActionsWithSubGroup()', () => {
});
test('cannot schdule for execution twice', () => {
- const alert = new Alert();
+ const alert = new Alert('1');
alert.scheduleActionsWithSubGroup('default', 'subgroup', { field: true });
expect(() =>
alert.scheduleActionsWithSubGroup('default', 'subgroup', { field: false })
@@ -400,7 +407,7 @@ describe('scheduleActionsWithSubGroup()', () => {
});
test('cannot schdule for execution twice with different subgroups', () => {
- const alert = new Alert();
+ const alert = new Alert('1');
alert.scheduleActionsWithSubGroup('default', 'subgroup', { field: true });
expect(() =>
alert.scheduleActionsWithSubGroup('default', 'subgroup', { field: false })
@@ -410,7 +417,7 @@ describe('scheduleActionsWithSubGroup()', () => {
});
test('cannot schdule for execution twice whether there are subgroups', () => {
- const alert = new Alert();
+ const alert = new Alert('1');
alert.scheduleActions('default', { field: true });
expect(() =>
alert.scheduleActionsWithSubGroup('default', 'subgroup', { field: false })
@@ -422,7 +429,7 @@ describe('scheduleActionsWithSubGroup()', () => {
describe('replaceState()', () => {
test('replaces previous state', () => {
- const alert = new Alert({
+ const alert = new Alert('1', {
state: { foo: true },
});
alert.replaceState({ bar: true });
@@ -434,7 +441,7 @@ describe('replaceState()', () => {
describe('updateLastScheduledActions()', () => {
test('replaces previous lastScheduledActions', () => {
- const alert = new Alert({
+ const alert = new Alert('1', {
meta: {},
});
alert.updateLastScheduledActions('default');
@@ -450,9 +457,82 @@ describe('updateLastScheduledActions()', () => {
});
});
+describe('getContext()', () => {
+ test('returns empty object when context has not been set', () => {
+ const alert = new Alert('1', {
+ state: { foo: true },
+ meta: {
+ lastScheduledActions: {
+ date: new Date(),
+ group: 'default',
+ },
+ },
+ });
+ expect(alert.getContext()).toStrictEqual({});
+ });
+
+ test('returns context when context has not been set', () => {
+ const alert = new Alert('1', {
+ state: { foo: true },
+ meta: {
+ lastScheduledActions: {
+ date: new Date(),
+ group: 'default',
+ },
+ },
+ });
+ alert.setContext({ field: true });
+ expect(alert.getContext()).toStrictEqual({ field: true });
+ });
+});
+
+describe('hasContext()', () => {
+ test('returns true when context has been set via scheduleActions()', () => {
+ const alert = new Alert('1', {
+ state: { foo: true },
+ meta: {
+ lastScheduledActions: {
+ date: new Date(),
+ group: 'default',
+ },
+ },
+ });
+ alert.scheduleActions('default', { field: true });
+ expect(alert.hasContext()).toEqual(true);
+ });
+
+ test('returns true when context has been set via setContext()', () => {
+ const alert = new Alert('1', {
+ state: { foo: true },
+ meta: {
+ lastScheduledActions: {
+ date: new Date(),
+ group: 'default',
+ },
+ },
+ });
+ alert.setContext({ field: true });
+ expect(alert.hasContext()).toEqual(true);
+ });
+
+ test('returns false when context has not been set', () => {
+ const alert = new Alert('1', {
+ state: { foo: true },
+ meta: {
+ lastScheduledActions: {
+ date: new Date(),
+ group: 'default',
+ },
+ },
+ });
+ expect(alert.hasContext()).toEqual(false);
+ });
+});
+
describe('toJSON', () => {
test('only serializes state and meta', () => {
const alertInstance = new Alert(
+ '1',
{
state: { foo: true },
meta: {
@@ -481,6 +561,7 @@ describe('toRaw', () => {
},
};
const alertInstance = new Alert(
+ '1',
raw
);
expect(alertInstance.toRaw()).toEqual(raw);
diff --git a/x-pack/plugins/alerting/server/alert/alert.ts b/x-pack/plugins/alerting/server/alert/alert.ts
index d34aa68ac1a11..bf29cacf556c1 100644
--- a/x-pack/plugins/alerting/server/alert/alert.ts
+++ b/x-pack/plugins/alerting/server/alert/alert.ts
@@ -5,6 +5,7 @@
* 2.0.
*/
+import { isEmpty } from 'lodash';
import {
AlertInstanceMeta,
AlertInstanceState,
@@ -33,7 +34,13 @@ export type PublicAlert<
ActionGroupIds extends string = DefaultActionGroupId
> = Pick<
Alert,
- 'getState' | 'replaceState' | 'scheduleActions' | 'scheduleActionsWithSubGroup'
+ | 'getState'
+ | 'replaceState'
+ | 'scheduleActions'
+ | 'scheduleActionsWithSubGroup'
+ | 'setContext'
+ | 'getContext'
+ | 'hasContext'
>;
export class Alert<
@@ -44,12 +51,20 @@ export class Alert<
private scheduledExecutionOptions?: ScheduledExecutionOptions;
private meta: AlertInstanceMeta;
private state: State;
+ private context: Context;
+ private readonly id: string;
- constructor({ state, meta = {} }: RawAlertInstance = {}) {
+ constructor(id: string, { state, meta = {} }: RawAlertInstance = {}) {
+ this.id = id;
this.state = (state || {}) as State;
+ this.context = {} as Context;
this.meta = meta;
}
+ getId() {
+ return this.id;
+ }
+
hasScheduledActions() {
return this.scheduledExecutionOptions !== undefined;
}
@@ -134,8 +149,17 @@ export class Alert<
return this.state;
}
+ getContext() {
+ return this.context;
+ }
+
+ hasContext() {
+ return !isEmpty(this.context);
+ }
+
scheduleActions(actionGroup: ActionGroupIds, context: Context = {} as Context) {
this.ensureHasNoScheduledActions();
+ this.setContext(context);
this.scheduledExecutionOptions = {
actionGroup,
context,
@@ -150,6 +174,7 @@ export class Alert<
context: Context = {} as Context
) {
this.ensureHasNoScheduledActions();
+ this.setContext(context);
this.scheduledExecutionOptions = {
actionGroup,
subgroup,
@@ -159,6 +184,11 @@ export class Alert<
return this;
}
+ setContext(context: Context) {
+ this.context = context;
+ return this;
+ }
+
private ensureHasNoScheduledActions() {
if (this.hasScheduledActions()) {
throw new Error('Alert instance execution has already been scheduled, cannot schedule twice');
diff --git a/x-pack/plugins/alerting/server/alert/create_alert_factory.test.ts b/x-pack/plugins/alerting/server/alert/create_alert_factory.test.ts
index ecb1a10bbac42..254da05c0dd53 100644
--- a/x-pack/plugins/alerting/server/alert/create_alert_factory.test.ts
+++ b/x-pack/plugins/alerting/server/alert/create_alert_factory.test.ts
@@ -6,64 +6,206 @@
*/
import sinon from 'sinon';
+import { loggingSystemMock } from 'src/core/server/mocks';
import { Alert } from './alert';
import { createAlertFactory } from './create_alert_factory';
+import { getRecoveredAlerts } from '../lib';
-let clock: sinon.SinonFakeTimers;
+jest.mock('../lib', () => ({
+ getRecoveredAlerts: jest.fn(),
+}));
-beforeAll(() => {
- clock = sinon.useFakeTimers();
-});
-beforeEach(() => clock.reset());
-afterAll(() => clock.restore());
-
-test('creates new alerts for ones not passed in', () => {
- const alertFactory = createAlertFactory({ alerts: {} });
- const result = alertFactory.create('1');
- expect(result).toMatchInlineSnapshot(`
- Object {
- "meta": Object {},
- "state": Object {},
- }
- `);
-});
+let clock: sinon.SinonFakeTimers;
+const logger = loggingSystemMock.create().get();
-test('reuses existing alerts', () => {
- const alert = new Alert({
- state: { foo: true },
- meta: { lastScheduledActions: { group: 'default', date: new Date() } },
+describe('createAlertFactory()', () => {
+ beforeAll(() => {
+ clock = sinon.useFakeTimers();
});
- const alertFactory = createAlertFactory({
- alerts: {
- '1': alert,
- },
+ beforeEach(() => clock.reset());
+ afterAll(() => clock.restore());
+
+ test('creates new alerts for ones not passed in', () => {
+ const alertFactory = createAlertFactory({
+ alerts: {},
+ logger,
+ });
+ const result = alertFactory.create('1');
+ expect(result).toMatchInlineSnapshot(`
+ Object {
+ "meta": Object {},
+ "state": Object {},
+ }
+ `);
+ expect(result.getId()).toEqual('1');
});
- const result = alertFactory.create('1');
- expect(result).toMatchInlineSnapshot(`
- Object {
- "meta": Object {
- "lastScheduledActions": Object {
- "date": "1970-01-01T00:00:00.000Z",
- "group": "default",
+
+ test('reuses existing alerts', () => {
+ const alert = new Alert('1', {
+ state: { foo: true },
+ meta: { lastScheduledActions: { group: 'default', date: new Date() } },
+ });
+ const alertFactory = createAlertFactory({
+ alerts: {
+ '1': alert,
+ },
+ logger,
+ });
+ const result = alertFactory.create('1');
+ expect(result).toMatchInlineSnapshot(`
+ Object {
+ "meta": Object {
+ "lastScheduledActions": Object {
+ "date": "1970-01-01T00:00:00.000Z",
+ "group": "default",
+ },
+ },
+ "state": Object {
+ "foo": true,
},
+ }
+ `);
+ });
+
+ test('mutates given alerts', () => {
+ const alerts = {};
+ const alertFactory = createAlertFactory({
+ alerts,
+ logger,
+ });
+ alertFactory.create('1');
+ expect(alerts).toMatchInlineSnapshot(`
+ Object {
+ "1": Object {
+ "meta": Object {},
+ "state": Object {},
+ },
+ }
+ `);
+ });
+
+ test('throws error when creating alerts after done() is called', () => {
+ const alertFactory = createAlertFactory({
+ alerts: {},
+ logger,
+ });
+ const result = alertFactory.create('1');
+ expect(result).toEqual({
+ meta: {},
+ state: {},
+ context: {},
+ scheduledExecutionOptions: undefined,
+ id: '1',
+ });
+
+ alertFactory.done();
+
+ expect(() => {
+ alertFactory.create('2');
+ }).toThrowErrorMatchingInlineSnapshot(
+ `"Can't create new alerts after calling done() in AlertsFactory."`
+ );
+ });
+
+ test('returns recovered alerts when setsRecoveryContext is true', () => {
+ (getRecoveredAlerts as jest.Mock).mockReturnValueOnce({
+ z: {
+ id: 'z',
+ state: { foo: true },
+ meta: { lastScheduledActions: { group: 'default', date: new Date() } },
},
- "state": Object {
- "foo": true,
+ y: {
+ id: 'y',
+ state: { foo: true },
+ meta: { lastScheduledActions: { group: 'default', date: new Date() } },
},
- }
- `);
-});
+ });
+ const alertFactory = createAlertFactory({
+ alerts: {},
+ logger,
+ canSetRecoveryContext: true,
+ });
+ const result = alertFactory.create('1');
+ expect(result).toEqual({
+ meta: {},
+ state: {},
+ context: {},
+ scheduledExecutionOptions: undefined,
+ id: '1',
+ });
-test('mutates given alerts', () => {
- const alerts = {};
- const alertFactory = createAlertFactory({ alerts });
- alertFactory.create('1');
- expect(alerts).toMatchInlineSnapshot(`
- Object {
- "1": Object {
- "meta": Object {},
- "state": Object {},
- },
- }
- `);
+ const { getRecoveredAlerts: getRecoveredAlertsFn } = alertFactory.done();
+ expect(getRecoveredAlertsFn).toBeDefined();
+ const recoveredAlerts = getRecoveredAlertsFn!();
+ expect(Array.isArray(recoveredAlerts)).toBe(true);
+ expect(recoveredAlerts.length).toEqual(2);
+ });
+
+ test('returns empty array if no recovered alerts', () => {
+ (getRecoveredAlerts as jest.Mock).mockReturnValueOnce({});
+ const alertFactory = createAlertFactory({
+ alerts: {},
+ logger,
+ canSetRecoveryContext: true,
+ });
+ const result = alertFactory.create('1');
+ expect(result).toEqual({
+ meta: {},
+ state: {},
+ context: {},
+ scheduledExecutionOptions: undefined,
+ id: '1',
+ });
+
+ const { getRecoveredAlerts: getRecoveredAlertsFn } = alertFactory.done();
+ const recoveredAlerts = getRecoveredAlertsFn!();
+ expect(Array.isArray(recoveredAlerts)).toBe(true);
+ expect(recoveredAlerts.length).toEqual(0);
+ });
+
+ test('returns empty array if getRecoveredAlerts returns null', () => {
+ (getRecoveredAlerts as jest.Mock).mockReturnValueOnce(null);
+ const alertFactory = createAlertFactory({
+ alerts: {},
+ logger,
+ canSetRecoveryContext: true,
+ });
+ const result = alertFactory.create('1');
+ expect(result).toEqual({
+ meta: {},
+ state: {},
+ context: {},
+ scheduledExecutionOptions: undefined,
+ id: '1',
+ });
+
+ const { getRecoveredAlerts: getRecoveredAlertsFn } = alertFactory.done();
+ const recoveredAlerts = getRecoveredAlertsFn!();
+ expect(Array.isArray(recoveredAlerts)).toBe(true);
+ expect(recoveredAlerts.length).toEqual(0);
+ });
+
+ test('returns empty array if recovered alerts exist but setsRecoveryContext is false', () => {
+ const alertFactory = createAlertFactory({
+ alerts: {},
+ logger,
+ canSetRecoveryContext: false,
+ });
+ const result = alertFactory.create('1');
+ expect(result).toEqual({
+ meta: {},
+ state: {},
+ context: {},
+ scheduledExecutionOptions: undefined,
+ id: '1',
+ });
+
+ const { getRecoveredAlerts: getRecoveredAlertsFn } = alertFactory.done();
+ const recoveredAlerts = getRecoveredAlertsFn!();
+ expect(Array.isArray(recoveredAlerts)).toBe(true);
+ expect(recoveredAlerts.length).toEqual(0);
+ expect(logger.debug).toHaveBeenCalledWith(
+ `Set doesSetRecoveryContext to true on rule type to get access to recovered alerts.`
+ );
+ });
});
diff --git a/x-pack/plugins/alerting/server/alert/create_alert_factory.ts b/x-pack/plugins/alerting/server/alert/create_alert_factory.ts
index 07f4dbc7b20ea..ad83b0a416c72 100644
--- a/x-pack/plugins/alerting/server/alert/create_alert_factory.ts
+++ b/x-pack/plugins/alerting/server/alert/create_alert_factory.ts
@@ -5,8 +5,18 @@
* 2.0.
*/
+import { Logger } from 'src/core/server';
import { AlertInstanceContext, AlertInstanceState } from '../types';
import { Alert } from './alert';
+import { getRecoveredAlerts } from '../lib';
+
+export interface AlertFactoryDoneUtils<
+ InstanceState extends AlertInstanceState,
+ InstanceContext extends AlertInstanceContext,
+ ActionGroupIds extends string
+> {
+ getRecoveredAlerts: () => Array>;
+}
export interface CreateAlertFactoryOpts<
InstanceState extends AlertInstanceState,
@@ -14,20 +24,50 @@ export interface CreateAlertFactoryOpts<
ActionGroupIds extends string
> {
alerts: Record>;
+ logger: Logger;
+ canSetRecoveryContext?: boolean;
}
export function createAlertFactory<
InstanceState extends AlertInstanceState,
InstanceContext extends AlertInstanceContext,
ActionGroupIds extends string
->({ alerts }: CreateAlertFactoryOpts) {
+>({
+ alerts,
+ logger,
+ canSetRecoveryContext = false,
+}: CreateAlertFactoryOpts) {
+ // Keep track of which alerts we started with so we can determine which have recovered
+ const initialAlertIds = new Set(Object.keys(alerts));
+ let isDone = false;
return {
create: (id: string): Alert => {
+ if (isDone) {
+ throw new Error(`Can't create new alerts after calling done() in AlertsFactory.`);
+ }
if (!alerts[id]) {
- alerts[id] = new Alert();
+ alerts[id] = new Alert(id);
}
return alerts[id];
},
+ done: (): AlertFactoryDoneUtils => {
+ isDone = true;
+ return {
+ getRecoveredAlerts: () => {
+ if (!canSetRecoveryContext) {
+ logger.debug(
+ `Set doesSetRecoveryContext to true on rule type to get access to recovered alerts.`
+ );
+ return [];
+ }
+
+ const recoveredAlerts = getRecoveredAlerts(alerts, initialAlertIds);
+ return Object.keys(recoveredAlerts ?? []).map(
+ (alertId: string) => recoveredAlerts[alertId]
+ );
+ },
+ };
+ },
};
}
diff --git a/x-pack/plugins/alerting/server/alert/index.ts b/x-pack/plugins/alerting/server/alert/index.ts
index 5e1a9ee626b57..2b5dc4791037e 100644
--- a/x-pack/plugins/alerting/server/alert/index.ts
+++ b/x-pack/plugins/alerting/server/alert/index.ts
@@ -8,3 +8,4 @@
export type { PublicAlert } from './alert';
export { Alert } from './alert';
export { createAlertFactory } from './create_alert_factory';
+export type { AlertFactoryDoneUtils } from './create_alert_factory';
diff --git a/x-pack/plugins/alerting/server/lib/get_recovered_alerts.test.ts b/x-pack/plugins/alerting/server/lib/get_recovered_alerts.test.ts
new file mode 100644
index 0000000000000..b984b04fc65d4
--- /dev/null
+++ b/x-pack/plugins/alerting/server/lib/get_recovered_alerts.test.ts
@@ -0,0 +1,40 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import { getRecoveredAlerts } from './get_recovered_alerts';
+import { Alert } from '../alert';
+import { AlertInstanceState, AlertInstanceContext, DefaultActionGroupId } from '../types';
+
+describe('getRecoveredAlerts', () => {
+ test('considers alert recovered if it has no scheduled actions', () => {
+ const alert1 = new Alert('1');
+ alert1.scheduleActions('default', { foo: '1' });
+
+ const alert2 = new Alert('2');
+ alert2.setContext({ foo: '2' });
+ const alerts = {
+ '1': alert1,
+ '2': alert2,
+ };
+
+ expect(getRecoveredAlerts(alerts, new Set(['1', '2']))).toEqual({
+ '2': alert2,
+ });
+ });
+
+ test('does not consider alert recovered if it has no actions but was not in original alerts list', () => {
+ const alert1 = new Alert('1');
+ alert1.scheduleActions('default', { foo: '1' });
+ const alert2 = new Alert('2');
+ const alerts = {
+ '1': alert1,
+ '2': alert2,
+ };
+
+ expect(getRecoveredAlerts(alerts, new Set(['1']))).toEqual({});
+ });
+});
diff --git a/x-pack/plugins/alerting/server/lib/get_recovered_alerts.ts b/x-pack/plugins/alerting/server/lib/get_recovered_alerts.ts
new file mode 100644
index 0000000000000..f389f56a813d0
--- /dev/null
+++ b/x-pack/plugins/alerting/server/lib/get_recovered_alerts.ts
@@ -0,0 +1,25 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import { Dictionary, pickBy } from 'lodash';
+import { Alert } from '../alert';
+import { AlertInstanceState, AlertInstanceContext } from '../types';
+
+export function getRecoveredAlerts<
+ InstanceState extends AlertInstanceState,
+ InstanceContext extends AlertInstanceContext,
+ RecoveryActionGroupId extends string
+>(
+ alerts: Record>,
+ originalAlertIds: Set
+): Dictionary> {
+ return pickBy(
+ alerts,
+ (alert: Alert, id) =>
+ !alert.hasScheduledActions() && originalAlertIds.has(id)
+ );
+}
diff --git a/x-pack/plugins/alerting/server/lib/index.ts b/x-pack/plugins/alerting/server/lib/index.ts
index 29526f17268f2..a5fa1b29c3044 100644
--- a/x-pack/plugins/alerting/server/lib/index.ts
+++ b/x-pack/plugins/alerting/server/lib/index.ts
@@ -24,3 +24,4 @@ export {
ruleExecutionStatusToRaw,
ruleExecutionStatusFromRaw,
} from './rule_execution_status';
+export { getRecoveredAlerts } from './get_recovered_alerts';
diff --git a/x-pack/plugins/alerting/server/mocks.ts b/x-pack/plugins/alerting/server/mocks.ts
index afbc3ef9cec43..f7872ba797856 100644
--- a/x-pack/plugins/alerting/server/mocks.ts
+++ b/x-pack/plugins/alerting/server/mocks.ts
@@ -7,7 +7,7 @@
import { rulesClientMock } from './rules_client.mock';
import { PluginSetupContract, PluginStartContract } from './plugin';
-import { Alert } from './alert';
+import { Alert, AlertFactoryDoneUtils } from './alert';
import {
elasticsearchServiceMock,
savedObjectsClientMock,
@@ -64,6 +64,17 @@ const createAlertFactoryMock = {
return mock as unknown as AlertInstanceMock;
},
+ done: <
+ InstanceState extends AlertInstanceState = AlertInstanceState,
+ InstanceContext extends AlertInstanceContext = AlertInstanceContext,
+ ActionGroupIds extends string = string
+ >() => {
+ const mock: jest.Mocked> =
+ {
+ getRecoveredAlerts: jest.fn().mockReturnValue([]),
+ };
+ return mock;
+ },
};
const createAbortableSearchClientMock = () => {
@@ -86,9 +97,11 @@ const createAlertServicesMock = <
InstanceContext extends AlertInstanceContext = AlertInstanceContext
>() => {
const alertFactoryMockCreate = createAlertFactoryMock.create();
+ const alertFactoryMockDone = createAlertFactoryMock.done();
return {
alertFactory: {
create: jest.fn().mockReturnValue(alertFactoryMockCreate),
+ done: jest.fn().mockReturnValue(alertFactoryMockDone),
},
savedObjectsClient: savedObjectsClientMock.create(),
scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(),
diff --git a/x-pack/plugins/alerting/server/plugin.ts b/x-pack/plugins/alerting/server/plugin.ts
index 70aad0d6921e1..ac3253346138a 100644
--- a/x-pack/plugins/alerting/server/plugin.ts
+++ b/x-pack/plugins/alerting/server/plugin.ts
@@ -293,6 +293,7 @@ export class AlertingPlugin {
ruleType.ruleTaskTimeout = ruleType.ruleTaskTimeout ?? config.defaultRuleTaskTimeout;
ruleType.cancelAlertsOnRuleTimeout =
ruleType.cancelAlertsOnRuleTimeout ?? config.cancelAlertsOnRuleTimeout;
+ ruleType.doesSetRecoveryContext = ruleType.doesSetRecoveryContext ?? false;
ruleTypeRegistry.register(ruleType);
});
},
diff --git a/x-pack/plugins/alerting/server/routes/rule_types.test.ts b/x-pack/plugins/alerting/server/routes/rule_types.test.ts
index 7deb2704fb7ec..752f729fb8e38 100644
--- a/x-pack/plugins/alerting/server/routes/rule_types.test.ts
+++ b/x-pack/plugins/alerting/server/routes/rule_types.test.ts
@@ -60,6 +60,7 @@ describe('ruleTypesRoute', () => {
enabledInLicense: true,
minimumScheduleInterval: '1m',
defaultScheduleInterval: '10m',
+ doesSetRecoveryContext: false,
} as RegistryAlertTypeWithAuth,
];
const expectedResult: Array> = [
@@ -74,6 +75,7 @@ describe('ruleTypesRoute', () => {
],
default_action_group_id: 'default',
default_schedule_interval: '10m',
+ does_set_recovery_context: false,
minimum_license_required: 'basic',
minimum_schedule_interval: '1m',
is_exportable: true,
@@ -109,6 +111,7 @@ describe('ruleTypesRoute', () => {
"authorized_consumers": Object {},
"default_action_group_id": "default",
"default_schedule_interval": "10m",
+ "does_set_recovery_context": false,
"enabled_in_license": true,
"id": "1",
"is_exportable": true,
diff --git a/x-pack/plugins/alerting/server/routes/rule_types.ts b/x-pack/plugins/alerting/server/routes/rule_types.ts
index d1f24538d76d8..7b2a0c63be198 100644
--- a/x-pack/plugins/alerting/server/routes/rule_types.ts
+++ b/x-pack/plugins/alerting/server/routes/rule_types.ts
@@ -25,6 +25,7 @@ const rewriteBodyRes: RewriteResponseCase = (result
authorizedConsumers,
minimumScheduleInterval,
defaultScheduleInterval,
+ doesSetRecoveryContext,
...rest
}) => ({
...rest,
@@ -39,6 +40,7 @@ const rewriteBodyRes: RewriteResponseCase = (result
authorized_consumers: authorizedConsumers,
minimum_schedule_interval: minimumScheduleInterval,
default_schedule_interval: defaultScheduleInterval,
+ does_set_recovery_context: doesSetRecoveryContext,
})
);
};
diff --git a/x-pack/plugins/alerting/server/rule_type_registry.test.ts b/x-pack/plugins/alerting/server/rule_type_registry.test.ts
index e23c7f25a4f76..8ba2847486bca 100644
--- a/x-pack/plugins/alerting/server/rule_type_registry.test.ts
+++ b/x-pack/plugins/alerting/server/rule_type_registry.test.ts
@@ -493,6 +493,7 @@ describe('list()', () => {
},
],
defaultActionGroupId: 'testActionGroup',
+ doesSetRecoveryContext: false,
isExportable: true,
ruleTaskTimeout: '20m',
minimumLicenseRequired: 'basic',
@@ -520,6 +521,7 @@ describe('list()', () => {
},
"defaultActionGroupId": "testActionGroup",
"defaultScheduleInterval": undefined,
+ "doesSetRecoveryContext": false,
"enabledInLicense": false,
"id": "test",
"isExportable": true,
diff --git a/x-pack/plugins/alerting/server/rule_type_registry.ts b/x-pack/plugins/alerting/server/rule_type_registry.ts
index 9b4f94f3510be..6673fb630ef59 100644
--- a/x-pack/plugins/alerting/server/rule_type_registry.ts
+++ b/x-pack/plugins/alerting/server/rule_type_registry.ts
@@ -51,6 +51,7 @@ export interface RegistryRuleType
| 'ruleTaskTimeout'
| 'minimumScheduleInterval'
| 'defaultScheduleInterval'
+ | 'doesSetRecoveryContext'
> {
id: string;
enabledInLicense: boolean;
@@ -331,6 +332,7 @@ export class RuleTypeRegistry {
ruleTaskTimeout,
minimumScheduleInterval,
defaultScheduleInterval,
+ doesSetRecoveryContext,
},
]: [string, UntypedNormalizedRuleType]) => ({
id,
@@ -345,6 +347,7 @@ export class RuleTypeRegistry {
ruleTaskTimeout,
minimumScheduleInterval,
defaultScheduleInterval,
+ doesSetRecoveryContext,
enabledInLicense: !!this.licenseState.getLicenseCheckForRuleType(
id,
name,
diff --git a/x-pack/plugins/alerting/server/rules_client/rules_client.ts b/x-pack/plugins/alerting/server/rules_client/rules_client.ts
index 63e35583bc9a1..72ef2dba89ce7 100644
--- a/x-pack/plugins/alerting/server/rules_client/rules_client.ts
+++ b/x-pack/plugins/alerting/server/rules_client/rules_client.ts
@@ -1337,7 +1337,7 @@ export class RulesClient {
const recoveredAlertInstances = mapValues, Alert>(
state.alertInstances ?? {},
- (rawAlertInstance) => new Alert(rawAlertInstance)
+ (rawAlertInstance, alertId) => new Alert(alertId, rawAlertInstance)
);
const recoveredAlertInstanceIds = Object.keys(recoveredAlertInstances);
diff --git a/x-pack/plugins/alerting/server/saved_objects/migrations.test.ts b/x-pack/plugins/alerting/server/saved_objects/migrations.test.ts
index 5e2d8efedbcb3..1d7d3d2a362a9 100644
--- a/x-pack/plugins/alerting/server/saved_objects/migrations.test.ts
+++ b/x-pack/plugins/alerting/server/saved_objects/migrations.test.ts
@@ -2063,31 +2063,172 @@ describe('successful migrations', () => {
{ params: { outputIndex: 'output-index', type: 'query' }, alertTypeId: 'not.siem.signals' },
true
);
- expect(migration800(alert, migrationContext).attributes.alertTypeId).toEqual(
- 'not.siem.signals'
- );
- expect(migration800(alert, migrationContext).attributes.enabled).toEqual(true);
- expect(migration800(alert, migrationContext).attributes.params.outputIndex).toEqual(
- 'output-index'
- );
+ const migratedAlert = migration800(alert, migrationContext);
+ expect(migratedAlert.attributes.alertTypeId).toEqual('not.siem.signals');
+ expect(migratedAlert.attributes.enabled).toEqual(true);
+ expect(migratedAlert.attributes.tags).toEqual(['foo']);
+ expect(migratedAlert.attributes.params.outputIndex).toEqual('output-index');
});
test.each(Object.keys(ruleTypeMappings) as RuleType[])(
- 'Changes AAD rule params accordingly if rule is a siem.signals %p rule',
+ 'changes AAD rule params accordingly if rule is a siem.signals %p rule',
(ruleType) => {
const migration800 = getMigrations(encryptedSavedObjectsSetup, isPreconfigured)['8.0.0'];
const alert = getMockData(
{ params: { outputIndex: 'output-index', type: ruleType }, alertTypeId: 'siem.signals' },
true
);
- expect(migration800(alert, migrationContext).attributes.alertTypeId).toEqual(
- ruleTypeMappings[ruleType]
- );
- expect(migration800(alert, migrationContext).attributes.enabled).toEqual(false);
- expect(migration800(alert, migrationContext).attributes.params.outputIndex).toEqual('');
+ const migratedAlert = migration800(alert, migrationContext);
+ expect(migratedAlert.attributes.alertTypeId).toEqual(ruleTypeMappings[ruleType]);
+ expect(migratedAlert.attributes.enabled).toEqual(false);
+ expect(migratedAlert.attributes.tags).toEqual(['foo']);
+ expect(migratedAlert.attributes.params.outputIndex).toEqual('');
}
);
+ describe('8.0.1', () => {
+ describe.each(Object.keys(ruleTypeMappings) as RuleType[])(
+ 'auto_disabled %p rule tags',
+ (ruleType) => {
+ const alert717Enabled = getMockData(
+ {
+ params: { outputIndex: 'output-index', type: ruleType },
+ alertTypeId: 'siem.signals',
+ enabled: true,
+ scheduledTaskId: 'abcd',
+ },
+ true
+ );
+ const alert717Disabled = getMockData(
+ {
+ params: { outputIndex: 'output-index', type: ruleType },
+ alertTypeId: 'siem.signals',
+ enabled: false,
+ },
+ true
+ );
+ const alert800 = getMockData(
+ {
+ params: { outputIndex: '', type: ruleType },
+ alertTypeId: ruleTypeMappings[ruleType],
+ enabled: false,
+ scheduledTaskId: 'abcd',
+ },
+ true
+ );
+
+ test('Does not update rule tags if rule has already been enabled', () => {
+ const migrations = getMigrations(encryptedSavedObjectsSetup, isPreconfigured);
+ const migration800 = migrations['8.0.0'];
+ const migration801 = migrations['8.0.1'];
+
+ // migrate to 8.0.0
+ const migratedAlert800 = migration800(alert717Enabled, migrationContext);
+ expect(migratedAlert800.attributes.enabled).toEqual(false);
+
+ // reenable rule
+ migratedAlert800.attributes.enabled = true;
+
+ // migrate to 8.0.1
+ const migratedAlert801 = migration801(migratedAlert800, migrationContext);
+
+ expect(migratedAlert801.attributes.alertTypeId).toEqual(ruleTypeMappings[ruleType]);
+ expect(migratedAlert801.attributes.enabled).toEqual(true);
+ expect(migratedAlert801.attributes.params.outputIndex).toEqual('');
+
+ // tags not updated
+ expect(migratedAlert801.attributes.tags).toEqual(['foo']);
+ });
+
+ test('Does not update rule tags if rule was already disabled before upgrading to 8.0', () => {
+ const migrations = getMigrations(encryptedSavedObjectsSetup, isPreconfigured);
+ const migration800 = migrations['8.0.0'];
+ const migration801 = migrations['8.0.1'];
+
+ // migrate to 8.0.0
+ const migratedAlert800 = migration800(alert717Disabled, migrationContext);
+ expect(migratedAlert800.attributes.enabled).toEqual(false);
+
+ // migrate to 8.0.1
+ const migratedAlert801 = migration801(migratedAlert800, migrationContext);
+
+ expect(migratedAlert801.attributes.alertTypeId).toEqual(ruleTypeMappings[ruleType]);
+ expect(migratedAlert801.attributes.enabled).toEqual(false);
+ expect(migratedAlert801.attributes.params.outputIndex).toEqual('');
+
+ // tags not updated
+ expect(migratedAlert801.attributes.tags).toEqual(['foo']);
+ });
+
+ test('Updates rule tags if rule was auto-disabled in 8.0 upgrade and not reenabled', () => {
+ const migrations = getMigrations(encryptedSavedObjectsSetup, isPreconfigured);
+ const migration800 = migrations['8.0.0'];
+ const migration801 = migrations['8.0.1'];
+
+ // migrate to 8.0.0
+ const migratedAlert800 = migration800(alert717Enabled, migrationContext);
+ expect(migratedAlert800.attributes.enabled).toEqual(false);
+
+ // migrate to 8.0.1
+ const migratedAlert801 = migration801(migratedAlert800, migrationContext);
+
+ expect(migratedAlert801.attributes.alertTypeId).toEqual(ruleTypeMappings[ruleType]);
+ expect(migratedAlert801.attributes.enabled).toEqual(false);
+ expect(migratedAlert801.attributes.params.outputIndex).toEqual('');
+
+ // tags updated
+ expect(migratedAlert801.attributes.tags).toEqual(['foo', 'auto_disabled_8.0']);
+ });
+
+ test('Updates rule tags correctly if tags are undefined', () => {
+ const migrations = getMigrations(encryptedSavedObjectsSetup, isPreconfigured);
+ const migration801 = migrations['8.0.1'];
+
+ const alert = {
+ ...alert800,
+ attributes: {
+ ...alert800.attributes,
+ tags: undefined,
+ },
+ };
+
+ // migrate to 8.0.1
+ const migratedAlert801 = migration801(alert, migrationContext);
+
+ expect(migratedAlert801.attributes.alertTypeId).toEqual(ruleTypeMappings[ruleType]);
+ expect(migratedAlert801.attributes.enabled).toEqual(false);
+ expect(migratedAlert801.attributes.params.outputIndex).toEqual('');
+
+ // tags updated
+ expect(migratedAlert801.attributes.tags).toEqual(['auto_disabled_8.0']);
+ });
+
+ test('Updates rule tags correctly if tags are null', () => {
+ const migrations = getMigrations(encryptedSavedObjectsSetup, isPreconfigured);
+ const migration801 = migrations['8.0.1'];
+
+ const alert = {
+ ...alert800,
+ attributes: {
+ ...alert800.attributes,
+ tags: null,
+ },
+ };
+
+ // migrate to 8.0.1
+ const migratedAlert801 = migration801(alert, migrationContext);
+
+ expect(migratedAlert801.attributes.alertTypeId).toEqual(ruleTypeMappings[ruleType]);
+ expect(migratedAlert801.attributes.enabled).toEqual(false);
+ expect(migratedAlert801.attributes.params.outputIndex).toEqual('');
+
+ // tags updated
+ expect(migratedAlert801.attributes.tags).toEqual(['auto_disabled_8.0']);
+ });
+ }
+ );
+ });
+
describe('Metrics Inventory Threshold rule', () => {
test('Migrates incorrect action group spelling', () => {
const migration800 = getMigrations(encryptedSavedObjectsSetup, isPreconfigured)['8.0.0'];
diff --git a/x-pack/plugins/alerting/server/saved_objects/migrations.ts b/x-pack/plugins/alerting/server/saved_objects/migrations.ts
index e664095e8c846..6e6c886d91b53 100644
--- a/x-pack/plugins/alerting/server/saved_objects/migrations.ts
+++ b/x-pack/plugins/alerting/server/saved_objects/migrations.ts
@@ -58,6 +58,9 @@ export const isAnyActionSupportIncidents = (doc: SavedObjectUnsanitizedDoc): boolean =>
doc.attributes.alertTypeId === 'siem.signals';
+export const isDetectionEngineAADRuleType = (doc: SavedObjectUnsanitizedDoc): boolean =>
+ (Object.values(ruleTypeMappings) as string[]).includes(doc.attributes.alertTypeId);
+
/**
* Returns true if the alert type is that of "siem.notifications" which is a legacy notification system that was deprecated in 7.16.0
* in favor of using the newer alerting notifications system.
@@ -136,6 +139,12 @@ export function getMigrations(
)
);
+ const migrationRules801 = createEsoMigration(
+ encryptedSavedObjects,
+ (doc: SavedObjectUnsanitizedDoc): doc is SavedObjectUnsanitizedDoc => true,
+ pipeMigrations(addSecuritySolutionAADRuleTypeTags)
+ );
+
return {
'7.10.0': executeMigrationWithErrorHandling(migrationWhenRBACWasIntroduced, '7.10.0'),
'7.11.0': executeMigrationWithErrorHandling(migrationAlertUpdatedAtAndNotifyWhen, '7.11.0'),
@@ -145,6 +154,7 @@ export function getMigrations(
'7.15.0': executeMigrationWithErrorHandling(migrationSecurityRules715, '7.15.0'),
'7.16.0': executeMigrationWithErrorHandling(migrateRules716, '7.16.0'),
'8.0.0': executeMigrationWithErrorHandling(migrationRules800, '8.0.0'),
+ '8.0.1': executeMigrationWithErrorHandling(migrationRules801, '8.0.1'),
};
}
@@ -672,6 +682,28 @@ function addSecuritySolutionAADRuleTypes(
: doc;
}
+function addSecuritySolutionAADRuleTypeTags(
+ doc: SavedObjectUnsanitizedDoc
+): SavedObjectUnsanitizedDoc {
+ const ruleType = doc.attributes.params.type;
+ return isDetectionEngineAADRuleType(doc) && isRuleType(ruleType)
+ ? {
+ ...doc,
+ attributes: {
+ ...doc.attributes,
+ // If the rule is disabled at this point, then the rule has not been re-enabled after
+ // running the 8.0.0 migrations. If `doc.attributes.scheduledTaskId` exists, then the
+ // rule was enabled prior to running the migration. Thus we know we should add the
+ // tag to indicate it was auto-disabled.
+ tags:
+ !doc.attributes.enabled && doc.attributes.scheduledTaskId
+ ? [...(doc.attributes.tags ?? []), 'auto_disabled_8.0']
+ : doc.attributes.tags ?? [],
+ },
+ }
+ : doc;
+}
+
function addThreatIndicatorPathToThreatMatchRules(
doc: SavedObjectUnsanitizedDoc
): SavedObjectUnsanitizedDoc {
diff --git a/x-pack/plugins/alerting/server/task_runner/task_runner.ts b/x-pack/plugins/alerting/server/task_runner/task_runner.ts
index 51d50c398c6f5..8bc4ad280873e 100644
--- a/x-pack/plugins/alerting/server/task_runner/task_runner.ts
+++ b/x-pack/plugins/alerting/server/task_runner/task_runner.ts
@@ -66,6 +66,7 @@ import {
Event,
} from '../lib/create_alert_event_log_record_object';
import { createAbortableEsClientFactory } from '../lib/create_abortable_es_client_factory';
+import { getRecoveredAlerts } from '../lib';
const FALLBACK_RETRY_INTERVAL = '5m';
const CONNECTIVITY_RETRY_INTERVAL = '5m';
@@ -334,7 +335,11 @@ export class TaskRunner<
const alerts = mapValues<
Record,
CreatedAlert
- >(alertRawInstances, (rawAlert) => new CreatedAlert(rawAlert));
+ >(
+ alertRawInstances,
+ (rawAlert, alertId) => new CreatedAlert(alertId, rawAlert)
+ );
+
const originalAlerts = cloneDeep(alerts);
const originalAlertIds = new Set(Object.keys(originalAlerts));
@@ -364,6 +369,8 @@ export class TaskRunner<
WithoutReservedActionGroups
>({
alerts,
+ logger: this.logger,
+ canSetRecoveryContext: ruleType.doesSetRecoveryContext ?? false,
}),
shouldWriteAlerts: () => this.shouldLogAndScheduleActionsForAlerts(),
shouldStopExecution: () => this.cancelled,
@@ -424,17 +431,15 @@ export class TaskRunner<
alerts,
(alert: CreatedAlert) => alert.hasScheduledActions()
);
- const recoveredAlerts = pickBy(
- alerts,
- (alert: CreatedAlert, id) =>
- !alert.hasScheduledActions() && originalAlertIds.has(id)
- );
+
+ const recoveredAlerts = getRecoveredAlerts(alerts, originalAlertIds);
logActiveAndRecoveredAlerts({
logger: this.logger,
activeAlerts: alertsWithScheduledActions,
recoveredAlerts,
ruleLabel,
+ canSetRecoveryContext: ruleType.doesSetRecoveryContext ?? false,
});
trackAlertDurations({
@@ -1155,7 +1160,7 @@ async function scheduleActionsForRecoveredAlerts<
alert.unscheduleActions();
const triggeredActionsForRecoveredAlert = await executionHandler({
actionGroup: recoveryActionGroup.id,
- context: {},
+ context: alert.getContext(),
state: {},
alertId: id,
});
@@ -1176,6 +1181,7 @@ interface LogActiveAndRecoveredAlertsParams<
activeAlerts: Dictionary>;
recoveredAlerts: Dictionary>;
ruleLabel: string;
+ canSetRecoveryContext: boolean;
}
function logActiveAndRecoveredAlerts<
@@ -1191,7 +1197,7 @@ function logActiveAndRecoveredAlerts<
RecoveryActionGroupId
>
) {
- const { logger, activeAlerts, recoveredAlerts, ruleLabel } = params;
+ const { logger, activeAlerts, recoveredAlerts, ruleLabel, canSetRecoveryContext } = params;
const activeAlertIds = Object.keys(activeAlerts);
const recoveredAlertIds = Object.keys(recoveredAlerts);
@@ -1218,6 +1224,16 @@ function logActiveAndRecoveredAlerts<
recoveredAlertIds
)}`
);
+
+ if (canSetRecoveryContext) {
+ for (const id of recoveredAlertIds) {
+ if (!recoveredAlerts[id].hasContext()) {
+ logger.debug(
+ `rule ${ruleLabel} has no recovery context specified for recovered alert ${id}`
+ );
+ }
+ }
+ }
}
}
diff --git a/x-pack/plugins/alerting/server/types.ts b/x-pack/plugins/alerting/server/types.ts
index 9d6302774f889..50acb67a3de47 100644
--- a/x-pack/plugins/alerting/server/types.ts
+++ b/x-pack/plugins/alerting/server/types.ts
@@ -7,7 +7,7 @@
import type { IRouter, RequestHandlerContext, SavedObjectReference } from 'src/core/server';
import type { PublicMethodsOf } from '@kbn/utility-types';
-import { PublicAlert } from './alert';
+import { AlertFactoryDoneUtils, PublicAlert } from './alert';
import { RuleTypeRegistry as OrigruleTypeRegistry } from './rule_type_registry';
import { PluginSetupContract, PluginStartContract } from './plugin';
import { RulesClient } from './rules_client';
@@ -76,6 +76,7 @@ export interface AlertServices<
> extends Services {
alertFactory: {
create: (id: string) => PublicAlert;
+ done: () => AlertFactoryDoneUtils;
};
shouldWriteAlerts: () => boolean;
shouldStopExecution: () => boolean;
@@ -167,6 +168,7 @@ export interface RuleType<
minimumScheduleInterval?: string;
ruleTaskTimeout?: string;
cancelAlertsOnRuleTimeout?: boolean;
+ doesSetRecoveryContext?: boolean;
}
export type UntypedRuleType = RuleType<
AlertTypeParams,
diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/integration_settings/apm_server_not_installed.ts b/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/integration_settings/apm_server_not_installed.ts
new file mode 100644
index 0000000000000..354ffa5e42e18
--- /dev/null
+++ b/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/integration_settings/apm_server_not_installed.ts
@@ -0,0 +1,44 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+const integrationsPath = '/app/integrations/browse';
+
+describe('when navigating to the integrations browse page', () => {
+ beforeEach(() => {
+ cy.loginAsReadOnlyUser();
+ cy.visit(integrationsPath);
+ });
+
+ it('should display Elastic APM integration option', () => {
+ cy.get('[data-test-subj="integration-card:epr:apm:featured').should(
+ 'exist'
+ );
+ cy.contains('Elastic APM');
+ });
+
+ describe('when clicking on the Elastic APM option but Fleet is not installed', () => {
+ it('should display Elastic APM in Fleet tab', () => {
+ cy.get('[data-test-subj="integration-card:epr:apm:featured').click();
+ cy.get('[aria-selected="true"]').contains('Elastic APM in Fleet');
+ cy.contains('Elastic APM now available in Fleet!');
+ cy.contains('APM integration');
+ });
+
+ it('should display no APM server detected when checking the apm server status', () => {
+ cy.intercept('POST', '/api/home/hits_status', {
+ count: 0,
+ }).as('hitsStatus');
+
+ cy.get('[data-test-subj="integration-card:epr:apm:featured').click();
+ cy.contains('Check APM Server status').click();
+ cy.wait('@hitsStatus');
+ cy.contains(
+ 'No APM Server detected. Please make sure it is running and you have updated to 7.0 or higher.'
+ );
+ });
+ });
+});
diff --git a/x-pack/plugins/apm/ftr_e2e/ftr_config.ts b/x-pack/plugins/apm/ftr_e2e/ftr_config.ts
index 84d1c40930c70..ec2e8d05a97dd 100644
--- a/x-pack/plugins/apm/ftr_e2e/ftr_config.ts
+++ b/x-pack/plugins/apm/ftr_e2e/ftr_config.ts
@@ -8,9 +8,6 @@
import { FtrConfigProviderContext } from '@kbn/test';
import { CA_CERT_PATH } from '@kbn/dev-utils';
-// Used to spin up a docker container with package registry service that will be used by fleet
-export const packageRegistryPort = 1234;
-
async function config({ readConfigFile }: FtrConfigProviderContext) {
const kibanaCommonTestsConfig = await readConfigFile(
require.resolve('../../../../test/common/config.js')
@@ -41,11 +38,6 @@ async function config({ readConfigFile }: FtrConfigProviderContext) {
'--csp.warnLegacyBrowsers=false',
// define custom kibana server args here
`--elasticsearch.ssl.certificateAuthorities=${CA_CERT_PATH}`,
-
- // Fleet config
- `--xpack.fleet.packages.0.name=endpoint`,
- `--xpack.fleet.packages.0.version=latest`,
- `--xpack.fleet.registryUrl=http://localhost:${packageRegistryPort}`,
],
},
};
diff --git a/x-pack/plugins/apm/ftr_e2e/ftr_config_run.ts b/x-pack/plugins/apm/ftr_e2e/ftr_config_run.ts
index 8fc87b49a6607..768ad9b3f79f6 100644
--- a/x-pack/plugins/apm/ftr_e2e/ftr_config_run.ts
+++ b/x-pack/plugins/apm/ftr_e2e/ftr_config_run.ts
@@ -5,41 +5,17 @@
* 2.0.
*/
-import { defineDockerServersConfig, FtrConfigProviderContext } from '@kbn/test';
+import { FtrConfigProviderContext } from '@kbn/test';
import cypress from 'cypress';
-import path from 'path';
import { cypressStart } from './cypress_start';
-import { packageRegistryPort } from './ftr_config';
import { FtrProviderContext } from './ftr_provider_context';
-export const dockerImage =
- 'docker.elastic.co/package-registry/distribution@sha256:de952debe048d903fc73e8a4472bb48bb95028d440cba852f21b863d47020c61';
-
async function ftrConfigRun({ readConfigFile }: FtrConfigProviderContext) {
const kibanaConfig = await readConfigFile(require.resolve('./ftr_config.ts'));
- // mount the config file for the package registry
- const dockerArgs: string[] = [
- '-v',
- `${path.join(
- path.dirname(__filename),
- './apis/fixtures/package_registry_config.yml'
- )}:/package-registry/config.yml`,
- ];
-
return {
...kibanaConfig.getAll(),
testRunner,
- dockerServers: defineDockerServersConfig({
- registry: {
- enabled: true,
- image: dockerImage,
- portInContainer: 8080,
- port: packageRegistryPort,
- args: dockerArgs,
- waitForLogLine: 'package manifests loaded',
- },
- }),
};
}
diff --git a/x-pack/plugins/apm/public/components/app/error_group_details/detail_view/__snapshots__/index.test.tsx.snap b/x-pack/plugins/apm/public/components/app/error_group_details/detail_view/__snapshots__/index.test.tsx.snap
index de13bf910ce0f..5f300b45de80a 100644
--- a/x-pack/plugins/apm/public/components/app/error_group_details/detail_view/__snapshots__/index.test.tsx.snap
+++ b/x-pack/plugins/apm/public/components/app/error_group_details/detail_view/__snapshots__/index.test.tsx.snap
@@ -34,11 +34,7 @@ exports[`DetailView should render Discover button 1`] = `
}
kuery=""
>
-
- View 10 occurrences in Discover.
-
+ View 10 occurrences in Discover.
`;
diff --git a/x-pack/plugins/apm/public/components/app/error_group_details/detail_view/index.tsx b/x-pack/plugins/apm/public/components/app/error_group_details/detail_view/index.tsx
index 97118bf763d43..0a6b134275121 100644
--- a/x-pack/plugins/apm/public/components/app/error_group_details/detail_view/index.tsx
+++ b/x-pack/plugins/apm/public/components/app/error_group_details/detail_view/index.tsx
@@ -6,7 +6,6 @@
*/
import {
- EuiButtonEmpty,
EuiIcon,
EuiPanel,
EuiSpacer,
@@ -100,16 +99,14 @@ export function DetailView({ errorGroup, urlParams, kuery }: Props) {
-
- {i18n.translate(
- 'xpack.apm.errorGroupDetails.viewOccurrencesInDiscoverButtonLabel',
- {
- defaultMessage:
- 'View {occurrencesCount} {occurrencesCount, plural, one {occurrence} other {occurrences}} in Discover.',
- values: { occurrencesCount },
- }
- )}
-
+ {i18n.translate(
+ 'xpack.apm.errorGroupDetails.viewOccurrencesInDiscoverButtonLabel',
+ {
+ defaultMessage:
+ 'View {occurrencesCount} {occurrencesCount, plural, one {occurrence} other {occurrences}} in Discover.',
+ values: { occurrencesCount },
+ }
+ )}
diff --git a/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/span_flyout/index.tsx b/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/span_flyout/index.tsx
index 0f7a6a295601b..477098aa81d04 100644
--- a/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/span_flyout/index.tsx
+++ b/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/span_flyout/index.tsx
@@ -7,7 +7,6 @@
import {
EuiBadge,
- EuiButtonEmpty,
EuiCallOut,
EuiFlexGroup,
EuiFlexItem,
@@ -126,14 +125,12 @@ export function SpanFlyout({
-
- {i18n.translate(
- 'xpack.apm.transactionDetails.spanFlyout.viewSpanInDiscoverButtonLabel',
- {
- defaultMessage: 'View span in Discover',
- }
- )}
-
+ {i18n.translate(
+ 'xpack.apm.transactionDetails.spanFlyout.viewSpanInDiscoverButtonLabel',
+ {
+ defaultMessage: 'View span in Discover',
+ }
+ )}
diff --git a/x-pack/plugins/apm/public/components/shared/transaction_action_menu/sections.test.ts b/x-pack/plugins/apm/public/components/shared/transaction_action_menu/sections.test.ts
index bcb52f4721dd5..1d37dde6c6343 100644
--- a/x-pack/plugins/apm/public/components/shared/transaction_action_menu/sections.test.ts
+++ b/x-pack/plugins/apm/public/components/shared/transaction_action_menu/sections.test.ts
@@ -67,7 +67,7 @@ describe('Transaction action menu', () => {
actions: [
{
key: 'sampleDocument',
- label: 'View sample document',
+ label: 'View transaction in Discover',
href: 'some-basepath/app/discover#/?_g=(refreshInterval:(pause:!t,value:0),time:(from:now-24h,to:now))&_a=(index:apm_static_index_pattern_id,interval:auto,query:(language:kuery,query:\'processor.event:"transaction" AND transaction.id:"123" AND trace.id:"123"\'))',
condition: true,
},
@@ -134,7 +134,7 @@ describe('Transaction action menu', () => {
actions: [
{
key: 'sampleDocument',
- label: 'View sample document',
+ label: 'View transaction in Discover',
href: 'some-basepath/app/discover#/?_g=(refreshInterval:(pause:!t,value:0),time:(from:now-24h,to:now))&_a=(index:apm_static_index_pattern_id,interval:auto,query:(language:kuery,query:\'processor.event:"transaction" AND transaction.id:"123" AND trace.id:"123"\'))',
condition: true,
},
@@ -200,7 +200,7 @@ describe('Transaction action menu', () => {
actions: [
{
key: 'sampleDocument',
- label: 'View sample document',
+ label: 'View transaction in Discover',
href: 'some-basepath/app/discover#/?_g=(refreshInterval:(pause:!t,value:0),time:(from:now-24h,to:now))&_a=(index:apm_static_index_pattern_id,interval:auto,query:(language:kuery,query:\'processor.event:"transaction" AND transaction.id:"123" AND trace.id:"123"\'))',
condition: true,
},
diff --git a/x-pack/plugins/apm/public/components/shared/transaction_action_menu/sections.ts b/x-pack/plugins/apm/public/components/shared/transaction_action_menu/sections.ts
index daf5cb0833b61..20c10b6d9557c 100644
--- a/x-pack/plugins/apm/public/components/shared/transaction_action_menu/sections.ts
+++ b/x-pack/plugins/apm/public/components/shared/transaction_action_menu/sections.ts
@@ -191,7 +191,7 @@ export const getSections = ({
label: i18n.translate(
'xpack.apm.transactionActionMenu.viewSampleDocumentLinkLabel',
{
- defaultMessage: 'View sample document',
+ defaultMessage: 'View transaction in Discover',
}
),
href: getDiscoverHref({
diff --git a/x-pack/plugins/apm/public/components/shared/transaction_action_menu/transaction_action_menu.test.tsx b/x-pack/plugins/apm/public/components/shared/transaction_action_menu/transaction_action_menu.test.tsx
index 4d82bb69ee9a5..851472cfedabe 100644
--- a/x-pack/plugins/apm/public/components/shared/transaction_action_menu/transaction_action_menu.test.tsx
+++ b/x-pack/plugins/apm/public/components/shared/transaction_action_menu/transaction_action_menu.test.tsx
@@ -74,7 +74,7 @@ describe('TransactionActionMenu component', () => {
Transactions.transactionWithMinimalData
);
- expect(queryByText('View sample document')).not.toBeNull();
+ expect(queryByText('View transaction in Discover')).not.toBeNull();
});
it('always renders the trace logs link', async () => {
diff --git a/x-pack/plugins/apm/server/lib/helpers/transactions/get_is_using_transaction_events.ts b/x-pack/plugins/apm/server/lib/helpers/transactions/get_is_using_transaction_events.ts
index 75be545a7e427..12c47936374e1 100644
--- a/x-pack/plugins/apm/server/lib/helpers/transactions/get_is_using_transaction_events.ts
+++ b/x-pack/plugins/apm/server/lib/helpers/transactions/get_is_using_transaction_events.ts
@@ -6,11 +6,11 @@
*/
import { getSearchAggregatedTransactions } from '.';
-import { SearchAggregatedTransactionSetting } from '../../../../common/aggregated_transactions';
import { Setup } from '../setup_request';
import { kqlQuery, rangeQuery } from '../../../../../observability/server';
import { ProcessorEvent } from '../../../../common/processor_event';
import { APMEventClient } from '../create_es_client/create_apm_event_client';
+import { SearchAggregatedTransactionSetting } from '../../../../common/aggregated_transactions';
export async function getIsUsingTransactionEvents({
setup: { config, apmEventClient },
@@ -23,20 +23,6 @@ export async function getIsUsingTransactionEvents({
start?: number;
end?: number;
}): Promise {
- const searchAggregatedTransactions = config.searchAggregatedTransactions;
-
- if (
- searchAggregatedTransactions === SearchAggregatedTransactionSetting.never
- ) {
- return false;
- }
- if (
- !kuery &&
- searchAggregatedTransactions === SearchAggregatedTransactionSetting.always
- ) {
- return false;
- }
-
const searchesAggregatedTransactions = await getSearchAggregatedTransactions({
config,
start,
@@ -45,7 +31,11 @@ export async function getIsUsingTransactionEvents({
kuery,
});
- if (!searchesAggregatedTransactions) {
+ if (
+ !searchesAggregatedTransactions &&
+ config.searchAggregatedTransactions !==
+ SearchAggregatedTransactionSetting.never
+ ) {
// if no aggregrated transactions, check if any transactions at all
return await getHasTransactions({
start,
diff --git a/x-pack/plugins/apm/server/routes/alerts/test_utils/index.ts b/x-pack/plugins/apm/server/routes/alerts/test_utils/index.ts
index f881b4476fe22..a34b3cdb1334d 100644
--- a/x-pack/plugins/apm/server/routes/alerts/test_utils/index.ts
+++ b/x-pack/plugins/apm/server/routes/alerts/test_utils/index.ts
@@ -42,7 +42,7 @@ export const createRuleTypeMocks = () => {
savedObjectsClient: {
get: () => ({ attributes: { consumer: APM_SERVER_FEATURE_ID } }),
},
- alertFactory: { create: jest.fn(() => ({ scheduleActions })) },
+ alertFactory: { create: jest.fn(() => ({ scheduleActions })), done: {} },
alertWithLifecycle: jest.fn(),
logger: loggerMock,
shouldWriteAlerts: () => true,
diff --git a/x-pack/plugins/cases/common/ui/types.ts b/x-pack/plugins/cases/common/ui/types.ts
index f6bfb510cab81..95135f4a0e9a0 100644
--- a/x-pack/plugins/cases/common/ui/types.ts
+++ b/x-pack/plugins/cases/common/ui/types.ts
@@ -26,15 +26,6 @@ export interface CasesContextFeatures {
export type CasesFeatures = Partial;
-export interface CasesContextValue {
- owner: string[];
- appId: string;
- appTitle: string;
- userCanCrud: boolean;
- basePath: string;
- features: CasesContextFeatures;
-}
-
export interface CasesUiConfigType {
markdownPlugins: {
lens: boolean;
diff --git a/x-pack/plugins/cases/public/components/cases_context/cases_context_reducer.ts b/x-pack/plugins/cases/public/components/cases_context/cases_context_reducer.ts
new file mode 100644
index 0000000000000..f948072323214
--- /dev/null
+++ b/x-pack/plugins/cases/public/components/cases_context/cases_context_reducer.ts
@@ -0,0 +1,50 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import { CreateCaseFlyoutProps } from '../create/flyout';
+
+export const getInitialCasesContextState = (): CasesContextState => {
+ return {
+ createCaseFlyout: {
+ isFlyoutOpen: false,
+ },
+ };
+};
+
+export interface CasesContextState {
+ createCaseFlyout: {
+ isFlyoutOpen: boolean;
+ props?: CreateCaseFlyoutProps;
+ };
+}
+
+export enum CasesContextStoreActionsList {
+ OPEN_CREATE_CASE_FLYOUT,
+ CLOSE_CREATE_CASE_FLYOUT,
+}
+export type CasesContextStoreAction =
+ | {
+ type: CasesContextStoreActionsList.OPEN_CREATE_CASE_FLYOUT;
+ payload: CreateCaseFlyoutProps;
+ }
+ | { type: CasesContextStoreActionsList.CLOSE_CREATE_CASE_FLYOUT };
+
+export const casesContextReducer: React.Reducer = (
+ state: CasesContextState,
+ action: CasesContextStoreAction
+): CasesContextState => {
+ switch (action.type) {
+ case CasesContextStoreActionsList.OPEN_CREATE_CASE_FLYOUT: {
+ return { ...state, createCaseFlyout: { isFlyoutOpen: true, props: action.payload } };
+ }
+ case CasesContextStoreActionsList.CLOSE_CREATE_CASE_FLYOUT: {
+ return { ...state, createCaseFlyout: { isFlyoutOpen: false } };
+ }
+ default:
+ return state;
+ }
+};
diff --git a/x-pack/plugins/cases/public/components/cases_context/cases_global_components.test.tsx b/x-pack/plugins/cases/public/components/cases_context/cases_global_components.test.tsx
new file mode 100644
index 0000000000000..53c9129812d8b
--- /dev/null
+++ b/x-pack/plugins/cases/public/components/cases_context/cases_global_components.test.tsx
@@ -0,0 +1,48 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import React from 'react';
+import { AppMockRenderer, createAppMockRenderer } from '../../common/mock';
+import { getCreateCaseFlyoutLazyNoProvider } from '../../methods/get_create_case_flyout';
+import { CasesGlobalComponents } from './cases_global_components';
+
+jest.mock('../../methods/get_create_case_flyout');
+
+const getCreateCaseFlyoutLazyNoProviderMock = getCreateCaseFlyoutLazyNoProvider as jest.Mock;
+
+describe('Cases context UI', () => {
+ let appMock: AppMockRenderer;
+
+ beforeEach(() => {
+ appMock = createAppMockRenderer();
+ getCreateCaseFlyoutLazyNoProviderMock.mockClear();
+ });
+
+ describe('create case flyout', () => {
+ it('should render the create case flyout when isFlyoutOpen is true', async () => {
+ const state = {
+ createCaseFlyout: {
+ isFlyoutOpen: true,
+ props: {
+ attachments: [],
+ },
+ },
+ };
+ appMock.render();
+ expect(getCreateCaseFlyoutLazyNoProviderMock).toHaveBeenCalledWith({ attachments: [] });
+ });
+ it('should not render the create case flyout when isFlyoutOpen is false', async () => {
+ const state = {
+ createCaseFlyout: {
+ isFlyoutOpen: false,
+ },
+ };
+ appMock.render();
+ expect(getCreateCaseFlyoutLazyNoProviderMock).not.toHaveBeenCalled();
+ });
+ });
+});
diff --git a/x-pack/plugins/cases/public/components/cases_context/cases_global_components.tsx b/x-pack/plugins/cases/public/components/cases_context/cases_global_components.tsx
new file mode 100644
index 0000000000000..42ff36e201df4
--- /dev/null
+++ b/x-pack/plugins/cases/public/components/cases_context/cases_global_components.tsx
@@ -0,0 +1,21 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import React from 'react';
+import { getCreateCaseFlyoutLazyNoProvider } from '../../methods';
+import { CasesContextState } from './cases_context_reducer';
+
+export const CasesGlobalComponents = React.memo(({ state }: { state: CasesContextState }) => {
+ return (
+ <>
+ {state.createCaseFlyout.isFlyoutOpen && state.createCaseFlyout.props !== undefined
+ ? getCreateCaseFlyoutLazyNoProvider(state.createCaseFlyout.props)
+ : null}
+ >
+ );
+});
+CasesGlobalComponents.displayName = 'CasesContextUi';
diff --git a/x-pack/plugins/cases/public/components/cases_context/index.tsx b/x-pack/plugins/cases/public/components/cases_context/index.tsx
index aceefad97382a..1f1da31595a04 100644
--- a/x-pack/plugins/cases/public/components/cases_context/index.tsx
+++ b/x-pack/plugins/cases/public/components/cases_context/index.tsx
@@ -5,21 +5,38 @@
* 2.0.
*/
-import React, { useState, useEffect } from 'react';
+import React, { useState, useEffect, useReducer, Dispatch } from 'react';
import { merge } from 'lodash';
-import { CasesContextValue, CasesFeatures } from '../../../common/ui/types';
import { DEFAULT_FEATURES } from '../../../common/constants';
import { DEFAULT_BASE_PATH } from '../../common/navigation';
import { useApplication } from './use_application';
+import {
+ CasesContextStoreAction,
+ casesContextReducer,
+ getInitialCasesContextState,
+} from './cases_context_reducer';
+import { CasesContextFeatures, CasesFeatures } from '../../containers/types';
+import { CasesGlobalComponents } from './cases_global_components';
-export const CasesContext = React.createContext(undefined);
+export type CasesContextValueDispatch = Dispatch;
+
+export interface CasesContextValue {
+ owner: string[];
+ appId: string;
+ appTitle: string;
+ userCanCrud: boolean;
+ basePath: string;
+ features: CasesContextFeatures;
+ dispatch: CasesContextValueDispatch;
+}
-export interface CasesContextProps
- extends Omit {
+export interface CasesContextProps extends Pick {
basePath?: string;
features?: CasesFeatures;
}
+export const CasesContext = React.createContext(undefined);
+
export interface CasesContextStateValue extends Omit {
appId?: string;
appTitle?: string;
@@ -30,6 +47,7 @@ export const CasesProvider: React.FC<{ value: CasesContextProps }> = ({
value: { owner, userCanCrud, basePath = DEFAULT_BASE_PATH, features = {} },
}) => {
const { appId, appTitle } = useApplication();
+ const [state, dispatch] = useReducer(casesContextReducer, getInitialCasesContextState());
const [value, setValue] = useState(() => ({
owner,
userCanCrud,
@@ -39,6 +57,7 @@ export const CasesProvider: React.FC<{ value: CasesContextProps }> = ({
* of the DEFAULT_FEATURES object
*/
features: merge({}, DEFAULT_FEATURES, features),
+ dispatch,
}));
/**
@@ -58,7 +77,10 @@ export const CasesProvider: React.FC<{ value: CasesContextProps }> = ({
}, [appTitle, appId, userCanCrud]);
return isCasesContextValue(value) ? (
- {children}
+
+
+ {children}
+
) : null;
};
CasesProvider.displayName = 'CasesProvider';
@@ -66,3 +88,6 @@ CasesProvider.displayName = 'CasesProvider';
function isCasesContextValue(value: CasesContextStateValue): value is CasesContextValue {
return value.appId != null && value.appTitle != null && value.userCanCrud != null;
}
+
+// eslint-disable-next-line import/no-default-export
+export default CasesProvider;
diff --git a/x-pack/plugins/cases/public/components/create/flyout/create_case_flyout.tsx b/x-pack/plugins/cases/public/components/create/flyout/create_case_flyout.tsx
index 0097df1587a73..c40dfc98513d8 100644
--- a/x-pack/plugins/cases/public/components/create/flyout/create_case_flyout.tsx
+++ b/x-pack/plugins/cases/public/components/create/flyout/create_case_flyout.tsx
@@ -16,8 +16,8 @@ import { UsePostComment } from '../../../containers/use_post_comment';
export interface CreateCaseFlyoutProps {
afterCaseCreated?: (theCase: Case, postComment: UsePostComment['postComment']) => Promise;
- onClose: () => void;
- onSuccess: (theCase: Case) => Promise;
+ onClose?: () => void;
+ onSuccess?: (theCase: Case) => Promise;
attachments?: CreateCaseAttachment;
}
@@ -66,6 +66,8 @@ const FormWrapper = styled.div`
export const CreateCaseFlyout = React.memo(
({ afterCaseCreated, onClose, onSuccess, attachments }) => {
+ const handleCancel = onClose || function () {};
+ const handleOnSuccess = onSuccess || async function () {};
return (
<>
@@ -85,8 +87,8 @@ export const CreateCaseFlyout = React.memo(
diff --git a/x-pack/plugins/cases/public/components/create/flyout/use_cases_add_to_new_case_flyout.test.tsx b/x-pack/plugins/cases/public/components/create/flyout/use_cases_add_to_new_case_flyout.test.tsx
new file mode 100644
index 0000000000000..2c3750887cb1d
--- /dev/null
+++ b/x-pack/plugins/cases/public/components/create/flyout/use_cases_add_to_new_case_flyout.test.tsx
@@ -0,0 +1,78 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+/* eslint-disable react/display-name */
+
+import { renderHook } from '@testing-library/react-hooks';
+import React from 'react';
+import { CasesContext } from '../../cases_context';
+import { CasesContextStoreActionsList } from '../../cases_context/cases_context_reducer';
+import { useCasesAddToNewCaseFlyout } from './use_cases_add_to_new_case_flyout';
+
+describe('use cases add to new case flyout hook', () => {
+ const dispatch = jest.fn();
+ let wrapper: React.FC;
+ beforeEach(() => {
+ dispatch.mockReset();
+ wrapper = ({ children }) => {
+ return (
+
+ {children}
+
+ );
+ };
+ });
+
+ it('should throw if called outside of a cases context', () => {
+ const { result } = renderHook(() => {
+ useCasesAddToNewCaseFlyout({});
+ });
+ expect(result.error?.message).toContain(
+ 'useCasesContext must be used within a CasesProvider and have a defined value'
+ );
+ });
+
+ it('should dispatch the open action when invoked', () => {
+ const { result } = renderHook(
+ () => {
+ return useCasesAddToNewCaseFlyout({});
+ },
+ { wrapper }
+ );
+ result.current.open();
+ expect(dispatch).toHaveBeenCalledWith(
+ expect.objectContaining({
+ type: CasesContextStoreActionsList.OPEN_CREATE_CASE_FLYOUT,
+ })
+ );
+ });
+
+ it('should dispatch the close action when invoked', () => {
+ const { result } = renderHook(
+ () => {
+ return useCasesAddToNewCaseFlyout({});
+ },
+ { wrapper }
+ );
+ result.current.close();
+ expect(dispatch).toHaveBeenCalledWith(
+ expect.objectContaining({
+ type: CasesContextStoreActionsList.CLOSE_CREATE_CASE_FLYOUT,
+ })
+ );
+ });
+});
diff --git a/x-pack/plugins/cases/public/components/create/flyout/use_cases_add_to_new_case_flyout.tsx b/x-pack/plugins/cases/public/components/create/flyout/use_cases_add_to_new_case_flyout.tsx
new file mode 100644
index 0000000000000..e9514ee582d99
--- /dev/null
+++ b/x-pack/plugins/cases/public/components/create/flyout/use_cases_add_to_new_case_flyout.tsx
@@ -0,0 +1,48 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import { useCallback } from 'react';
+import { CasesContextStoreActionsList } from '../../cases_context/cases_context_reducer';
+import { useCasesContext } from '../../cases_context/use_cases_context';
+import { CreateCaseFlyoutProps } from './create_case_flyout';
+
+export const useCasesAddToNewCaseFlyout = (props: CreateCaseFlyoutProps) => {
+ const context = useCasesContext();
+
+ const closeFlyout = useCallback(() => {
+ context.dispatch({
+ type: CasesContextStoreActionsList.CLOSE_CREATE_CASE_FLYOUT,
+ });
+ }, [context]);
+
+ const openFlyout = useCallback(() => {
+ context.dispatch({
+ type: CasesContextStoreActionsList.OPEN_CREATE_CASE_FLYOUT,
+ payload: {
+ ...props,
+ onClose: () => {
+ closeFlyout();
+ if (props.onClose) {
+ return props.onClose();
+ }
+ },
+ afterCaseCreated: async (...args) => {
+ closeFlyout();
+ if (props.afterCaseCreated) {
+ return props.afterCaseCreated(...args);
+ }
+ },
+ },
+ });
+ }, [closeFlyout, context, props]);
+ return {
+ open: openFlyout,
+ close: closeFlyout,
+ };
+};
+
+export type UseCasesAddToNewCaseFlyout = typeof useCasesAddToNewCaseFlyout;
diff --git a/x-pack/plugins/cases/public/components/create/form.tsx b/x-pack/plugins/cases/public/components/create/form.tsx
index c4784f9a891b1..c4646ff7f7c02 100644
--- a/x-pack/plugins/cases/public/components/create/form.tsx
+++ b/x-pack/plugins/cases/public/components/create/form.tsx
@@ -57,6 +57,7 @@ const MySpinner = styled(EuiLoadingSpinner)`
`;
export type SupportedCreateCaseAttachment = CommentRequestAlertType | CommentRequestUserType;
export type CreateCaseAttachment = SupportedCreateCaseAttachment[];
+export type CaseAttachments = SupportedCreateCaseAttachment[];
export interface CreateCaseFormFieldsProps {
connectors: ActionConnector[];
diff --git a/x-pack/plugins/cases/public/index.tsx b/x-pack/plugins/cases/public/index.tsx
index 79eefba78a488..be23b9a46893b 100644
--- a/x-pack/plugins/cases/public/index.tsx
+++ b/x-pack/plugins/cases/public/index.tsx
@@ -19,6 +19,8 @@ export type { GetCreateCaseFlyoutProps } from './methods/get_create_case_flyout'
export type { GetAllCasesSelectorModalProps } from './methods/get_all_cases_selector_modal';
export type { GetRecentCasesProps } from './methods/get_recent_cases';
+export type { CaseAttachments } from './components/create/form';
+
export type { ICasesDeepLinkId } from './common/navigation';
export {
getCasesDeepLinks,
diff --git a/x-pack/plugins/cases/public/methods/get_cases_context.tsx b/x-pack/plugins/cases/public/methods/get_cases_context.tsx
new file mode 100644
index 0000000000000..a2314696773b0
--- /dev/null
+++ b/x-pack/plugins/cases/public/methods/get_cases_context.tsx
@@ -0,0 +1,34 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import { EuiLoadingSpinner } from '@elastic/eui';
+import React, { lazy, ReactNode, Suspense } from 'react';
+import { CasesContextProps } from '../components/cases_context';
+
+export type GetCasesContextProps = CasesContextProps;
+
+const CasesProviderLazy: React.FC<{ value: GetCasesContextProps }> = lazy(
+ () => import('../components/cases_context')
+);
+
+const CasesProviderLazyWrapper = ({
+ owner,
+ userCanCrud,
+ features,
+ children,
+}: GetCasesContextProps & { children: ReactNode }) => {
+ return (
+ }>
+ {children}
+
+ );
+};
+CasesProviderLazyWrapper.displayName = 'CasesProviderLazyWrapper';
+
+export const getCasesContextLazy = () => {
+ return CasesProviderLazyWrapper;
+};
diff --git a/x-pack/plugins/cases/public/methods/get_create_case_flyout.tsx b/x-pack/plugins/cases/public/methods/get_create_case_flyout.tsx
index 90fbeafaa9ed0..a0453c8fbb47e 100644
--- a/x-pack/plugins/cases/public/methods/get_create_case_flyout.tsx
+++ b/x-pack/plugins/cases/public/methods/get_create_case_flyout.tsx
@@ -12,7 +12,7 @@ import { CasesProvider, CasesContextProps } from '../components/cases_context';
export type GetCreateCaseFlyoutProps = CreateCaseFlyoutProps & CasesContextProps;
-const CreateCaseFlyoutLazy: React.FC = lazy(
+export const CreateCaseFlyoutLazy: React.FC = lazy(
() => import('../components/create/flyout')
);
export const getCreateCaseFlyoutLazy = ({
@@ -35,3 +35,9 @@ export const getCreateCaseFlyoutLazy = ({
);
+
+export const getCreateCaseFlyoutLazyNoProvider = (props: CreateCaseFlyoutProps) => (
+ }>
+
+
+);
diff --git a/x-pack/plugins/cases/public/mocks.ts b/x-pack/plugins/cases/public/mocks.ts
index 6f508d9b6da3b..7c89bb1ddc2f9 100644
--- a/x-pack/plugins/cases/public/mocks.ts
+++ b/x-pack/plugins/cases/public/mocks.ts
@@ -10,9 +10,14 @@ import { CasesUiStart } from './types';
const createStartContract = (): jest.Mocked => ({
canUseCases: jest.fn(),
getCases: jest.fn(),
+ getCasesContext: jest.fn(),
getAllCasesSelectorModal: jest.fn(),
getCreateCaseFlyout: jest.fn(),
getRecentCases: jest.fn(),
+ getCreateCaseFlyoutNoProvider: jest.fn(),
+ hooks: {
+ getUseCasesAddToNewCaseFlyout: jest.fn(),
+ },
});
export const casesPluginMock = {
diff --git a/x-pack/plugins/cases/public/plugin.ts b/x-pack/plugins/cases/public/plugin.ts
index 70882560edb77..acf51c8380f65 100644
--- a/x-pack/plugins/cases/public/plugin.ts
+++ b/x-pack/plugins/cases/public/plugin.ts
@@ -14,8 +14,11 @@ import {
getAllCasesSelectorModalLazy,
getCreateCaseFlyoutLazy,
canUseCases,
+ getCreateCaseFlyoutLazyNoProvider,
} from './methods';
import { CasesUiConfigType } from '../common/ui/types';
+import { getCasesContextLazy } from './methods/get_cases_context';
+import { useCasesAddToNewCaseFlyout } from './components/create/flyout/use_cases_add_to_new_case_flyout';
/**
* @public
@@ -35,9 +38,14 @@ export class CasesUiPlugin implements Plugin}
*/
getCases: (props: GetCasesProps) => ReactElement;
+ getCasesContext: () => (
+ props: GetCasesContextProps & { children: ReactNode }
+ ) => ReactElement;
/**
* Modal to select a case in a list of all owner cases
* @param props GetAllCasesSelectorModalProps
@@ -78,10 +84,16 @@ export interface CasesUiStart {
* @returns A react component that is a flyout for creating a case
*/
getCreateCaseFlyout: (props: GetCreateCaseFlyoutProps) => ReactElement;
+ getCreateCaseFlyoutNoProvider: (
+ props: CreateCaseFlyoutProps
+ ) => ReactElement;
/**
* Get the recent cases component
* @param props GetRecentCasesProps
* @returns A react component for showing recent cases
*/
getRecentCases: (props: GetRecentCasesProps) => ReactElement;
+ hooks: {
+ getUseCasesAddToNewCaseFlyout: UseCasesAddToNewCaseFlyout;
+ };
}
diff --git a/x-pack/plugins/dashboard_enhanced/common/drilldowns/dashboard_drilldown/types.ts b/x-pack/plugins/dashboard_enhanced/common/drilldowns/dashboard_drilldown/types.ts
index f2d0fcdb178ed..ee68681ccc8f5 100644
--- a/x-pack/plugins/dashboard_enhanced/common/drilldowns/dashboard_drilldown/types.ts
+++ b/x-pack/plugins/dashboard_enhanced/common/drilldowns/dashboard_drilldown/types.ts
@@ -10,4 +10,5 @@ export type DrilldownConfig = {
dashboardId?: string;
useCurrentFilters: boolean;
useCurrentDateRange: boolean;
+ openInNewTab: boolean;
};
diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/abstract_dashboard_drilldown/abstract_dashboard_drilldown.tsx b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/abstract_dashboard_drilldown/abstract_dashboard_drilldown.tsx
index 5ee62cd414d4c..1e58b13c00004 100644
--- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/abstract_dashboard_drilldown/abstract_dashboard_drilldown.tsx
+++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/abstract_dashboard_drilldown/abstract_dashboard_drilldown.tsx
@@ -69,6 +69,7 @@ export abstract class AbstractDashboardDrilldown