;
```
Returns:
diff --git a/docs/development/core/public/kibana-plugin-core-public.chromestart.md b/docs/development/core/public/kibana-plugin-core-public.chromestart.md
index 7d9d47df544d0..c179e089d7cfd 100644
--- a/docs/development/core/public/kibana-plugin-core-public.chromestart.md
+++ b/docs/development/core/public/kibana-plugin-core-public.chromestart.md
@@ -56,7 +56,7 @@ core.chrome.setHelpExtension(elem => {
| [getBrand$()](./kibana-plugin-core-public.chromestart.getbrand_.md) | Get an observable of the current brand information. |
| [getBreadcrumbs$()](./kibana-plugin-core-public.chromestart.getbreadcrumbs_.md) | Get an observable of the current list of breadcrumbs |
| [getHelpExtension$()](./kibana-plugin-core-public.chromestart.gethelpextension_.md) | Get an observable of the current custom help conttent |
-| [getIsCollapsed$()](./kibana-plugin-core-public.chromestart.getiscollapsed_.md) | Get an observable of the current collapsed state of the chrome. |
+| [getIsNavDrawerLocked$()](./kibana-plugin-core-public.chromestart.getisnavdrawerlocked_.md) | Get an observable of the current locked state of the nav drawer. |
| [getIsVisible$()](./kibana-plugin-core-public.chromestart.getisvisible_.md) | Get an observable of the current visibility state of the chrome. |
| [removeApplicationClass(className)](./kibana-plugin-core-public.chromestart.removeapplicationclass.md) | Remove a className added with addApplicationClass()
. If className is unknown it is ignored. |
| [setAppTitle(appTitle)](./kibana-plugin-core-public.chromestart.setapptitle.md) | Sets the current app's title |
@@ -65,6 +65,5 @@ core.chrome.setHelpExtension(elem => {
| [setBreadcrumbs(newBreadcrumbs)](./kibana-plugin-core-public.chromestart.setbreadcrumbs.md) | Override the current set of breadcrumbs |
| [setHelpExtension(helpExtension)](./kibana-plugin-core-public.chromestart.sethelpextension.md) | Override the current set of custom help content |
| [setHelpSupportUrl(url)](./kibana-plugin-core-public.chromestart.sethelpsupporturl.md) | Override the default support URL shown in the help menu |
-| [setIsCollapsed(isCollapsed)](./kibana-plugin-core-public.chromestart.setiscollapsed.md) | Set the collapsed state of the chrome navigation. |
| [setIsVisible(isVisible)](./kibana-plugin-core-public.chromestart.setisvisible.md) | Set the temporary visibility for the chrome. This does nothing if the chrome is hidden by default and should be used to hide the chrome for things like full-screen modes with an exit button. |
diff --git a/docs/development/core/public/kibana-plugin-core-public.chromestart.setiscollapsed.md b/docs/development/core/public/kibana-plugin-core-public.chromestart.setiscollapsed.md
deleted file mode 100644
index b1843ef326d96..0000000000000
--- a/docs/development/core/public/kibana-plugin-core-public.chromestart.setiscollapsed.md
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [ChromeStart](./kibana-plugin-core-public.chromestart.md) > [setIsCollapsed](./kibana-plugin-core-public.chromestart.setiscollapsed.md)
-
-## ChromeStart.setIsCollapsed() method
-
-Set the collapsed state of the chrome navigation.
-
-Signature:
-
-```typescript
-setIsCollapsed(isCollapsed: boolean): void;
-```
-
-## Parameters
-
-| Parameter | Type | Description |
-| --- | --- | --- |
-| isCollapsed | boolean
| |
-
-Returns:
-
-`void`
-
diff --git a/docs/development/core/server/kibana-plugin-core-server.routeconfig.validate.md b/docs/development/core/server/kibana-plugin-core-server.routeconfig.validate.md
index 204d8a786fede..3bbabc04f2500 100644
--- a/docs/development/core/server/kibana-plugin-core-server.routeconfig.validate.md
+++ b/docs/development/core/server/kibana-plugin-core-server.routeconfig.validate.md
@@ -14,7 +14,7 @@ validate: RouteValidatorFullConfig | false;
## Remarks
-You \*must\* specify a validation schema to be able to read: - url path segments - request query - request body To opt out of validating the request, specify `validate: false`. In this case request params, query, and body will be \*\*empty\*\* objects and have no access to raw values. In some cases you may want to use another validation library. To do this, you need to instruct the `@kbn/config-schema` library to output \*\*non-validated values\*\* with setting schema as `schema.object({}, { allowUnknowns: true })`;
+You \*must\* specify a validation schema to be able to read: - url path segments - request query - request body To opt out of validating the request, specify `validate: false`. In this case request params, query, and body will be \*\*empty\*\* objects and have no access to raw values. In some cases you may want to use another validation library. To do this, you need to instruct the `@kbn/config-schema` library to output \*\*non-validated values\*\* with setting schema as `schema.object({}, { unknowns: 'allow' })`;
## Example
@@ -49,7 +49,7 @@ router.get({
path: 'path/{id}',
validate: {
// handler has access to raw non-validated params in runtime
- params: schema.object({}, { allowUnknowns: true })
+ params: schema.object({}, { unknowns: 'allow' })
},
},
(context, req, res,) {
diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.esfilters.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.esfilters.md
index e03072f9a41c3..7fd65e5db35f3 100644
--- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.esfilters.md
+++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.esfilters.md
@@ -44,8 +44,8 @@ esFilters: {
getPhraseFilterField: (filter: import("../common").PhraseFilter) => string;
getPhraseFilterValue: (filter: import("../common").PhraseFilter) => string | number | boolean;
getDisplayValueFromFilter: typeof getDisplayValueFromFilter;
- compareFilters: (first: import("../common").Filter | import("../common").Filter[], second: import("../common").Filter | import("../common").Filter[], comparatorOptions?: import("./query/filter_manager/lib/compare_filters").FilterCompareOptions) => boolean;
- COMPARE_ALL_OPTIONS: import("./query/filter_manager/lib/compare_filters").FilterCompareOptions;
+ compareFilters: (first: import("../common").Filter | import("../common").Filter[], second: import("../common").Filter | import("../common").Filter[], comparatorOptions?: import("../common").FilterCompareOptions) => boolean;
+ COMPARE_ALL_OPTIONS: import("../common").FilterCompareOptions;
generateFilters: typeof generateFilters;
onlyDisabledFiltersChanged: (newFilters?: import("../common").Filter[] | undefined, oldFilters?: import("../common").Filter[] | undefined) => boolean;
changeTimeFilter: typeof changeTimeFilter;
diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.icancel.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.icancel.md
deleted file mode 100644
index 27141c68ae1a7..0000000000000
--- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.icancel.md
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [ICancel](./kibana-plugin-plugins-data-server.icancel.md)
-
-## ICancel type
-
-Signature:
-
-```typescript
-export declare type ICancel = (id: string) => Promise;
-```
diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchcancel.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchcancel.md
new file mode 100644
index 0000000000000..99c30515e8da6
--- /dev/null
+++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchcancel.md
@@ -0,0 +1,11 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [ISearchCancel](./kibana-plugin-plugins-data-server.isearchcancel.md)
+
+## ISearchCancel type
+
+Signature:
+
+```typescript
+export declare type ISearchCancel = (id: string) => Promise;
+```
diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.md
index 12d53f1a35ea0..e756eb9b72905 100644
--- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.md
+++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.md
@@ -67,9 +67,9 @@
| Type Alias | Description |
| --- | --- |
| [FieldFormatsGetConfigFn](./kibana-plugin-plugins-data-server.fieldformatsgetconfigfn.md) | |
-| [ICancel](./kibana-plugin-plugins-data-server.icancel.md) | |
| [IFieldFormatsRegistry](./kibana-plugin-plugins-data-server.ifieldformatsregistry.md) | |
| [ISearch](./kibana-plugin-plugins-data-server.isearch.md) | |
+| [ISearchCancel](./kibana-plugin-plugins-data-server.isearchcancel.md) | |
| [ParsedInterval](./kibana-plugin-plugins-data-server.parsedinterval.md) | |
| [TSearchStrategyProvider](./kibana-plugin-plugins-data-server.tsearchstrategyprovider.md) | Search strategy provider creates an instance of a search strategy with the request handler context bound to it. This way every search strategy can use whatever information they require from the request context. |
diff --git a/docs/settings/monitoring-settings.asciidoc b/docs/settings/monitoring-settings.asciidoc
index 8586d26e9a07a..6645f49029a51 100644
--- a/docs/settings/monitoring-settings.asciidoc
+++ b/docs/settings/monitoring-settings.asciidoc
@@ -20,9 +20,7 @@ which support the same values as <>.
To control how data is collected from your {es} nodes, you configure
{ref}/monitoring-settings.html[`xpack.monitoring.collection`
settings] in `elasticsearch.yml`. To control how monitoring data is collected
-from Logstash, you configure
-{logstash-ref}/monitoring-internal-collection.html#monitoring-settings[`xpack.monitoring` settings]
-in `logstash.yml`.
+from Logstash, configure monitoring settings in `logstash.yml`.
For more information, see
{ref}/monitor-elasticsearch-cluster.html[Monitor a cluster].
diff --git a/package.json b/package.json
index 261b3ad74d9b7..aa9c8f6c40160 100644
--- a/package.json
+++ b/package.json
@@ -77,7 +77,7 @@
"url": "https://github.com/elastic/kibana.git"
},
"resolutions": {
- "**/@types/node": "10.12.27",
+ "**/@types/node": ">=10.17.17 <10.20.0",
"**/@types/react": "^16.9.19",
"**/@types/react-router": "^5.1.3",
"**/@types/hapi": "^17.0.18",
@@ -119,7 +119,7 @@
"@elastic/apm-rum": "^4.6.0",
"@elastic/charts": "^17.1.1",
"@elastic/datemath": "5.0.2",
- "@elastic/ems-client": "7.6.0",
+ "@elastic/ems-client": "7.7.0",
"@elastic/eui": "20.0.2",
"@elastic/filesaver": "1.1.2",
"@elastic/good": "8.1.1-kibana2",
@@ -239,7 +239,7 @@
"react-resize-detector": "^4.2.0",
"react-router-dom": "^5.1.2",
"react-sizeme": "^2.3.6",
- "react-use": "^13.13.0",
+ "react-use": "^13.27.0",
"reactcss": "1.2.3",
"redux": "^4.0.5",
"redux-actions": "^2.6.5",
@@ -350,7 +350,7 @@
"@types/mocha": "^5.2.7",
"@types/moment-timezone": "^0.5.12",
"@types/mustache": "^0.8.31",
- "@types/node": "^10.12.27",
+ "@types/node": ">=10.17.17 <10.20.0",
"@types/node-forge": "^0.9.0",
"@types/normalize-path": "^3.0.0",
"@types/numeral": "^0.0.26",
diff --git a/packages/kbn-config-schema/README.md b/packages/kbn-config-schema/README.md
index 8719a2ae558ab..a4f2c1f6458cf 100644
--- a/packages/kbn-config-schema/README.md
+++ b/packages/kbn-config-schema/README.md
@@ -239,7 +239,7 @@ __Output type:__ `{ [K in keyof TProps]: TypeOf } as TObject`
__Options:__
* `defaultValue: TObject | Reference | (() => TObject)` - defines a default value, see [Default values](#default-values) section for more details.
* `validate: (value: TObject) => string | void` - defines a custom validator function, see [Custom validation](#custom-validation) section for more details.
- * `allowUnknowns: boolean` - indicates whether unknown object properties should be allowed. It's `false` by default.
+ * `unknowns: 'allow' | 'ignore' | 'forbid'` - indicates whether unknown object properties should be allowed, ignored, or forbidden. It's `forbid` by default.
__Usage:__
```typescript
@@ -250,7 +250,7 @@ const valueSchema = schema.object({
```
__Notes:__
-* Using `allowUnknowns` is discouraged and should only be used in exceptional circumstances. Consider using `schema.recordOf()` instead.
+* Using `unknowns: 'allow'` is discouraged and should only be used in exceptional circumstances. Consider using `schema.recordOf()` instead.
* Currently `schema.object()` always has a default value of `{}`, but this may change in the near future. Try to not rely on this behaviour and specify default value explicitly or use `schema.maybe()` if the value is optional.
* `schema.object()` also supports a json string as input if it can be safely parsed using `JSON.parse` and if the resulting value is a plain object.
diff --git a/packages/kbn-config-schema/src/internals/index.ts b/packages/kbn-config-schema/src/internals/index.ts
index 8f5d09e5b8b49..f84e14d2f741d 100644
--- a/packages/kbn-config-schema/src/internals/index.ts
+++ b/packages/kbn-config-schema/src/internals/index.ts
@@ -314,7 +314,8 @@ export const internals = Joi.extend([
for (const [entryKey, entryValue] of value) {
const { value: validatedEntryKey, error: keyError } = Joi.validate(
entryKey,
- params.key
+ params.key,
+ { presence: 'required' }
);
if (keyError) {
@@ -323,7 +324,8 @@ export const internals = Joi.extend([
const { value: validatedEntryValue, error: valueError } = Joi.validate(
entryValue,
- params.value
+ params.value,
+ { presence: 'required' }
);
if (valueError) {
@@ -374,7 +376,8 @@ export const internals = Joi.extend([
for (const [entryKey, entryValue] of Object.entries(value)) {
const { value: validatedEntryKey, error: keyError } = Joi.validate(
entryKey,
- params.key
+ params.key,
+ { presence: 'required' }
);
if (keyError) {
@@ -383,7 +386,8 @@ export const internals = Joi.extend([
const { value: validatedEntryValue, error: valueError } = Joi.validate(
entryValue,
- params.value
+ params.value,
+ { presence: 'required' }
);
if (valueError) {
diff --git a/packages/kbn-config-schema/src/types/map_of_type.test.ts b/packages/kbn-config-schema/src/types/map_of_type.test.ts
index b015f51bdc8ad..1c5a227ef0fac 100644
--- a/packages/kbn-config-schema/src/types/map_of_type.test.ts
+++ b/packages/kbn-config-schema/src/types/map_of_type.test.ts
@@ -159,6 +159,24 @@ test('object within mapOf', () => {
expect(type.validate(value)).toEqual(expected);
});
+test('enforces required object fields within mapOf', () => {
+ const type = schema.mapOf(
+ schema.string(),
+ schema.object({
+ bar: schema.object({
+ baz: schema.number(),
+ }),
+ })
+ );
+ const value = {
+ foo: {},
+ };
+
+ expect(() => type.validate(value)).toThrowErrorMatchingInlineSnapshot(
+ `"[foo.bar.baz]: expected value of type [number] but got [undefined]"`
+ );
+});
+
test('error preserves full path', () => {
const type = schema.object({
grandParentKey: schema.object({
diff --git a/packages/kbn-config-schema/src/types/map_type.ts b/packages/kbn-config-schema/src/types/map_type.ts
index 231c3726ae9d5..6da664bf95616 100644
--- a/packages/kbn-config-schema/src/types/map_type.ts
+++ b/packages/kbn-config-schema/src/types/map_type.ts
@@ -57,7 +57,10 @@ export class MapOfType extends Type> {
path.length,
0,
// If `key` validation failed, let's stress that to make error more obvious.
- type === 'map.key' ? `key("${entryKey}")` : entryKey.toString()
+ type === 'map.key' ? `key("${entryKey}")` : entryKey.toString(),
+ // Error could have happened deep inside value/key schema and error message should
+ // include full path.
+ ...(reason instanceof SchemaTypeError ? reason.path : [])
);
return reason instanceof SchemaTypesError
diff --git a/packages/kbn-config-schema/src/types/object_type.test.ts b/packages/kbn-config-schema/src/types/object_type.test.ts
index 29e341983fde9..47a0f5f7a5491 100644
--- a/packages/kbn-config-schema/src/types/object_type.test.ts
+++ b/packages/kbn-config-schema/src/types/object_type.test.ts
@@ -276,10 +276,10 @@ test('individual keys can validated', () => {
);
});
-test('allow unknown keys when allowUnknowns = true', () => {
+test('allow unknown keys when unknowns = `allow`', () => {
const type = schema.object(
{ foo: schema.string({ defaultValue: 'test' }) },
- { allowUnknowns: true }
+ { unknowns: 'allow' }
);
expect(
@@ -292,10 +292,10 @@ test('allow unknown keys when allowUnknowns = true', () => {
});
});
-test('allowUnknowns = true affects only own keys', () => {
+test('unknowns = `allow` affects only own keys', () => {
const type = schema.object(
{ foo: schema.object({ bar: schema.string() }) },
- { allowUnknowns: true }
+ { unknowns: 'allow' }
);
expect(() =>
@@ -308,10 +308,10 @@ test('allowUnknowns = true affects only own keys', () => {
).toThrowErrorMatchingInlineSnapshot(`"[foo.baz]: definition for this key is missing"`);
});
-test('does not allow unknown keys when allowUnknowns = false', () => {
+test('does not allow unknown keys when unknowns = `forbid`', () => {
const type = schema.object(
{ foo: schema.string({ defaultValue: 'test' }) },
- { allowUnknowns: false }
+ { unknowns: 'forbid' }
);
expect(() =>
type.validate({
@@ -319,3 +319,34 @@ test('does not allow unknown keys when allowUnknowns = false', () => {
})
).toThrowErrorMatchingInlineSnapshot(`"[bar]: definition for this key is missing"`);
});
+
+test('allow and remove unknown keys when unknowns = `ignore`', () => {
+ const type = schema.object(
+ { foo: schema.string({ defaultValue: 'test' }) },
+ { unknowns: 'ignore' }
+ );
+
+ expect(
+ type.validate({
+ bar: 'baz',
+ })
+ ).toEqual({
+ foo: 'test',
+ });
+});
+
+test('unknowns = `ignore` affects only own keys', () => {
+ const type = schema.object(
+ { foo: schema.object({ bar: schema.string() }) },
+ { unknowns: 'ignore' }
+ );
+
+ expect(() =>
+ type.validate({
+ foo: {
+ bar: 'bar',
+ baz: 'baz',
+ },
+ })
+ ).toThrowErrorMatchingInlineSnapshot(`"[foo.baz]: definition for this key is missing"`);
+});
diff --git a/packages/kbn-config-schema/src/types/object_type.ts b/packages/kbn-config-schema/src/types/object_type.ts
index f34acd0d2ce65..5a50e714a5931 100644
--- a/packages/kbn-config-schema/src/types/object_type.ts
+++ b/packages/kbn-config-schema/src/types/object_type.ts
@@ -30,17 +30,25 @@ export type TypeOf> = RT['type'];
// this might not have perfect _rendering_ output, but it will be typed.
export type ObjectResultType = Readonly<{ [K in keyof P]: TypeOf
}>;
+interface UnknownOptions {
+ /**
+ * Options for dealing with unknown keys:
+ * - allow: unknown keys will be permitted
+ * - ignore: unknown keys will not fail validation, but will be stripped out
+ * - forbid (default): unknown keys will fail validation
+ */
+ unknowns?: 'allow' | 'ignore' | 'forbid';
+}
+
export type ObjectTypeOptions
= TypeOptions<
{ [K in keyof P]: TypeOf
}
-> & {
- /** Should uknown keys not be defined in the schema be allowed. Defaults to `false` */
- allowUnknowns?: boolean;
-};
+> &
+ UnknownOptions;
export class ObjectType
extends Type> {
private props: Record;
- constructor(props: P, { allowUnknowns = false, ...typeOptions }: ObjectTypeOptions = {}) {
+ constructor(props: P, { unknowns = 'forbid', ...typeOptions }: ObjectTypeOptions
= {}) {
const schemaKeys = {} as Record;
for (const [key, value] of Object.entries(props)) {
schemaKeys[key] = value.getSchema();
@@ -50,7 +58,8 @@ export class ObjectType extends Type>
.keys(schemaKeys)
.default()
.optional()
- .unknown(Boolean(allowUnknowns));
+ .unknown(unknowns === 'allow')
+ .options({ stripUnknown: { objects: unknowns === 'ignore' } });
super(schema, typeOptions);
this.props = schemaKeys;
diff --git a/packages/kbn-config-schema/src/types/record_of_type.test.ts b/packages/kbn-config-schema/src/types/record_of_type.test.ts
index ef15e7b0f6ad6..aee7dde71c3e4 100644
--- a/packages/kbn-config-schema/src/types/record_of_type.test.ts
+++ b/packages/kbn-config-schema/src/types/record_of_type.test.ts
@@ -159,6 +159,24 @@ test('object within recordOf', () => {
expect(type.validate(value)).toEqual({ foo: { bar: 123 } });
});
+test('enforces required object fields within recordOf', () => {
+ const type = schema.recordOf(
+ schema.string(),
+ schema.object({
+ bar: schema.object({
+ baz: schema.number(),
+ }),
+ })
+ );
+ const value = {
+ foo: {},
+ };
+
+ expect(() => type.validate(value)).toThrowErrorMatchingInlineSnapshot(
+ `"[foo.bar.baz]: expected value of type [number] but got [undefined]"`
+ );
+});
+
test('error preserves full path', () => {
const type = schema.object({
grandParentKey: schema.object({
diff --git a/packages/kbn-config-schema/src/types/record_type.ts b/packages/kbn-config-schema/src/types/record_type.ts
index c6d4b4d71b4f1..ef9e70cbabc08 100644
--- a/packages/kbn-config-schema/src/types/record_type.ts
+++ b/packages/kbn-config-schema/src/types/record_type.ts
@@ -49,7 +49,10 @@ export class RecordOfType extends Type> {
path.length,
0,
// If `key` validation failed, let's stress that to make error more obvious.
- type === 'record.key' ? `key("${entryKey}")` : entryKey.toString()
+ type === 'record.key' ? `key("${entryKey}")` : entryKey.toString(),
+ // Error could have happened deep inside value/key schema and error message should
+ // include full path.
+ ...(reason instanceof SchemaTypeError ? reason.path : [])
);
return reason instanceof SchemaTypesError
diff --git a/packages/kbn-dev-utils/src/run/run.ts b/packages/kbn-dev-utils/src/run/run.ts
index e185f86cc3bf7..35477e988d837 100644
--- a/packages/kbn-dev-utils/src/run/run.ts
+++ b/packages/kbn-dev-utils/src/run/run.ts
@@ -17,6 +17,8 @@
* under the License.
*/
+import { inspect } from 'util';
+
// @ts-ignore @types are outdated and module is super simple
import exitHook from 'exit-hook';
@@ -62,7 +64,11 @@ export async function run(fn: RunFn, options: Options = {}) {
process.on('unhandledRejection', error => {
log.error('UNHANDLED PROMISE REJECTION');
- log.error(error);
+ log.error(
+ error instanceof Error
+ ? error
+ : new Error(`non-Error type rejection value: ${inspect(error)}`)
+ );
process.exit(1);
});
diff --git a/packages/kbn-pm/dist/index.js b/packages/kbn-pm/dist/index.js
index 338d489300526..9fab74ea47a87 100644
--- a/packages/kbn-pm/dist/index.js
+++ b/packages/kbn-pm/dist/index.js
@@ -94,7 +94,7 @@ __webpack_require__.r(__webpack_exports__);
/* harmony import */ var _cli__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "run", function() { return _cli__WEBPACK_IMPORTED_MODULE_0__["run"]; });
-/* harmony import */ var _production__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(704);
+/* harmony import */ var _production__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(705);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "buildProductionProjects", function() { return _production__WEBPACK_IMPORTED_MODULE_1__["buildProductionProjects"]; });
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "prepareExternalProjectDependencies", function() { return _production__WEBPACK_IMPORTED_MODULE_1__["prepareExternalProjectDependencies"]; });
@@ -39806,6 +39806,7 @@ exports.isFailError = fail_1.isFailError;
*/
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = __webpack_require__(36);
+const util_1 = __webpack_require__(29);
// @ts-ignore @types are outdated and module is super simple
const exit_hook_1 = tslib_1.__importDefault(__webpack_require__(348));
const tooling_log_1 = __webpack_require__(415);
@@ -39825,7 +39826,9 @@ async function run(fn, options = {}) {
});
process.on('unhandledRejection', error => {
log.error('UNHANDLED PROMISE REJECTION');
- log.error(error);
+ log.error(error instanceof Error
+ ? error
+ : new Error(`non-Error type rejection value: ${util_1.inspect(error)}`));
process.exit(1);
});
const handleErrorWithoutExit = (error) => {
@@ -57074,7 +57077,7 @@ async function getChangesForProjects(projects, kbn, log) {
log.verbose('getting changed files');
const {
stdout
- } = await execa__WEBPACK_IMPORTED_MODULE_3___default()('git', ['ls-files', '-dmt', '--', ...Array.from(projects.values()).map(p => p.path)], {
+ } = await execa__WEBPACK_IMPORTED_MODULE_3___default()('git', ['ls-files', '-dmt', '--', ...Array.from(projects.values()).filter(p => kbn.isPartOfRepo(p)).map(p => p.path)], {
cwd: kbn.getAbsolute()
});
const output = stdout.trim();
@@ -57117,6 +57120,11 @@ async function getChangesForProjects(projects, kbn, log) {
const changesByProject = new Map();
for (const project of sortedRelevantProjects) {
+ if (kbn.isOutsideRepo(project)) {
+ changesByProject.set(project, undefined);
+ continue;
+ }
+
const ownChanges = new Map();
const prefix = kbn.getRelative(project.path);
@@ -57141,6 +57149,10 @@ async function getChangesForProjects(projects, kbn, log) {
async function getLatestSha(project, kbn) {
+ if (kbn.isOutsideRepo(project)) {
+ return;
+ }
+
const {
stdout
} = await execa__WEBPACK_IMPORTED_MODULE_3___default()('git', ['log', '-n', '1', '--pretty=format:%H', '--', project.path], {
@@ -57200,7 +57212,7 @@ async function getChecksum(project, changes, yarnLock, kbn, log) {
log.verbose(`[${project.name}] local sha:`, sha);
}
- if (Array.from(changes.values()).includes('invalid')) {
+ if (!changes || Array.from(changes.values()).includes('invalid')) {
log.warning(`[${project.name}] unable to determine local changes, caching disabled`);
return;
}
@@ -79162,8 +79174,10 @@ __webpack_require__.r(__webpack_exports__);
/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var multimatch__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(700);
/* harmony import */ var multimatch__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(multimatch__WEBPACK_IMPORTED_MODULE_1__);
-/* harmony import */ var _projects__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(501);
-/* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(579);
+/* harmony import */ var is_path_inside__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(704);
+/* harmony import */ var is_path_inside__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(is_path_inside__WEBPACK_IMPORTED_MODULE_2__);
+/* harmony import */ var _projects__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(501);
+/* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(579);
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(source, true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(source).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
@@ -79192,6 +79206,7 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.definePrope
+
/**
* Helper class for dealing with a set of projects as children of
* the Kibana project. The kbn/pm is currently implemented to be
@@ -79206,7 +79221,7 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.definePrope
class Kibana {
static async loadFrom(rootPath) {
- return new Kibana((await Object(_projects__WEBPACK_IMPORTED_MODULE_2__["getProjects"])(rootPath, Object(_config__WEBPACK_IMPORTED_MODULE_3__["getProjectPaths"])({
+ return new Kibana((await Object(_projects__WEBPACK_IMPORTED_MODULE_3__["getProjects"])(rootPath, Object(_config__WEBPACK_IMPORTED_MODULE_4__["getProjectPaths"])({
rootPath
}))));
}
@@ -79265,7 +79280,7 @@ class Kibana {
getProjectAndDeps(name) {
const project = this.getProject(name);
- return Object(_projects__WEBPACK_IMPORTED_MODULE_2__["includeTransitiveProjects"])([project], this.allWorkspaceProjects);
+ return Object(_projects__WEBPACK_IMPORTED_MODULE_3__["includeTransitiveProjects"])([project], this.allWorkspaceProjects);
}
/** filter the projects to just those matching certain paths/include/exclude tags */
@@ -79274,7 +79289,7 @@ class Kibana {
const allProjects = this.getAllProjects();
const filteredProjects = new Map();
const pkgJsonPaths = Array.from(allProjects.values()).map(p => p.packageJsonLocation);
- const filteredPkgJsonGlobs = Object(_config__WEBPACK_IMPORTED_MODULE_3__["getProjectPaths"])(_objectSpread({}, options, {
+ const filteredPkgJsonGlobs = Object(_config__WEBPACK_IMPORTED_MODULE_4__["getProjectPaths"])(_objectSpread({}, options, {
rootPath: this.kibanaProject.path
})).map(g => path__WEBPACK_IMPORTED_MODULE_0___default.a.resolve(g, 'package.json'));
const matchingPkgJsonPaths = multimatch__WEBPACK_IMPORTED_MODULE_1___default()(pkgJsonPaths, filteredPkgJsonGlobs);
@@ -79292,6 +79307,14 @@ class Kibana {
return filteredProjects;
}
+ isPartOfRepo(project) {
+ return project.path === this.kibanaProject.path || is_path_inside__WEBPACK_IMPORTED_MODULE_2___default()(project.path, this.kibanaProject.path);
+ }
+
+ isOutsideRepo(project) {
+ return !this.isPartOfRepo(project);
+ }
+
}
/***/ }),
@@ -79385,14 +79408,42 @@ module.exports = arrify;
/***/ }),
/* 704 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+const path = __webpack_require__(16);
+
+module.exports = (childPath, parentPath) => {
+ childPath = path.resolve(childPath);
+ parentPath = path.resolve(parentPath);
+
+ if (process.platform === 'win32') {
+ childPath = childPath.toLowerCase();
+ parentPath = parentPath.toLowerCase();
+ }
+
+ if (childPath === parentPath) {
+ return false;
+ }
+
+ childPath += path.sep;
+ parentPath += path.sep;
+
+ return childPath.startsWith(parentPath);
+};
+
+
+/***/ }),
+/* 705 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.r(__webpack_exports__);
-/* harmony import */ var _build_production_projects__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(705);
+/* harmony import */ var _build_production_projects__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(706);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "buildProductionProjects", function() { return _build_production_projects__WEBPACK_IMPORTED_MODULE_0__["buildProductionProjects"]; });
-/* harmony import */ var _prepare_project_dependencies__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(928);
+/* harmony import */ var _prepare_project_dependencies__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(929);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "prepareExternalProjectDependencies", function() { return _prepare_project_dependencies__WEBPACK_IMPORTED_MODULE_1__["prepareExternalProjectDependencies"]; });
/*
@@ -79417,13 +79468,13 @@ __webpack_require__.r(__webpack_exports__);
/***/ }),
-/* 705 */
+/* 706 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "buildProductionProjects", function() { return buildProductionProjects; });
-/* harmony import */ var cpy__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(706);
+/* harmony import */ var cpy__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(707);
/* harmony import */ var cpy__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(cpy__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var del__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(587);
/* harmony import */ var del__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(del__WEBPACK_IMPORTED_MODULE_1__);
@@ -79565,7 +79616,7 @@ async function copyToBuild(project, kibanaRoot, buildRoot) {
}
/***/ }),
-/* 706 */
+/* 707 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -79573,13 +79624,13 @@ async function copyToBuild(project, kibanaRoot, buildRoot) {
const EventEmitter = __webpack_require__(379);
const path = __webpack_require__(16);
const os = __webpack_require__(11);
-const pAll = __webpack_require__(707);
-const arrify = __webpack_require__(709);
-const globby = __webpack_require__(710);
+const pAll = __webpack_require__(708);
+const arrify = __webpack_require__(710);
+const globby = __webpack_require__(711);
const isGlob = __webpack_require__(605);
-const cpFile = __webpack_require__(913);
-const junk = __webpack_require__(925);
-const CpyError = __webpack_require__(926);
+const cpFile = __webpack_require__(914);
+const junk = __webpack_require__(926);
+const CpyError = __webpack_require__(927);
const defaultOptions = {
ignoreJunk: true
@@ -79698,12 +79749,12 @@ module.exports = (source, destination, {
/***/ }),
-/* 707 */
+/* 708 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
-const pMap = __webpack_require__(708);
+const pMap = __webpack_require__(709);
module.exports = (iterable, options) => pMap(iterable, element => element(), options);
// TODO: Remove this for the next major release
@@ -79711,7 +79762,7 @@ module.exports.default = module.exports;
/***/ }),
-/* 708 */
+/* 709 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -79790,7 +79841,7 @@ module.exports.default = pMap;
/***/ }),
-/* 709 */
+/* 710 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -79820,17 +79871,17 @@ module.exports = arrify;
/***/ }),
-/* 710 */
+/* 711 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
const fs = __webpack_require__(23);
-const arrayUnion = __webpack_require__(711);
-const glob = __webpack_require__(713);
-const fastGlob = __webpack_require__(718);
-const dirGlob = __webpack_require__(906);
-const gitignore = __webpack_require__(909);
+const arrayUnion = __webpack_require__(712);
+const glob = __webpack_require__(714);
+const fastGlob = __webpack_require__(719);
+const dirGlob = __webpack_require__(907);
+const gitignore = __webpack_require__(910);
const DEFAULT_FILTER = () => false;
@@ -79975,12 +80026,12 @@ module.exports.gitignore = gitignore;
/***/ }),
-/* 711 */
+/* 712 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
-var arrayUniq = __webpack_require__(712);
+var arrayUniq = __webpack_require__(713);
module.exports = function () {
return arrayUniq([].concat.apply([], arguments));
@@ -79988,7 +80039,7 @@ module.exports = function () {
/***/ }),
-/* 712 */
+/* 713 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -80057,7 +80108,7 @@ if ('Set' in global) {
/***/ }),
-/* 713 */
+/* 714 */
/***/ (function(module, exports, __webpack_require__) {
// Approach:
@@ -80106,13 +80157,13 @@ var fs = __webpack_require__(23)
var rp = __webpack_require__(503)
var minimatch = __webpack_require__(505)
var Minimatch = minimatch.Minimatch
-var inherits = __webpack_require__(714)
+var inherits = __webpack_require__(715)
var EE = __webpack_require__(379).EventEmitter
var path = __webpack_require__(16)
var assert = __webpack_require__(30)
var isAbsolute = __webpack_require__(511)
-var globSync = __webpack_require__(716)
-var common = __webpack_require__(717)
+var globSync = __webpack_require__(717)
+var common = __webpack_require__(718)
var alphasort = common.alphasort
var alphasorti = common.alphasorti
var setopts = common.setopts
@@ -80853,7 +80904,7 @@ Glob.prototype._stat2 = function (f, abs, er, stat, cb) {
/***/ }),
-/* 714 */
+/* 715 */
/***/ (function(module, exports, __webpack_require__) {
try {
@@ -80863,12 +80914,12 @@ try {
module.exports = util.inherits;
} catch (e) {
/* istanbul ignore next */
- module.exports = __webpack_require__(715);
+ module.exports = __webpack_require__(716);
}
/***/ }),
-/* 715 */
+/* 716 */
/***/ (function(module, exports) {
if (typeof Object.create === 'function') {
@@ -80901,7 +80952,7 @@ if (typeof Object.create === 'function') {
/***/ }),
-/* 716 */
+/* 717 */
/***/ (function(module, exports, __webpack_require__) {
module.exports = globSync
@@ -80911,12 +80962,12 @@ var fs = __webpack_require__(23)
var rp = __webpack_require__(503)
var minimatch = __webpack_require__(505)
var Minimatch = minimatch.Minimatch
-var Glob = __webpack_require__(713).Glob
+var Glob = __webpack_require__(714).Glob
var util = __webpack_require__(29)
var path = __webpack_require__(16)
var assert = __webpack_require__(30)
var isAbsolute = __webpack_require__(511)
-var common = __webpack_require__(717)
+var common = __webpack_require__(718)
var alphasort = common.alphasort
var alphasorti = common.alphasorti
var setopts = common.setopts
@@ -81393,7 +81444,7 @@ GlobSync.prototype._makeAbs = function (f) {
/***/ }),
-/* 717 */
+/* 718 */
/***/ (function(module, exports, __webpack_require__) {
exports.alphasort = alphasort
@@ -81639,10 +81690,10 @@ function childrenIgnored (self, path) {
/***/ }),
-/* 718 */
+/* 719 */
/***/ (function(module, exports, __webpack_require__) {
-const pkg = __webpack_require__(719);
+const pkg = __webpack_require__(720);
module.exports = pkg.async;
module.exports.default = pkg.async;
@@ -81655,19 +81706,19 @@ module.exports.generateTasks = pkg.generateTasks;
/***/ }),
-/* 719 */
+/* 720 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
-var optionsManager = __webpack_require__(720);
-var taskManager = __webpack_require__(721);
-var reader_async_1 = __webpack_require__(877);
-var reader_stream_1 = __webpack_require__(901);
-var reader_sync_1 = __webpack_require__(902);
-var arrayUtils = __webpack_require__(904);
-var streamUtils = __webpack_require__(905);
+var optionsManager = __webpack_require__(721);
+var taskManager = __webpack_require__(722);
+var reader_async_1 = __webpack_require__(878);
+var reader_stream_1 = __webpack_require__(902);
+var reader_sync_1 = __webpack_require__(903);
+var arrayUtils = __webpack_require__(905);
+var streamUtils = __webpack_require__(906);
/**
* Synchronous API.
*/
@@ -81733,7 +81784,7 @@ function isString(source) {
/***/ }),
-/* 720 */
+/* 721 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -81771,13 +81822,13 @@ exports.prepare = prepare;
/***/ }),
-/* 721 */
+/* 722 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
-var patternUtils = __webpack_require__(722);
+var patternUtils = __webpack_require__(723);
/**
* Generate tasks based on parent directory of each pattern.
*/
@@ -81868,16 +81919,16 @@ exports.convertPatternGroupToTask = convertPatternGroupToTask;
/***/ }),
-/* 722 */
+/* 723 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var path = __webpack_require__(16);
-var globParent = __webpack_require__(723);
-var isGlob = __webpack_require__(726);
-var micromatch = __webpack_require__(727);
+var globParent = __webpack_require__(724);
+var isGlob = __webpack_require__(727);
+var micromatch = __webpack_require__(728);
var GLOBSTAR = '**';
/**
* Return true for static pattern.
@@ -82023,15 +82074,15 @@ exports.matchAny = matchAny;
/***/ }),
-/* 723 */
+/* 724 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
var path = __webpack_require__(16);
-var isglob = __webpack_require__(724);
-var pathDirname = __webpack_require__(725);
+var isglob = __webpack_require__(725);
+var pathDirname = __webpack_require__(726);
var isWin32 = __webpack_require__(11).platform() === 'win32';
module.exports = function globParent(str) {
@@ -82054,7 +82105,7 @@ module.exports = function globParent(str) {
/***/ }),
-/* 724 */
+/* 725 */
/***/ (function(module, exports, __webpack_require__) {
/*!
@@ -82085,7 +82136,7 @@ module.exports = function isGlob(str) {
/***/ }),
-/* 725 */
+/* 726 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -82235,7 +82286,7 @@ module.exports.win32 = win32;
/***/ }),
-/* 726 */
+/* 727 */
/***/ (function(module, exports, __webpack_require__) {
/*!
@@ -82287,7 +82338,7 @@ module.exports = function isGlob(str, options) {
/***/ }),
-/* 727 */
+/* 728 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -82298,18 +82349,18 @@ module.exports = function isGlob(str, options) {
*/
var util = __webpack_require__(29);
-var braces = __webpack_require__(728);
-var toRegex = __webpack_require__(830);
-var extend = __webpack_require__(838);
+var braces = __webpack_require__(729);
+var toRegex = __webpack_require__(831);
+var extend = __webpack_require__(839);
/**
* Local dependencies
*/
-var compilers = __webpack_require__(841);
-var parsers = __webpack_require__(873);
-var cache = __webpack_require__(874);
-var utils = __webpack_require__(875);
+var compilers = __webpack_require__(842);
+var parsers = __webpack_require__(874);
+var cache = __webpack_require__(875);
+var utils = __webpack_require__(876);
var MAX_LENGTH = 1024 * 64;
/**
@@ -83171,7 +83222,7 @@ module.exports = micromatch;
/***/ }),
-/* 728 */
+/* 729 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -83181,18 +83232,18 @@ module.exports = micromatch;
* Module dependencies
*/
-var toRegex = __webpack_require__(729);
-var unique = __webpack_require__(741);
-var extend = __webpack_require__(738);
+var toRegex = __webpack_require__(730);
+var unique = __webpack_require__(742);
+var extend = __webpack_require__(739);
/**
* Local dependencies
*/
-var compilers = __webpack_require__(742);
-var parsers = __webpack_require__(757);
-var Braces = __webpack_require__(767);
-var utils = __webpack_require__(743);
+var compilers = __webpack_require__(743);
+var parsers = __webpack_require__(758);
+var Braces = __webpack_require__(768);
+var utils = __webpack_require__(744);
var MAX_LENGTH = 1024 * 64;
var cache = {};
@@ -83496,15 +83547,15 @@ module.exports = braces;
/***/ }),
-/* 729 */
+/* 730 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
-var define = __webpack_require__(730);
-var extend = __webpack_require__(738);
-var not = __webpack_require__(740);
+var define = __webpack_require__(731);
+var extend = __webpack_require__(739);
+var not = __webpack_require__(741);
var MAX_LENGTH = 1024 * 64;
/**
@@ -83651,7 +83702,7 @@ module.exports.makeRe = makeRe;
/***/ }),
-/* 730 */
+/* 731 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -83664,7 +83715,7 @@ module.exports.makeRe = makeRe;
-var isDescriptor = __webpack_require__(731);
+var isDescriptor = __webpack_require__(732);
module.exports = function defineProperty(obj, prop, val) {
if (typeof obj !== 'object' && typeof obj !== 'function') {
@@ -83689,7 +83740,7 @@ module.exports = function defineProperty(obj, prop, val) {
/***/ }),
-/* 731 */
+/* 732 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -83702,9 +83753,9 @@ module.exports = function defineProperty(obj, prop, val) {
-var typeOf = __webpack_require__(732);
-var isAccessor = __webpack_require__(733);
-var isData = __webpack_require__(736);
+var typeOf = __webpack_require__(733);
+var isAccessor = __webpack_require__(734);
+var isData = __webpack_require__(737);
module.exports = function isDescriptor(obj, key) {
if (typeOf(obj) !== 'object') {
@@ -83718,7 +83769,7 @@ module.exports = function isDescriptor(obj, key) {
/***/ }),
-/* 732 */
+/* 733 */
/***/ (function(module, exports) {
var toString = Object.prototype.toString;
@@ -83871,7 +83922,7 @@ function isBuffer(val) {
/***/ }),
-/* 733 */
+/* 734 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -83884,7 +83935,7 @@ function isBuffer(val) {
-var typeOf = __webpack_require__(734);
+var typeOf = __webpack_require__(735);
// accessor descriptor properties
var accessor = {
@@ -83947,10 +83998,10 @@ module.exports = isAccessorDescriptor;
/***/ }),
-/* 734 */
+/* 735 */
/***/ (function(module, exports, __webpack_require__) {
-var isBuffer = __webpack_require__(735);
+var isBuffer = __webpack_require__(736);
var toString = Object.prototype.toString;
/**
@@ -84069,7 +84120,7 @@ module.exports = function kindOf(val) {
/***/ }),
-/* 735 */
+/* 736 */
/***/ (function(module, exports) {
/*!
@@ -84096,7 +84147,7 @@ function isSlowBuffer (obj) {
/***/ }),
-/* 736 */
+/* 737 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -84109,7 +84160,7 @@ function isSlowBuffer (obj) {
-var typeOf = __webpack_require__(737);
+var typeOf = __webpack_require__(738);
// data descriptor properties
var data = {
@@ -84158,10 +84209,10 @@ module.exports = isDataDescriptor;
/***/ }),
-/* 737 */
+/* 738 */
/***/ (function(module, exports, __webpack_require__) {
-var isBuffer = __webpack_require__(735);
+var isBuffer = __webpack_require__(736);
var toString = Object.prototype.toString;
/**
@@ -84280,13 +84331,13 @@ module.exports = function kindOf(val) {
/***/ }),
-/* 738 */
+/* 739 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
-var isObject = __webpack_require__(739);
+var isObject = __webpack_require__(740);
module.exports = function extend(o/*, objects*/) {
if (!isObject(o)) { o = {}; }
@@ -84320,7 +84371,7 @@ function hasOwn(obj, key) {
/***/ }),
-/* 739 */
+/* 740 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -84340,13 +84391,13 @@ module.exports = function isExtendable(val) {
/***/ }),
-/* 740 */
+/* 741 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
-var extend = __webpack_require__(738);
+var extend = __webpack_require__(739);
/**
* The main export is a function that takes a `pattern` string and an `options` object.
@@ -84413,7 +84464,7 @@ module.exports = toRegex;
/***/ }),
-/* 741 */
+/* 742 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -84463,13 +84514,13 @@ module.exports.immutable = function uniqueImmutable(arr) {
/***/ }),
-/* 742 */
+/* 743 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
-var utils = __webpack_require__(743);
+var utils = __webpack_require__(744);
module.exports = function(braces, options) {
braces.compiler
@@ -84752,25 +84803,25 @@ function hasQueue(node) {
/***/ }),
-/* 743 */
+/* 744 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
-var splitString = __webpack_require__(744);
+var splitString = __webpack_require__(745);
var utils = module.exports;
/**
* Module dependencies
*/
-utils.extend = __webpack_require__(738);
-utils.flatten = __webpack_require__(750);
-utils.isObject = __webpack_require__(748);
-utils.fillRange = __webpack_require__(751);
-utils.repeat = __webpack_require__(756);
-utils.unique = __webpack_require__(741);
+utils.extend = __webpack_require__(739);
+utils.flatten = __webpack_require__(751);
+utils.isObject = __webpack_require__(749);
+utils.fillRange = __webpack_require__(752);
+utils.repeat = __webpack_require__(757);
+utils.unique = __webpack_require__(742);
utils.define = function(obj, key, val) {
Object.defineProperty(obj, key, {
@@ -85102,7 +85153,7 @@ utils.escapeRegex = function(str) {
/***/ }),
-/* 744 */
+/* 745 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -85115,7 +85166,7 @@ utils.escapeRegex = function(str) {
-var extend = __webpack_require__(745);
+var extend = __webpack_require__(746);
module.exports = function(str, options, fn) {
if (typeof str !== 'string') {
@@ -85280,14 +85331,14 @@ function keepEscaping(opts, str, idx) {
/***/ }),
-/* 745 */
+/* 746 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
-var isExtendable = __webpack_require__(746);
-var assignSymbols = __webpack_require__(749);
+var isExtendable = __webpack_require__(747);
+var assignSymbols = __webpack_require__(750);
module.exports = Object.assign || function(obj/*, objects*/) {
if (obj === null || typeof obj === 'undefined') {
@@ -85347,7 +85398,7 @@ function isEnum(obj, key) {
/***/ }),
-/* 746 */
+/* 747 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -85360,7 +85411,7 @@ function isEnum(obj, key) {
-var isPlainObject = __webpack_require__(747);
+var isPlainObject = __webpack_require__(748);
module.exports = function isExtendable(val) {
return isPlainObject(val) || typeof val === 'function' || Array.isArray(val);
@@ -85368,7 +85419,7 @@ module.exports = function isExtendable(val) {
/***/ }),
-/* 747 */
+/* 748 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -85381,7 +85432,7 @@ module.exports = function isExtendable(val) {
-var isObject = __webpack_require__(748);
+var isObject = __webpack_require__(749);
function isObjectObject(o) {
return isObject(o) === true
@@ -85412,7 +85463,7 @@ module.exports = function isPlainObject(o) {
/***/ }),
-/* 748 */
+/* 749 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -85431,7 +85482,7 @@ module.exports = function isObject(val) {
/***/ }),
-/* 749 */
+/* 750 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -85478,7 +85529,7 @@ module.exports = function(receiver, objects) {
/***/ }),
-/* 750 */
+/* 751 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -85507,7 +85558,7 @@ function flat(arr, res) {
/***/ }),
-/* 751 */
+/* 752 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -85521,10 +85572,10 @@ function flat(arr, res) {
var util = __webpack_require__(29);
-var isNumber = __webpack_require__(752);
-var extend = __webpack_require__(738);
-var repeat = __webpack_require__(754);
-var toRegex = __webpack_require__(755);
+var isNumber = __webpack_require__(753);
+var extend = __webpack_require__(739);
+var repeat = __webpack_require__(755);
+var toRegex = __webpack_require__(756);
/**
* Return a range of numbers or letters.
@@ -85722,7 +85773,7 @@ module.exports = fillRange;
/***/ }),
-/* 752 */
+/* 753 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -85735,7 +85786,7 @@ module.exports = fillRange;
-var typeOf = __webpack_require__(753);
+var typeOf = __webpack_require__(754);
module.exports = function isNumber(num) {
var type = typeOf(num);
@@ -85751,10 +85802,10 @@ module.exports = function isNumber(num) {
/***/ }),
-/* 753 */
+/* 754 */
/***/ (function(module, exports, __webpack_require__) {
-var isBuffer = __webpack_require__(735);
+var isBuffer = __webpack_require__(736);
var toString = Object.prototype.toString;
/**
@@ -85873,7 +85924,7 @@ module.exports = function kindOf(val) {
/***/ }),
-/* 754 */
+/* 755 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -85950,7 +86001,7 @@ function repeat(str, num) {
/***/ }),
-/* 755 */
+/* 756 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -85963,8 +86014,8 @@ function repeat(str, num) {
-var repeat = __webpack_require__(754);
-var isNumber = __webpack_require__(752);
+var repeat = __webpack_require__(755);
+var isNumber = __webpack_require__(753);
var cache = {};
function toRegexRange(min, max, options) {
@@ -86251,7 +86302,7 @@ module.exports = toRegexRange;
/***/ }),
-/* 756 */
+/* 757 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -86276,14 +86327,14 @@ module.exports = function repeat(ele, num) {
/***/ }),
-/* 757 */
+/* 758 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
-var Node = __webpack_require__(758);
-var utils = __webpack_require__(743);
+var Node = __webpack_require__(759);
+var utils = __webpack_require__(744);
/**
* Braces parsers
@@ -86643,15 +86694,15 @@ function concatNodes(pos, node, parent, options) {
/***/ }),
-/* 758 */
+/* 759 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
-var isObject = __webpack_require__(748);
-var define = __webpack_require__(759);
-var utils = __webpack_require__(766);
+var isObject = __webpack_require__(749);
+var define = __webpack_require__(760);
+var utils = __webpack_require__(767);
var ownNames;
/**
@@ -87142,7 +87193,7 @@ exports = module.exports = Node;
/***/ }),
-/* 759 */
+/* 760 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -87155,7 +87206,7 @@ exports = module.exports = Node;
-var isDescriptor = __webpack_require__(760);
+var isDescriptor = __webpack_require__(761);
module.exports = function defineProperty(obj, prop, val) {
if (typeof obj !== 'object' && typeof obj !== 'function') {
@@ -87180,7 +87231,7 @@ module.exports = function defineProperty(obj, prop, val) {
/***/ }),
-/* 760 */
+/* 761 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -87193,9 +87244,9 @@ module.exports = function defineProperty(obj, prop, val) {
-var typeOf = __webpack_require__(761);
-var isAccessor = __webpack_require__(762);
-var isData = __webpack_require__(764);
+var typeOf = __webpack_require__(762);
+var isAccessor = __webpack_require__(763);
+var isData = __webpack_require__(765);
module.exports = function isDescriptor(obj, key) {
if (typeOf(obj) !== 'object') {
@@ -87209,7 +87260,7 @@ module.exports = function isDescriptor(obj, key) {
/***/ }),
-/* 761 */
+/* 762 */
/***/ (function(module, exports) {
var toString = Object.prototype.toString;
@@ -87344,7 +87395,7 @@ function isBuffer(val) {
/***/ }),
-/* 762 */
+/* 763 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -87357,7 +87408,7 @@ function isBuffer(val) {
-var typeOf = __webpack_require__(763);
+var typeOf = __webpack_require__(764);
// accessor descriptor properties
var accessor = {
@@ -87420,7 +87471,7 @@ module.exports = isAccessorDescriptor;
/***/ }),
-/* 763 */
+/* 764 */
/***/ (function(module, exports) {
var toString = Object.prototype.toString;
@@ -87555,7 +87606,7 @@ function isBuffer(val) {
/***/ }),
-/* 764 */
+/* 765 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -87568,7 +87619,7 @@ function isBuffer(val) {
-var typeOf = __webpack_require__(765);
+var typeOf = __webpack_require__(766);
module.exports = function isDataDescriptor(obj, prop) {
// data descriptor properties
@@ -87611,7 +87662,7 @@ module.exports = function isDataDescriptor(obj, prop) {
/***/ }),
-/* 765 */
+/* 766 */
/***/ (function(module, exports) {
var toString = Object.prototype.toString;
@@ -87746,13 +87797,13 @@ function isBuffer(val) {
/***/ }),
-/* 766 */
+/* 767 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
-var typeOf = __webpack_require__(753);
+var typeOf = __webpack_require__(754);
var utils = module.exports;
/**
@@ -88772,17 +88823,17 @@ function assert(val, message) {
/***/ }),
-/* 767 */
+/* 768 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
-var extend = __webpack_require__(738);
-var Snapdragon = __webpack_require__(768);
-var compilers = __webpack_require__(742);
-var parsers = __webpack_require__(757);
-var utils = __webpack_require__(743);
+var extend = __webpack_require__(739);
+var Snapdragon = __webpack_require__(769);
+var compilers = __webpack_require__(743);
+var parsers = __webpack_require__(758);
+var utils = __webpack_require__(744);
/**
* Customize Snapdragon parser and renderer
@@ -88883,17 +88934,17 @@ module.exports = Braces;
/***/ }),
-/* 768 */
+/* 769 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
-var Base = __webpack_require__(769);
-var define = __webpack_require__(730);
-var Compiler = __webpack_require__(798);
-var Parser = __webpack_require__(827);
-var utils = __webpack_require__(807);
+var Base = __webpack_require__(770);
+var define = __webpack_require__(731);
+var Compiler = __webpack_require__(799);
+var Parser = __webpack_require__(828);
+var utils = __webpack_require__(808);
var regexCache = {};
var cache = {};
@@ -89064,20 +89115,20 @@ module.exports.Parser = Parser;
/***/ }),
-/* 769 */
+/* 770 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
var util = __webpack_require__(29);
-var define = __webpack_require__(770);
-var CacheBase = __webpack_require__(771);
-var Emitter = __webpack_require__(772);
-var isObject = __webpack_require__(748);
-var merge = __webpack_require__(789);
-var pascal = __webpack_require__(792);
-var cu = __webpack_require__(793);
+var define = __webpack_require__(771);
+var CacheBase = __webpack_require__(772);
+var Emitter = __webpack_require__(773);
+var isObject = __webpack_require__(749);
+var merge = __webpack_require__(790);
+var pascal = __webpack_require__(793);
+var cu = __webpack_require__(794);
/**
* Optionally define a custom `cache` namespace to use.
@@ -89506,7 +89557,7 @@ module.exports.namespace = namespace;
/***/ }),
-/* 770 */
+/* 771 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -89519,7 +89570,7 @@ module.exports.namespace = namespace;
-var isDescriptor = __webpack_require__(760);
+var isDescriptor = __webpack_require__(761);
module.exports = function defineProperty(obj, prop, val) {
if (typeof obj !== 'object' && typeof obj !== 'function') {
@@ -89544,21 +89595,21 @@ module.exports = function defineProperty(obj, prop, val) {
/***/ }),
-/* 771 */
+/* 772 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
-var isObject = __webpack_require__(748);
-var Emitter = __webpack_require__(772);
-var visit = __webpack_require__(773);
-var toPath = __webpack_require__(776);
-var union = __webpack_require__(777);
-var del = __webpack_require__(781);
-var get = __webpack_require__(779);
-var has = __webpack_require__(786);
-var set = __webpack_require__(780);
+var isObject = __webpack_require__(749);
+var Emitter = __webpack_require__(773);
+var visit = __webpack_require__(774);
+var toPath = __webpack_require__(777);
+var union = __webpack_require__(778);
+var del = __webpack_require__(782);
+var get = __webpack_require__(780);
+var has = __webpack_require__(787);
+var set = __webpack_require__(781);
/**
* Create a `Cache` constructor that when instantiated will
@@ -89812,7 +89863,7 @@ module.exports.namespace = namespace;
/***/ }),
-/* 772 */
+/* 773 */
/***/ (function(module, exports, __webpack_require__) {
@@ -89981,7 +90032,7 @@ Emitter.prototype.hasListeners = function(event){
/***/ }),
-/* 773 */
+/* 774 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -89994,8 +90045,8 @@ Emitter.prototype.hasListeners = function(event){
-var visit = __webpack_require__(774);
-var mapVisit = __webpack_require__(775);
+var visit = __webpack_require__(775);
+var mapVisit = __webpack_require__(776);
module.exports = function(collection, method, val) {
var result;
@@ -90018,7 +90069,7 @@ module.exports = function(collection, method, val) {
/***/ }),
-/* 774 */
+/* 775 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -90031,7 +90082,7 @@ module.exports = function(collection, method, val) {
-var isObject = __webpack_require__(748);
+var isObject = __webpack_require__(749);
module.exports = function visit(thisArg, method, target, val) {
if (!isObject(thisArg) && typeof thisArg !== 'function') {
@@ -90058,14 +90109,14 @@ module.exports = function visit(thisArg, method, target, val) {
/***/ }),
-/* 775 */
+/* 776 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
var util = __webpack_require__(29);
-var visit = __webpack_require__(774);
+var visit = __webpack_require__(775);
/**
* Map `visit` over an array of objects.
@@ -90102,7 +90153,7 @@ function isObject(val) {
/***/ }),
-/* 776 */
+/* 777 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -90115,7 +90166,7 @@ function isObject(val) {
-var typeOf = __webpack_require__(753);
+var typeOf = __webpack_require__(754);
module.exports = function toPath(args) {
if (typeOf(args) !== 'arguments') {
@@ -90142,16 +90193,16 @@ function filter(arr) {
/***/ }),
-/* 777 */
+/* 778 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
-var isObject = __webpack_require__(739);
-var union = __webpack_require__(778);
-var get = __webpack_require__(779);
-var set = __webpack_require__(780);
+var isObject = __webpack_require__(740);
+var union = __webpack_require__(779);
+var get = __webpack_require__(780);
+var set = __webpack_require__(781);
module.exports = function unionValue(obj, prop, value) {
if (!isObject(obj)) {
@@ -90179,7 +90230,7 @@ function arrayify(val) {
/***/ }),
-/* 778 */
+/* 779 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -90215,7 +90266,7 @@ module.exports = function union(init) {
/***/ }),
-/* 779 */
+/* 780 */
/***/ (function(module, exports) {
/*!
@@ -90271,7 +90322,7 @@ function toString(val) {
/***/ }),
-/* 780 */
+/* 781 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -90284,10 +90335,10 @@ function toString(val) {
-var split = __webpack_require__(744);
-var extend = __webpack_require__(738);
-var isPlainObject = __webpack_require__(747);
-var isObject = __webpack_require__(739);
+var split = __webpack_require__(745);
+var extend = __webpack_require__(739);
+var isPlainObject = __webpack_require__(748);
+var isObject = __webpack_require__(740);
module.exports = function(obj, prop, val) {
if (!isObject(obj)) {
@@ -90333,7 +90384,7 @@ function isValidKey(key) {
/***/ }),
-/* 781 */
+/* 782 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -90346,8 +90397,8 @@ function isValidKey(key) {
-var isObject = __webpack_require__(748);
-var has = __webpack_require__(782);
+var isObject = __webpack_require__(749);
+var has = __webpack_require__(783);
module.exports = function unset(obj, prop) {
if (!isObject(obj)) {
@@ -90372,7 +90423,7 @@ module.exports = function unset(obj, prop) {
/***/ }),
-/* 782 */
+/* 783 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -90385,9 +90436,9 @@ module.exports = function unset(obj, prop) {
-var isObject = __webpack_require__(783);
-var hasValues = __webpack_require__(785);
-var get = __webpack_require__(779);
+var isObject = __webpack_require__(784);
+var hasValues = __webpack_require__(786);
+var get = __webpack_require__(780);
module.exports = function(obj, prop, noZero) {
if (isObject(obj)) {
@@ -90398,7 +90449,7 @@ module.exports = function(obj, prop, noZero) {
/***/ }),
-/* 783 */
+/* 784 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -90411,7 +90462,7 @@ module.exports = function(obj, prop, noZero) {
-var isArray = __webpack_require__(784);
+var isArray = __webpack_require__(785);
module.exports = function isObject(val) {
return val != null && typeof val === 'object' && isArray(val) === false;
@@ -90419,7 +90470,7 @@ module.exports = function isObject(val) {
/***/ }),
-/* 784 */
+/* 785 */
/***/ (function(module, exports) {
var toString = {}.toString;
@@ -90430,7 +90481,7 @@ module.exports = Array.isArray || function (arr) {
/***/ }),
-/* 785 */
+/* 786 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -90473,7 +90524,7 @@ module.exports = function hasValue(o, noZero) {
/***/ }),
-/* 786 */
+/* 787 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -90486,9 +90537,9 @@ module.exports = function hasValue(o, noZero) {
-var isObject = __webpack_require__(748);
-var hasValues = __webpack_require__(787);
-var get = __webpack_require__(779);
+var isObject = __webpack_require__(749);
+var hasValues = __webpack_require__(788);
+var get = __webpack_require__(780);
module.exports = function(val, prop) {
return hasValues(isObject(val) && prop ? get(val, prop) : val);
@@ -90496,7 +90547,7 @@ module.exports = function(val, prop) {
/***/ }),
-/* 787 */
+/* 788 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -90509,8 +90560,8 @@ module.exports = function(val, prop) {
-var typeOf = __webpack_require__(788);
-var isNumber = __webpack_require__(752);
+var typeOf = __webpack_require__(789);
+var isNumber = __webpack_require__(753);
module.exports = function hasValue(val) {
// is-number checks for NaN and other edge cases
@@ -90563,10 +90614,10 @@ module.exports = function hasValue(val) {
/***/ }),
-/* 788 */
+/* 789 */
/***/ (function(module, exports, __webpack_require__) {
-var isBuffer = __webpack_require__(735);
+var isBuffer = __webpack_require__(736);
var toString = Object.prototype.toString;
/**
@@ -90688,14 +90739,14 @@ module.exports = function kindOf(val) {
/***/ }),
-/* 789 */
+/* 790 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
-var isExtendable = __webpack_require__(790);
-var forIn = __webpack_require__(791);
+var isExtendable = __webpack_require__(791);
+var forIn = __webpack_require__(792);
function mixinDeep(target, objects) {
var len = arguments.length, i = 0;
@@ -90759,7 +90810,7 @@ module.exports = mixinDeep;
/***/ }),
-/* 790 */
+/* 791 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -90772,7 +90823,7 @@ module.exports = mixinDeep;
-var isPlainObject = __webpack_require__(747);
+var isPlainObject = __webpack_require__(748);
module.exports = function isExtendable(val) {
return isPlainObject(val) || typeof val === 'function' || Array.isArray(val);
@@ -90780,7 +90831,7 @@ module.exports = function isExtendable(val) {
/***/ }),
-/* 791 */
+/* 792 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -90803,7 +90854,7 @@ module.exports = function forIn(obj, fn, thisArg) {
/***/ }),
-/* 792 */
+/* 793 */
/***/ (function(module, exports) {
/*!
@@ -90830,14 +90881,14 @@ module.exports = pascalcase;
/***/ }),
-/* 793 */
+/* 794 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
var util = __webpack_require__(29);
-var utils = __webpack_require__(794);
+var utils = __webpack_require__(795);
/**
* Expose class utils
@@ -91202,7 +91253,7 @@ cu.bubble = function(Parent, events) {
/***/ }),
-/* 794 */
+/* 795 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -91216,10 +91267,10 @@ var utils = {};
* Lazily required module dependencies
*/
-utils.union = __webpack_require__(778);
-utils.define = __webpack_require__(730);
-utils.isObj = __webpack_require__(748);
-utils.staticExtend = __webpack_require__(795);
+utils.union = __webpack_require__(779);
+utils.define = __webpack_require__(731);
+utils.isObj = __webpack_require__(749);
+utils.staticExtend = __webpack_require__(796);
/**
@@ -91230,7 +91281,7 @@ module.exports = utils;
/***/ }),
-/* 795 */
+/* 796 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -91243,8 +91294,8 @@ module.exports = utils;
-var copy = __webpack_require__(796);
-var define = __webpack_require__(730);
+var copy = __webpack_require__(797);
+var define = __webpack_require__(731);
var util = __webpack_require__(29);
/**
@@ -91327,15 +91378,15 @@ module.exports = extend;
/***/ }),
-/* 796 */
+/* 797 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
-var typeOf = __webpack_require__(753);
-var copyDescriptor = __webpack_require__(797);
-var define = __webpack_require__(730);
+var typeOf = __webpack_require__(754);
+var copyDescriptor = __webpack_require__(798);
+var define = __webpack_require__(731);
/**
* Copy static properties, prototype properties, and descriptors from one object to another.
@@ -91508,7 +91559,7 @@ module.exports.has = has;
/***/ }),
-/* 797 */
+/* 798 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -91596,16 +91647,16 @@ function isObject(val) {
/***/ }),
-/* 798 */
+/* 799 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
-var use = __webpack_require__(799);
-var define = __webpack_require__(730);
-var debug = __webpack_require__(801)('snapdragon:compiler');
-var utils = __webpack_require__(807);
+var use = __webpack_require__(800);
+var define = __webpack_require__(731);
+var debug = __webpack_require__(802)('snapdragon:compiler');
+var utils = __webpack_require__(808);
/**
* Create a new `Compiler` with the given `options`.
@@ -91759,7 +91810,7 @@ Compiler.prototype = {
// source map support
if (opts.sourcemap) {
- var sourcemaps = __webpack_require__(826);
+ var sourcemaps = __webpack_require__(827);
sourcemaps(this);
this.mapVisit(this.ast.nodes);
this.applySourceMaps();
@@ -91780,7 +91831,7 @@ module.exports = Compiler;
/***/ }),
-/* 799 */
+/* 800 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -91793,7 +91844,7 @@ module.exports = Compiler;
-var utils = __webpack_require__(800);
+var utils = __webpack_require__(801);
module.exports = function base(app, opts) {
if (!utils.isObject(app) && typeof app !== 'function') {
@@ -91908,7 +91959,7 @@ module.exports = function base(app, opts) {
/***/ }),
-/* 800 */
+/* 801 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -91922,8 +91973,8 @@ var utils = {};
* Lazily required module dependencies
*/
-utils.define = __webpack_require__(730);
-utils.isObject = __webpack_require__(748);
+utils.define = __webpack_require__(731);
+utils.isObject = __webpack_require__(749);
utils.isString = function(val) {
@@ -91938,7 +91989,7 @@ module.exports = utils;
/***/ }),
-/* 801 */
+/* 802 */
/***/ (function(module, exports, __webpack_require__) {
/**
@@ -91947,14 +91998,14 @@ module.exports = utils;
*/
if (typeof process !== 'undefined' && process.type === 'renderer') {
- module.exports = __webpack_require__(802);
+ module.exports = __webpack_require__(803);
} else {
- module.exports = __webpack_require__(805);
+ module.exports = __webpack_require__(806);
}
/***/ }),
-/* 802 */
+/* 803 */
/***/ (function(module, exports, __webpack_require__) {
/**
@@ -91963,7 +92014,7 @@ if (typeof process !== 'undefined' && process.type === 'renderer') {
* Expose `debug()` as the module.
*/
-exports = module.exports = __webpack_require__(803);
+exports = module.exports = __webpack_require__(804);
exports.log = log;
exports.formatArgs = formatArgs;
exports.save = save;
@@ -92145,7 +92196,7 @@ function localstorage() {
/***/ }),
-/* 803 */
+/* 804 */
/***/ (function(module, exports, __webpack_require__) {
@@ -92161,7 +92212,7 @@ exports.coerce = coerce;
exports.disable = disable;
exports.enable = enable;
exports.enabled = enabled;
-exports.humanize = __webpack_require__(804);
+exports.humanize = __webpack_require__(805);
/**
* The currently active debug mode names, and names to skip.
@@ -92353,7 +92404,7 @@ function coerce(val) {
/***/ }),
-/* 804 */
+/* 805 */
/***/ (function(module, exports) {
/**
@@ -92511,7 +92562,7 @@ function plural(ms, n, name) {
/***/ }),
-/* 805 */
+/* 806 */
/***/ (function(module, exports, __webpack_require__) {
/**
@@ -92527,7 +92578,7 @@ var util = __webpack_require__(29);
* Expose `debug()` as the module.
*/
-exports = module.exports = __webpack_require__(803);
+exports = module.exports = __webpack_require__(804);
exports.init = init;
exports.log = log;
exports.formatArgs = formatArgs;
@@ -92706,7 +92757,7 @@ function createWritableStdioStream (fd) {
case 'PIPE':
case 'TCP':
- var net = __webpack_require__(806);
+ var net = __webpack_require__(807);
stream = new net.Socket({
fd: fd,
readable: false,
@@ -92765,13 +92816,13 @@ exports.enable(load());
/***/ }),
-/* 806 */
+/* 807 */
/***/ (function(module, exports) {
module.exports = require("net");
/***/ }),
-/* 807 */
+/* 808 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -92781,9 +92832,9 @@ module.exports = require("net");
* Module dependencies
*/
-exports.extend = __webpack_require__(738);
-exports.SourceMap = __webpack_require__(808);
-exports.sourceMapResolve = __webpack_require__(819);
+exports.extend = __webpack_require__(739);
+exports.SourceMap = __webpack_require__(809);
+exports.sourceMapResolve = __webpack_require__(820);
/**
* Convert backslash in the given string to forward slashes
@@ -92826,7 +92877,7 @@ exports.last = function(arr, n) {
/***/ }),
-/* 808 */
+/* 809 */
/***/ (function(module, exports, __webpack_require__) {
/*
@@ -92834,13 +92885,13 @@ exports.last = function(arr, n) {
* Licensed under the New BSD license. See LICENSE.txt or:
* http://opensource.org/licenses/BSD-3-Clause
*/
-exports.SourceMapGenerator = __webpack_require__(809).SourceMapGenerator;
-exports.SourceMapConsumer = __webpack_require__(815).SourceMapConsumer;
-exports.SourceNode = __webpack_require__(818).SourceNode;
+exports.SourceMapGenerator = __webpack_require__(810).SourceMapGenerator;
+exports.SourceMapConsumer = __webpack_require__(816).SourceMapConsumer;
+exports.SourceNode = __webpack_require__(819).SourceNode;
/***/ }),
-/* 809 */
+/* 810 */
/***/ (function(module, exports, __webpack_require__) {
/* -*- Mode: js; js-indent-level: 2; -*- */
@@ -92850,10 +92901,10 @@ exports.SourceNode = __webpack_require__(818).SourceNode;
* http://opensource.org/licenses/BSD-3-Clause
*/
-var base64VLQ = __webpack_require__(810);
-var util = __webpack_require__(812);
-var ArraySet = __webpack_require__(813).ArraySet;
-var MappingList = __webpack_require__(814).MappingList;
+var base64VLQ = __webpack_require__(811);
+var util = __webpack_require__(813);
+var ArraySet = __webpack_require__(814).ArraySet;
+var MappingList = __webpack_require__(815).MappingList;
/**
* An instance of the SourceMapGenerator represents a source map which is
@@ -93262,7 +93313,7 @@ exports.SourceMapGenerator = SourceMapGenerator;
/***/ }),
-/* 810 */
+/* 811 */
/***/ (function(module, exports, __webpack_require__) {
/* -*- Mode: js; js-indent-level: 2; -*- */
@@ -93302,7 +93353,7 @@ exports.SourceMapGenerator = SourceMapGenerator;
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-var base64 = __webpack_require__(811);
+var base64 = __webpack_require__(812);
// A single base 64 digit can contain 6 bits of data. For the base 64 variable
// length quantities we use in the source map spec, the first bit is the sign,
@@ -93408,7 +93459,7 @@ exports.decode = function base64VLQ_decode(aStr, aIndex, aOutParam) {
/***/ }),
-/* 811 */
+/* 812 */
/***/ (function(module, exports) {
/* -*- Mode: js; js-indent-level: 2; -*- */
@@ -93481,7 +93532,7 @@ exports.decode = function (charCode) {
/***/ }),
-/* 812 */
+/* 813 */
/***/ (function(module, exports) {
/* -*- Mode: js; js-indent-level: 2; -*- */
@@ -93904,7 +93955,7 @@ exports.compareByGeneratedPositionsInflated = compareByGeneratedPositionsInflate
/***/ }),
-/* 813 */
+/* 814 */
/***/ (function(module, exports, __webpack_require__) {
/* -*- Mode: js; js-indent-level: 2; -*- */
@@ -93914,7 +93965,7 @@ exports.compareByGeneratedPositionsInflated = compareByGeneratedPositionsInflate
* http://opensource.org/licenses/BSD-3-Clause
*/
-var util = __webpack_require__(812);
+var util = __webpack_require__(813);
var has = Object.prototype.hasOwnProperty;
var hasNativeMap = typeof Map !== "undefined";
@@ -94031,7 +94082,7 @@ exports.ArraySet = ArraySet;
/***/ }),
-/* 814 */
+/* 815 */
/***/ (function(module, exports, __webpack_require__) {
/* -*- Mode: js; js-indent-level: 2; -*- */
@@ -94041,7 +94092,7 @@ exports.ArraySet = ArraySet;
* http://opensource.org/licenses/BSD-3-Clause
*/
-var util = __webpack_require__(812);
+var util = __webpack_require__(813);
/**
* Determine whether mappingB is after mappingA with respect to generated
@@ -94116,7 +94167,7 @@ exports.MappingList = MappingList;
/***/ }),
-/* 815 */
+/* 816 */
/***/ (function(module, exports, __webpack_require__) {
/* -*- Mode: js; js-indent-level: 2; -*- */
@@ -94126,11 +94177,11 @@ exports.MappingList = MappingList;
* http://opensource.org/licenses/BSD-3-Clause
*/
-var util = __webpack_require__(812);
-var binarySearch = __webpack_require__(816);
-var ArraySet = __webpack_require__(813).ArraySet;
-var base64VLQ = __webpack_require__(810);
-var quickSort = __webpack_require__(817).quickSort;
+var util = __webpack_require__(813);
+var binarySearch = __webpack_require__(817);
+var ArraySet = __webpack_require__(814).ArraySet;
+var base64VLQ = __webpack_require__(811);
+var quickSort = __webpack_require__(818).quickSort;
function SourceMapConsumer(aSourceMap) {
var sourceMap = aSourceMap;
@@ -95204,7 +95255,7 @@ exports.IndexedSourceMapConsumer = IndexedSourceMapConsumer;
/***/ }),
-/* 816 */
+/* 817 */
/***/ (function(module, exports) {
/* -*- Mode: js; js-indent-level: 2; -*- */
@@ -95321,7 +95372,7 @@ exports.search = function search(aNeedle, aHaystack, aCompare, aBias) {
/***/ }),
-/* 817 */
+/* 818 */
/***/ (function(module, exports) {
/* -*- Mode: js; js-indent-level: 2; -*- */
@@ -95441,7 +95492,7 @@ exports.quickSort = function (ary, comparator) {
/***/ }),
-/* 818 */
+/* 819 */
/***/ (function(module, exports, __webpack_require__) {
/* -*- Mode: js; js-indent-level: 2; -*- */
@@ -95451,8 +95502,8 @@ exports.quickSort = function (ary, comparator) {
* http://opensource.org/licenses/BSD-3-Clause
*/
-var SourceMapGenerator = __webpack_require__(809).SourceMapGenerator;
-var util = __webpack_require__(812);
+var SourceMapGenerator = __webpack_require__(810).SourceMapGenerator;
+var util = __webpack_require__(813);
// Matches a Windows-style `\r\n` newline or a `\n` newline used by all other
// operating systems these days (capturing the result).
@@ -95860,17 +95911,17 @@ exports.SourceNode = SourceNode;
/***/ }),
-/* 819 */
+/* 820 */
/***/ (function(module, exports, __webpack_require__) {
// Copyright 2014, 2015, 2016, 2017 Simon Lydell
// X11 (“MIT”) Licensed. (See LICENSE.)
-var sourceMappingURL = __webpack_require__(820)
-var resolveUrl = __webpack_require__(821)
-var decodeUriComponent = __webpack_require__(822)
-var urix = __webpack_require__(824)
-var atob = __webpack_require__(825)
+var sourceMappingURL = __webpack_require__(821)
+var resolveUrl = __webpack_require__(822)
+var decodeUriComponent = __webpack_require__(823)
+var urix = __webpack_require__(825)
+var atob = __webpack_require__(826)
@@ -96168,7 +96219,7 @@ module.exports = {
/***/ }),
-/* 820 */
+/* 821 */
/***/ (function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_RESULT__;// Copyright 2014 Simon Lydell
@@ -96231,7 +96282,7 @@ void (function(root, factory) {
/***/ }),
-/* 821 */
+/* 822 */
/***/ (function(module, exports, __webpack_require__) {
// Copyright 2014 Simon Lydell
@@ -96249,13 +96300,13 @@ module.exports = resolveUrl
/***/ }),
-/* 822 */
+/* 823 */
/***/ (function(module, exports, __webpack_require__) {
// Copyright 2017 Simon Lydell
// X11 (“MIT”) Licensed. (See LICENSE.)
-var decodeUriComponent = __webpack_require__(823)
+var decodeUriComponent = __webpack_require__(824)
function customDecodeUriComponent(string) {
// `decodeUriComponent` turns `+` into ` `, but that's not wanted.
@@ -96266,7 +96317,7 @@ module.exports = customDecodeUriComponent
/***/ }),
-/* 823 */
+/* 824 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -96367,7 +96418,7 @@ module.exports = function (encodedURI) {
/***/ }),
-/* 824 */
+/* 825 */
/***/ (function(module, exports, __webpack_require__) {
// Copyright 2014 Simon Lydell
@@ -96390,7 +96441,7 @@ module.exports = urix
/***/ }),
-/* 825 */
+/* 826 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -96404,7 +96455,7 @@ module.exports = atob.atob = atob;
/***/ }),
-/* 826 */
+/* 827 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -96412,8 +96463,8 @@ module.exports = atob.atob = atob;
var fs = __webpack_require__(23);
var path = __webpack_require__(16);
-var define = __webpack_require__(730);
-var utils = __webpack_require__(807);
+var define = __webpack_require__(731);
+var utils = __webpack_require__(808);
/**
* Expose `mixin()`.
@@ -96556,19 +96607,19 @@ exports.comment = function(node) {
/***/ }),
-/* 827 */
+/* 828 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
-var use = __webpack_require__(799);
+var use = __webpack_require__(800);
var util = __webpack_require__(29);
-var Cache = __webpack_require__(828);
-var define = __webpack_require__(730);
-var debug = __webpack_require__(801)('snapdragon:parser');
-var Position = __webpack_require__(829);
-var utils = __webpack_require__(807);
+var Cache = __webpack_require__(829);
+var define = __webpack_require__(731);
+var debug = __webpack_require__(802)('snapdragon:parser');
+var Position = __webpack_require__(830);
+var utils = __webpack_require__(808);
/**
* Create a new `Parser` with the given `input` and `options`.
@@ -97096,7 +97147,7 @@ module.exports = Parser;
/***/ }),
-/* 828 */
+/* 829 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -97203,13 +97254,13 @@ MapCache.prototype.del = function mapDelete(key) {
/***/ }),
-/* 829 */
+/* 830 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
-var define = __webpack_require__(730);
+var define = __webpack_require__(731);
/**
* Store position for a node
@@ -97224,16 +97275,16 @@ module.exports = function Position(start, parser) {
/***/ }),
-/* 830 */
+/* 831 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
-var safe = __webpack_require__(831);
-var define = __webpack_require__(837);
-var extend = __webpack_require__(838);
-var not = __webpack_require__(840);
+var safe = __webpack_require__(832);
+var define = __webpack_require__(838);
+var extend = __webpack_require__(839);
+var not = __webpack_require__(841);
var MAX_LENGTH = 1024 * 64;
/**
@@ -97386,10 +97437,10 @@ module.exports.makeRe = makeRe;
/***/ }),
-/* 831 */
+/* 832 */
/***/ (function(module, exports, __webpack_require__) {
-var parse = __webpack_require__(832);
+var parse = __webpack_require__(833);
var types = parse.types;
module.exports = function (re, opts) {
@@ -97435,13 +97486,13 @@ function isRegExp (x) {
/***/ }),
-/* 832 */
+/* 833 */
/***/ (function(module, exports, __webpack_require__) {
-var util = __webpack_require__(833);
-var types = __webpack_require__(834);
-var sets = __webpack_require__(835);
-var positions = __webpack_require__(836);
+var util = __webpack_require__(834);
+var types = __webpack_require__(835);
+var sets = __webpack_require__(836);
+var positions = __webpack_require__(837);
module.exports = function(regexpStr) {
@@ -97723,11 +97774,11 @@ module.exports.types = types;
/***/ }),
-/* 833 */
+/* 834 */
/***/ (function(module, exports, __webpack_require__) {
-var types = __webpack_require__(834);
-var sets = __webpack_require__(835);
+var types = __webpack_require__(835);
+var sets = __webpack_require__(836);
// All of these are private and only used by randexp.
@@ -97840,7 +97891,7 @@ exports.error = function(regexp, msg) {
/***/ }),
-/* 834 */
+/* 835 */
/***/ (function(module, exports) {
module.exports = {
@@ -97856,10 +97907,10 @@ module.exports = {
/***/ }),
-/* 835 */
+/* 836 */
/***/ (function(module, exports, __webpack_require__) {
-var types = __webpack_require__(834);
+var types = __webpack_require__(835);
var INTS = function() {
return [{ type: types.RANGE , from: 48, to: 57 }];
@@ -97944,10 +97995,10 @@ exports.anyChar = function() {
/***/ }),
-/* 836 */
+/* 837 */
/***/ (function(module, exports, __webpack_require__) {
-var types = __webpack_require__(834);
+var types = __webpack_require__(835);
exports.wordBoundary = function() {
return { type: types.POSITION, value: 'b' };
@@ -97967,7 +98018,7 @@ exports.end = function() {
/***/ }),
-/* 837 */
+/* 838 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -97980,8 +98031,8 @@ exports.end = function() {
-var isobject = __webpack_require__(748);
-var isDescriptor = __webpack_require__(760);
+var isobject = __webpack_require__(749);
+var isDescriptor = __webpack_require__(761);
var define = (typeof Reflect !== 'undefined' && Reflect.defineProperty)
? Reflect.defineProperty
: Object.defineProperty;
@@ -98012,14 +98063,14 @@ module.exports = function defineProperty(obj, key, val) {
/***/ }),
-/* 838 */
+/* 839 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
-var isExtendable = __webpack_require__(839);
-var assignSymbols = __webpack_require__(749);
+var isExtendable = __webpack_require__(840);
+var assignSymbols = __webpack_require__(750);
module.exports = Object.assign || function(obj/*, objects*/) {
if (obj === null || typeof obj === 'undefined') {
@@ -98079,7 +98130,7 @@ function isEnum(obj, key) {
/***/ }),
-/* 839 */
+/* 840 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -98092,7 +98143,7 @@ function isEnum(obj, key) {
-var isPlainObject = __webpack_require__(747);
+var isPlainObject = __webpack_require__(748);
module.exports = function isExtendable(val) {
return isPlainObject(val) || typeof val === 'function' || Array.isArray(val);
@@ -98100,14 +98151,14 @@ module.exports = function isExtendable(val) {
/***/ }),
-/* 840 */
+/* 841 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
-var extend = __webpack_require__(838);
-var safe = __webpack_require__(831);
+var extend = __webpack_require__(839);
+var safe = __webpack_require__(832);
/**
* The main export is a function that takes a `pattern` string and an `options` object.
@@ -98179,14 +98230,14 @@ module.exports = toRegex;
/***/ }),
-/* 841 */
+/* 842 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
-var nanomatch = __webpack_require__(842);
-var extglob = __webpack_require__(857);
+var nanomatch = __webpack_require__(843);
+var extglob = __webpack_require__(858);
module.exports = function(snapdragon) {
var compilers = snapdragon.compiler.compilers;
@@ -98263,7 +98314,7 @@ function escapeExtglobs(compiler) {
/***/ }),
-/* 842 */
+/* 843 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -98274,17 +98325,17 @@ function escapeExtglobs(compiler) {
*/
var util = __webpack_require__(29);
-var toRegex = __webpack_require__(729);
-var extend = __webpack_require__(843);
+var toRegex = __webpack_require__(730);
+var extend = __webpack_require__(844);
/**
* Local dependencies
*/
-var compilers = __webpack_require__(845);
-var parsers = __webpack_require__(846);
-var cache = __webpack_require__(849);
-var utils = __webpack_require__(851);
+var compilers = __webpack_require__(846);
+var parsers = __webpack_require__(847);
+var cache = __webpack_require__(850);
+var utils = __webpack_require__(852);
var MAX_LENGTH = 1024 * 64;
/**
@@ -99108,14 +99159,14 @@ module.exports = nanomatch;
/***/ }),
-/* 843 */
+/* 844 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
-var isExtendable = __webpack_require__(844);
-var assignSymbols = __webpack_require__(749);
+var isExtendable = __webpack_require__(845);
+var assignSymbols = __webpack_require__(750);
module.exports = Object.assign || function(obj/*, objects*/) {
if (obj === null || typeof obj === 'undefined') {
@@ -99175,7 +99226,7 @@ function isEnum(obj, key) {
/***/ }),
-/* 844 */
+/* 845 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -99188,7 +99239,7 @@ function isEnum(obj, key) {
-var isPlainObject = __webpack_require__(747);
+var isPlainObject = __webpack_require__(748);
module.exports = function isExtendable(val) {
return isPlainObject(val) || typeof val === 'function' || Array.isArray(val);
@@ -99196,7 +99247,7 @@ module.exports = function isExtendable(val) {
/***/ }),
-/* 845 */
+/* 846 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -99542,15 +99593,15 @@ module.exports = function(nanomatch, options) {
/***/ }),
-/* 846 */
+/* 847 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
-var regexNot = __webpack_require__(740);
-var toRegex = __webpack_require__(729);
-var isOdd = __webpack_require__(847);
+var regexNot = __webpack_require__(741);
+var toRegex = __webpack_require__(730);
+var isOdd = __webpack_require__(848);
/**
* Characters to use in negation regex (we want to "not" match
@@ -99936,7 +99987,7 @@ module.exports.not = NOT_REGEX;
/***/ }),
-/* 847 */
+/* 848 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -99949,7 +100000,7 @@ module.exports.not = NOT_REGEX;
-var isNumber = __webpack_require__(848);
+var isNumber = __webpack_require__(849);
module.exports = function isOdd(i) {
if (!isNumber(i)) {
@@ -99963,7 +100014,7 @@ module.exports = function isOdd(i) {
/***/ }),
-/* 848 */
+/* 849 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -99991,14 +100042,14 @@ module.exports = function isNumber(num) {
/***/ }),
-/* 849 */
+/* 850 */
/***/ (function(module, exports, __webpack_require__) {
-module.exports = new (__webpack_require__(850))();
+module.exports = new (__webpack_require__(851))();
/***/ }),
-/* 850 */
+/* 851 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -100011,7 +100062,7 @@ module.exports = new (__webpack_require__(850))();
-var MapCache = __webpack_require__(828);
+var MapCache = __webpack_require__(829);
/**
* Create a new `FragmentCache` with an optional object to use for `caches`.
@@ -100133,7 +100184,7 @@ exports = module.exports = FragmentCache;
/***/ }),
-/* 851 */
+/* 852 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -100146,14 +100197,14 @@ var path = __webpack_require__(16);
* Module dependencies
*/
-var isWindows = __webpack_require__(852)();
-var Snapdragon = __webpack_require__(768);
-utils.define = __webpack_require__(853);
-utils.diff = __webpack_require__(854);
-utils.extend = __webpack_require__(843);
-utils.pick = __webpack_require__(855);
-utils.typeOf = __webpack_require__(856);
-utils.unique = __webpack_require__(741);
+var isWindows = __webpack_require__(853)();
+var Snapdragon = __webpack_require__(769);
+utils.define = __webpack_require__(854);
+utils.diff = __webpack_require__(855);
+utils.extend = __webpack_require__(844);
+utils.pick = __webpack_require__(856);
+utils.typeOf = __webpack_require__(857);
+utils.unique = __webpack_require__(742);
/**
* Returns true if the given value is effectively an empty string
@@ -100519,7 +100570,7 @@ utils.unixify = function(options) {
/***/ }),
-/* 852 */
+/* 853 */
/***/ (function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/*!
@@ -100547,7 +100598,7 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
/***/ }),
-/* 853 */
+/* 854 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -100560,8 +100611,8 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
-var isobject = __webpack_require__(748);
-var isDescriptor = __webpack_require__(760);
+var isobject = __webpack_require__(749);
+var isDescriptor = __webpack_require__(761);
var define = (typeof Reflect !== 'undefined' && Reflect.defineProperty)
? Reflect.defineProperty
: Object.defineProperty;
@@ -100592,7 +100643,7 @@ module.exports = function defineProperty(obj, key, val) {
/***/ }),
-/* 854 */
+/* 855 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -100646,7 +100697,7 @@ function diffArray(one, two) {
/***/ }),
-/* 855 */
+/* 856 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -100659,7 +100710,7 @@ function diffArray(one, two) {
-var isObject = __webpack_require__(748);
+var isObject = __webpack_require__(749);
module.exports = function pick(obj, keys) {
if (!isObject(obj) && typeof obj !== 'function') {
@@ -100688,7 +100739,7 @@ module.exports = function pick(obj, keys) {
/***/ }),
-/* 856 */
+/* 857 */
/***/ (function(module, exports) {
var toString = Object.prototype.toString;
@@ -100823,7 +100874,7 @@ function isBuffer(val) {
/***/ }),
-/* 857 */
+/* 858 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -100833,18 +100884,18 @@ function isBuffer(val) {
* Module dependencies
*/
-var extend = __webpack_require__(738);
-var unique = __webpack_require__(741);
-var toRegex = __webpack_require__(729);
+var extend = __webpack_require__(739);
+var unique = __webpack_require__(742);
+var toRegex = __webpack_require__(730);
/**
* Local dependencies
*/
-var compilers = __webpack_require__(858);
-var parsers = __webpack_require__(869);
-var Extglob = __webpack_require__(872);
-var utils = __webpack_require__(871);
+var compilers = __webpack_require__(859);
+var parsers = __webpack_require__(870);
+var Extglob = __webpack_require__(873);
+var utils = __webpack_require__(872);
var MAX_LENGTH = 1024 * 64;
/**
@@ -101161,13 +101212,13 @@ module.exports = extglob;
/***/ }),
-/* 858 */
+/* 859 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
-var brackets = __webpack_require__(859);
+var brackets = __webpack_require__(860);
/**
* Extglob compilers
@@ -101337,7 +101388,7 @@ module.exports = function(extglob) {
/***/ }),
-/* 859 */
+/* 860 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -101347,17 +101398,17 @@ module.exports = function(extglob) {
* Local dependencies
*/
-var compilers = __webpack_require__(860);
-var parsers = __webpack_require__(862);
+var compilers = __webpack_require__(861);
+var parsers = __webpack_require__(863);
/**
* Module dependencies
*/
-var debug = __webpack_require__(864)('expand-brackets');
-var extend = __webpack_require__(738);
-var Snapdragon = __webpack_require__(768);
-var toRegex = __webpack_require__(729);
+var debug = __webpack_require__(865)('expand-brackets');
+var extend = __webpack_require__(739);
+var Snapdragon = __webpack_require__(769);
+var toRegex = __webpack_require__(730);
/**
* Parses the given POSIX character class `pattern` and returns a
@@ -101555,13 +101606,13 @@ module.exports = brackets;
/***/ }),
-/* 860 */
+/* 861 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
-var posix = __webpack_require__(861);
+var posix = __webpack_require__(862);
module.exports = function(brackets) {
brackets.compiler
@@ -101649,7 +101700,7 @@ module.exports = function(brackets) {
/***/ }),
-/* 861 */
+/* 862 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -101678,14 +101729,14 @@ module.exports = {
/***/ }),
-/* 862 */
+/* 863 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
-var utils = __webpack_require__(863);
-var define = __webpack_require__(730);
+var utils = __webpack_require__(864);
+var define = __webpack_require__(731);
/**
* Text regex
@@ -101904,14 +101955,14 @@ module.exports.TEXT_REGEX = TEXT_REGEX;
/***/ }),
-/* 863 */
+/* 864 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
-var toRegex = __webpack_require__(729);
-var regexNot = __webpack_require__(740);
+var toRegex = __webpack_require__(730);
+var regexNot = __webpack_require__(741);
var cached;
/**
@@ -101945,7 +101996,7 @@ exports.createRegex = function(pattern, include) {
/***/ }),
-/* 864 */
+/* 865 */
/***/ (function(module, exports, __webpack_require__) {
/**
@@ -101954,14 +102005,14 @@ exports.createRegex = function(pattern, include) {
*/
if (typeof process !== 'undefined' && process.type === 'renderer') {
- module.exports = __webpack_require__(865);
+ module.exports = __webpack_require__(866);
} else {
- module.exports = __webpack_require__(868);
+ module.exports = __webpack_require__(869);
}
/***/ }),
-/* 865 */
+/* 866 */
/***/ (function(module, exports, __webpack_require__) {
/**
@@ -101970,7 +102021,7 @@ if (typeof process !== 'undefined' && process.type === 'renderer') {
* Expose `debug()` as the module.
*/
-exports = module.exports = __webpack_require__(866);
+exports = module.exports = __webpack_require__(867);
exports.log = log;
exports.formatArgs = formatArgs;
exports.save = save;
@@ -102152,7 +102203,7 @@ function localstorage() {
/***/ }),
-/* 866 */
+/* 867 */
/***/ (function(module, exports, __webpack_require__) {
@@ -102168,7 +102219,7 @@ exports.coerce = coerce;
exports.disable = disable;
exports.enable = enable;
exports.enabled = enabled;
-exports.humanize = __webpack_require__(867);
+exports.humanize = __webpack_require__(868);
/**
* The currently active debug mode names, and names to skip.
@@ -102360,7 +102411,7 @@ function coerce(val) {
/***/ }),
-/* 867 */
+/* 868 */
/***/ (function(module, exports) {
/**
@@ -102518,7 +102569,7 @@ function plural(ms, n, name) {
/***/ }),
-/* 868 */
+/* 869 */
/***/ (function(module, exports, __webpack_require__) {
/**
@@ -102534,7 +102585,7 @@ var util = __webpack_require__(29);
* Expose `debug()` as the module.
*/
-exports = module.exports = __webpack_require__(866);
+exports = module.exports = __webpack_require__(867);
exports.init = init;
exports.log = log;
exports.formatArgs = formatArgs;
@@ -102713,7 +102764,7 @@ function createWritableStdioStream (fd) {
case 'PIPE':
case 'TCP':
- var net = __webpack_require__(806);
+ var net = __webpack_require__(807);
stream = new net.Socket({
fd: fd,
readable: false,
@@ -102772,15 +102823,15 @@ exports.enable(load());
/***/ }),
-/* 869 */
+/* 870 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
-var brackets = __webpack_require__(859);
-var define = __webpack_require__(870);
-var utils = __webpack_require__(871);
+var brackets = __webpack_require__(860);
+var define = __webpack_require__(871);
+var utils = __webpack_require__(872);
/**
* Characters to use in text regex (we want to "not" match
@@ -102935,7 +102986,7 @@ module.exports = parsers;
/***/ }),
-/* 870 */
+/* 871 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -102948,7 +102999,7 @@ module.exports = parsers;
-var isDescriptor = __webpack_require__(760);
+var isDescriptor = __webpack_require__(761);
module.exports = function defineProperty(obj, prop, val) {
if (typeof obj !== 'object' && typeof obj !== 'function') {
@@ -102973,14 +103024,14 @@ module.exports = function defineProperty(obj, prop, val) {
/***/ }),
-/* 871 */
+/* 872 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
-var regex = __webpack_require__(740);
-var Cache = __webpack_require__(850);
+var regex = __webpack_require__(741);
+var Cache = __webpack_require__(851);
/**
* Utils
@@ -103049,7 +103100,7 @@ utils.createRegex = function(str) {
/***/ }),
-/* 872 */
+/* 873 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -103059,16 +103110,16 @@ utils.createRegex = function(str) {
* Module dependencies
*/
-var Snapdragon = __webpack_require__(768);
-var define = __webpack_require__(870);
-var extend = __webpack_require__(738);
+var Snapdragon = __webpack_require__(769);
+var define = __webpack_require__(871);
+var extend = __webpack_require__(739);
/**
* Local dependencies
*/
-var compilers = __webpack_require__(858);
-var parsers = __webpack_require__(869);
+var compilers = __webpack_require__(859);
+var parsers = __webpack_require__(870);
/**
* Customize Snapdragon parser and renderer
@@ -103134,16 +103185,16 @@ module.exports = Extglob;
/***/ }),
-/* 873 */
+/* 874 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
-var extglob = __webpack_require__(857);
-var nanomatch = __webpack_require__(842);
-var regexNot = __webpack_require__(740);
-var toRegex = __webpack_require__(830);
+var extglob = __webpack_require__(858);
+var nanomatch = __webpack_require__(843);
+var regexNot = __webpack_require__(741);
+var toRegex = __webpack_require__(831);
var not;
/**
@@ -103224,14 +103275,14 @@ function textRegex(pattern) {
/***/ }),
-/* 874 */
+/* 875 */
/***/ (function(module, exports, __webpack_require__) {
-module.exports = new (__webpack_require__(850))();
+module.exports = new (__webpack_require__(851))();
/***/ }),
-/* 875 */
+/* 876 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -103244,13 +103295,13 @@ var path = __webpack_require__(16);
* Module dependencies
*/
-var Snapdragon = __webpack_require__(768);
-utils.define = __webpack_require__(837);
-utils.diff = __webpack_require__(854);
-utils.extend = __webpack_require__(838);
-utils.pick = __webpack_require__(855);
-utils.typeOf = __webpack_require__(876);
-utils.unique = __webpack_require__(741);
+var Snapdragon = __webpack_require__(769);
+utils.define = __webpack_require__(838);
+utils.diff = __webpack_require__(855);
+utils.extend = __webpack_require__(839);
+utils.pick = __webpack_require__(856);
+utils.typeOf = __webpack_require__(877);
+utils.unique = __webpack_require__(742);
/**
* Returns true if the platform is windows, or `path.sep` is `\\`.
@@ -103547,7 +103598,7 @@ utils.unixify = function(options) {
/***/ }),
-/* 876 */
+/* 877 */
/***/ (function(module, exports) {
var toString = Object.prototype.toString;
@@ -103682,7 +103733,7 @@ function isBuffer(val) {
/***/ }),
-/* 877 */
+/* 878 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -103701,9 +103752,9 @@ var __extends = (this && this.__extends) || (function () {
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
-var readdir = __webpack_require__(878);
-var reader_1 = __webpack_require__(891);
-var fs_stream_1 = __webpack_require__(895);
+var readdir = __webpack_require__(879);
+var reader_1 = __webpack_require__(892);
+var fs_stream_1 = __webpack_require__(896);
var ReaderAsync = /** @class */ (function (_super) {
__extends(ReaderAsync, _super);
function ReaderAsync() {
@@ -103764,15 +103815,15 @@ exports.default = ReaderAsync;
/***/ }),
-/* 878 */
+/* 879 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
-const readdirSync = __webpack_require__(879);
-const readdirAsync = __webpack_require__(887);
-const readdirStream = __webpack_require__(890);
+const readdirSync = __webpack_require__(880);
+const readdirAsync = __webpack_require__(888);
+const readdirStream = __webpack_require__(891);
module.exports = exports = readdirAsyncPath;
exports.readdir = exports.readdirAsync = exports.async = readdirAsyncPath;
@@ -103856,7 +103907,7 @@ function readdirStreamStat (dir, options) {
/***/ }),
-/* 879 */
+/* 880 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -103864,11 +103915,11 @@ function readdirStreamStat (dir, options) {
module.exports = readdirSync;
-const DirectoryReader = __webpack_require__(880);
+const DirectoryReader = __webpack_require__(881);
let syncFacade = {
- fs: __webpack_require__(885),
- forEach: __webpack_require__(886),
+ fs: __webpack_require__(886),
+ forEach: __webpack_require__(887),
sync: true
};
@@ -103897,7 +103948,7 @@ function readdirSync (dir, options, internalOptions) {
/***/ }),
-/* 880 */
+/* 881 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -103906,9 +103957,9 @@ function readdirSync (dir, options, internalOptions) {
const Readable = __webpack_require__(27).Readable;
const EventEmitter = __webpack_require__(379).EventEmitter;
const path = __webpack_require__(16);
-const normalizeOptions = __webpack_require__(881);
-const stat = __webpack_require__(883);
-const call = __webpack_require__(884);
+const normalizeOptions = __webpack_require__(882);
+const stat = __webpack_require__(884);
+const call = __webpack_require__(885);
/**
* Asynchronously reads the contents of a directory and streams the results
@@ -104284,14 +104335,14 @@ module.exports = DirectoryReader;
/***/ }),
-/* 881 */
+/* 882 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
const path = __webpack_require__(16);
-const globToRegExp = __webpack_require__(882);
+const globToRegExp = __webpack_require__(883);
module.exports = normalizeOptions;
@@ -104468,7 +104519,7 @@ function normalizeOptions (options, internalOptions) {
/***/ }),
-/* 882 */
+/* 883 */
/***/ (function(module, exports) {
module.exports = function (glob, opts) {
@@ -104605,13 +104656,13 @@ module.exports = function (glob, opts) {
/***/ }),
-/* 883 */
+/* 884 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
-const call = __webpack_require__(884);
+const call = __webpack_require__(885);
module.exports = stat;
@@ -104686,7 +104737,7 @@ function symlinkStat (fs, path, lstats, callback) {
/***/ }),
-/* 884 */
+/* 885 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -104747,14 +104798,14 @@ function callOnce (fn) {
/***/ }),
-/* 885 */
+/* 886 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
const fs = __webpack_require__(23);
-const call = __webpack_require__(884);
+const call = __webpack_require__(885);
/**
* A facade around {@link fs.readdirSync} that allows it to be called
@@ -104818,7 +104869,7 @@ exports.lstat = function (path, callback) {
/***/ }),
-/* 886 */
+/* 887 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -104847,7 +104898,7 @@ function syncForEach (array, iterator, done) {
/***/ }),
-/* 887 */
+/* 888 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -104855,12 +104906,12 @@ function syncForEach (array, iterator, done) {
module.exports = readdirAsync;
-const maybe = __webpack_require__(888);
-const DirectoryReader = __webpack_require__(880);
+const maybe = __webpack_require__(889);
+const DirectoryReader = __webpack_require__(881);
let asyncFacade = {
fs: __webpack_require__(23),
- forEach: __webpack_require__(889),
+ forEach: __webpack_require__(890),
async: true
};
@@ -104902,7 +104953,7 @@ function readdirAsync (dir, options, callback, internalOptions) {
/***/ }),
-/* 888 */
+/* 889 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -104929,7 +104980,7 @@ module.exports = function maybe (cb, promise) {
/***/ }),
-/* 889 */
+/* 890 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -104965,7 +105016,7 @@ function asyncForEach (array, iterator, done) {
/***/ }),
-/* 890 */
+/* 891 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -104973,11 +105024,11 @@ function asyncForEach (array, iterator, done) {
module.exports = readdirStream;
-const DirectoryReader = __webpack_require__(880);
+const DirectoryReader = __webpack_require__(881);
let streamFacade = {
fs: __webpack_require__(23),
- forEach: __webpack_require__(889),
+ forEach: __webpack_require__(890),
async: true
};
@@ -104997,16 +105048,16 @@ function readdirStream (dir, options, internalOptions) {
/***/ }),
-/* 891 */
+/* 892 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var path = __webpack_require__(16);
-var deep_1 = __webpack_require__(892);
-var entry_1 = __webpack_require__(894);
-var pathUtil = __webpack_require__(893);
+var deep_1 = __webpack_require__(893);
+var entry_1 = __webpack_require__(895);
+var pathUtil = __webpack_require__(894);
var Reader = /** @class */ (function () {
function Reader(options) {
this.options = options;
@@ -105072,14 +105123,14 @@ exports.default = Reader;
/***/ }),
-/* 892 */
+/* 893 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
-var pathUtils = __webpack_require__(893);
-var patternUtils = __webpack_require__(722);
+var pathUtils = __webpack_require__(894);
+var patternUtils = __webpack_require__(723);
var DeepFilter = /** @class */ (function () {
function DeepFilter(options, micromatchOptions) {
this.options = options;
@@ -105162,7 +105213,7 @@ exports.default = DeepFilter;
/***/ }),
-/* 893 */
+/* 894 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -105193,14 +105244,14 @@ exports.makeAbsolute = makeAbsolute;
/***/ }),
-/* 894 */
+/* 895 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
-var pathUtils = __webpack_require__(893);
-var patternUtils = __webpack_require__(722);
+var pathUtils = __webpack_require__(894);
+var patternUtils = __webpack_require__(723);
var EntryFilter = /** @class */ (function () {
function EntryFilter(options, micromatchOptions) {
this.options = options;
@@ -105285,7 +105336,7 @@ exports.default = EntryFilter;
/***/ }),
-/* 895 */
+/* 896 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -105305,8 +105356,8 @@ var __extends = (this && this.__extends) || (function () {
})();
Object.defineProperty(exports, "__esModule", { value: true });
var stream = __webpack_require__(27);
-var fsStat = __webpack_require__(896);
-var fs_1 = __webpack_require__(900);
+var fsStat = __webpack_require__(897);
+var fs_1 = __webpack_require__(901);
var FileSystemStream = /** @class */ (function (_super) {
__extends(FileSystemStream, _super);
function FileSystemStream() {
@@ -105356,14 +105407,14 @@ exports.default = FileSystemStream;
/***/ }),
-/* 896 */
+/* 897 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
-const optionsManager = __webpack_require__(897);
-const statProvider = __webpack_require__(899);
+const optionsManager = __webpack_require__(898);
+const statProvider = __webpack_require__(900);
/**
* Asynchronous API.
*/
@@ -105394,13 +105445,13 @@ exports.statSync = statSync;
/***/ }),
-/* 897 */
+/* 898 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
-const fsAdapter = __webpack_require__(898);
+const fsAdapter = __webpack_require__(899);
function prepare(opts) {
const options = Object.assign({
fs: fsAdapter.getFileSystemAdapter(opts ? opts.fs : undefined),
@@ -105413,7 +105464,7 @@ exports.prepare = prepare;
/***/ }),
-/* 898 */
+/* 899 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -105436,7 +105487,7 @@ exports.getFileSystemAdapter = getFileSystemAdapter;
/***/ }),
-/* 899 */
+/* 900 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -105488,7 +105539,7 @@ exports.isFollowedSymlink = isFollowedSymlink;
/***/ }),
-/* 900 */
+/* 901 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -105519,7 +105570,7 @@ exports.default = FileSystem;
/***/ }),
-/* 901 */
+/* 902 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -105539,9 +105590,9 @@ var __extends = (this && this.__extends) || (function () {
})();
Object.defineProperty(exports, "__esModule", { value: true });
var stream = __webpack_require__(27);
-var readdir = __webpack_require__(878);
-var reader_1 = __webpack_require__(891);
-var fs_stream_1 = __webpack_require__(895);
+var readdir = __webpack_require__(879);
+var reader_1 = __webpack_require__(892);
+var fs_stream_1 = __webpack_require__(896);
var TransformStream = /** @class */ (function (_super) {
__extends(TransformStream, _super);
function TransformStream(reader) {
@@ -105609,7 +105660,7 @@ exports.default = ReaderStream;
/***/ }),
-/* 902 */
+/* 903 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -105628,9 +105679,9 @@ var __extends = (this && this.__extends) || (function () {
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
-var readdir = __webpack_require__(878);
-var reader_1 = __webpack_require__(891);
-var fs_sync_1 = __webpack_require__(903);
+var readdir = __webpack_require__(879);
+var reader_1 = __webpack_require__(892);
+var fs_sync_1 = __webpack_require__(904);
var ReaderSync = /** @class */ (function (_super) {
__extends(ReaderSync, _super);
function ReaderSync() {
@@ -105690,7 +105741,7 @@ exports.default = ReaderSync;
/***/ }),
-/* 903 */
+/* 904 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -105709,8 +105760,8 @@ var __extends = (this && this.__extends) || (function () {
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
-var fsStat = __webpack_require__(896);
-var fs_1 = __webpack_require__(900);
+var fsStat = __webpack_require__(897);
+var fs_1 = __webpack_require__(901);
var FileSystemSync = /** @class */ (function (_super) {
__extends(FileSystemSync, _super);
function FileSystemSync() {
@@ -105756,7 +105807,7 @@ exports.default = FileSystemSync;
/***/ }),
-/* 904 */
+/* 905 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -105772,7 +105823,7 @@ exports.flatten = flatten;
/***/ }),
-/* 905 */
+/* 906 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -105793,13 +105844,13 @@ exports.merge = merge;
/***/ }),
-/* 906 */
+/* 907 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
const path = __webpack_require__(16);
-const pathType = __webpack_require__(907);
+const pathType = __webpack_require__(908);
const getExtensions = extensions => extensions.length > 1 ? `{${extensions.join(',')}}` : extensions[0];
@@ -105865,13 +105916,13 @@ module.exports.sync = (input, opts) => {
/***/ }),
-/* 907 */
+/* 908 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
const fs = __webpack_require__(23);
-const pify = __webpack_require__(908);
+const pify = __webpack_require__(909);
function type(fn, fn2, fp) {
if (typeof fp !== 'string') {
@@ -105914,7 +105965,7 @@ exports.symlinkSync = typeSync.bind(null, 'lstatSync', 'isSymbolicLink');
/***/ }),
-/* 908 */
+/* 909 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -106005,17 +106056,17 @@ module.exports = (obj, opts) => {
/***/ }),
-/* 909 */
+/* 910 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
const fs = __webpack_require__(23);
const path = __webpack_require__(16);
-const fastGlob = __webpack_require__(718);
-const gitIgnore = __webpack_require__(910);
-const pify = __webpack_require__(911);
-const slash = __webpack_require__(912);
+const fastGlob = __webpack_require__(719);
+const gitIgnore = __webpack_require__(911);
+const pify = __webpack_require__(912);
+const slash = __webpack_require__(913);
const DEFAULT_IGNORE = [
'**/node_modules/**',
@@ -106113,7 +106164,7 @@ module.exports.sync = options => {
/***/ }),
-/* 910 */
+/* 911 */
/***/ (function(module, exports) {
// A simple implementation of make-array
@@ -106582,7 +106633,7 @@ module.exports = options => new IgnoreBase(options)
/***/ }),
-/* 911 */
+/* 912 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -106657,7 +106708,7 @@ module.exports = (input, options) => {
/***/ }),
-/* 912 */
+/* 913 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -106675,17 +106726,17 @@ module.exports = input => {
/***/ }),
-/* 913 */
+/* 914 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
const path = __webpack_require__(16);
const {constants: fsConstants} = __webpack_require__(23);
-const pEvent = __webpack_require__(914);
-const CpFileError = __webpack_require__(917);
-const fs = __webpack_require__(921);
-const ProgressEmitter = __webpack_require__(924);
+const pEvent = __webpack_require__(915);
+const CpFileError = __webpack_require__(918);
+const fs = __webpack_require__(922);
+const ProgressEmitter = __webpack_require__(925);
const cpFileAsync = async (source, destination, options, progressEmitter) => {
let readError;
@@ -106799,12 +106850,12 @@ module.exports.sync = (source, destination, options) => {
/***/ }),
-/* 914 */
+/* 915 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
-const pTimeout = __webpack_require__(915);
+const pTimeout = __webpack_require__(916);
const symbolAsyncIterator = Symbol.asyncIterator || '@@asyncIterator';
@@ -107095,12 +107146,12 @@ module.exports.iterator = (emitter, event, options) => {
/***/ }),
-/* 915 */
+/* 916 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
-const pFinally = __webpack_require__(916);
+const pFinally = __webpack_require__(917);
class TimeoutError extends Error {
constructor(message) {
@@ -107146,7 +107197,7 @@ module.exports.TimeoutError = TimeoutError;
/***/ }),
-/* 916 */
+/* 917 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -107168,12 +107219,12 @@ module.exports = (promise, onFinally) => {
/***/ }),
-/* 917 */
+/* 918 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
-const NestedError = __webpack_require__(918);
+const NestedError = __webpack_require__(919);
class CpFileError extends NestedError {
constructor(message, nested) {
@@ -107187,10 +107238,10 @@ module.exports = CpFileError;
/***/ }),
-/* 918 */
+/* 919 */
/***/ (function(module, exports, __webpack_require__) {
-var inherits = __webpack_require__(919);
+var inherits = __webpack_require__(920);
var NestedError = function (message, nested) {
this.nested = nested;
@@ -107241,7 +107292,7 @@ module.exports = NestedError;
/***/ }),
-/* 919 */
+/* 920 */
/***/ (function(module, exports, __webpack_require__) {
try {
@@ -107249,12 +107300,12 @@ try {
if (typeof util.inherits !== 'function') throw '';
module.exports = util.inherits;
} catch (e) {
- module.exports = __webpack_require__(920);
+ module.exports = __webpack_require__(921);
}
/***/ }),
-/* 920 */
+/* 921 */
/***/ (function(module, exports) {
if (typeof Object.create === 'function') {
@@ -107283,16 +107334,16 @@ if (typeof Object.create === 'function') {
/***/ }),
-/* 921 */
+/* 922 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
const {promisify} = __webpack_require__(29);
const fs = __webpack_require__(22);
-const makeDir = __webpack_require__(922);
-const pEvent = __webpack_require__(914);
-const CpFileError = __webpack_require__(917);
+const makeDir = __webpack_require__(923);
+const pEvent = __webpack_require__(915);
+const CpFileError = __webpack_require__(918);
const stat = promisify(fs.stat);
const lstat = promisify(fs.lstat);
@@ -107389,7 +107440,7 @@ exports.copyFileSync = (source, destination, flags) => {
/***/ }),
-/* 922 */
+/* 923 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -107397,7 +107448,7 @@ exports.copyFileSync = (source, destination, flags) => {
const fs = __webpack_require__(23);
const path = __webpack_require__(16);
const {promisify} = __webpack_require__(29);
-const semver = __webpack_require__(923);
+const semver = __webpack_require__(924);
const defaults = {
mode: 0o777 & (~process.umask()),
@@ -107546,7 +107597,7 @@ module.exports.sync = (input, options) => {
/***/ }),
-/* 923 */
+/* 924 */
/***/ (function(module, exports) {
exports = module.exports = SemVer
@@ -109148,7 +109199,7 @@ function coerce (version, options) {
/***/ }),
-/* 924 */
+/* 925 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -109189,7 +109240,7 @@ module.exports = ProgressEmitter;
/***/ }),
-/* 925 */
+/* 926 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -109235,12 +109286,12 @@ exports.default = module.exports;
/***/ }),
-/* 926 */
+/* 927 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
-const NestedError = __webpack_require__(927);
+const NestedError = __webpack_require__(928);
class CpyError extends NestedError {
constructor(message, nested) {
@@ -109254,7 +109305,7 @@ module.exports = CpyError;
/***/ }),
-/* 927 */
+/* 928 */
/***/ (function(module, exports, __webpack_require__) {
var inherits = __webpack_require__(29).inherits;
@@ -109310,7 +109361,7 @@ module.exports = NestedError;
/***/ }),
-/* 928 */
+/* 929 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
diff --git a/packages/kbn-pm/package.json b/packages/kbn-pm/package.json
index 444d46307b059..a05e1634226e5 100644
--- a/packages/kbn-pm/package.json
+++ b/packages/kbn-pm/package.json
@@ -26,7 +26,7 @@
"@types/lodash.clonedeepwith": "^4.5.3",
"@types/log-symbols": "^2.0.0",
"@types/ncp": "^2.0.1",
- "@types/node": "^10.12.27",
+ "@types/node": ">=10.17.17 <10.20.0",
"@types/ora": "^1.3.5",
"@types/read-pkg": "^4.0.0",
"@types/strip-ansi": "^3.0.0",
@@ -48,6 +48,7 @@
"globby": "^8.0.1",
"has-ansi": "^3.0.0",
"indent-string": "^3.2.0",
+ "is-path-inside": "^3.0.2",
"lodash.clonedeepwith": "^4.5.0",
"log-symbols": "^2.2.0",
"multimatch": "^4.0.0",
diff --git a/packages/kbn-pm/src/utils/kibana.ts b/packages/kbn-pm/src/utils/kibana.ts
index 36f697d19fc1f..58af98b2a92db 100644
--- a/packages/kbn-pm/src/utils/kibana.ts
+++ b/packages/kbn-pm/src/utils/kibana.ts
@@ -20,6 +20,7 @@
import Path from 'path';
import multimatch from 'multimatch';
+import isPathInside from 'is-path-inside';
import { ProjectMap, getProjects, includeTransitiveProjects } from './projects';
import { Project } from './project';
@@ -121,4 +122,15 @@ export class Kibana {
return filteredProjects;
}
+
+ isPartOfRepo(project: Project) {
+ return (
+ project.path === this.kibanaProject.path ||
+ isPathInside(project.path, this.kibanaProject.path)
+ );
+ }
+
+ isOutsideRepo(project: Project) {
+ return !this.isPartOfRepo(project);
+ }
}
diff --git a/packages/kbn-pm/src/utils/project_checksums.ts b/packages/kbn-pm/src/utils/project_checksums.ts
index 2fd24c8fc9577..572f2adb19bd9 100644
--- a/packages/kbn-pm/src/utils/project_checksums.ts
+++ b/packages/kbn-pm/src/utils/project_checksums.ts
@@ -43,7 +43,14 @@ async function getChangesForProjects(projects: ProjectMap, kbn: Kibana, log: Too
const { stdout } = await execa(
'git',
- ['ls-files', '-dmt', '--', ...Array.from(projects.values()).map(p => p.path)],
+ [
+ 'ls-files',
+ '-dmt',
+ '--',
+ ...Array.from(projects.values())
+ .filter(p => kbn.isPartOfRepo(p))
+ .map(p => p.path),
+ ],
{
cwd: kbn.getAbsolute(),
}
@@ -84,9 +91,14 @@ async function getChangesForProjects(projects: ProjectMap, kbn: Kibana, log: Too
}
const sortedRelevantProjects = Array.from(projects.values()).sort(projectBySpecificitySorter);
- const changesByProject = new Map();
+ const changesByProject = new Map();
for (const project of sortedRelevantProjects) {
+ if (kbn.isOutsideRepo(project)) {
+ changesByProject.set(project, undefined);
+ continue;
+ }
+
const ownChanges: Changes = new Map();
const prefix = kbn.getRelative(project.path);
@@ -114,6 +126,10 @@ async function getChangesForProjects(projects: ProjectMap, kbn: Kibana, log: Too
/** Get the latest commit sha for a project */
async function getLatestSha(project: Project, kbn: Kibana) {
+ if (kbn.isOutsideRepo(project)) {
+ return;
+ }
+
const { stdout } = await execa(
'git',
['log', '-n', '1', '--pretty=format:%H', '--', project.path],
@@ -175,7 +191,7 @@ function resolveDepsForProject(project: Project, yarnLock: YarnLock, kbn: Kibana
*/
async function getChecksum(
project: Project,
- changes: Changes,
+ changes: Changes | undefined,
yarnLock: YarnLock,
kbn: Kibana,
log: ToolingLog
@@ -185,7 +201,7 @@ async function getChecksum(
log.verbose(`[${project.name}] local sha:`, sha);
}
- if (Array.from(changes.values()).includes('invalid')) {
+ if (!changes || Array.from(changes.values()).includes('invalid')) {
log.warning(`[${project.name}] unable to determine local changes, caching disabled`);
return;
}
@@ -248,7 +264,7 @@ export async function getAllChecksums(kbn: Kibana, log: ToolingLog) {
Array.from(projects.values()).map(async project => {
cacheKeys.set(
project.name,
- await getChecksum(project, changesByProject.get(project)!, yarnLock, kbn, log)
+ await getChecksum(project, changesByProject.get(project), yarnLock, kbn, log)
);
})
);
diff --git a/packages/kbn-test/src/functional_test_runner/cli.ts b/packages/kbn-test/src/functional_test_runner/cli.ts
index 3aaaa47ead5b6..276a51c3a6a99 100644
--- a/packages/kbn-test/src/functional_test_runner/cli.ts
+++ b/packages/kbn-test/src/functional_test_runner/cli.ts
@@ -18,6 +18,7 @@
*/
import { resolve } from 'path';
+import { inspect } from 'util';
import { run, createFlagError, Flags } from '@kbn/dev-utils';
import { FunctionalTestRunner } from './functional_test_runner';
@@ -86,7 +87,11 @@ export function runFtrCli() {
}
};
- process.on('unhandledRejection', err => teardown(err));
+ process.on('unhandledRejection', err =>
+ teardown(
+ err instanceof Error ? err : new Error(`non-Error type rejection value: ${inspect(err)}`)
+ )
+ );
process.on('SIGTERM', () => teardown());
process.on('SIGINT', () => teardown());
diff --git a/packages/kbn-test/src/functional_test_runner/lib/config/schema.ts b/packages/kbn-test/src/functional_test_runner/lib/config/schema.ts
index 28e8396d0beba..66f17ab579ec3 100644
--- a/packages/kbn-test/src/functional_test_runner/lib/config/schema.ts
+++ b/packages/kbn-test/src/functional_test_runner/lib/config/schema.ts
@@ -255,5 +255,20 @@ export const schema = Joi.object()
fixedHeaderHeight: Joi.number().default(50),
})
.default(),
+
+ // settings for the security service if there is no defaultRole defined, then default to superuser role.
+ security: Joi.object()
+ .keys({
+ roles: Joi.object().default(),
+ defaultRoles: Joi.array()
+ .items(Joi.string())
+ .when('$primary', {
+ is: true,
+ then: Joi.array().min(1),
+ })
+ .default(['superuser']),
+ disableTestUser: Joi.boolean(),
+ })
+ .default(),
})
.default();
diff --git a/src/core/public/chrome/chrome_service.mock.ts b/src/core/public/chrome/chrome_service.mock.ts
index bd932c5961eca..89007461b63e6 100644
--- a/src/core/public/chrome/chrome_service.mock.ts
+++ b/src/core/public/chrome/chrome_service.mock.ts
@@ -61,8 +61,6 @@ const createStartContractMock = () => {
getBrand$: jest.fn(),
setIsVisible: jest.fn(),
getIsVisible$: jest.fn(),
- setIsCollapsed: jest.fn(),
- getIsCollapsed$: jest.fn(),
addApplicationClass: jest.fn(),
removeApplicationClass: jest.fn(),
getApplicationClasses$: jest.fn(),
@@ -73,15 +71,16 @@ const createStartContractMock = () => {
getHelpExtension$: jest.fn(),
setHelpExtension: jest.fn(),
setHelpSupportUrl: jest.fn(),
+ getIsNavDrawerLocked$: jest.fn(),
};
startContract.navLinks.getAll.mockReturnValue([]);
startContract.getBrand$.mockReturnValue(new BehaviorSubject({} as ChromeBrand));
startContract.getIsVisible$.mockReturnValue(new BehaviorSubject(false));
- startContract.getIsCollapsed$.mockReturnValue(new BehaviorSubject(false));
startContract.getApplicationClasses$.mockReturnValue(new BehaviorSubject(['class-name']));
startContract.getBadge$.mockReturnValue(new BehaviorSubject({} as ChromeBadge));
startContract.getBreadcrumbs$.mockReturnValue(new BehaviorSubject([{} as ChromeBreadcrumb]));
startContract.getHelpExtension$.mockReturnValue(new BehaviorSubject(undefined));
+ startContract.getIsNavDrawerLocked$.mockReturnValue(new BehaviorSubject(false));
return startContract;
};
diff --git a/src/core/public/chrome/chrome_service.test.ts b/src/core/public/chrome/chrome_service.test.ts
index 9018b21973634..bf531aaa00fac 100644
--- a/src/core/public/chrome/chrome_service.test.ts
+++ b/src/core/public/chrome/chrome_service.test.ts
@@ -259,40 +259,6 @@ describe('start', () => {
});
});
- describe('is collapsed', () => {
- it('updates/emits isCollapsed', async () => {
- const { chrome, service } = await start();
- const promise = chrome
- .getIsCollapsed$()
- .pipe(toArray())
- .toPromise();
-
- chrome.setIsCollapsed(true);
- chrome.setIsCollapsed(false);
- chrome.setIsCollapsed(true);
- service.stop();
-
- await expect(promise).resolves.toMatchInlineSnapshot(`
- Array [
- false,
- true,
- false,
- true,
- ]
- `);
- });
-
- it('only stores true in localStorage', async () => {
- const { chrome } = await start();
-
- chrome.setIsCollapsed(true);
- expect(store.size).toBe(1);
-
- chrome.setIsCollapsed(false);
- expect(store.size).toBe(0);
- });
- });
-
describe('application classes', () => {
it('updates/emits the application classes', async () => {
const { chrome, service } = await start();
@@ -442,12 +408,12 @@ describe('start', () => {
});
describe('stop', () => {
- it('completes applicationClass$, isCollapsed$, breadcrumbs$, isVisible$, and brand$ observables', async () => {
+ it('completes applicationClass$, getIsNavDrawerLocked, breadcrumbs$, isVisible$, and brand$ observables', async () => {
const { chrome, service } = await start();
const promise = Rx.combineLatest(
chrome.getBrand$(),
chrome.getApplicationClasses$(),
- chrome.getIsCollapsed$(),
+ chrome.getIsNavDrawerLocked$(),
chrome.getBreadcrumbs$(),
chrome.getIsVisible$(),
chrome.getHelpExtension$()
@@ -465,7 +431,7 @@ describe('stop', () => {
Rx.combineLatest(
chrome.getBrand$(),
chrome.getApplicationClasses$(),
- chrome.getIsCollapsed$(),
+ chrome.getIsNavDrawerLocked$(),
chrome.getBreadcrumbs$(),
chrome.getIsVisible$(),
chrome.getHelpExtension$()
diff --git a/src/core/public/chrome/chrome_service.tsx b/src/core/public/chrome/chrome_service.tsx
index 2b0b115ce068e..7c9b644b8b984 100644
--- a/src/core/public/chrome/chrome_service.tsx
+++ b/src/core/public/chrome/chrome_service.tsx
@@ -34,14 +34,14 @@ import { ChromeNavLinks, NavLinksService } from './nav_links';
import { ChromeRecentlyAccessed, RecentlyAccessedService } from './recently_accessed';
import { NavControlsService, ChromeNavControls } from './nav_controls';
import { DocTitleService, ChromeDocTitle } from './doc_title';
-import { LoadingIndicator, HeaderWrapper as Header } from './ui';
+import { LoadingIndicator, Header } from './ui';
import { DocLinksStart } from '../doc_links';
import { ChromeHelpExtensionMenuLink } from './ui/header/header_help_menu';
import { KIBANA_ASK_ELASTIC_LINK } from './constants';
import { IUiSettingsClient } from '../ui_settings';
export { ChromeNavControls, ChromeRecentlyAccessed, ChromeDocTitle };
-const IS_COLLAPSED_KEY = 'core.chrome.isCollapsed';
+const IS_LOCKED_KEY = 'core.chrome.isLocked';
/** @public */
export interface ChromeBadge {
@@ -146,18 +146,25 @@ export class ChromeService {
const appTitle$ = new BehaviorSubject('Kibana');
const brand$ = new BehaviorSubject({});
- const isCollapsed$ = new BehaviorSubject(!!localStorage.getItem(IS_COLLAPSED_KEY));
const applicationClasses$ = new BehaviorSubject>(new Set());
const helpExtension$ = new BehaviorSubject(undefined);
const breadcrumbs$ = new BehaviorSubject([]);
const badge$ = new BehaviorSubject(undefined);
const helpSupportUrl$ = new BehaviorSubject(KIBANA_ASK_ELASTIC_LINK);
+ const isNavDrawerLocked$ = new BehaviorSubject(localStorage.getItem(IS_LOCKED_KEY) === 'true');
const navControls = this.navControls.start();
const navLinks = this.navLinks.start({ application, http });
const recentlyAccessed = await this.recentlyAccessed.start({ http });
const docTitle = this.docTitle.start({ document: window.document });
+ const setIsNavDrawerLocked = (isLocked: boolean) => {
+ isNavDrawerLocked$.next(isLocked);
+ localStorage.setItem(IS_LOCKED_KEY, `${isLocked}`);
+ };
+
+ const getIsNavDrawerLocked$ = isNavDrawerLocked$.pipe(takeUntil(this.stop$));
+
if (!this.params.browserSupportsCsp && injectedMetadata.getCspConfig().warnLegacyBrowsers) {
notifications.toasts.addWarning(
i18n.translate('core.chrome.legacyBrowserWarning', {
@@ -193,6 +200,8 @@ export class ChromeService {
recentlyAccessed$={recentlyAccessed.get$()}
navControlsLeft$={navControls.getLeft$()}
navControlsRight$={navControls.getRight$()}
+ onIsLockedUpdate={setIsNavDrawerLocked}
+ isLocked$={getIsNavDrawerLocked$}
/>
),
@@ -214,17 +223,6 @@ export class ChromeService {
setIsVisible: (isVisible: boolean) => this.toggleHidden$.next(!isVisible),
- getIsCollapsed$: () => isCollapsed$.pipe(takeUntil(this.stop$)),
-
- setIsCollapsed: (isCollapsed: boolean) => {
- isCollapsed$.next(isCollapsed);
- if (isCollapsed) {
- localStorage.setItem(IS_COLLAPSED_KEY, 'true');
- } else {
- localStorage.removeItem(IS_COLLAPSED_KEY);
- }
- },
-
getApplicationClasses$: () =>
applicationClasses$.pipe(
map(set => [...set]),
@@ -262,6 +260,8 @@ export class ChromeService {
},
setHelpSupportUrl: (url: string) => helpSupportUrl$.next(url),
+
+ getIsNavDrawerLocked$: () => getIsNavDrawerLocked$,
};
}
@@ -353,16 +353,6 @@ export interface ChromeStart {
*/
setIsVisible(isVisible: boolean): void;
- /**
- * Get an observable of the current collapsed state of the chrome.
- */
- getIsCollapsed$(): Observable;
-
- /**
- * Set the collapsed state of the chrome navigation.
- */
- setIsCollapsed(isCollapsed: boolean): void;
-
/**
* Get the current set of classNames that will be set on the application container.
*/
@@ -413,6 +403,11 @@ export interface ChromeStart {
* @param url The updated support URL
*/
setHelpSupportUrl(url: string): void;
+
+ /**
+ * Get an observable of the current locked state of the nav drawer.
+ */
+ getIsNavDrawerLocked$(): Observable;
}
/** @internal */
diff --git a/src/core/public/chrome/ui/_loading_indicator.scss b/src/core/public/chrome/ui/_loading_indicator.scss
index 80694347393ce..026c23b93b040 100644
--- a/src/core/public/chrome/ui/_loading_indicator.scss
+++ b/src/core/public/chrome/ui/_loading_indicator.scss
@@ -22,29 +22,34 @@ $kbnLoadingIndicatorColor2: tint($euiColorAccent, 60%);
}
}
- .kbnLoadingIndicator__bar {
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- position: absolute;
- z-index: $euiZLevel1 + 1;
- visibility: visible;
- display: block;
- animation: kbn-animate-loading-indicator 2s linear infinite;
- background-color: $kbnLoadingIndicatorColor2;
- background-image: linear-gradient(to right,
- $kbnLoadingIndicatorColor1 0%,
- $kbnLoadingIndicatorColor1 50%,
- $kbnLoadingIndicatorColor2 50%,
- $kbnLoadingIndicatorColor2 100%
- );
- background-repeat: repeat-x;
- background-size: $kbnLoadingIndicatorBackgroundSize $kbnLoadingIndicatorBackgroundSize;
- width: 200%;
- }
+.kbnLoadingIndicator__bar {
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ position: absolute;
+ z-index: $euiZLevel1 + 1;
+ visibility: visible;
+ display: block;
+ animation: kbn-animate-loading-indicator 2s linear infinite;
+ background-color: $kbnLoadingIndicatorColor2;
+ background-image: linear-gradient(
+ to right,
+ $kbnLoadingIndicatorColor1 0%,
+ $kbnLoadingIndicatorColor1 50%,
+ $kbnLoadingIndicatorColor2 50%,
+ $kbnLoadingIndicatorColor2 100%
+ );
+ background-repeat: repeat-x;
+ background-size: $kbnLoadingIndicatorBackgroundSize $kbnLoadingIndicatorBackgroundSize;
+ width: 200%;
+}
- @keyframes kbn-animate-loading-indicator {
- from { transform: translateX(0); }
- to { transform: translateX(-$kbnLoadingIndicatorBackgroundSize); }
+@keyframes kbn-animate-loading-indicator {
+ from {
+ transform: translateX(0);
}
+ to {
+ transform: translateX(-$kbnLoadingIndicatorBackgroundSize);
+ }
+}
diff --git a/src/core/public/chrome/ui/header/header.tsx b/src/core/public/chrome/ui/header/header.tsx
index c9a583f39b30c..4dec084fd8a83 100644
--- a/src/core/public/chrome/ui/header/header.tsx
+++ b/src/core/public/chrome/ui/header/header.tsx
@@ -30,6 +30,7 @@ import {
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import React, { Component, createRef } from 'react';
+import classnames from 'classnames';
import * as Rx from 'rxjs';
import {
ChromeBadge,
@@ -68,8 +69,8 @@ export interface HeaderProps {
navControlsLeft$: Rx.Observable;
navControlsRight$: Rx.Observable;
basePath: HttpStart['basePath'];
- isLocked?: boolean;
- onIsLockedUpdate?: OnIsLockedUpdate;
+ isLocked$: Rx.Observable;
+ onIsLockedUpdate: OnIsLockedUpdate;
}
interface State {
@@ -81,6 +82,7 @@ interface State {
navControlsLeft: readonly ChromeNavControl[];
navControlsRight: readonly ChromeNavControl[];
currentAppId: string | undefined;
+ isLocked: boolean;
}
export class Header extends Component {
@@ -99,6 +101,7 @@ export class Header extends Component {
navControlsLeft: [],
navControlsRight: [],
currentAppId: '',
+ isLocked: false,
};
}
@@ -109,11 +112,12 @@ export class Header extends Component {
this.props.forceAppSwitcherNavigation$,
this.props.navLinks$,
this.props.recentlyAccessed$,
- // Types for combineLatest only handle up to 6 inferred types so we combine these two separately.
+ // Types for combineLatest only handle up to 6 inferred types so we combine these separately.
Rx.combineLatest(
this.props.navControlsLeft$,
this.props.navControlsRight$,
- this.props.application.currentAppId$
+ this.props.application.currentAppId$,
+ this.props.isLocked$
)
).subscribe({
next: ([
@@ -122,7 +126,7 @@ export class Header extends Component {
forceNavigation,
navLinks,
recentlyAccessed,
- [navControlsLeft, navControlsRight, currentAppId],
+ [navControlsLeft, navControlsRight, currentAppId, isLocked],
]) => {
this.setState({
appTitle,
@@ -133,6 +137,7 @@ export class Header extends Component {
navControlsLeft,
navControlsRight,
currentAppId,
+ isLocked,
});
},
});
@@ -181,8 +186,16 @@ export class Header extends Component {
return null;
}
+ const className = classnames(
+ 'chrHeaderWrapper',
+ {
+ 'chrHeaderWrapper--navIsLocked': this.state.isLocked,
+ },
+ 'hide-for-sharing'
+ );
+
return (
-
+
@@ -220,7 +233,7 @@ export class Header extends Component {
= props => {
- const initialIsLocked = localStorage.getItem(IS_LOCKED_KEY);
- const [isLocked, setIsLocked] = useState(initialIsLocked === 'true');
- const setIsLockedStored = (locked: boolean) => {
- localStorage.setItem(IS_LOCKED_KEY, `${locked}`);
- setIsLocked(locked);
- };
- const className = classnames(
- 'chrHeaderWrapper',
- {
- 'chrHeaderWrapper--navIsLocked': isLocked,
- },
- 'hide-for-sharing'
- );
- return (
-
-
-
- );
-};
diff --git a/src/core/public/chrome/ui/header/index.ts b/src/core/public/chrome/ui/header/index.ts
index 4521f1f74b31b..49e002a66d939 100644
--- a/src/core/public/chrome/ui/header/index.ts
+++ b/src/core/public/chrome/ui/header/index.ts
@@ -18,7 +18,6 @@
*/
export { Header, HeaderProps } from './header';
-export { HeaderWrapper } from './header_wrapper';
export {
ChromeHelpExtensionMenuLink,
ChromeHelpExtensionMenuCustomLink,
diff --git a/src/core/public/chrome/ui/index.ts b/src/core/public/chrome/ui/index.ts
index 81b2fdfb0fcc0..460e19b7d9780 100644
--- a/src/core/public/chrome/ui/index.ts
+++ b/src/core/public/chrome/ui/index.ts
@@ -20,7 +20,6 @@
export { LoadingIndicator } from './loading_indicator';
export {
Header,
- HeaderWrapper,
ChromeHelpExtensionMenuLink,
ChromeHelpExtensionMenuCustomLink,
ChromeHelpExtensionMenuDiscussLink,
diff --git a/src/core/public/public.api.md b/src/core/public/public.api.md
index fa5dc745e6931..7428280b2dccb 100644
--- a/src/core/public/public.api.md
+++ b/src/core/public/public.api.md
@@ -337,7 +337,7 @@ export interface ChromeStart {
getBrand$(): Observable;
getBreadcrumbs$(): Observable;
getHelpExtension$(): Observable;
- getIsCollapsed$(): Observable;
+ getIsNavDrawerLocked$(): Observable;
getIsVisible$(): Observable;
navControls: ChromeNavControls;
navLinks: ChromeNavLinks;
@@ -349,7 +349,6 @@ export interface ChromeStart {
setBreadcrumbs(newBreadcrumbs: ChromeBreadcrumb[]): void;
setHelpExtension(helpExtension?: ChromeHelpExtension): void;
setHelpSupportUrl(url: string): void;
- setIsCollapsed(isCollapsed: boolean): void;
setIsVisible(isVisible: boolean): void;
}
diff --git a/src/core/server/http/router/route.ts b/src/core/server/http/router/route.ts
index bb0a8616e7222..9789d266587af 100644
--- a/src/core/server/http/router/route.ts
+++ b/src/core/server/http/router/route.ts
@@ -179,7 +179,7 @@ export interface RouteConfig {
* access to raw values.
* In some cases you may want to use another validation library. To do this, you need to
* instruct the `@kbn/config-schema` library to output **non-validated values** with
- * setting schema as `schema.object({}, { allowUnknowns: true })`;
+ * setting schema as `schema.object({}, { unknowns: 'allow' })`;
*
* @example
* ```ts
@@ -212,7 +212,7 @@ export interface RouteConfig
{
* path: 'path/{id}',
* validate: {
* // handler has access to raw non-validated params in runtime
- * params: schema.object({}, { allowUnknowns: true })
+ * params: schema.object({}, { unknowns: 'allow' })
* },
* },
* (context, req, res,) {
diff --git a/src/core/server/http/router/router.test.ts b/src/core/server/http/router/router.test.ts
index a936da6a40a9f..9655e2153b863 100644
--- a/src/core/server/http/router/router.test.ts
+++ b/src/core/server/http/router/router.test.ts
@@ -59,7 +59,7 @@ describe('Router', () => {
{
path: '/',
options: { body: { output: 'file' } } as any, // We explicitly don't support 'file'
- validate: { body: schema.object({}, { allowUnknowns: true }) },
+ validate: { body: schema.object({}, { unknowns: 'allow' }) },
},
(context, req, res) => res.ok({})
)
diff --git a/src/core/server/rendering/views/styles.tsx b/src/core/server/rendering/views/styles.tsx
index 9ab9f2ad0d6b8..71b42e3464118 100644
--- a/src/core/server/rendering/views/styles.tsx
+++ b/src/core/server/rendering/views/styles.tsx
@@ -53,7 +53,7 @@ export const Styles: FunctionComponent = ({ darkMode }) => {
.kbnWelcomeView {
line-height: 1.5;
- background-color: #FFF;
+ background-color: ${darkMode ? '#1D1E24' : '#FFF'};
height: 100%;
display: -webkit-box;
display: -webkit-flex;
@@ -97,6 +97,7 @@ export const Styles: FunctionComponent = ({ darkMode }) => {
line-height: 40px !important;
height: 40px !important;
color: #98a2b3;
+ color: ${darkMode ? '#98A2B3' : '#69707D'};
}
.kbnLoaderWrap {
@@ -128,7 +129,7 @@ export const Styles: FunctionComponent = ({ darkMode }) => {
width: 32px;
height: 4px;
overflow: hidden;
- background-color: #D3DAE6;
+ background-color: ${darkMode ? '#25262E' : '#F5F7FA'};
line-height: 1;
}
@@ -142,7 +143,7 @@ export const Styles: FunctionComponent = ({ darkMode }) => {
left: 0;
transform: scaleX(0) translateX(0%);
animation: kbnProgress 1s cubic-bezier(.694, .0482, .335, 1) infinite;
- background-color: #006DE4;
+ background-color: ${darkMode ? '#1BA9F5' : '#006DE4'};
}
@keyframes kbnProgress {
diff --git a/src/core/server/ui_settings/routes/set_many.ts b/src/core/server/ui_settings/routes/set_many.ts
index 5623c3fe11b80..d19a36a7ce768 100644
--- a/src/core/server/ui_settings/routes/set_many.ts
+++ b/src/core/server/ui_settings/routes/set_many.ts
@@ -24,7 +24,7 @@ import { CannotOverrideError } from '../ui_settings_errors';
const validate = {
body: schema.object({
- changes: schema.object({}, { allowUnknowns: true }),
+ changes: schema.object({}, { unknowns: 'allow' }),
}),
};
diff --git a/src/core/server/ui_settings/ui_settings_config.ts b/src/core/server/ui_settings/ui_settings_config.ts
index a54d482a0296a..a0ac48e2dd089 100644
--- a/src/core/server/ui_settings/ui_settings_config.ts
+++ b/src/core/server/ui_settings/ui_settings_config.ts
@@ -39,7 +39,7 @@ const configSchema = schema.object({
})
),
},
- { allowUnknowns: true }
+ { unknowns: 'allow' }
),
});
diff --git a/src/legacy/core_plugins/kibana/common/utils/__tests__/shorten_dotted_string.js b/src/legacy/core_plugins/kibana/common/utils/__tests__/shorten_dotted_string.js
deleted file mode 100644
index 267ca74c7c42a..0000000000000
--- a/src/legacy/core_plugins/kibana/common/utils/__tests__/shorten_dotted_string.js
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Licensed to Elasticsearch B.V. under one or more contributor
- * license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright
- * ownership. Elasticsearch B.V. licenses this file to you under
- * the Apache License, Version 2.0 (the "License"); you may
- * not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import expect from '@kbn/expect';
-import { shortenDottedString } from '../shorten_dotted_string';
-
-describe('shortenDottedString', () => {
- it('Convert a dot.notated.string into a short string', () => {
- expect(shortenDottedString('dot.notated.string')).to.equal('d.n.string');
- });
-
- it('Ignores non-string values', () => {
- expect(shortenDottedString(true)).to.equal(true);
- expect(shortenDottedString(123)).to.equal(123);
- const obj = { key: 'val' };
- expect(shortenDottedString(obj)).to.equal(obj);
- });
-});
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/legacy_imports.ts b/src/legacy/core_plugins/kibana/public/dashboard/legacy_imports.ts
index b497f73f3df2a..3f81bfe5aadf2 100644
--- a/src/legacy/core_plugins/kibana/public/dashboard/legacy_imports.ts
+++ b/src/legacy/core_plugins/kibana/public/dashboard/legacy_imports.ts
@@ -33,7 +33,6 @@ export { IInjector } from 'ui/chrome';
export { absoluteToParsedUrl } from 'ui/url/absolute_to_parsed_url';
export {
configureAppAngularModule,
- ensureDefaultIndexPattern,
IPrivate,
migrateLegacyQuery,
PrivateProvider,
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/legacy_app.js b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/legacy_app.js
index f7baba663da75..64abbdfb87d58 100644
--- a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/legacy_app.js
+++ b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/legacy_app.js
@@ -23,11 +23,11 @@ import dashboardTemplate from './dashboard_app.html';
import dashboardListingTemplate from './listing/dashboard_listing_ng_wrapper.html';
import { createHashHistory } from 'history';
-import { ensureDefaultIndexPattern } from '../legacy_imports';
import { initDashboardAppDirective } from './dashboard_app';
import { createDashboardEditUrl, DashboardConstants } from './dashboard_constants';
import {
createKbnUrlStateStorage,
+ ensureDefaultIndexPattern,
redirectWhenMissing,
InvalidJSONProperty,
SavedObjectNotFound,
@@ -137,8 +137,8 @@ export function initDashboardApp(app, deps) {
});
},
resolve: {
- dash: function($rootScope, $route, kbnUrl, history) {
- return ensureDefaultIndexPattern(deps.core, deps.data, $rootScope, kbnUrl).then(() => {
+ dash: function($route, history) {
+ return ensureDefaultIndexPattern(deps.core, deps.data, history).then(() => {
const savedObjectsClient = deps.savedObjectsClient;
const title = $route.current.params.title;
if (title) {
@@ -172,11 +172,9 @@ export function initDashboardApp(app, deps) {
controller: createNewDashboardCtrl,
requireUICapability: 'dashboard.createNew',
resolve: {
- dash: function($rootScope, kbnUrl, history) {
- return ensureDefaultIndexPattern(deps.core, deps.data, $rootScope, kbnUrl)
- .then(() => {
- return deps.savedDashboards.get();
- })
+ dash: history =>
+ ensureDefaultIndexPattern(deps.core, deps.data, history)
+ .then(() => deps.savedDashboards.get())
.catch(
redirectWhenMissing({
history,
@@ -185,8 +183,7 @@ export function initDashboardApp(app, deps) {
},
toastNotifications: deps.core.notifications.toasts,
})
- );
- },
+ ),
},
})
.when(createDashboardEditUrl(':id'), {
@@ -194,13 +191,11 @@ export function initDashboardApp(app, deps) {
template: dashboardTemplate,
controller: createNewDashboardCtrl,
resolve: {
- dash: function($rootScope, $route, kbnUrl, history) {
+ dash: function($route, kbnUrl, history) {
const id = $route.current.params.id;
- return ensureDefaultIndexPattern(deps.core, deps.data, $rootScope, kbnUrl)
- .then(() => {
- return deps.savedDashboards.get(id);
- })
+ return ensureDefaultIndexPattern(deps.core, deps.data, history)
+ .then(() => deps.savedDashboards.get(id))
.then(savedDashboard => {
deps.chrome.recentlyAccessed.add(
savedDashboard.getFullPath(),
diff --git a/src/legacy/core_plugins/kibana/public/discover/kibana_services.ts b/src/legacy/core_plugins/kibana/public/discover/kibana_services.ts
index 8202ba13b30cc..725e94f16e2e8 100644
--- a/src/legacy/core_plugins/kibana/public/discover/kibana_services.ts
+++ b/src/legacy/core_plugins/kibana/public/discover/kibana_services.ts
@@ -53,17 +53,18 @@ export { wrapInI18nContext } from 'ui/i18n';
import { search } from '../../../../../plugins/data/public';
export const { getRequestInspectorStats, getResponseInspectorStats, tabifyAggResponse } = search;
// @ts-ignore
-export { shortenDottedString } from '../../common/utils/shorten_dotted_string';
-// @ts-ignore
export { intervalOptions } from 'ui/agg_types';
-export { subscribeWithScope } from '../../../../../plugins/kibana_legacy/public';
// @ts-ignore
export { timezoneProvider } from 'ui/vis/lib/timezone';
-export { unhashUrl, redirectWhenMissing } from '../../../../../plugins/kibana_utils/public';
export {
+ unhashUrl,
+ redirectWhenMissing,
ensureDefaultIndexPattern,
+} from '../../../../../plugins/kibana_utils/public';
+export {
formatMsg,
formatStack,
+ subscribeWithScope,
} from '../../../../../plugins/kibana_legacy/public';
// EXPORT types
diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/field_name/field_name.tsx b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/field_name/field_name.tsx
index 26d8a5abb2471..1b3b16332fa4f 100644
--- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/field_name/field_name.tsx
+++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/field_name/field_name.tsx
@@ -21,7 +21,7 @@ import classNames from 'classnames';
import { EuiFlexGroup, EuiFlexItem, EuiToolTip } from '@elastic/eui';
import { FieldIcon, FieldIconProps } from '../../../../../../../../../plugins/kibana_react/public';
-import { shortenDottedString } from '../../../../kibana_services';
+import { shortenDottedString } from '../../../helpers';
import { getFieldTypeName } from './field_type_name';
// property field is provided at discover's field chooser
diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover.js b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover.js
index 6978781fe6696..9a383565f4f43 100644
--- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover.js
+++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover.js
@@ -115,9 +115,9 @@ app.config($routeProvider => {
template: indexTemplate,
reloadOnSearch: false,
resolve: {
- savedObjects: function($route, kbnUrl, Promise, $rootScope) {
+ savedObjects: function($route, Promise) {
const savedSearchId = $route.current.params.id;
- return ensureDefaultIndexPattern(core, data, $rootScope, kbnUrl).then(() => {
+ return ensureDefaultIndexPattern(core, data, history).then(() => {
const { appStateContainer } = getState({ history });
const { index } = appStateContainer.getState();
return Promise.props({
diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/components/table_header/helpers.tsx b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/components/table_header/helpers.tsx
index a2ad18d59d935..bd48b1e083871 100644
--- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/components/table_header/helpers.tsx
+++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/components/table_header/helpers.tsx
@@ -16,7 +16,8 @@
* specific language governing permissions and limitations
* under the License.
*/
-import { IndexPattern, shortenDottedString } from '../../../../../kibana_services';
+import { IndexPattern } from '../../../../../kibana_services';
+import { shortenDottedString } from '../../../../helpers';
export type SortOrder = [string, string];
export interface ColumnProps {
diff --git a/src/legacy/ui/public/chrome/services/index.js b/src/legacy/core_plugins/kibana/public/discover/np_ready/helpers/index.ts
similarity index 92%
rename from src/legacy/ui/public/chrome/services/index.js
rename to src/legacy/core_plugins/kibana/public/discover/np_ready/helpers/index.ts
index 3b3967f51b2ff..7196c96989e97 100644
--- a/src/legacy/ui/public/chrome/services/index.js
+++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/helpers/index.ts
@@ -17,4 +17,4 @@
* under the License.
*/
-import './global_nav_state';
+export { shortenDottedString } from './shorten_dotted_string';
diff --git a/src/legacy/core_plugins/kibana/common/utils/shorten_dotted_string.js b/src/legacy/core_plugins/kibana/public/discover/np_ready/helpers/shorten_dotted_string.ts
similarity index 81%
rename from src/legacy/core_plugins/kibana/common/utils/shorten_dotted_string.js
rename to src/legacy/core_plugins/kibana/public/discover/np_ready/helpers/shorten_dotted_string.ts
index ca76a2a537742..9d78a96784339 100644
--- a/src/legacy/core_plugins/kibana/common/utils/shorten_dotted_string.js
+++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/helpers/shorten_dotted_string.ts
@@ -22,10 +22,5 @@ const DOT_PREFIX_RE = /(.).+?\./g;
/**
* Convert a dot.notated.string into a short
* version (d.n.string)
- *
- * @param {string} str - the long string to convert
- * @return {string}
*/
-export function shortenDottedString(input) {
- return typeof input !== 'string' ? input : input.replace(DOT_PREFIX_RE, '$1.');
-}
+export const shortenDottedString = (input: string) => input.replace(DOT_PREFIX_RE, '$1.');
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/table/__jest__/__snapshots__/table.test.js.snap b/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/table/__jest__/__snapshots__/table.test.js.snap
index 805131042f385..a4dcfb9c38184 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/table/__jest__/__snapshots__/table.test.js.snap
+++ b/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/table/__jest__/__snapshots__/table.test.js.snap
@@ -126,6 +126,7 @@ exports[`Table prevents saved objects from being deleted 1`] = `
Array [
Object {
"align": "center",
+ "data-test-subj": "savedObjectsTableRowType",
"description": "Type of the saved object",
"field": "type",
"name": "Type",
@@ -134,6 +135,7 @@ exports[`Table prevents saved objects from being deleted 1`] = `
"width": "50px",
},
Object {
+ "data-test-subj": "savedObjectsTableRowTitle",
"dataType": "string",
"description": "Title of the saved object",
"field": "meta.title",
@@ -145,6 +147,7 @@ exports[`Table prevents saved objects from being deleted 1`] = `
"actions": Array [
Object {
"available": [Function],
+ "data-test-subj": "savedObjectsTableAction-inspect",
"description": "Inspect this saved object",
"icon": "inspect",
"name": "Inspect",
@@ -152,6 +155,7 @@ exports[`Table prevents saved objects from being deleted 1`] = `
"type": "icon",
},
Object {
+ "data-test-subj": "savedObjectsTableAction-relationships",
"description": "View the relationships this saved object has to other saved objects",
"icon": "kqlSelector",
"name": "Relationships",
@@ -198,6 +202,7 @@ exports[`Table prevents saved objects from being deleted 1`] = `
}
}
responsive={true}
+ rowProps={[Function]}
selection={
Object {
"onSelectionChange": [Function],
@@ -334,6 +339,7 @@ exports[`Table should render normally 1`] = `
Array [
Object {
"align": "center",
+ "data-test-subj": "savedObjectsTableRowType",
"description": "Type of the saved object",
"field": "type",
"name": "Type",
@@ -342,6 +348,7 @@ exports[`Table should render normally 1`] = `
"width": "50px",
},
Object {
+ "data-test-subj": "savedObjectsTableRowTitle",
"dataType": "string",
"description": "Title of the saved object",
"field": "meta.title",
@@ -353,6 +360,7 @@ exports[`Table should render normally 1`] = `
"actions": Array [
Object {
"available": [Function],
+ "data-test-subj": "savedObjectsTableAction-inspect",
"description": "Inspect this saved object",
"icon": "inspect",
"name": "Inspect",
@@ -360,6 +368,7 @@ exports[`Table should render normally 1`] = `
"type": "icon",
},
Object {
+ "data-test-subj": "savedObjectsTableAction-relationships",
"description": "View the relationships this saved object has to other saved objects",
"icon": "kqlSelector",
"name": "Relationships",
@@ -406,6 +415,7 @@ exports[`Table should render normally 1`] = `
}
}
responsive={true}
+ rowProps={[Function]}
selection={
Object {
"onSelectionChange": [Function],
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/table/table.js b/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/table/table.js
index a119817fdc0c9..386b35399b754 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/table/table.js
+++ b/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/table/table.js
@@ -178,6 +178,7 @@ export class Table extends PureComponent {
{ defaultMessage: 'Type of the saved object' }
),
sortable: false,
+ 'data-test-subj': 'savedObjectsTableRowType',
render: (type, object) => {
return (
@@ -201,6 +202,7 @@ export class Table extends PureComponent {
),
dataType: 'string',
sortable: false,
+ 'data-test-subj': 'savedObjectsTableRowTitle',
render: (title, object) => {
const { path } = object.meta.inAppUrl || {};
const canGoInApp = this.props.canGoInApp(object);
@@ -230,6 +232,7 @@ export class Table extends PureComponent {
icon: 'inspect',
onClick: object => goInspectObject(object),
available: object => !!object.meta.editUrl,
+ 'data-test-subj': 'savedObjectsTableAction-inspect',
},
{
name: i18n.translate(
@@ -246,10 +249,12 @@ export class Table extends PureComponent {
type: 'icon',
icon: 'kqlSelector',
onClick: object => onShowRelationships(object),
+ 'data-test-subj': 'savedObjectsTableAction-relationships',
},
...this.extraActions.map(action => {
return {
...action.euiAction,
+ 'data-test-subj': `savedObjectsTableAction-${action.id}`,
onClick: object => {
this.setState({
activeAction: action,
@@ -372,6 +377,9 @@ export class Table extends PureComponent {
pagination={pagination}
selection={selection}
onChange={onTableChange}
+ rowProps={item => ({
+ 'data-test-subj': `savedObjectsTableRow row-${item.id}`,
+ })}
/>
diff --git a/src/legacy/core_plugins/kibana/public/visualize/legacy_imports.ts b/src/legacy/core_plugins/kibana/public/visualize/legacy_imports.ts
index 69af466a03729..e6b7a29e28d89 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/legacy_imports.ts
+++ b/src/legacy/core_plugins/kibana/public/visualize/legacy_imports.ts
@@ -33,7 +33,6 @@ export { DashboardConstants } from '../dashboard/np_ready/dashboard_constants';
export { VisSavedObject, VISUALIZE_EMBEDDABLE_TYPE } from '../../../visualizations/public/';
export {
configureAppAngularModule,
- ensureDefaultIndexPattern,
IPrivate,
migrateLegacyQuery,
PrivateProvider,
diff --git a/src/legacy/core_plugins/kibana/public/visualize/np_ready/legacy_app.js b/src/legacy/core_plugins/kibana/public/visualize/np_ready/legacy_app.js
index 1002f401706cd..0f1d50b149cd9 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/np_ready/legacy_app.js
+++ b/src/legacy/core_plugins/kibana/public/visualize/np_ready/legacy_app.js
@@ -24,6 +24,7 @@ import { createHashHistory } from 'history';
import {
createKbnUrlStateStorage,
redirectWhenMissing,
+ ensureDefaultIndexPattern,
} from '../../../../../../plugins/kibana_utils/public';
import editorTemplate from './editor/editor.html';
@@ -32,7 +33,6 @@ import visualizeListingTemplate from './listing/visualize_listing.html';
import { initVisualizeAppDirective } from './visualize_app';
import { VisualizeConstants } from './visualize_constants';
import { VisualizeListingController } from './listing/visualize_listing';
-import { ensureDefaultIndexPattern } from '../legacy_imports';
import {
getLandingBreadcrumbs,
@@ -82,8 +82,7 @@ export function initVisualizeApp(app, deps) {
controllerAs: 'listingController',
resolve: {
createNewVis: () => false,
- hasDefaultIndex: ($rootScope, kbnUrl) =>
- ensureDefaultIndexPattern(deps.core, deps.data, $rootScope, kbnUrl),
+ hasDefaultIndex: history => ensureDefaultIndexPattern(deps.core, deps.data, history),
},
})
.when(VisualizeConstants.WIZARD_STEP_1_PAGE_PATH, {
@@ -94,8 +93,7 @@ export function initVisualizeApp(app, deps) {
controllerAs: 'listingController',
resolve: {
createNewVis: () => true,
- hasDefaultIndex: ($rootScope, kbnUrl) =>
- ensureDefaultIndexPattern(deps.core, deps.data, $rootScope, kbnUrl),
+ hasDefaultIndex: history => ensureDefaultIndexPattern(deps.core, deps.data, history),
},
})
.when(VisualizeConstants.CREATE_PATH, {
@@ -103,7 +101,7 @@ export function initVisualizeApp(app, deps) {
template: editorTemplate,
k7Breadcrumbs: getCreateBreadcrumbs,
resolve: {
- savedVis: function($route, $rootScope, kbnUrl, history) {
+ savedVis: function($route, history) {
const { core, data, savedVisualizations, visualizations, toastNotifications } = deps;
const visTypes = visualizations.all();
const visType = find(visTypes, { name: $route.current.params.type });
@@ -121,7 +119,7 @@ export function initVisualizeApp(app, deps) {
);
}
- return ensureDefaultIndexPattern(core, data, $rootScope, kbnUrl)
+ return ensureDefaultIndexPattern(core, data, history)
.then(() => savedVisualizations.get($route.current.params))
.then(savedVis => {
if (savedVis.vis.type.setup) {
@@ -144,9 +142,9 @@ export function initVisualizeApp(app, deps) {
template: editorTemplate,
k7Breadcrumbs: getEditBreadcrumbs,
resolve: {
- savedVis: function($route, $rootScope, kbnUrl, history) {
+ savedVis: function($route, history) {
const { chrome, core, data, savedVisualizations, toastNotifications } = deps;
- return ensureDefaultIndexPattern(core, data, $rootScope, kbnUrl)
+ return ensureDefaultIndexPattern(core, data, history)
.then(() => savedVisualizations.get($route.current.params.id))
.then(savedVis => {
chrome.recentlyAccessed.add(savedVis.getFullPath(), savedVis.title, savedVis.id);
diff --git a/src/legacy/ui/public/chrome/chrome.js b/src/legacy/ui/public/chrome/chrome.js
index 3355870eabfe7..7a75ad906a870 100644
--- a/src/legacy/ui/public/chrome/chrome.js
+++ b/src/legacy/ui/public/chrome/chrome.js
@@ -28,7 +28,6 @@ import '../private';
import '../promises';
import '../directives/storage';
import '../directives/watch_multi';
-import './services';
import '../react_components';
import '../i18n';
diff --git a/src/legacy/ui/public/chrome/services/global_nav_state.js b/src/legacy/ui/public/chrome/services/global_nav_state.js
deleted file mode 100644
index 5a67806852fe8..0000000000000
--- a/src/legacy/ui/public/chrome/services/global_nav_state.js
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Licensed to Elasticsearch B.V. under one or more contributor
- * license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright
- * ownership. Elasticsearch B.V. licenses this file to you under
- * the Apache License, Version 2.0 (the "License"); you may
- * not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import { distinctUntilChanged } from 'rxjs/operators';
-import { npStart } from 'ui/new_platform';
-import { uiModules } from '../../modules';
-
-const newPlatformChrome = npStart.core.chrome;
-
-uiModules.get('kibana').service('globalNavState', $rootScope => {
- let isOpen = false;
- newPlatformChrome
- .getIsCollapsed$()
- .pipe(distinctUntilChanged())
- .subscribe(isCollapsed => {
- $rootScope.$evalAsync(() => {
- isOpen = !isCollapsed;
- $rootScope.$broadcast('globalNavState:change');
- });
- });
-
- return {
- isOpen: () => isOpen,
-
- setOpen: newValue => {
- newPlatformChrome.setIsCollapsed(!newValue);
- },
- };
-});
diff --git a/src/legacy/ui/public/exit_full_screen/__snapshots__/exit_full_screen_button.test.js.snap b/src/legacy/ui/public/exit_full_screen/__snapshots__/exit_full_screen_button.test.js.snap
index 27226eb010ba2..365f3afdab395 100644
--- a/src/legacy/ui/public/exit_full_screen/__snapshots__/exit_full_screen_button.test.js.snap
+++ b/src/legacy/ui/public/exit_full_screen/__snapshots__/exit_full_screen_button.test.js.snap
@@ -12,19 +12,45 @@ exports[`is rendered 1`] = `
-
- Exit full screen
+ class="euiFlexItem euiFlexItem--flexGrowZero"
+ >
+
+
+
+
diff --git a/src/legacy/ui/public/legacy_compat/index.ts b/src/legacy/ui/public/legacy_compat/index.ts
index 3b700c8d59399..2067fa6489304 100644
--- a/src/legacy/ui/public/legacy_compat/index.ts
+++ b/src/legacy/ui/public/legacy_compat/index.ts
@@ -17,7 +17,4 @@
* under the License.
*/
-export {
- configureAppAngularModule,
- ensureDefaultIndexPattern,
-} from '../../../../plugins/kibana_legacy/public';
+export { configureAppAngularModule } from '../../../../plugins/kibana_legacy/public';
diff --git a/src/legacy/ui/public/new_platform/new_platform.karma_mock.js b/src/legacy/ui/public/new_platform/new_platform.karma_mock.js
index ea84ba1ad2838..c58a7d2fbb5cd 100644
--- a/src/legacy/ui/public/new_platform/new_platform.karma_mock.js
+++ b/src/legacy/ui/public/new_platform/new_platform.karma_mock.js
@@ -21,13 +21,15 @@ import sinon from 'sinon';
import { getFieldFormatsRegistry } from '../../../../test_utils/public/stub_field_formats';
import { METRIC_TYPE } from '@kbn/analytics';
import {
+ setFieldFormats,
setIndexPatterns,
- setQueryService,
- setUiSettings,
setInjectedMetadata,
- setFieldFormats,
- setSearchService,
+ setHttp,
+ setNotifications,
setOverlays,
+ setQueryService,
+ setSearchService,
+ setUiSettings,
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
} from '../../../../plugins/data/public/services';
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
@@ -477,11 +479,13 @@ export function __start__(coreStart) {
// Services that need to be set in the legacy platform since the legacy data plugin
// which previously provided them has been removed.
+ setHttp(npStart.core.http);
+ setNotifications(npStart.core.notifications);
+ setOverlays(npStart.core.overlays);
setUiSettings(npStart.core.uiSettings);
- setQueryService(npStart.plugins.data.query);
- setIndexPatterns(npStart.plugins.data.indexPatterns);
setFieldFormats(npStart.plugins.data.fieldFormats);
+ setIndexPatterns(npStart.plugins.data.indexPatterns);
+ setQueryService(npStart.plugins.data.query);
setSearchService(npStart.plugins.data.search);
setAggs(npStart.plugins.data.search.aggs);
- setOverlays(npStart.core.overlays);
}
diff --git a/src/legacy/ui/public/new_platform/new_platform.test.ts b/src/legacy/ui/public/new_platform/new_platform.test.ts
index 498f05457bba9..dd41093f3a1f0 100644
--- a/src/legacy/ui/public/new_platform/new_platform.test.ts
+++ b/src/legacy/ui/public/new_platform/new_platform.test.ts
@@ -20,8 +20,19 @@
jest.mock('history');
import { setRootControllerMock, historyMock } from './new_platform.test.mocks';
-import { legacyAppRegister, __reset__, __setup__ } from './new_platform';
+import {
+ legacyAppRegister,
+ __reset__,
+ __setup__,
+ __start__,
+ PluginsSetup,
+ PluginsStart,
+} from './new_platform';
+// eslint-disable-next-line @kbn/eslint/no-restricted-paths
+import * as dataServices from '../../../../plugins/data/public/services';
+import { LegacyCoreSetup, LegacyCoreStart } from '../../../../core/public';
import { coreMock } from '../../../../core/public/mocks';
+import { npSetup, npStart } from './__mocks__';
describe('ui/new_platform', () => {
describe('legacyAppRegister', () => {
@@ -108,4 +119,25 @@ describe('ui/new_platform', () => {
expect(unmountMock).toHaveBeenCalled();
});
});
+
+ describe('service getters', () => {
+ const services: Record = dataServices;
+ const getters = Object.keys(services).filter(k => k.substring(0, 3) === 'get');
+
+ getters.forEach(g => {
+ it(`sets a value for ${g}`, () => {
+ __reset__();
+ __setup__(
+ (coreMock.createSetup() as unknown) as LegacyCoreSetup,
+ (npSetup.plugins as unknown) as PluginsSetup
+ );
+ __start__(
+ (coreMock.createStart() as unknown) as LegacyCoreStart,
+ (npStart.plugins as unknown) as PluginsStart
+ );
+
+ expect(services[g]()).toBeDefined();
+ });
+ });
+ });
});
diff --git a/src/legacy/ui/public/new_platform/new_platform.ts b/src/legacy/ui/public/new_platform/new_platform.ts
index 07e17ad562291..deb8387fee29c 100644
--- a/src/legacy/ui/public/new_platform/new_platform.ts
+++ b/src/legacy/ui/public/new_platform/new_platform.ts
@@ -31,13 +31,15 @@ import {
} from '../../../../core/public';
import { Plugin as DataPlugin } from '../../../../plugins/data/public';
import {
+ setFieldFormats,
setIndexPatterns,
- setQueryService,
- setUiSettings,
setInjectedMetadata,
- setFieldFormats,
- setSearchService,
+ setHttp,
+ setNotifications,
setOverlays,
+ setQueryService,
+ setSearchService,
+ setUiSettings,
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
} from '../../../../plugins/data/public/services';
import { Plugin as ExpressionsPlugin } from '../../../../plugins/expressions/public';
@@ -141,12 +143,14 @@ export function __start__(coreStart: LegacyCoreStart, plugins: PluginsStart) {
// Services that need to be set in the legacy platform since the legacy data plugin
// which previously provided them has been removed.
+ setHttp(npStart.core.http);
+ setNotifications(npStart.core.notifications);
+ setOverlays(npStart.core.overlays);
setUiSettings(npStart.core.uiSettings);
- setQueryService(npStart.plugins.data.query);
- setIndexPatterns(npStart.plugins.data.indexPatterns);
setFieldFormats(npStart.plugins.data.fieldFormats);
+ setIndexPatterns(npStart.plugins.data.indexPatterns);
+ setQueryService(npStart.plugins.data.query);
setSearchService(npStart.plugins.data.search);
- setOverlays(npStart.core.overlays);
}
/** Flag used to ensure `legacyAppRegister` is only called once. */
diff --git a/src/legacy/ui/public/vis/map/service_settings.js b/src/legacy/ui/public/vis/map/service_settings.js
index 233ee526c439b..9f3d21831e3da 100644
--- a/src/legacy/ui/public/vis/map/service_settings.js
+++ b/src/legacy/ui/public/vis/map/service_settings.js
@@ -47,7 +47,8 @@ uiModules
this._showZoomMessage = true;
this._emsClient = new EMSClient({
language: i18n.getLocale(),
- kbnVersion: kbnVersion,
+ appVersion: kbnVersion,
+ appName: 'kibana',
fileApiUrl: mapConfig.emsFileApiUrl,
tileApiUrl: mapConfig.emsTileApiUrl,
htmlSanitizer: $sanitize,
diff --git a/src/plugins/console/public/lib/kb/kb.js b/src/plugins/console/public/lib/kb/kb.js
index 95896bed02988..053b82bd81d0a 100644
--- a/src/plugins/console/public/lib/kb/kb.js
+++ b/src/plugins/console/public/lib/kb/kb.js
@@ -147,13 +147,9 @@ function loadApisFromJson(
}
export function setActiveApi(api) {
- if (_.isString(api)) {
+ if (!api) {
$.ajax({
- url:
- '../api/console/api_server?sense_version=' +
- encodeURIComponent('@@SENSE_VERSION') +
- '&apis=' +
- encodeURIComponent(api),
+ url: '../api/console/api_server',
dataType: 'json', // disable automatic guessing
}).then(
function(data) {
@@ -169,7 +165,7 @@ export function setActiveApi(api) {
ACTIVE_API = api;
}
-setActiveApi('es_6_0');
+setActiveApi();
export const _test = {
loadApisFromJson: loadApisFromJson,
diff --git a/src/plugins/console/server/lib/index.ts b/src/plugins/console/server/lib/index.ts
index 98004768f880b..2347084b73a66 100644
--- a/src/plugins/console/server/lib/index.ts
+++ b/src/plugins/console/server/lib/index.ts
@@ -22,4 +22,4 @@ export { ProxyConfigCollection } from './proxy_config_collection';
export { proxyRequest } from './proxy_request';
export { getElasticsearchProxyConfig } from './elasticsearch_proxy_config';
export { setHeaders } from './set_headers';
-export { addProcessorDefinition, addExtensionSpecFilePath } from './spec_definitions';
+export { addProcessorDefinition, addExtensionSpecFilePath, loadSpec } from './spec_definitions';
diff --git a/src/plugins/console/server/lib/spec_definitions/es_6_0.js b/src/plugins/console/server/lib/spec_definitions/es.js
similarity index 54%
rename from src/plugins/console/server/lib/spec_definitions/es_6_0.js
rename to src/plugins/console/server/lib/spec_definitions/es.js
index 171d232407956..fc24a64f8a6f4 100644
--- a/src/plugins/console/server/lib/spec_definitions/es_6_0.js
+++ b/src/plugins/console/server/lib/spec_definitions/es.js
@@ -18,26 +18,30 @@
*/
import Api from './api';
-import { getSpec } from './spec';
-import { register } from './es_6_0/ingest';
-const ES_6_0 = new Api('es_6_0');
-const spec = getSpec();
+import { getSpec } from './json';
+import { register } from './js/ingest';
+const ES = new Api('es');
-// adding generated specs
-Object.keys(spec).forEach(endpoint => {
- ES_6_0.addEndpointDescription(endpoint, spec[endpoint]);
-});
+export const loadSpec = () => {
+ const spec = getSpec();
-//adding globals and custom API definitions
-require('./es_6_0/aliases')(ES_6_0);
-require('./es_6_0/aggregations')(ES_6_0);
-require('./es_6_0/document')(ES_6_0);
-require('./es_6_0/filter')(ES_6_0);
-require('./es_6_0/globals')(ES_6_0);
-register(ES_6_0);
-require('./es_6_0/mappings')(ES_6_0);
-require('./es_6_0/query')(ES_6_0);
-require('./es_6_0/reindex')(ES_6_0);
-require('./es_6_0/search')(ES_6_0);
+ // adding generated specs
+ Object.keys(spec).forEach(endpoint => {
+ ES.addEndpointDescription(endpoint, spec[endpoint]);
+ });
-export default ES_6_0;
+ // adding globals and custom API definitions
+ require('./js/aliases')(ES);
+ require('./js/aggregations')(ES);
+ require('./js/document')(ES);
+ require('./js/filter')(ES);
+ require('./js/globals')(ES);
+ register(ES);
+ require('./js/mappings')(ES);
+ require('./js/settings')(ES);
+ require('./js/query')(ES);
+ require('./js/reindex')(ES);
+ require('./js/search')(ES);
+};
+
+export default ES;
diff --git a/src/plugins/console/server/lib/spec_definitions/index.d.ts b/src/plugins/console/server/lib/spec_definitions/index.d.ts
index 0a79d3fb386f1..da0125a186c15 100644
--- a/src/plugins/console/server/lib/spec_definitions/index.d.ts
+++ b/src/plugins/console/server/lib/spec_definitions/index.d.ts
@@ -19,6 +19,13 @@
export declare function addProcessorDefinition(...args: any[]): any;
-export declare function resolveApi(senseVersion: string, apis: string[]): object;
+export declare function resolveApi(): object;
export declare function addExtensionSpecFilePath(...args: any[]): any;
+
+/**
+ * A function that synchronously reads files JSON from disk and builds
+ * the autocomplete structures served to the client. This must be called
+ * after any extensions have been loaded.
+ */
+export declare function loadSpec(): any;
diff --git a/src/plugins/console/server/lib/spec_definitions/index.js b/src/plugins/console/server/lib/spec_definitions/index.js
index 3fe1913d5a193..abf55639fbee8 100644
--- a/src/plugins/console/server/lib/spec_definitions/index.js
+++ b/src/plugins/console/server/lib/spec_definitions/index.js
@@ -17,8 +17,10 @@
* under the License.
*/
-export { addProcessorDefinition } from './es_6_0/ingest';
+export { addProcessorDefinition } from './js/ingest';
-export { addExtensionSpecFilePath } from './spec';
+export { addExtensionSpecFilePath } from './json';
+
+export { loadSpec } from './es';
export { resolveApi } from './server';
diff --git a/src/plugins/console/server/lib/spec_definitions/es_6_0/aggregations.js b/src/plugins/console/server/lib/spec_definitions/js/aggregations.js
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/es_6_0/aggregations.js
rename to src/plugins/console/server/lib/spec_definitions/js/aggregations.js
diff --git a/src/plugins/console/server/lib/spec_definitions/es_6_0/aliases.js b/src/plugins/console/server/lib/spec_definitions/js/aliases.js
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/es_6_0/aliases.js
rename to src/plugins/console/server/lib/spec_definitions/js/aliases.js
diff --git a/src/plugins/console/server/lib/spec_definitions/es_6_0/document.js b/src/plugins/console/server/lib/spec_definitions/js/document.js
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/es_6_0/document.js
rename to src/plugins/console/server/lib/spec_definitions/js/document.js
diff --git a/src/plugins/console/server/lib/spec_definitions/es_6_0/filter.js b/src/plugins/console/server/lib/spec_definitions/js/filter.js
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/es_6_0/filter.js
rename to src/plugins/console/server/lib/spec_definitions/js/filter.js
diff --git a/src/plugins/console/server/lib/spec_definitions/es_6_0/globals.js b/src/plugins/console/server/lib/spec_definitions/js/globals.js
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/es_6_0/globals.js
rename to src/plugins/console/server/lib/spec_definitions/js/globals.js
diff --git a/src/plugins/console/server/lib/spec_definitions/es_6_0/ingest.js b/src/plugins/console/server/lib/spec_definitions/js/ingest.js
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/es_6_0/ingest.js
rename to src/plugins/console/server/lib/spec_definitions/js/ingest.js
diff --git a/src/plugins/console/server/lib/spec_definitions/es_6_0/mappings.js b/src/plugins/console/server/lib/spec_definitions/js/mappings.js
similarity index 99%
rename from src/plugins/console/server/lib/spec_definitions/es_6_0/mappings.js
rename to src/plugins/console/server/lib/spec_definitions/js/mappings.js
index 8c31e5bc6fbb2..5884d14d4dc8b 100644
--- a/src/plugins/console/server/lib/spec_definitions/es_6_0/mappings.js
+++ b/src/plugins/console/server/lib/spec_definitions/js/mappings.js
@@ -19,9 +19,7 @@
const _ = require('lodash');
-const BOOLEAN = {
- __one_of: [true, false],
-};
+import { BOOLEAN } from './shared';
export default function(api) {
api.addEndpointDescription('put_mapping', {
diff --git a/src/plugins/console/server/lib/spec_definitions/es_6_0/query/dsl.js b/src/plugins/console/server/lib/spec_definitions/js/query/dsl.js
similarity index 99%
rename from src/plugins/console/server/lib/spec_definitions/es_6_0/query/dsl.js
rename to src/plugins/console/server/lib/spec_definitions/js/query/dsl.js
index a5f0d15dee0e9..16b952fe0fe4f 100644
--- a/src/plugins/console/server/lib/spec_definitions/es_6_0/query/dsl.js
+++ b/src/plugins/console/server/lib/spec_definitions/js/query/dsl.js
@@ -281,9 +281,11 @@ export function queryDsl(api) {
__scope_link: '.',
},
],
- filter: {
- __scope_link: 'GLOBAL.filter',
- },
+ filter: [
+ {
+ __scope_link: 'GLOBAL.filter',
+ },
+ ],
minimum_should_match: 1,
boost: 1.0,
},
diff --git a/src/plugins/console/server/lib/spec_definitions/es_6_0/query/index.js b/src/plugins/console/server/lib/spec_definitions/js/query/index.js
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/es_6_0/query/index.js
rename to src/plugins/console/server/lib/spec_definitions/js/query/index.js
diff --git a/src/plugins/console/server/lib/spec_definitions/es_6_0/query/templates.js b/src/plugins/console/server/lib/spec_definitions/js/query/templates.js
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/es_6_0/query/templates.js
rename to src/plugins/console/server/lib/spec_definitions/js/query/templates.js
diff --git a/src/plugins/console/server/lib/spec_definitions/es_6_0/reindex.js b/src/plugins/console/server/lib/spec_definitions/js/reindex.js
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/es_6_0/reindex.js
rename to src/plugins/console/server/lib/spec_definitions/js/reindex.js
diff --git a/src/plugins/console/server/lib/spec_definitions/es_6_0/search.js b/src/plugins/console/server/lib/spec_definitions/js/search.js
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/es_6_0/search.js
rename to src/plugins/console/server/lib/spec_definitions/js/search.js
diff --git a/src/plugins/console/server/lib/spec_definitions/js/settings.js b/src/plugins/console/server/lib/spec_definitions/js/settings.js
new file mode 100644
index 0000000000000..26cd0987c34a5
--- /dev/null
+++ b/src/plugins/console/server/lib/spec_definitions/js/settings.js
@@ -0,0 +1,74 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { BOOLEAN } from './shared';
+
+export default function(api) {
+ api.addEndpointDescription('put_settings', {
+ data_autocomplete_rules: {
+ refresh_interval: '1s',
+ number_of_shards: 1,
+ number_of_replicas: 1,
+ 'blocks.read_only': BOOLEAN,
+ 'blocks.read': BOOLEAN,
+ 'blocks.write': BOOLEAN,
+ 'blocks.metadata': BOOLEAN,
+ term_index_interval: 32,
+ term_index_divisor: 1,
+ 'translog.flush_threshold_ops': 5000,
+ 'translog.flush_threshold_size': '200mb',
+ 'translog.flush_threshold_period': '30m',
+ 'translog.disable_flush': BOOLEAN,
+ 'cache.filter.max_size': '2gb',
+ 'cache.filter.expire': '2h',
+ 'gateway.snapshot_interval': '10s',
+ routing: {
+ allocation: {
+ include: {
+ tag: '',
+ },
+ exclude: {
+ tag: '',
+ },
+ require: {
+ tag: '',
+ },
+ total_shards_per_node: -1,
+ },
+ },
+ 'recovery.initial_shards': {
+ __one_of: ['quorum', 'quorum-1', 'half', 'full', 'full-1'],
+ },
+ 'ttl.disable_purge': BOOLEAN,
+ analysis: {
+ analyzer: {},
+ tokenizer: {},
+ filter: {},
+ char_filter: {},
+ },
+ 'cache.query.enable': BOOLEAN,
+ shadow_replicas: BOOLEAN,
+ shared_filesystem: BOOLEAN,
+ data_path: 'path',
+ codec: {
+ __one_of: ['default', 'best_compression', 'lucene_default'],
+ },
+ },
+ });
+}
diff --git a/src/legacy/ui/public/indices/index.js b/src/plugins/console/server/lib/spec_definitions/js/shared.js
similarity index 81%
rename from src/legacy/ui/public/indices/index.js
rename to src/plugins/console/server/lib/spec_definitions/js/shared.js
index c1646bd66e367..ace189e2d0913 100644
--- a/src/legacy/ui/public/indices/index.js
+++ b/src/plugins/console/server/lib/spec_definitions/js/shared.js
@@ -17,10 +17,6 @@
* under the License.
*/
-export { INDEX_ILLEGAL_CHARACTERS_VISIBLE } from './constants';
-
-export {
- indexNameBeginsWithPeriod,
- findIllegalCharactersInIndexName,
- indexNameContainsSpaces,
-} from './validate';
+export const BOOLEAN = Object.freeze({
+ __one_of: [true, false],
+});
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/.eslintrc b/src/plugins/console/server/lib/spec_definitions/json/.eslintrc
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/.eslintrc
rename to src/plugins/console/server/lib/spec_definitions/json/.eslintrc
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/_common.json b/src/plugins/console/server/lib/spec_definitions/json/generated/_common.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/_common.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/_common.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/bulk.json b/src/plugins/console/server/lib/spec_definitions/json/generated/bulk.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/bulk.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/bulk.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/cat.aliases.json b/src/plugins/console/server/lib/spec_definitions/json/generated/cat.aliases.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/cat.aliases.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/cat.aliases.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/cat.allocation.json b/src/plugins/console/server/lib/spec_definitions/json/generated/cat.allocation.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/cat.allocation.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/cat.allocation.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/cat.count.json b/src/plugins/console/server/lib/spec_definitions/json/generated/cat.count.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/cat.count.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/cat.count.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/cat.fielddata.json b/src/plugins/console/server/lib/spec_definitions/json/generated/cat.fielddata.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/cat.fielddata.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/cat.fielddata.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/cat.health.json b/src/plugins/console/server/lib/spec_definitions/json/generated/cat.health.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/cat.health.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/cat.health.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/cat.help.json b/src/plugins/console/server/lib/spec_definitions/json/generated/cat.help.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/cat.help.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/cat.help.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/cat.indices.json b/src/plugins/console/server/lib/spec_definitions/json/generated/cat.indices.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/cat.indices.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/cat.indices.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/cat.master.json b/src/plugins/console/server/lib/spec_definitions/json/generated/cat.master.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/cat.master.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/cat.master.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/cat.nodeattrs.json b/src/plugins/console/server/lib/spec_definitions/json/generated/cat.nodeattrs.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/cat.nodeattrs.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/cat.nodeattrs.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/cat.nodes.json b/src/plugins/console/server/lib/spec_definitions/json/generated/cat.nodes.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/cat.nodes.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/cat.nodes.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/cat.pending_tasks.json b/src/plugins/console/server/lib/spec_definitions/json/generated/cat.pending_tasks.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/cat.pending_tasks.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/cat.pending_tasks.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/cat.plugins.json b/src/plugins/console/server/lib/spec_definitions/json/generated/cat.plugins.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/cat.plugins.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/cat.plugins.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/cat.recovery.json b/src/plugins/console/server/lib/spec_definitions/json/generated/cat.recovery.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/cat.recovery.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/cat.recovery.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/cat.repositories.json b/src/plugins/console/server/lib/spec_definitions/json/generated/cat.repositories.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/cat.repositories.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/cat.repositories.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/cat.segments.json b/src/plugins/console/server/lib/spec_definitions/json/generated/cat.segments.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/cat.segments.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/cat.segments.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/cat.shards.json b/src/plugins/console/server/lib/spec_definitions/json/generated/cat.shards.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/cat.shards.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/cat.shards.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/cat.snapshots.json b/src/plugins/console/server/lib/spec_definitions/json/generated/cat.snapshots.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/cat.snapshots.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/cat.snapshots.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/cat.tasks.json b/src/plugins/console/server/lib/spec_definitions/json/generated/cat.tasks.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/cat.tasks.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/cat.tasks.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/cat.templates.json b/src/plugins/console/server/lib/spec_definitions/json/generated/cat.templates.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/cat.templates.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/cat.templates.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/cat.thread_pool.json b/src/plugins/console/server/lib/spec_definitions/json/generated/cat.thread_pool.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/cat.thread_pool.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/cat.thread_pool.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/clear_scroll.json b/src/plugins/console/server/lib/spec_definitions/json/generated/clear_scroll.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/clear_scroll.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/clear_scroll.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/cluster.allocation_explain.json b/src/plugins/console/server/lib/spec_definitions/json/generated/cluster.allocation_explain.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/cluster.allocation_explain.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/cluster.allocation_explain.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/cluster.get_settings.json b/src/plugins/console/server/lib/spec_definitions/json/generated/cluster.get_settings.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/cluster.get_settings.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/cluster.get_settings.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/cluster.health.json b/src/plugins/console/server/lib/spec_definitions/json/generated/cluster.health.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/cluster.health.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/cluster.health.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/cluster.pending_tasks.json b/src/plugins/console/server/lib/spec_definitions/json/generated/cluster.pending_tasks.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/cluster.pending_tasks.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/cluster.pending_tasks.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/cluster.put_settings.json b/src/plugins/console/server/lib/spec_definitions/json/generated/cluster.put_settings.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/cluster.put_settings.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/cluster.put_settings.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/cluster.remote_info.json b/src/plugins/console/server/lib/spec_definitions/json/generated/cluster.remote_info.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/cluster.remote_info.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/cluster.remote_info.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/cluster.reroute.json b/src/plugins/console/server/lib/spec_definitions/json/generated/cluster.reroute.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/cluster.reroute.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/cluster.reroute.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/cluster.state.json b/src/plugins/console/server/lib/spec_definitions/json/generated/cluster.state.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/cluster.state.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/cluster.state.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/cluster.stats.json b/src/plugins/console/server/lib/spec_definitions/json/generated/cluster.stats.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/cluster.stats.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/cluster.stats.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/count.json b/src/plugins/console/server/lib/spec_definitions/json/generated/count.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/count.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/count.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/create.json b/src/plugins/console/server/lib/spec_definitions/json/generated/create.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/create.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/create.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/delete.json b/src/plugins/console/server/lib/spec_definitions/json/generated/delete.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/delete.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/delete.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/delete_by_query.json b/src/plugins/console/server/lib/spec_definitions/json/generated/delete_by_query.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/delete_by_query.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/delete_by_query.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/delete_by_query_rethrottle.json b/src/plugins/console/server/lib/spec_definitions/json/generated/delete_by_query_rethrottle.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/delete_by_query_rethrottle.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/delete_by_query_rethrottle.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/delete_script.json b/src/plugins/console/server/lib/spec_definitions/json/generated/delete_script.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/delete_script.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/delete_script.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/exists.json b/src/plugins/console/server/lib/spec_definitions/json/generated/exists.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/exists.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/exists.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/exists_source.json b/src/plugins/console/server/lib/spec_definitions/json/generated/exists_source.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/exists_source.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/exists_source.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/explain.json b/src/plugins/console/server/lib/spec_definitions/json/generated/explain.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/explain.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/explain.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/field_caps.json b/src/plugins/console/server/lib/spec_definitions/json/generated/field_caps.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/field_caps.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/field_caps.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/get.json b/src/plugins/console/server/lib/spec_definitions/json/generated/get.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/get.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/get.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/get_script.json b/src/plugins/console/server/lib/spec_definitions/json/generated/get_script.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/get_script.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/get_script.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/get_script_context.json b/src/plugins/console/server/lib/spec_definitions/json/generated/get_script_context.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/get_script_context.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/get_script_context.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/get_script_languages.json b/src/plugins/console/server/lib/spec_definitions/json/generated/get_script_languages.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/get_script_languages.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/get_script_languages.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/get_source.json b/src/plugins/console/server/lib/spec_definitions/json/generated/get_source.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/get_source.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/get_source.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/index.json b/src/plugins/console/server/lib/spec_definitions/json/generated/index.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/index.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/index.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.analyze.json b/src/plugins/console/server/lib/spec_definitions/json/generated/indices.analyze.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/indices.analyze.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/indices.analyze.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.clear_cache.json b/src/plugins/console/server/lib/spec_definitions/json/generated/indices.clear_cache.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/indices.clear_cache.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/indices.clear_cache.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.clone.json b/src/plugins/console/server/lib/spec_definitions/json/generated/indices.clone.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/indices.clone.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/indices.clone.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.close.json b/src/plugins/console/server/lib/spec_definitions/json/generated/indices.close.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/indices.close.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/indices.close.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.create.json b/src/plugins/console/server/lib/spec_definitions/json/generated/indices.create.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/indices.create.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/indices.create.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.delete.json b/src/plugins/console/server/lib/spec_definitions/json/generated/indices.delete.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/indices.delete.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/indices.delete.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.delete_alias.json b/src/plugins/console/server/lib/spec_definitions/json/generated/indices.delete_alias.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/indices.delete_alias.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/indices.delete_alias.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.delete_template.json b/src/plugins/console/server/lib/spec_definitions/json/generated/indices.delete_template.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/indices.delete_template.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/indices.delete_template.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.exists.json b/src/plugins/console/server/lib/spec_definitions/json/generated/indices.exists.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/indices.exists.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/indices.exists.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.exists_alias.json b/src/plugins/console/server/lib/spec_definitions/json/generated/indices.exists_alias.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/indices.exists_alias.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/indices.exists_alias.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.exists_template.json b/src/plugins/console/server/lib/spec_definitions/json/generated/indices.exists_template.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/indices.exists_template.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/indices.exists_template.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.exists_type.json b/src/plugins/console/server/lib/spec_definitions/json/generated/indices.exists_type.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/indices.exists_type.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/indices.exists_type.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.flush.json b/src/plugins/console/server/lib/spec_definitions/json/generated/indices.flush.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/indices.flush.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/indices.flush.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.flush_synced.json b/src/plugins/console/server/lib/spec_definitions/json/generated/indices.flush_synced.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/indices.flush_synced.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/indices.flush_synced.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.forcemerge.json b/src/plugins/console/server/lib/spec_definitions/json/generated/indices.forcemerge.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/indices.forcemerge.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/indices.forcemerge.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.get.json b/src/plugins/console/server/lib/spec_definitions/json/generated/indices.get.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/indices.get.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/indices.get.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.get_alias.json b/src/plugins/console/server/lib/spec_definitions/json/generated/indices.get_alias.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/indices.get_alias.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/indices.get_alias.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.get_field_mapping.json b/src/plugins/console/server/lib/spec_definitions/json/generated/indices.get_field_mapping.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/indices.get_field_mapping.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/indices.get_field_mapping.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.get_mapping.json b/src/plugins/console/server/lib/spec_definitions/json/generated/indices.get_mapping.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/indices.get_mapping.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/indices.get_mapping.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.get_settings.json b/src/plugins/console/server/lib/spec_definitions/json/generated/indices.get_settings.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/indices.get_settings.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/indices.get_settings.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.get_template.json b/src/plugins/console/server/lib/spec_definitions/json/generated/indices.get_template.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/indices.get_template.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/indices.get_template.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.get_upgrade.json b/src/plugins/console/server/lib/spec_definitions/json/generated/indices.get_upgrade.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/indices.get_upgrade.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/indices.get_upgrade.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.open.json b/src/plugins/console/server/lib/spec_definitions/json/generated/indices.open.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/indices.open.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/indices.open.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.put_alias.json b/src/plugins/console/server/lib/spec_definitions/json/generated/indices.put_alias.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/indices.put_alias.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/indices.put_alias.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.put_mapping.json b/src/plugins/console/server/lib/spec_definitions/json/generated/indices.put_mapping.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/indices.put_mapping.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/indices.put_mapping.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.put_settings.json b/src/plugins/console/server/lib/spec_definitions/json/generated/indices.put_settings.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/indices.put_settings.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/indices.put_settings.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.put_template.json b/src/plugins/console/server/lib/spec_definitions/json/generated/indices.put_template.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/indices.put_template.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/indices.put_template.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.recovery.json b/src/plugins/console/server/lib/spec_definitions/json/generated/indices.recovery.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/indices.recovery.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/indices.recovery.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.refresh.json b/src/plugins/console/server/lib/spec_definitions/json/generated/indices.refresh.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/indices.refresh.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/indices.refresh.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.rollover.json b/src/plugins/console/server/lib/spec_definitions/json/generated/indices.rollover.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/indices.rollover.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/indices.rollover.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.segments.json b/src/plugins/console/server/lib/spec_definitions/json/generated/indices.segments.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/indices.segments.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/indices.segments.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.shard_stores.json b/src/plugins/console/server/lib/spec_definitions/json/generated/indices.shard_stores.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/indices.shard_stores.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/indices.shard_stores.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.shrink.json b/src/plugins/console/server/lib/spec_definitions/json/generated/indices.shrink.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/indices.shrink.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/indices.shrink.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.split.json b/src/plugins/console/server/lib/spec_definitions/json/generated/indices.split.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/indices.split.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/indices.split.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.stats.json b/src/plugins/console/server/lib/spec_definitions/json/generated/indices.stats.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/indices.stats.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/indices.stats.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.update_aliases.json b/src/plugins/console/server/lib/spec_definitions/json/generated/indices.update_aliases.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/indices.update_aliases.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/indices.update_aliases.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.upgrade.json b/src/plugins/console/server/lib/spec_definitions/json/generated/indices.upgrade.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/indices.upgrade.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/indices.upgrade.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/indices.validate_query.json b/src/plugins/console/server/lib/spec_definitions/json/generated/indices.validate_query.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/indices.validate_query.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/indices.validate_query.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/info.json b/src/plugins/console/server/lib/spec_definitions/json/generated/info.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/info.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/info.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/ingest.delete_pipeline.json b/src/plugins/console/server/lib/spec_definitions/json/generated/ingest.delete_pipeline.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/ingest.delete_pipeline.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/ingest.delete_pipeline.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/ingest.get_pipeline.json b/src/plugins/console/server/lib/spec_definitions/json/generated/ingest.get_pipeline.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/ingest.get_pipeline.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/ingest.get_pipeline.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/ingest.processor_grok.json b/src/plugins/console/server/lib/spec_definitions/json/generated/ingest.processor_grok.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/ingest.processor_grok.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/ingest.processor_grok.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/ingest.put_pipeline.json b/src/plugins/console/server/lib/spec_definitions/json/generated/ingest.put_pipeline.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/ingest.put_pipeline.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/ingest.put_pipeline.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/ingest.simulate.json b/src/plugins/console/server/lib/spec_definitions/json/generated/ingest.simulate.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/ingest.simulate.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/ingest.simulate.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/mget.json b/src/plugins/console/server/lib/spec_definitions/json/generated/mget.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/mget.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/mget.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/msearch.json b/src/plugins/console/server/lib/spec_definitions/json/generated/msearch.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/msearch.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/msearch.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/msearch_template.json b/src/plugins/console/server/lib/spec_definitions/json/generated/msearch_template.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/msearch_template.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/msearch_template.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/mtermvectors.json b/src/plugins/console/server/lib/spec_definitions/json/generated/mtermvectors.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/mtermvectors.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/mtermvectors.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/nodes.hot_threads.json b/src/plugins/console/server/lib/spec_definitions/json/generated/nodes.hot_threads.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/nodes.hot_threads.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/nodes.hot_threads.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/nodes.info.json b/src/plugins/console/server/lib/spec_definitions/json/generated/nodes.info.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/nodes.info.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/nodes.info.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/nodes.reload_secure_settings.json b/src/plugins/console/server/lib/spec_definitions/json/generated/nodes.reload_secure_settings.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/nodes.reload_secure_settings.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/nodes.reload_secure_settings.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/nodes.stats.json b/src/plugins/console/server/lib/spec_definitions/json/generated/nodes.stats.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/nodes.stats.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/nodes.stats.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/nodes.usage.json b/src/plugins/console/server/lib/spec_definitions/json/generated/nodes.usage.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/nodes.usage.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/nodes.usage.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/ping.json b/src/plugins/console/server/lib/spec_definitions/json/generated/ping.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/ping.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/ping.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/put_script.json b/src/plugins/console/server/lib/spec_definitions/json/generated/put_script.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/put_script.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/put_script.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/rank_eval.json b/src/plugins/console/server/lib/spec_definitions/json/generated/rank_eval.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/rank_eval.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/rank_eval.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/reindex.json b/src/plugins/console/server/lib/spec_definitions/json/generated/reindex.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/reindex.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/reindex.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/reindex_rethrottle.json b/src/plugins/console/server/lib/spec_definitions/json/generated/reindex_rethrottle.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/reindex_rethrottle.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/reindex_rethrottle.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/render_search_template.json b/src/plugins/console/server/lib/spec_definitions/json/generated/render_search_template.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/render_search_template.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/render_search_template.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/scripts_painless_execute.json b/src/plugins/console/server/lib/spec_definitions/json/generated/scripts_painless_execute.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/scripts_painless_execute.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/scripts_painless_execute.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/scroll.json b/src/plugins/console/server/lib/spec_definitions/json/generated/scroll.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/scroll.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/scroll.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/search.json b/src/plugins/console/server/lib/spec_definitions/json/generated/search.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/search.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/search.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/search_shards.json b/src/plugins/console/server/lib/spec_definitions/json/generated/search_shards.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/search_shards.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/search_shards.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/search_template.json b/src/plugins/console/server/lib/spec_definitions/json/generated/search_template.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/search_template.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/search_template.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/snapshot.cleanup_repository.json b/src/plugins/console/server/lib/spec_definitions/json/generated/snapshot.cleanup_repository.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/snapshot.cleanup_repository.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/snapshot.cleanup_repository.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/snapshot.create.json b/src/plugins/console/server/lib/spec_definitions/json/generated/snapshot.create.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/snapshot.create.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/snapshot.create.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/snapshot.create_repository.json b/src/plugins/console/server/lib/spec_definitions/json/generated/snapshot.create_repository.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/snapshot.create_repository.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/snapshot.create_repository.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/snapshot.delete.json b/src/plugins/console/server/lib/spec_definitions/json/generated/snapshot.delete.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/snapshot.delete.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/snapshot.delete.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/snapshot.delete_repository.json b/src/plugins/console/server/lib/spec_definitions/json/generated/snapshot.delete_repository.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/snapshot.delete_repository.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/snapshot.delete_repository.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/snapshot.get.json b/src/plugins/console/server/lib/spec_definitions/json/generated/snapshot.get.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/snapshot.get.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/snapshot.get.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/snapshot.get_repository.json b/src/plugins/console/server/lib/spec_definitions/json/generated/snapshot.get_repository.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/snapshot.get_repository.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/snapshot.get_repository.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/snapshot.restore.json b/src/plugins/console/server/lib/spec_definitions/json/generated/snapshot.restore.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/snapshot.restore.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/snapshot.restore.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/snapshot.status.json b/src/plugins/console/server/lib/spec_definitions/json/generated/snapshot.status.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/snapshot.status.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/snapshot.status.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/snapshot.verify_repository.json b/src/plugins/console/server/lib/spec_definitions/json/generated/snapshot.verify_repository.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/snapshot.verify_repository.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/snapshot.verify_repository.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/tasks.cancel.json b/src/plugins/console/server/lib/spec_definitions/json/generated/tasks.cancel.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/tasks.cancel.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/tasks.cancel.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/tasks.get.json b/src/plugins/console/server/lib/spec_definitions/json/generated/tasks.get.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/tasks.get.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/tasks.get.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/tasks.list.json b/src/plugins/console/server/lib/spec_definitions/json/generated/tasks.list.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/tasks.list.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/tasks.list.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/termvectors.json b/src/plugins/console/server/lib/spec_definitions/json/generated/termvectors.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/termvectors.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/termvectors.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/update.json b/src/plugins/console/server/lib/spec_definitions/json/generated/update.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/update.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/update.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/update_by_query.json b/src/plugins/console/server/lib/spec_definitions/json/generated/update_by_query.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/update_by_query.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/update_by_query.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/generated/update_by_query_rethrottle.json b/src/plugins/console/server/lib/spec_definitions/json/generated/update_by_query_rethrottle.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/generated/update_by_query_rethrottle.json
rename to src/plugins/console/server/lib/spec_definitions/json/generated/update_by_query_rethrottle.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/index.js b/src/plugins/console/server/lib/spec_definitions/json/index.js
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/index.js
rename to src/plugins/console/server/lib/spec_definitions/json/index.js
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/overrides/clear_scroll.json b/src/plugins/console/server/lib/spec_definitions/json/overrides/clear_scroll.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/overrides/clear_scroll.json
rename to src/plugins/console/server/lib/spec_definitions/json/overrides/clear_scroll.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/overrides/cluster.health.json b/src/plugins/console/server/lib/spec_definitions/json/overrides/cluster.health.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/overrides/cluster.health.json
rename to src/plugins/console/server/lib/spec_definitions/json/overrides/cluster.health.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/overrides/cluster.put_settings.json b/src/plugins/console/server/lib/spec_definitions/json/overrides/cluster.put_settings.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/overrides/cluster.put_settings.json
rename to src/plugins/console/server/lib/spec_definitions/json/overrides/cluster.put_settings.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/overrides/cluster.reroute.json b/src/plugins/console/server/lib/spec_definitions/json/overrides/cluster.reroute.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/overrides/cluster.reroute.json
rename to src/plugins/console/server/lib/spec_definitions/json/overrides/cluster.reroute.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/overrides/count.json b/src/plugins/console/server/lib/spec_definitions/json/overrides/count.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/overrides/count.json
rename to src/plugins/console/server/lib/spec_definitions/json/overrides/count.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/overrides/indices.analyze.json b/src/plugins/console/server/lib/spec_definitions/json/overrides/indices.analyze.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/overrides/indices.analyze.json
rename to src/plugins/console/server/lib/spec_definitions/json/overrides/indices.analyze.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/overrides/indices.clone.json b/src/plugins/console/server/lib/spec_definitions/json/overrides/indices.clone.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/overrides/indices.clone.json
rename to src/plugins/console/server/lib/spec_definitions/json/overrides/indices.clone.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/overrides/indices.create.json b/src/plugins/console/server/lib/spec_definitions/json/overrides/indices.create.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/overrides/indices.create.json
rename to src/plugins/console/server/lib/spec_definitions/json/overrides/indices.create.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/overrides/indices.delete_template.json b/src/plugins/console/server/lib/spec_definitions/json/overrides/indices.delete_template.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/overrides/indices.delete_template.json
rename to src/plugins/console/server/lib/spec_definitions/json/overrides/indices.delete_template.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/overrides/indices.exists_template.json b/src/plugins/console/server/lib/spec_definitions/json/overrides/indices.exists_template.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/overrides/indices.exists_template.json
rename to src/plugins/console/server/lib/spec_definitions/json/overrides/indices.exists_template.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/overrides/indices.get_field_mapping.json b/src/plugins/console/server/lib/spec_definitions/json/overrides/indices.get_field_mapping.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/overrides/indices.get_field_mapping.json
rename to src/plugins/console/server/lib/spec_definitions/json/overrides/indices.get_field_mapping.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/overrides/indices.get_mapping.json b/src/plugins/console/server/lib/spec_definitions/json/overrides/indices.get_mapping.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/overrides/indices.get_mapping.json
rename to src/plugins/console/server/lib/spec_definitions/json/overrides/indices.get_mapping.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/overrides/indices.get_template.json b/src/plugins/console/server/lib/spec_definitions/json/overrides/indices.get_template.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/overrides/indices.get_template.json
rename to src/plugins/console/server/lib/spec_definitions/json/overrides/indices.get_template.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/overrides/indices.put_alias.json b/src/plugins/console/server/lib/spec_definitions/json/overrides/indices.put_alias.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/overrides/indices.put_alias.json
rename to src/plugins/console/server/lib/spec_definitions/json/overrides/indices.put_alias.json
diff --git a/src/plugins/console/server/lib/spec_definitions/json/overrides/indices.put_settings.json b/src/plugins/console/server/lib/spec_definitions/json/overrides/indices.put_settings.json
new file mode 100644
index 0000000000000..2ae8fd82be4d8
--- /dev/null
+++ b/src/plugins/console/server/lib/spec_definitions/json/overrides/indices.put_settings.json
@@ -0,0 +1,7 @@
+{
+ "indices.put_settings": {
+ "data_autocomplete_rules": {
+ "__scope_link": "put_settings"
+ }
+ }
+}
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/overrides/indices.put_template.json b/src/plugins/console/server/lib/spec_definitions/json/overrides/indices.put_template.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/overrides/indices.put_template.json
rename to src/plugins/console/server/lib/spec_definitions/json/overrides/indices.put_template.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/overrides/indices.rollover.json b/src/plugins/console/server/lib/spec_definitions/json/overrides/indices.rollover.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/overrides/indices.rollover.json
rename to src/plugins/console/server/lib/spec_definitions/json/overrides/indices.rollover.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/overrides/indices.update_aliases.json b/src/plugins/console/server/lib/spec_definitions/json/overrides/indices.update_aliases.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/overrides/indices.update_aliases.json
rename to src/plugins/console/server/lib/spec_definitions/json/overrides/indices.update_aliases.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/overrides/indices.validate_query.json b/src/plugins/console/server/lib/spec_definitions/json/overrides/indices.validate_query.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/overrides/indices.validate_query.json
rename to src/plugins/console/server/lib/spec_definitions/json/overrides/indices.validate_query.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/overrides/snapshot.create.json b/src/plugins/console/server/lib/spec_definitions/json/overrides/snapshot.create.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/overrides/snapshot.create.json
rename to src/plugins/console/server/lib/spec_definitions/json/overrides/snapshot.create.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/overrides/snapshot.create_repository.json b/src/plugins/console/server/lib/spec_definitions/json/overrides/snapshot.create_repository.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/overrides/snapshot.create_repository.json
rename to src/plugins/console/server/lib/spec_definitions/json/overrides/snapshot.create_repository.json
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/overrides/snapshot.restore.json b/src/plugins/console/server/lib/spec_definitions/json/overrides/snapshot.restore.json
similarity index 100%
rename from src/plugins/console/server/lib/spec_definitions/spec/overrides/snapshot.restore.json
rename to src/plugins/console/server/lib/spec_definitions/json/overrides/snapshot.restore.json
diff --git a/src/plugins/console/server/lib/spec_definitions/server.js b/src/plugins/console/server/lib/spec_definitions/server.js
index dd700bf019507..cb855958d403a 100644
--- a/src/plugins/console/server/lib/spec_definitions/server.js
+++ b/src/plugins/console/server/lib/spec_definitions/server.js
@@ -17,21 +17,10 @@
* under the License.
*/
-import _ from 'lodash';
+import es from './es';
-const KNOWN_APIS = ['es_6_0'];
-
-export function resolveApi(senseVersion, apis) {
- const result = {};
- _.each(apis, function(name) {
- {
- if (KNOWN_APIS.includes(name)) {
- // for now we ignore sense_version. might add it in the api name later
- const api = require('./' + name); // eslint-disable-line import/no-dynamic-require
- result[name] = api.asJson();
- }
- }
- });
-
- return result;
+export function resolveApi() {
+ return {
+ es: es.asJson(),
+ };
}
diff --git a/src/plugins/console/server/lib/spec_definitions/server.test.js b/src/plugins/console/server/lib/spec_definitions/server.test.js
deleted file mode 100644
index 747689237c177..0000000000000
--- a/src/plugins/console/server/lib/spec_definitions/server.test.js
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Licensed to Elasticsearch B.V. under one or more contributor
- * license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright
- * ownership. Elasticsearch B.V. licenses this file to you under
- * the Apache License, Version 2.0 (the "License"); you may
- * not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-import { resolveApi } from './server';
-
-describe('resolveApi', () => {
- it('allows known APIs to be resolved', () => {
- const mockReply = jest.fn(result => ({ type: () => result }));
- const result = resolveApi('Sense Version', ['es_6_0'], { response: mockReply });
- expect(result).toMatchObject({
- es_6_0: {
- endpoints: expect.any(Object),
- globals: expect.any(Object),
- name: expect.any(String),
- },
- });
- });
-
- it('does not resolve APIs that are not known', () => {
- const mockReply = jest.fn(result => ({ type: () => result }));
- const result = resolveApi('Sense Version', ['unknown'], { response: mockReply });
- expect(result).toEqual({});
- });
-
- it('handles request for apis that are known and unknown', () => {
- const mockReply = jest.fn(result => ({ type: () => result }));
- const result = resolveApi('Sense Version', ['es_6_0'], { response: mockReply });
- expect(result).toMatchObject({
- es_6_0: {
- endpoints: expect.any(Object),
- globals: expect.any(Object),
- name: expect.any(String),
- },
- });
- });
-});
diff --git a/src/plugins/console/server/lib/spec_definitions/spec/overrides/indices.put_settings.json b/src/plugins/console/server/lib/spec_definitions/spec/overrides/indices.put_settings.json
deleted file mode 100644
index 2e1e3024665a4..0000000000000
--- a/src/plugins/console/server/lib/spec_definitions/spec/overrides/indices.put_settings.json
+++ /dev/null
@@ -1,108 +0,0 @@
-{
- "indices.put_settings": {
- "data_autocomplete_rules": {
- "refresh_interval": "1s",
- "number_of_shards": 1,
- "number_of_replicas": 1,
- "blocks.read_only": {
- "__one_of": [
- false,
- true
- ]
- },
- "blocks.read": {
- "__one_of": [
- true,
- false
- ]
- },
- "blocks.write": {
- "__one_of": [
- true,
- false
- ]
- },
- "blocks.metadata": {
- "__one_of": [
- true,
- false
- ]
- },
- "term_index_interval": 32,
- "term_index_divisor": 1,
- "translog.flush_threshold_ops": 5000,
- "translog.flush_threshold_size": "200mb",
- "translog.flush_threshold_period": "30m",
- "translog.disable_flush": {
- "__one_of": [
- true,
- false
- ]
- },
- "cache.filter.max_size": "2gb",
- "cache.filter.expire": "2h",
- "gateway.snapshot_interval": "10s",
- "routing": {
- "allocation": {
- "include": {
- "tag": ""
- },
- "exclude": {
- "tag": ""
- },
- "require": {
- "tag": ""
- },
- "total_shards_per_node": -1
- }
- },
- "recovery.initial_shards": {
- "__one_of": [
- "quorum",
- "quorum-1",
- "half",
- "full",
- "full-1"
- ]
- },
- "ttl.disable_purge": {
- "__one_of": [
- true,
- false
- ]
- },
- "analysis": {
- "analyzer": {},
- "tokenizer": {},
- "filter": {},
- "char_filter": {}
- },
- "cache.query.enable": {
- "__one_of": [
- true,
- false
- ]
- },
- "shadow_replicas": {
- "__one_of": [
- true,
- false
- ]
- },
- "shared_filesystem": {
- "__one_of": [
- true,
- false
- ]
- },
- "data_path": "path",
- "codec": {
- "__one_of": [
- "default",
- "best_compression",
- "lucene_default"
- ]
- }
- }
- }
-}
diff --git a/src/plugins/console/server/plugin.ts b/src/plugins/console/server/plugin.ts
index 65647bd5acb7c..1954918f4d74f 100644
--- a/src/plugins/console/server/plugin.ts
+++ b/src/plugins/console/server/plugin.ts
@@ -21,7 +21,12 @@ import { CoreSetup, Logger, Plugin, PluginInitializerContext } from 'kibana/serv
import { readLegacyEsConfig } from '../../../legacy/core_plugins/console_legacy';
-import { ProxyConfigCollection, addExtensionSpecFilePath, addProcessorDefinition } from './lib';
+import {
+ ProxyConfigCollection,
+ addExtensionSpecFilePath,
+ addProcessorDefinition,
+ loadSpec,
+} from './lib';
import { ConfigType } from './config';
import { registerProxyRoute } from './routes/api/console/proxy';
import { registerSpecDefinitionsRoute } from './routes/api/console/spec_definitions';
@@ -75,5 +80,7 @@ export class ConsoleServerPlugin implements Plugin {
};
}
- start() {}
+ start() {
+ loadSpec();
+ }
}
diff --git a/src/plugins/console/server/routes/api/console/spec_definitions/index.ts b/src/plugins/console/server/routes/api/console/spec_definitions/index.ts
index e2ece37f407ac..88bc250bbfce6 100644
--- a/src/plugins/console/server/routes/api/console/spec_definitions/index.ts
+++ b/src/plugins/console/server/routes/api/console/spec_definitions/index.ts
@@ -16,33 +16,19 @@
* specific language governing permissions and limitations
* under the License.
*/
-import { schema, TypeOf } from '@kbn/config-schema';
import { IRouter, RequestHandler } from 'kibana/server';
import { resolveApi } from '../../../../lib/spec_definitions';
export const registerSpecDefinitionsRoute = ({ router }: { router: IRouter }) => {
- const handler: RequestHandler> = async (
- ctx,
- request,
- response
- ) => {
- const { sense_version: version, apis } = request.query;
-
+ const handler: RequestHandler = async (ctx, request, response) => {
return response.ok({
- body: resolveApi(version, apis.split(',')),
+ body: resolveApi(),
headers: {
'Content-Type': 'application/json',
},
});
};
- const validate = {
- query: schema.object({
- sense_version: schema.string({ defaultValue: '' }),
- apis: schema.string(),
- }),
- };
-
- router.get({ path: '/api/console/api_server', validate }, handler);
- router.post({ path: '/api/console/api_server', validate }, handler);
+ router.get({ path: '/api/console/api_server', validate: false }, handler);
+ router.post({ path: '/api/console/api_server', validate: false }, handler);
};
diff --git a/src/plugins/data/README.md b/src/plugins/data/README.md
index 53618ec049e7c..0fa304c988935 100644
--- a/src/plugins/data/README.md
+++ b/src/plugins/data/README.md
@@ -6,4 +6,4 @@
- `filter`
- `index_patterns`
- `query`
-- `search`
+- `search`
\ No newline at end of file
diff --git a/src/plugins/data/public/query/filter_manager/lib/compare_filters.test.ts b/src/plugins/data/common/query/filter_manager/compare_filters.test.ts
similarity index 99%
rename from src/plugins/data/public/query/filter_manager/lib/compare_filters.test.ts
rename to src/plugins/data/common/query/filter_manager/compare_filters.test.ts
index da8f5b3564948..b0bb2f754d6cf 100644
--- a/src/plugins/data/public/query/filter_manager/lib/compare_filters.test.ts
+++ b/src/plugins/data/common/query/filter_manager/compare_filters.test.ts
@@ -18,7 +18,7 @@
*/
import { compareFilters, COMPARE_ALL_OPTIONS } from './compare_filters';
-import { buildEmptyFilter, buildQueryFilter, FilterStateStore } from '../../../../common';
+import { buildEmptyFilter, buildQueryFilter, FilterStateStore } from '../../es_query';
describe('filter manager utilities', () => {
describe('compare filters', () => {
diff --git a/src/plugins/data/public/query/filter_manager/lib/compare_filters.ts b/src/plugins/data/common/query/filter_manager/compare_filters.ts
similarity index 98%
rename from src/plugins/data/public/query/filter_manager/lib/compare_filters.ts
rename to src/plugins/data/common/query/filter_manager/compare_filters.ts
index a2105fdc1d3ef..e047d5e0665d5 100644
--- a/src/plugins/data/public/query/filter_manager/lib/compare_filters.ts
+++ b/src/plugins/data/common/query/filter_manager/compare_filters.ts
@@ -18,7 +18,7 @@
*/
import { defaults, isEqual, omit, map } from 'lodash';
-import { FilterMeta, Filter } from '../../../../common';
+import { FilterMeta, Filter } from '../../es_query';
export interface FilterCompareOptions {
disabled?: boolean;
diff --git a/src/plugins/data/public/query/filter_manager/lib/dedup_filters.test.ts b/src/plugins/data/common/query/filter_manager/dedup_filters.test.ts
similarity index 95%
rename from src/plugins/data/public/query/filter_manager/lib/dedup_filters.test.ts
rename to src/plugins/data/common/query/filter_manager/dedup_filters.test.ts
index ecc0ec94e07c8..228489de37daa 100644
--- a/src/plugins/data/public/query/filter_manager/lib/dedup_filters.test.ts
+++ b/src/plugins/data/common/query/filter_manager/dedup_filters.test.ts
@@ -18,14 +18,8 @@
*/
import { dedupFilters } from './dedup_filters';
-import {
- Filter,
- IIndexPattern,
- IFieldType,
- buildRangeFilter,
- buildQueryFilter,
- FilterStateStore,
-} from '../../../../common';
+import { Filter, buildRangeFilter, buildQueryFilter, FilterStateStore } from '../../es_query';
+import { IIndexPattern, IFieldType } from '../../index_patterns';
describe('filter manager utilities', () => {
let indexPattern: IIndexPattern;
diff --git a/src/plugins/data/public/query/filter_manager/lib/dedup_filters.ts b/src/plugins/data/common/query/filter_manager/dedup_filters.ts
similarity index 97%
rename from src/plugins/data/public/query/filter_manager/lib/dedup_filters.ts
rename to src/plugins/data/common/query/filter_manager/dedup_filters.ts
index d5d0e70504b41..7d1b00ac10c0d 100644
--- a/src/plugins/data/public/query/filter_manager/lib/dedup_filters.ts
+++ b/src/plugins/data/common/query/filter_manager/dedup_filters.ts
@@ -19,7 +19,7 @@
import { filter, find } from 'lodash';
import { compareFilters, FilterCompareOptions } from './compare_filters';
-import { Filter } from '../../../../common';
+import { Filter } from '../../es_query';
/**
* Combine 2 filter collections, removing duplicates
diff --git a/src/plugins/data/common/query/filter_manager/index.ts b/src/plugins/data/common/query/filter_manager/index.ts
new file mode 100644
index 0000000000000..315c124f083a8
--- /dev/null
+++ b/src/plugins/data/common/query/filter_manager/index.ts
@@ -0,0 +1,22 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+export { dedupFilters } from './dedup_filters';
+export { uniqFilters } from './uniq_filters';
+export { compareFilters, COMPARE_ALL_OPTIONS, FilterCompareOptions } from './compare_filters';
diff --git a/src/plugins/data/public/query/filter_manager/lib/uniq_filters.test.ts b/src/plugins/data/common/query/filter_manager/uniq_filters.test.ts
similarity index 99%
rename from src/plugins/data/public/query/filter_manager/lib/uniq_filters.test.ts
rename to src/plugins/data/common/query/filter_manager/uniq_filters.test.ts
index 8b525a3d2a2e4..5a35e85c95eaa 100644
--- a/src/plugins/data/public/query/filter_manager/lib/uniq_filters.test.ts
+++ b/src/plugins/data/common/query/filter_manager/uniq_filters.test.ts
@@ -18,7 +18,7 @@
*/
import { uniqFilters } from './uniq_filters';
-import { buildQueryFilter, Filter, FilterStateStore } from '../../../../common';
+import { buildQueryFilter, Filter, FilterStateStore } from '../../es_query';
describe('filter manager utilities', () => {
describe('niqFilter', () => {
diff --git a/src/plugins/data/public/query/filter_manager/lib/uniq_filters.ts b/src/plugins/data/common/query/filter_manager/uniq_filters.ts
similarity index 96%
rename from src/plugins/data/public/query/filter_manager/lib/uniq_filters.ts
rename to src/plugins/data/common/query/filter_manager/uniq_filters.ts
index 44c102d7ab15d..683cbf7c78a89 100644
--- a/src/plugins/data/public/query/filter_manager/lib/uniq_filters.ts
+++ b/src/plugins/data/common/query/filter_manager/uniq_filters.ts
@@ -17,8 +17,8 @@
* under the License.
*/
import { each, union } from 'lodash';
+import { Filter } from '../../es_query';
import { dedupFilters } from './dedup_filters';
-import { Filter } from '../../../../common';
/**
* Remove duplicate filters from an array of filters
diff --git a/src/plugins/data/common/query/index.ts b/src/plugins/data/common/query/index.ts
index d8f7b5091eb8f..421cc4f63e4ef 100644
--- a/src/plugins/data/common/query/index.ts
+++ b/src/plugins/data/common/query/index.ts
@@ -17,4 +17,5 @@
* under the License.
*/
+export * from './filter_manager';
export * from './types';
diff --git a/src/plugins/data/public/index.ts b/src/plugins/data/public/index.ts
index 58bd9a5ab05d7..339a5fea91c5f 100644
--- a/src/plugins/data/public/index.ts
+++ b/src/plugins/data/public/index.ts
@@ -47,13 +47,13 @@ import {
isQueryStringFilter,
isRangeFilter,
toggleFilterNegated,
+ compareFilters,
+ COMPARE_ALL_OPTIONS,
} from '../common';
import { FilterLabel } from './ui/filter_bar';
import {
- compareFilters,
- COMPARE_ALL_OPTIONS,
generateFilters,
onlyDisabledFiltersChanged,
changeTimeFilter,
diff --git a/src/plugins/data/public/plugin.ts b/src/plugins/data/public/plugin.ts
index a01c133712206..fc5dde94fa851 100644
--- a/src/plugins/data/public/plugin.ts
+++ b/src/plugins/data/public/plugin.ts
@@ -39,6 +39,7 @@ import { createIndexPatternSelect } from './ui/index_pattern_select';
import { IndexPatternsService } from './index_patterns';
import {
setFieldFormats,
+ setHttp,
setIndexPatterns,
setInjectedMetadata,
setNotifications,
@@ -128,6 +129,7 @@ export class DataPublicPlugin implements Plugin string;
getPhraseFilterValue: (filter: import("../common").PhraseFilter) => string | number | boolean;
getDisplayValueFromFilter: typeof getDisplayValueFromFilter;
- compareFilters: (first: import("../common").Filter | import("../common").Filter[], second: import("../common").Filter | import("../common").Filter[], comparatorOptions?: import("./query/filter_manager/lib/compare_filters").FilterCompareOptions) => boolean;
- COMPARE_ALL_OPTIONS: import("./query/filter_manager/lib/compare_filters").FilterCompareOptions;
+ compareFilters: (first: import("../common").Filter | import("../common").Filter[], second: import("../common").Filter | import("../common").Filter[], comparatorOptions?: import("../common").FilterCompareOptions) => boolean;
+ COMPARE_ALL_OPTIONS: import("../common").FilterCompareOptions;
generateFilters: typeof generateFilters;
onlyDisabledFiltersChanged: (newFilters?: import("../common").Filter[] | undefined, oldFilters?: import("../common").Filter[] | undefined) => boolean;
changeTimeFilter: typeof changeTimeFilter;
@@ -1843,8 +1843,8 @@ export type TSearchStrategyProvider = (context: ISearc
// src/plugins/data/public/index.ts:405:1 - (ae-forgotten-export) The symbol "parseInterval" needs to be exported by the entry point index.d.ts
// src/plugins/data/public/index.ts:406:1 - (ae-forgotten-export) The symbol "propFilter" needs to be exported by the entry point index.d.ts
// src/plugins/data/public/index.ts:409:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts
-// src/plugins/data/public/query/state_sync/connect_to_query_state.ts:34:33 - (ae-forgotten-export) The symbol "FilterStateStore" needs to be exported by the entry point index.d.ts
-// src/plugins/data/public/query/state_sync/connect_to_query_state.ts:38:1 - (ae-forgotten-export) The symbol "QueryStateChange" needs to be exported by the entry point index.d.ts
+// src/plugins/data/public/query/state_sync/connect_to_query_state.ts:33:33 - (ae-forgotten-export) The symbol "FilterStateStore" needs to be exported by the entry point index.d.ts
+// src/plugins/data/public/query/state_sync/connect_to_query_state.ts:37:1 - (ae-forgotten-export) The symbol "QueryStateChange" needs to be exported by the entry point index.d.ts
// src/plugins/data/public/types.ts:52:5 - (ae-forgotten-export) The symbol "createFiltersFromEvent" needs to be exported by the entry point index.d.ts
// src/plugins/data/public/types.ts:60:5 - (ae-forgotten-export) The symbol "IndexPatternSelectProps" needs to be exported by the entry point index.d.ts
diff --git a/src/plugins/data/public/query/filter_manager/filter_manager.ts b/src/plugins/data/public/query/filter_manager/filter_manager.ts
index c951953b26555..fba1866ebd615 100644
--- a/src/plugins/data/public/query/filter_manager/filter_manager.ts
+++ b/src/plugins/data/public/query/filter_manager/filter_manager.ts
@@ -22,13 +22,19 @@ import { Subject } from 'rxjs';
import { IUiSettingsClient } from 'src/core/public';
-import { COMPARE_ALL_OPTIONS, compareFilters } from './lib/compare_filters';
import { sortFilters } from './lib/sort_filters';
import { mapAndFlattenFilters } from './lib/map_and_flatten_filters';
-import { uniqFilters } from './lib/uniq_filters';
import { onlyDisabledFiltersChanged } from './lib/only_disabled';
import { PartitionedFilters } from './types';
-import { FilterStateStore, Filter, isFilterPinned } from '../../../common';
+
+import {
+ FilterStateStore,
+ Filter,
+ uniqFilters,
+ isFilterPinned,
+ compareFilters,
+ COMPARE_ALL_OPTIONS,
+} from '../../../common';
export class FilterManager {
private filters: Filter[] = [];
diff --git a/src/plugins/data/public/query/filter_manager/index.ts b/src/plugins/data/public/query/filter_manager/index.ts
index 09990adacde45..be512c503d531 100644
--- a/src/plugins/data/public/query/filter_manager/index.ts
+++ b/src/plugins/data/public/query/filter_manager/index.ts
@@ -19,8 +19,6 @@
export { FilterManager } from './filter_manager';
-export { uniqFilters } from './lib/uniq_filters';
export { mapAndFlattenFilters } from './lib/map_and_flatten_filters';
export { onlyDisabledFiltersChanged } from './lib/only_disabled';
export { generateFilters } from './lib/generate_filters';
-export { compareFilters, COMPARE_ALL_OPTIONS } from './lib/compare_filters';
diff --git a/src/plugins/data/public/query/filter_manager/lib/only_disabled.ts b/src/plugins/data/public/query/filter_manager/lib/only_disabled.ts
index 34e1ac38ae95f..18c51ebeabe54 100644
--- a/src/plugins/data/public/query/filter_manager/lib/only_disabled.ts
+++ b/src/plugins/data/public/query/filter_manager/lib/only_disabled.ts
@@ -18,8 +18,7 @@
*/
import { filter } from 'lodash';
-import { Filter } from '../../../../common';
-import { compareFilters, COMPARE_ALL_OPTIONS } from './compare_filters';
+import { Filter, compareFilters, COMPARE_ALL_OPTIONS } from '../../../../common';
const isEnabled = (f: Filter) => f && f.meta && !f.meta.disabled;
diff --git a/src/plugins/data/public/query/state_sync/connect_to_query_state.ts b/src/plugins/data/public/query/state_sync/connect_to_query_state.ts
index a22e66860c765..331d8969f2483 100644
--- a/src/plugins/data/public/query/state_sync/connect_to_query_state.ts
+++ b/src/plugins/data/public/query/state_sync/connect_to_query_state.ts
@@ -21,10 +21,9 @@ import { Subscription } from 'rxjs';
import { filter, map } from 'rxjs/operators';
import _ from 'lodash';
import { BaseStateContainer } from '../../../../kibana_utils/public';
-import { COMPARE_ALL_OPTIONS, compareFilters } from '../filter_manager/lib/compare_filters';
import { QuerySetup, QueryStart } from '../query_service';
import { QueryState, QueryStateChange } from './types';
-import { FilterStateStore } from '../../../common/es_query/filters';
+import { FilterStateStore, COMPARE_ALL_OPTIONS, compareFilters } from '../../../common';
/**
* Helper to setup two-way syncing of global data and a state container
diff --git a/src/plugins/data/public/query/state_sync/create_global_query_observable.ts b/src/plugins/data/public/query/state_sync/create_global_query_observable.ts
index d0d97bfaaeb36..dd075f9be7d94 100644
--- a/src/plugins/data/public/query/state_sync/create_global_query_observable.ts
+++ b/src/plugins/data/public/query/state_sync/create_global_query_observable.ts
@@ -20,10 +20,10 @@
import { Observable, Subscription } from 'rxjs';
import { map, tap } from 'rxjs/operators';
import { TimefilterSetup } from '../timefilter';
-import { COMPARE_ALL_OPTIONS, compareFilters, FilterManager } from '../filter_manager';
+import { FilterManager } from '../filter_manager';
import { QueryState, QueryStateChange } from './index';
import { createStateContainer } from '../../../../kibana_utils/public';
-import { isFilterPinned } from '../../../common/es_query/filters';
+import { isFilterPinned, compareFilters, COMPARE_ALL_OPTIONS } from '../../../common';
export function createQueryStateObservable({
timefilter: { timefilter },
diff --git a/src/plugins/data/server/autocomplete/value_suggestions_route.ts b/src/plugins/data/server/autocomplete/value_suggestions_route.ts
index 03dbd40984412..b7569a22e9fc9 100644
--- a/src/plugins/data/server/autocomplete/value_suggestions_route.ts
+++ b/src/plugins/data/server/autocomplete/value_suggestions_route.ts
@@ -39,7 +39,7 @@ export function registerValueSuggestionsRoute(
{
index: schema.string(),
},
- { allowUnknowns: false }
+ { unknowns: 'allow' }
),
body: schema.object(
{
@@ -47,7 +47,7 @@ export function registerValueSuggestionsRoute(
query: schema.string(),
boolFilter: schema.maybe(schema.any()),
},
- { allowUnknowns: false }
+ { unknowns: 'allow' }
),
},
},
diff --git a/src/plugins/data/server/index.ts b/src/plugins/data/server/index.ts
index 0165486fc2de7..5038b4226fad8 100644
--- a/src/plugins/data/server/index.ts
+++ b/src/plugins/data/server/index.ts
@@ -166,7 +166,7 @@ export { ParsedInterval } from '../common';
export {
ISearch,
- ICancel,
+ ISearchCancel,
ISearchOptions,
IRequestTypesMap,
IResponseTypesMap,
diff --git a/src/plugins/data/server/search/i_route_handler_search_context.ts b/src/plugins/data/server/search/i_route_handler_search_context.ts
index 89862781b826e..9888c774ea104 100644
--- a/src/plugins/data/server/search/i_route_handler_search_context.ts
+++ b/src/plugins/data/server/search/i_route_handler_search_context.ts
@@ -17,9 +17,9 @@
* under the License.
*/
-import { ISearchGeneric, ICancelGeneric } from './i_search';
+import { ISearchGeneric, ISearchCancelGeneric } from './i_search';
export interface IRouteHandlerSearchContext {
search: ISearchGeneric;
- cancel: ICancelGeneric;
+ cancel: ISearchCancelGeneric;
}
diff --git a/src/plugins/data/server/search/i_search.ts b/src/plugins/data/server/search/i_search.ts
index ea014c5e136d9..fa4aa72ac7287 100644
--- a/src/plugins/data/server/search/i_search.ts
+++ b/src/plugins/data/server/search/i_search.ts
@@ -42,7 +42,7 @@ export type ISearchGeneric = Promise;
-export type ICancelGeneric = (
+export type ISearchCancelGeneric = (
id: string,
strategy?: T
) => Promise;
@@ -52,4 +52,4 @@ export type ISearch = (
options?: ISearchOptions
) => Promise;
-export type ICancel = (id: string) => Promise;
+export type ISearchCancel = (id: string) => Promise;
diff --git a/src/plugins/data/server/search/i_search_strategy.ts b/src/plugins/data/server/search/i_search_strategy.ts
index 4cfc9608383a9..9b405034f883f 100644
--- a/src/plugins/data/server/search/i_search_strategy.ts
+++ b/src/plugins/data/server/search/i_search_strategy.ts
@@ -18,7 +18,7 @@
*/
import { APICaller } from 'kibana/server';
-import { ISearch, ICancel, ISearchGeneric } from './i_search';
+import { ISearch, ISearchCancel, ISearchGeneric } from './i_search';
import { TStrategyTypes } from './strategy_types';
import { ISearchContext } from './i_search_context';
@@ -28,7 +28,7 @@ import { ISearchContext } from './i_search_context';
*/
export interface ISearchStrategy {
search: ISearch;
- cancel?: ICancel;
+ cancel?: ISearchCancel;
}
/**
diff --git a/src/plugins/data/server/search/index.ts b/src/plugins/data/server/search/index.ts
index 385e96ee803b6..15738a3befb27 100644
--- a/src/plugins/data/server/search/index.ts
+++ b/src/plugins/data/server/search/index.ts
@@ -21,7 +21,13 @@ export { ISearchSetup } from './i_search_setup';
export { ISearchContext } from './i_search_context';
-export { ISearch, ICancel, ISearchOptions, IRequestTypesMap, IResponseTypesMap } from './i_search';
+export {
+ ISearch,
+ ISearchCancel,
+ ISearchOptions,
+ IRequestTypesMap,
+ IResponseTypesMap,
+} from './i_search';
export { TStrategyTypes } from './strategy_types';
diff --git a/src/plugins/data/server/search/routes.ts b/src/plugins/data/server/search/routes.ts
index e618f99084aed..b90d7d4ff80ce 100644
--- a/src/plugins/data/server/search/routes.ts
+++ b/src/plugins/data/server/search/routes.ts
@@ -28,9 +28,9 @@ export function registerSearchRoute(router: IRouter): void {
validate: {
params: schema.object({ strategy: schema.string() }),
- query: schema.object({}, { allowUnknowns: true }),
+ query: schema.object({}, { unknowns: 'allow' }),
- body: schema.object({}, { allowUnknowns: true }),
+ body: schema.object({}, { unknowns: 'allow' }),
},
},
async (context, request, res) => {
@@ -64,7 +64,7 @@ export function registerSearchRoute(router: IRouter): void {
id: schema.string(),
}),
- query: schema.object({}, { allowUnknowns: true }),
+ query: schema.object({}, { unknowns: 'allow' }),
},
},
async (context, request, res) => {
diff --git a/src/plugins/data/server/server.api.md b/src/plugins/data/server/server.api.md
index 2a2d9bb414c14..178b2949a9456 100644
--- a/src/plugins/data/server/server.api.md
+++ b/src/plugins/data/server/server.api.md
@@ -329,12 +329,6 @@ export function getDefaultSearchParams(config: SharedGlobalConfig): {
restTotalHitsAsInt: boolean;
};
-// Warning: (ae-forgotten-export) The symbol "TStrategyTypes" needs to be exported by the entry point index.d.ts
-// Warning: (ae-missing-release-tag) "ICancel" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
-//
-// @public (undocumented)
-export type ICancel = (id: string) => Promise;
-
// Warning: (ae-missing-release-tag) "IFieldFormatsRegistry" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
@@ -507,11 +501,17 @@ export interface IResponseTypesMap {
[ES_SEARCH_STRATEGY]: IEsSearchResponse;
}
+// Warning: (ae-forgotten-export) The symbol "TStrategyTypes" needs to be exported by the entry point index.d.ts
// Warning: (ae-missing-release-tag) "ISearch" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
export type ISearch = (request: IRequestTypesMap[T], options?: ISearchOptions) => Promise;
+// Warning: (ae-missing-release-tag) "ISearchCancel" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
+//
+// @public (undocumented)
+export type ISearchCancel = (id: string) => Promise;
+
// Warning: (ae-missing-release-tag) "ISearchContext" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
diff --git a/src/plugins/es_ui_shared/public/index.ts b/src/plugins/es_ui_shared/public/index.ts
index 2925e5e16458e..8ed01b9b61c7e 100644
--- a/src/plugins/es_ui_shared/public/index.ts
+++ b/src/plugins/es_ui_shared/public/index.ts
@@ -27,3 +27,5 @@ export {
sendRequest,
useRequest,
} from './request/np_ready_request';
+
+export { indices } from './indices';
diff --git a/src/legacy/ui/public/indices/constants/index.js b/src/plugins/es_ui_shared/public/indices/constants/index.ts
similarity index 94%
rename from src/legacy/ui/public/indices/constants/index.js
rename to src/plugins/es_ui_shared/public/indices/constants/index.ts
index 72ecc2e4c87de..825975fa161b5 100644
--- a/src/legacy/ui/public/indices/constants/index.js
+++ b/src/plugins/es_ui_shared/public/indices/constants/index.ts
@@ -17,7 +17,7 @@
* under the License.
*/
-import { indexPatterns } from '../../../../../plugins/data/public';
+import { indexPatterns } from '../../../../data/public';
export const INDEX_ILLEGAL_CHARACTERS_VISIBLE = [...indexPatterns.ILLEGAL_CHARACTERS_VISIBLE, '*'];
diff --git a/src/plugins/es_ui_shared/public/indices/index.ts b/src/plugins/es_ui_shared/public/indices/index.ts
new file mode 100644
index 0000000000000..a6d279a5c2b4f
--- /dev/null
+++ b/src/plugins/es_ui_shared/public/indices/index.ts
@@ -0,0 +1,33 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { INDEX_ILLEGAL_CHARACTERS_VISIBLE } from './constants';
+
+import {
+ indexNameBeginsWithPeriod,
+ findIllegalCharactersInIndexName,
+ indexNameContainsSpaces,
+} from './validate';
+
+export const indices = {
+ INDEX_ILLEGAL_CHARACTERS_VISIBLE,
+ indexNameBeginsWithPeriod,
+ findIllegalCharactersInIndexName,
+ indexNameContainsSpaces,
+};
diff --git a/src/legacy/ui/public/indices/validate/index.js b/src/plugins/es_ui_shared/public/indices/validate/index.ts
similarity index 100%
rename from src/legacy/ui/public/indices/validate/index.js
rename to src/plugins/es_ui_shared/public/indices/validate/index.ts
diff --git a/src/legacy/ui/public/indices/validate/validate_index.test.js b/src/plugins/es_ui_shared/public/indices/validate/validate_index.test.ts
similarity index 100%
rename from src/legacy/ui/public/indices/validate/validate_index.test.js
rename to src/plugins/es_ui_shared/public/indices/validate/validate_index.test.ts
diff --git a/src/legacy/ui/public/indices/validate/validate_index.js b/src/plugins/es_ui_shared/public/indices/validate/validate_index.ts
similarity index 67%
rename from src/legacy/ui/public/indices/validate/validate_index.js
rename to src/plugins/es_ui_shared/public/indices/validate/validate_index.ts
index 5deaa83a807d9..00ac1342400ac 100644
--- a/src/legacy/ui/public/indices/validate/validate_index.js
+++ b/src/plugins/es_ui_shared/public/indices/validate/validate_index.ts
@@ -19,23 +19,29 @@
import { INDEX_ILLEGAL_CHARACTERS_VISIBLE } from '../constants';
-// Names beginning with periods are reserved for system indices.
-export function indexNameBeginsWithPeriod(indexName = '') {
+// Names beginning with periods are reserved for hidden indices.
+export function indexNameBeginsWithPeriod(indexName?: string): boolean {
+ if (indexName === undefined) {
+ return false;
+ }
return indexName[0] === '.';
}
-export function findIllegalCharactersInIndexName(indexName) {
- const illegalCharacters = INDEX_ILLEGAL_CHARACTERS_VISIBLE.reduce((chars, char) => {
- if (indexName.includes(char)) {
- chars.push(char);
- }
+export function findIllegalCharactersInIndexName(indexName: string): string[] {
+ const illegalCharacters = INDEX_ILLEGAL_CHARACTERS_VISIBLE.reduce(
+ (chars: string[], char: string): string[] => {
+ if (indexName.includes(char)) {
+ chars.push(char);
+ }
- return chars;
- }, []);
+ return chars;
+ },
+ []
+ );
return illegalCharacters;
}
-export function indexNameContainsSpaces(indexName) {
+export function indexNameContainsSpaces(indexName: string): boolean {
return indexName.includes(' ');
}
diff --git a/src/plugins/es_ui_shared/static/forms/helpers/field_validators/index_name.ts b/src/plugins/es_ui_shared/static/forms/helpers/field_validators/index_name.ts
index 524cac27341ab..5e969fa715172 100644
--- a/src/plugins/es_ui_shared/static/forms/helpers/field_validators/index_name.ts
+++ b/src/plugins/es_ui_shared/static/forms/helpers/field_validators/index_name.ts
@@ -17,14 +17,11 @@
* under the License.
*/
-// Note: we can't import from "ui/indices" as the TS Type definition don't exist
-// import { INDEX_ILLEGAL_CHARACTERS_VISIBLE } from 'ui/indices';
+import { indices } from '../../../../public';
import { ValidationFunc } from '../../hook_form_lib';
import { startsWith, containsChars } from '../../../validators/string';
import { ERROR_CODE } from './types';
-const INDEX_ILLEGAL_CHARACTERS = ['\\', '/', '?', '"', '<', '>', '|', '*'];
-
export const indexNameField = (i18n: any) => (
...args: Parameters
): ReturnType> => {
@@ -51,7 +48,9 @@ export const indexNameField = (i18n: any) => (
};
}
- const { charsFound, doesContain } = containsChars(INDEX_ILLEGAL_CHARACTERS)(value as string);
+ const { charsFound, doesContain } = containsChars(indices.INDEX_ILLEGAL_CHARACTERS_VISIBLE)(
+ value as string
+ );
if (doesContain) {
return {
message: i18n.translate('esUi.forms.fieldValidation.indexNameInvalidCharactersError', {
diff --git a/src/plugins/expressions/common/expression_functions/specs/kibana_context.ts b/src/plugins/expressions/common/expression_functions/specs/kibana_context.ts
index 4092dfbba00d5..b8be273d7bbd3 100644
--- a/src/plugins/expressions/common/expression_functions/specs/kibana_context.ts
+++ b/src/plugins/expressions/common/expression_functions/specs/kibana_context.ts
@@ -16,10 +16,11 @@
* specific language governing permissions and limitations
* under the License.
*/
-
+import { uniq } from 'lodash';
import { i18n } from '@kbn/i18n';
import { ExpressionFunctionDefinition } from '../../expression_functions';
import { KibanaContext } from '../../expression_types';
+import { Query, uniqFilters } from '../../../../data/common';
interface Arguments {
q?: string | null;
@@ -35,6 +36,15 @@ export type ExpressionFunctionKibanaContext = ExpressionFunctionDefinition<
Promise
>;
+const getParsedValue = (data: any, defaultValue: any) =>
+ typeof data === 'string' && data.length ? JSON.parse(data) || defaultValue : defaultValue;
+
+const mergeQueries = (first: Query | Query[] = [], second: Query | Query[]) =>
+ uniq(
+ [...(Array.isArray(first) ? first : [first]), ...(Array.isArray(second) ? second : [second])],
+ (n: any) => JSON.stringify(n.query)
+ );
+
export const kibanaContextFunction: ExpressionFunctionKibanaContext = {
name: 'kibana_context',
type: 'kibana_context',
@@ -75,9 +85,9 @@ export const kibanaContextFunction: ExpressionFunctionKibanaContext = {
},
async fn(input, args, { getSavedObject }) {
- const queryArg = args.q ? JSON.parse(args.q) : [];
- let queries = Array.isArray(queryArg) ? queryArg : [queryArg];
- let filters = args.filters ? JSON.parse(args.filters) : [];
+ const timeRange = getParsedValue(args.timeRange, input?.timeRange);
+ let queries = mergeQueries(input?.query, getParsedValue(args?.q, []));
+ let filters = [...(input?.filters || []), ...getParsedValue(args?.filters, [])];
if (args.savedSearchId) {
if (typeof getSavedObject !== 'function') {
@@ -89,29 +99,20 @@ export const kibanaContextFunction: ExpressionFunctionKibanaContext = {
}
const obj = await getSavedObject('search', args.savedSearchId);
const search = obj.attributes.kibanaSavedObjectMeta as { searchSourceJSON: string };
- const data = JSON.parse(search.searchSourceJSON) as { query: string; filter: any[] };
- queries = queries.concat(data.query);
- filters = filters.concat(data.filter);
- }
+ const { query, filter } = getParsedValue(search.searchSourceJSON, {});
- if (input && input.query) {
- queries = queries.concat(input.query);
- }
-
- if (input && input.filters) {
- filters = filters.concat(input.filters).filter((f: any) => !f.meta.disabled);
+ if (query) {
+ queries = mergeQueries(queries, query);
+ }
+ if (filter) {
+ filters = [...filters, ...(Array.isArray(filter) ? filter : [filter])];
+ }
}
- const timeRange = args.timeRange
- ? JSON.parse(args.timeRange)
- : input
- ? input.timeRange
- : undefined;
-
return {
type: 'kibana_context',
query: queries,
- filters,
+ filters: uniqFilters(filters).filter((f: any) => !f.meta?.disabled),
timeRange,
};
},
diff --git a/src/plugins/kibana_legacy/public/angular/index.ts b/src/plugins/kibana_legacy/public/angular/index.ts
index 5fc37ac39612a..16bae6c4cffe0 100644
--- a/src/plugins/kibana_legacy/public/angular/index.ts
+++ b/src/plugins/kibana_legacy/public/angular/index.ts
@@ -21,7 +21,6 @@ export { PromiseServiceCreator } from './promises';
// @ts-ignore
export { watchMultiDecorator } from './watch_multi';
export * from './angular_config';
-export { ensureDefaultIndexPattern } from './ensure_default_index_pattern';
// @ts-ignore
export { createTopNavDirective, createTopNavHelper, loadKbnTopNavDirectives } from './kbn_top_nav';
export { subscribeWithScope } from './subscribe_with_scope';
diff --git a/src/plugins/kibana_react/public/exit_full_screen_button/__snapshots__/exit_full_screen_button.test.tsx.snap b/src/plugins/kibana_react/public/exit_full_screen_button/__snapshots__/exit_full_screen_button.test.tsx.snap
index 39bd66ff71c61..ee97a5acfd3d2 100644
--- a/src/plugins/kibana_react/public/exit_full_screen_button/__snapshots__/exit_full_screen_button.test.tsx.snap
+++ b/src/plugins/kibana_react/public/exit_full_screen_button/__snapshots__/exit_full_screen_button.test.tsx.snap
@@ -17,27 +17,88 @@ exports[`is rendered 1`] = `
-
-
- Exit full screen
-
-
-
-
+
+
+
+
+
+
+
+
+ Elastic Kibana
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/plugins/kibana_react/public/exit_full_screen_button/_exit_full_screen_button.scss b/src/plugins/kibana_react/public/exit_full_screen_button/_exit_full_screen_button.scss
index e810fe0ccdba6..a2e951cb5b775 100644
--- a/src/plugins/kibana_react/public/exit_full_screen_button/_exit_full_screen_button.scss
+++ b/src/plugins/kibana_react/public/exit_full_screen_button/_exit_full_screen_button.scss
@@ -4,66 +4,40 @@
*/
.dshExitFullScreenButton {
- height: $euiSizeXXL;
- left: 0;
- bottom: 0;
+ @include euiBottomShadow;
+
+ left: $euiSizeS;
+ bottom: $euiSizeS;
position: fixed;
display: block;
padding: 0;
border: none;
background: none;
z-index: 5;
+ background: $euiColorFullShade;
+ padding: $euiSizeXS;
+ border-radius: $euiBorderRadius;
+ text-align: left;
- &:hover,
- &:focus {
- transition: all $euiAnimSpeedExtraSlow $euiAnimSlightResistance;
- z-index: 10 !important; /* 1 */
+ &:hover {
+ background: $euiColorFullShade;
- .dshExitFullScreenButton__text {
- transition: all $euiAnimSpeedNormal $euiAnimSlightResistance;
- transform: translateX(-$euiSize);
+ .dshExitFullScreenButton__icon {
+ color: $euiColorEmptyShade;
}
}
}
-.dshExitFullScreenButton__logo {
- display: block;
- // Just darken the background for all themes because the logo is always white
- background-color: shade($euiColorPrimary, 25%);
- height: $euiSizeXXL;
-
- // These numbers are very specific to the Kibana logo size
- width: 92px;
- background-image: url('ui/assets/images/kibana.svg');
- background-position: 8px 5px;
- background-size: 72px 30px;
- background-repeat: no-repeat;
-
- z-index: $euiZLevel1;
+.dshExitFullScreenButton__title {
+ line-height: 1.2;
+ color: $euiColorEmptyShade;
}
-/**
- * 1. Calc made to allow caret in text to peek out / animate.
- */
-
.dshExitFullScreenButton__text {
- background: $euiColorPrimary;
- color: $euiColorEmptyShade;
- line-height: $euiSizeXXL;
- display: inline-block;
- font-size: $euiFontSizeS;
- height: $euiSizeXXL;
- position: absolute;
- left: calc(100% + #{$euiSize}); /* 1 */
- top: 0px;
- bottom: 0px;
- white-space: nowrap;
- padding: 0px $euiSizeXS 0px $euiSizeM;
- transition: all .2s ease;
- transform: translateX(-100%);
- z-index: -1;
-
- .euiIcon {
- margin-left: $euiSizeXS;
- }
+ line-height: 1.2;
+ color: makeHighContrastColor($euiColorMediumShade, $euiColorFullShade);
+}
+
+.dshExitFullScreenButton__icon {
+ color: makeHighContrastColor($euiColorMediumShade, $euiColorFullShade);
}
diff --git a/src/plugins/kibana_react/public/exit_full_screen_button/exit_full_screen_button.tsx b/src/plugins/kibana_react/public/exit_full_screen_button/exit_full_screen_button.tsx
index 5ce508ec1ed5b..97fc02ac64e12 100644
--- a/src/plugins/kibana_react/public/exit_full_screen_button/exit_full_screen_button.tsx
+++ b/src/plugins/kibana_react/public/exit_full_screen_button/exit_full_screen_button.tsx
@@ -20,7 +20,7 @@
import { i18n } from '@kbn/i18n';
import React, { PureComponent } from 'react';
import { EuiScreenReaderOnly, keyCodes } from '@elastic/eui';
-import { EuiIcon } from '@elastic/eui';
+import { EuiIcon, EuiTitle, EuiFlexGroup, EuiFlexItem, EuiText } from '@elastic/eui';
export interface ExitFullScreenButtonProps {
onExitFullScreenMode: () => void;
@@ -61,17 +61,40 @@ class ExitFullScreenButtonUi extends PureComponent {
)}
className="dshExitFullScreenButton"
onClick={this.props.onExitFullScreenMode}
+ data-test-subj="exitFullScreenModeLogo"
>
-
-
- {i18n.translate('kibana-react.exitFullScreenButton.exitFullScreenModeButtonLabel', {
- defaultMessage: 'Exit full screen',
- })}
-
-
+
+
+
+
+
+
+
+
+ {i18n.translate(
+ 'kibana-react.exitFullScreenButton.exitFullScreenModeButtonTitle',
+ {
+ defaultMessage: 'Elastic Kibana',
+ }
+ )}
+
+
+
+
+ {i18n.translate(
+ 'kibana-react.exitFullScreenButton.exitFullScreenModeButtonText',
+ {
+ defaultMessage: 'Exit full screen',
+ }
+ )}
+
+
+
+
+
+
+
+
diff --git a/src/plugins/kibana_legacy/public/angular/ensure_default_index_pattern.tsx b/src/plugins/kibana_utils/public/history/ensure_default_index_pattern.tsx
similarity index 67%
rename from src/plugins/kibana_legacy/public/angular/ensure_default_index_pattern.tsx
rename to src/plugins/kibana_utils/public/history/ensure_default_index_pattern.tsx
index 1a3bb84ae7575..7992f650cb372 100644
--- a/src/plugins/kibana_legacy/public/angular/ensure_default_index_pattern.tsx
+++ b/src/plugins/kibana_utils/public/history/ensure_default_index_pattern.tsx
@@ -18,14 +18,13 @@
*/
import { contains } from 'lodash';
-import { IRootScopeService } from 'angular';
import React from 'react';
-import ReactDOM from 'react-dom';
+import { History } from 'history';
import { i18n } from '@kbn/i18n';
-import { I18nProvider } from '@kbn/i18n/react';
import { EuiCallOut } from '@elastic/eui';
import { CoreStart } from 'kibana/public';
import { DataPublicPluginStart } from 'src/plugins/data/public';
+import { toMountPoint } from '../../../kibana_react/public';
let bannerId: string;
let timeoutId: NodeJS.Timeout | undefined;
@@ -39,18 +38,17 @@ let timeoutId: NodeJS.Timeout | undefined;
* resolve to wait for the URL change to happen.
*/
export async function ensureDefaultIndexPattern(
- newPlatform: CoreStart,
+ core: CoreStart,
data: DataPublicPluginStart,
- $rootScope: IRootScopeService,
- kbnUrl: any
+ history: History
) {
const patterns = await data.indexPatterns.getIds();
- let defaultId = newPlatform.uiSettings.get('defaultIndex');
+ let defaultId = core.uiSettings.get('defaultIndex');
let defined = !!defaultId;
const exists = contains(patterns, defaultId);
if (defined && !exists) {
- newPlatform.uiSettings.remove('defaultIndex');
+ core.uiSettings.remove('defaultIndex');
defaultId = defined = false;
}
@@ -61,10 +59,9 @@ export async function ensureDefaultIndexPattern(
// If there is any index pattern created, set the first as default
if (patterns.length >= 1) {
defaultId = patterns[0];
- newPlatform.uiSettings.set('defaultIndex', defaultId);
+ core.uiSettings.set('defaultIndex', defaultId);
} else {
- const canManageIndexPatterns =
- newPlatform.application.capabilities.management.kibana.index_patterns;
+ const canManageIndexPatterns = core.application.capabilities.management.kibana.index_patterns;
const redirectTarget = canManageIndexPatterns ? '/management/kibana/index_pattern' : '/home';
if (timeoutId) {
@@ -73,31 +70,27 @@ export async function ensureDefaultIndexPattern(
// Avoid being hostile to new users who don't have an index pattern setup yet
// give them a friendly info message instead of a terse error message
- bannerId = newPlatform.overlays.banners.replace(bannerId, (element: HTMLElement) => {
- ReactDOM.render(
-
-
- ,
- element
- );
- return () => ReactDOM.unmountComponentAtNode(element);
- });
+ bannerId = core.overlays.banners.replace(
+ bannerId,
+ toMountPoint(
+
+ )
+ );
// hide the message after the user has had a chance to acknowledge it -- so it doesn't permanently stick around
timeoutId = setTimeout(() => {
- newPlatform.overlays.banners.remove(bannerId);
+ core.overlays.banners.remove(bannerId);
timeoutId = undefined;
}, 15000);
- kbnUrl.change(redirectTarget);
- $rootScope.$digest();
+ history.push(redirectTarget);
// return never-resolving promise to stop resolving and wait for the url change
return new Promise(() => {});
diff --git a/src/plugins/kibana_utils/public/history/index.ts b/src/plugins/kibana_utils/public/history/index.ts
index bb13ea09f928a..1a73bbb6b04a1 100644
--- a/src/plugins/kibana_utils/public/history/index.ts
+++ b/src/plugins/kibana_utils/public/history/index.ts
@@ -19,3 +19,4 @@
export { removeQueryParam } from './remove_query_param';
export { redirectWhenMissing } from './redirect_when_missing';
+export { ensureDefaultIndexPattern } from './ensure_default_index_pattern';
diff --git a/src/plugins/kibana_utils/public/index.ts b/src/plugins/kibana_utils/public/index.ts
index 47f90cbe2a627..1876e688c989a 100644
--- a/src/plugins/kibana_utils/public/index.ts
+++ b/src/plugins/kibana_utils/public/index.ts
@@ -73,5 +73,5 @@ export {
StartSyncStateFnType,
StopSyncStateFnType,
} from './state_sync';
-export { removeQueryParam, redirectWhenMissing } from './history';
+export { removeQueryParam, redirectWhenMissing, ensureDefaultIndexPattern } from './history';
export { applyDiff } from './state_management/utils/diff_object';
diff --git a/src/plugins/timelion/config.ts b/src/plugins/timelion/config.ts
index 561fb4de9f58d..eaea1aaca1b7b 100644
--- a/src/plugins/timelion/config.ts
+++ b/src/plugins/timelion/config.ts
@@ -25,7 +25,7 @@ export const configSchema = schema.object(
graphiteUrls: schema.maybe(schema.arrayOf(schema.string())),
},
// This option should be removed as soon as we entirely migrate config from legacy Timelion plugin.
- { allowUnknowns: true }
+ { unknowns: 'allow' }
);
export type ConfigSchema = TypeOf;
diff --git a/src/plugins/timelion/server/routes/run.ts b/src/plugins/timelion/server/routes/run.ts
index b7a4179da768e..b773bba68ea81 100644
--- a/src/plugins/timelion/server/routes/run.ts
+++ b/src/plugins/timelion/server/routes/run.ts
@@ -78,15 +78,11 @@ export function runRoute(
es: schema.object({
filter: schema.object({
bool: schema.object({
- filter: schema.maybe(
- schema.arrayOf(schema.object({}, { allowUnknowns: true }))
- ),
- must: schema.maybe(schema.arrayOf(schema.object({}, { allowUnknowns: true }))),
- should: schema.maybe(
- schema.arrayOf(schema.object({}, { allowUnknowns: true }))
- ),
+ filter: schema.maybe(schema.arrayOf(schema.object({}, { unknowns: 'allow' }))),
+ must: schema.maybe(schema.arrayOf(schema.object({}, { unknowns: 'allow' }))),
+ should: schema.maybe(schema.arrayOf(schema.object({}, { unknowns: 'allow' }))),
must_not: schema.maybe(
- schema.arrayOf(schema.object({}, { allowUnknowns: true }))
+ schema.arrayOf(schema.object({}, { unknowns: 'allow' }))
),
}),
}),
diff --git a/src/plugins/vis_type_timeseries/server/routes/vis.ts b/src/plugins/vis_type_timeseries/server/routes/vis.ts
index e2d1e4d114ad5..9abbc4ad617dc 100644
--- a/src/plugins/vis_type_timeseries/server/routes/vis.ts
+++ b/src/plugins/vis_type_timeseries/server/routes/vis.ts
@@ -23,7 +23,7 @@ import { getVisData, GetVisDataOptions } from '../lib/get_vis_data';
import { visPayloadSchema } from './post_vis_schema';
import { Framework, ValidationTelemetryServiceSetup } from '../index';
-const escapeHatch = schema.object({}, { allowUnknowns: true });
+const escapeHatch = schema.object({}, { unknowns: 'allow' });
export const visDataRoutes = (
router: IRouter,
diff --git a/test/common/services/security/role.ts b/test/common/services/security/role.ts
index 0e7572882f80d..dfc6ff9b164e5 100644
--- a/test/common/services/security/role.ts
+++ b/test/common/services/security/role.ts
@@ -43,7 +43,6 @@ export class Role {
`Expected status code of 204, received ${status} ${statusText}: ${util.inspect(data)}`
);
}
- this.log.debug(`created role ${name}`);
}
public async delete(name: string) {
@@ -56,6 +55,5 @@ export class Role {
)}`
);
}
- this.log.debug(`deleted role ${name}`);
}
}
diff --git a/test/common/services/security/security.ts b/test/common/services/security/security.ts
index 4eebb7b6697e0..6ad0933a2a5a2 100644
--- a/test/common/services/security/security.ts
+++ b/test/common/services/security/security.ts
@@ -23,15 +23,21 @@ import { Role } from './role';
import { User } from './user';
import { RoleMappings } from './role_mappings';
import { FtrProviderContext } from '../../ftr_provider_context';
+import { createTestUserService } from './test_user';
-export function SecurityServiceProvider({ getService }: FtrProviderContext) {
+export async function SecurityServiceProvider(context: FtrProviderContext) {
+ const { getService } = context;
const log = getService('log');
const config = getService('config');
const url = formatUrl(config.get('servers.kibana'));
+ const role = new Role(url, log);
+ const user = new User(url, log);
+ const testUser = await createTestUserService(role, user, context);
return new (class SecurityService {
- role = new Role(url, log);
roleMappings = new RoleMappings(url, log);
- user = new User(url, log);
+ testUser = testUser;
+ role = role;
+ user = user;
})();
}
diff --git a/test/common/services/security/test_user.ts b/test/common/services/security/test_user.ts
new file mode 100644
index 0000000000000..7f01c64d291a5
--- /dev/null
+++ b/test/common/services/security/test_user.ts
@@ -0,0 +1,92 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import { Role } from './role';
+import { User } from './user';
+import { FtrProviderContext } from '../../ftr_provider_context';
+import { Browser } from '../../../functional/services/browser';
+import { TestSubjects } from '../../../functional/services/test_subjects';
+
+export async function createTestUserService(
+ role: Role,
+ user: User,
+ { getService, hasService }: FtrProviderContext
+) {
+ const log = getService('log');
+ const config = getService('config');
+ // @ts-ignore browser service is not normally available in common.
+ const browser: Browser | void = hasService('browser') && getService('browser');
+ const testSubjects: TestSubjects | void =
+ // @ts-ignore testSubject service is not normally available in common.
+ hasService('testSubjects') && getService('testSubjects');
+ const kibanaServer = getService('kibanaServer');
+
+ const enabledPlugins = config.get('security.disableTestUser')
+ ? []
+ : await kibanaServer.plugins.getEnabledIds();
+ const isEnabled = () => {
+ return enabledPlugins.includes('security') && !config.get('security.disableTestUser');
+ };
+ if (isEnabled()) {
+ log.debug('===============creating roles and users===============');
+ for (const [name, definition] of Object.entries(config.get('security.roles'))) {
+ // create the defined roles (need to map array to create roles)
+ await role.create(name, definition);
+ }
+ try {
+ // delete the test_user if present (will it error if the user doesn't exist?)
+ await user.delete('test_user');
+ } catch (exception) {
+ log.debug('no test user to delete');
+ }
+
+ // create test_user with username and pwd
+ log.debug(`default roles = ${config.get('security.defaultRoles')}`);
+ await user.create('test_user', {
+ password: 'changeme',
+ roles: config.get('security.defaultRoles'),
+ full_name: 'test user',
+ });
+ }
+
+ return new (class TestUser {
+ async restoreDefaults() {
+ if (isEnabled()) {
+ await this.setRoles(config.get('security.defaultRoles'));
+ }
+ }
+
+ async setRoles(roles: string[]) {
+ if (isEnabled()) {
+ log.debug(`set roles = ${roles}`);
+ await user.create('test_user', {
+ password: 'changeme',
+ roles,
+ full_name: 'test user',
+ });
+
+ if (browser && testSubjects) {
+ if (await testSubjects.exists('kibanaChrome', { allowHidden: true })) {
+ await browser.refresh();
+ await testSubjects.find('kibanaChrome', config.get('timeouts.find') * 10);
+ }
+ }
+ }
+ }
+ })();
+}
diff --git a/test/functional/apps/context/_date_nanos.js b/test/functional/apps/context/_date_nanos.js
index d4acdb0b4d5c0..bd132e3745caa 100644
--- a/test/functional/apps/context/_date_nanos.js
+++ b/test/functional/apps/context/_date_nanos.js
@@ -26,11 +26,13 @@ const TEST_STEP_SIZE = 3;
export default function({ getService, getPageObjects }) {
const kibanaServer = getService('kibanaServer');
const docTable = getService('docTable');
+ const security = getService('security');
const PageObjects = getPageObjects(['common', 'context', 'timePicker', 'discover']);
const esArchiver = getService('esArchiver');
describe('context view for date_nanos', () => {
before(async function() {
+ await security.testUser.setRoles(['kibana_admin', 'kibana_date_nanos']);
await esArchiver.loadIfNeeded('date_nanos');
await kibanaServer.uiSettings.replace({ defaultIndex: TEST_INDEX_PATTERN });
await kibanaServer.uiSettings.update({
@@ -39,8 +41,9 @@ export default function({ getService, getPageObjects }) {
});
});
- after(function unloadMakelogs() {
- return esArchiver.unload('date_nanos');
+ after(async function unloadMakelogs() {
+ await security.testUser.restoreDefaults();
+ await esArchiver.unload('date_nanos');
});
it('displays predessors - anchor - successors in right order ', async function() {
diff --git a/test/functional/apps/context/_date_nanos_custom_timestamp.js b/test/functional/apps/context/_date_nanos_custom_timestamp.js
index 046cca0aba8c6..7834b29931a65 100644
--- a/test/functional/apps/context/_date_nanos_custom_timestamp.js
+++ b/test/functional/apps/context/_date_nanos_custom_timestamp.js
@@ -26,12 +26,14 @@ const TEST_STEP_SIZE = 3;
export default function({ getService, getPageObjects }) {
const kibanaServer = getService('kibanaServer');
const docTable = getService('docTable');
+ const security = getService('security');
const PageObjects = getPageObjects(['common', 'context', 'timePicker', 'discover']);
const esArchiver = getService('esArchiver');
// skipped due to a recent change in ES that caused search_after queries with data containing
// custom timestamp formats like in the testdata to fail
describe.skip('context view for date_nanos with custom timestamp', () => {
before(async function() {
+ await security.testUser.setRoles(['kibana_admin', 'kibana_date_nanos_custom']);
await esArchiver.loadIfNeeded('date_nanos_custom');
await kibanaServer.uiSettings.replace({ defaultIndex: TEST_INDEX_PATTERN });
await kibanaServer.uiSettings.update({
@@ -40,10 +42,6 @@ export default function({ getService, getPageObjects }) {
});
});
- after(function unloadMakelogs() {
- return esArchiver.unload('date_nanos_custom');
- });
-
it('displays predessors - anchor - successors in right order ', async function() {
await PageObjects.context.navigateTo(TEST_INDEX_PATTERN, '1');
const actualRowsText = await docTable.getRowsText();
@@ -54,5 +52,10 @@ export default function({ getService, getPageObjects }) {
];
expect(actualRowsText).to.eql(expectedRowsText);
});
+
+ after(async function() {
+ await security.testUser.restoreDefaults();
+ await esArchiver.unload('date_nanos_custom');
+ });
});
}
diff --git a/test/functional/apps/dashboard/dashboard_filtering.js b/test/functional/apps/dashboard/dashboard_filtering.js
index ec8a48ca74911..f388993dcaf7d 100644
--- a/test/functional/apps/dashboard/dashboard_filtering.js
+++ b/test/functional/apps/dashboard/dashboard_filtering.js
@@ -33,6 +33,7 @@ export default function({ getService, getPageObjects }) {
const filterBar = getService('filterBar');
const esArchiver = getService('esArchiver');
const kibanaServer = getService('kibanaServer');
+ const security = getService('security');
const dashboardPanelActions = getService('dashboardPanelActions');
const PageObjects = getPageObjects(['common', 'dashboard', 'header', 'visualize', 'timePicker']);
@@ -41,6 +42,7 @@ export default function({ getService, getPageObjects }) {
before(async () => {
await esArchiver.load('dashboard/current/kibana');
+ await security.testUser.setRoles(['kibana_admin', 'test_logstash_reader', 'animals']);
await kibanaServer.uiSettings.replace({
defaultIndex: '0bf35f60-3dc9-11e8-8660-4d65aa086b3c',
});
@@ -49,6 +51,10 @@ export default function({ getService, getPageObjects }) {
await PageObjects.dashboard.gotoDashboardLandingPage();
});
+ after(async () => {
+ await security.testUser.restoreDefaults();
+ });
+
describe('adding a filter that excludes all data', () => {
before(async () => {
await PageObjects.dashboard.clickNewDashboard();
diff --git a/test/functional/apps/dashboard/index.js b/test/functional/apps/dashboard/index.js
index 13e8631445393..5e96a55b19014 100644
--- a/test/functional/apps/dashboard/index.js
+++ b/test/functional/apps/dashboard/index.js
@@ -23,6 +23,7 @@ export default function({ getService, loadTestFile }) {
async function loadCurrentData() {
await browser.setWindowSize(1300, 900);
+ await esArchiver.unload('logstash_functional');
await esArchiver.loadIfNeeded('dashboard/current/data');
}
diff --git a/test/functional/apps/dashboard/time_zones.js b/test/functional/apps/dashboard/time_zones.js
index f374d6526fcf1..b7698a7d6ac4b 100644
--- a/test/functional/apps/dashboard/time_zones.js
+++ b/test/functional/apps/dashboard/time_zones.js
@@ -22,7 +22,6 @@ import expect from '@kbn/expect';
export default function({ getService, getPageObjects }) {
const pieChart = getService('pieChart');
- const browser = getService('browser');
const esArchiver = getService('esArchiver');
const kibanaServer = getService('kibanaServer');
const PageObjects = getPageObjects(['dashboard', 'timePicker', 'settings', 'common']);
@@ -48,7 +47,6 @@ export default function({ getService, getPageObjects }) {
after(async () => {
await kibanaServer.uiSettings.replace({ 'dateFormat:tz': 'UTC' });
- await browser.refresh();
});
it('Exported dashboard adjusts EST time to UTC', async () => {
diff --git a/test/functional/apps/discover/_date_nanos.js b/test/functional/apps/discover/_date_nanos.js
index 9b06b9ac84cfd..99a37cc18feaa 100644
--- a/test/functional/apps/discover/_date_nanos.js
+++ b/test/functional/apps/discover/_date_nanos.js
@@ -23,6 +23,7 @@ export default function({ getService, getPageObjects }) {
const esArchiver = getService('esArchiver');
const PageObjects = getPageObjects(['common', 'timePicker', 'discover']);
const kibanaServer = getService('kibanaServer');
+ const security = getService('security');
const fromTime = 'Sep 22, 2019 @ 20:31:44.000';
const toTime = 'Sep 23, 2019 @ 03:31:44.000';
@@ -30,12 +31,14 @@ export default function({ getService, getPageObjects }) {
before(async function() {
await esArchiver.loadIfNeeded('date_nanos');
await kibanaServer.uiSettings.replace({ defaultIndex: 'date-nanos' });
+ await security.testUser.setRoles(['kibana_admin', 'kibana_date_nanos']);
await PageObjects.common.navigateToApp('discover');
await PageObjects.timePicker.setAbsoluteRange(fromTime, toTime);
});
- after(function unloadMakelogs() {
- return esArchiver.unload('date_nanos');
+ after(async function unloadMakelogs() {
+ await security.testUser.restoreDefaults();
+ await esArchiver.unload('date_nanos');
});
it('should show a timestamp with nanoseconds in the first result row', async function() {
diff --git a/test/functional/apps/discover/_date_nanos_mixed.js b/test/functional/apps/discover/_date_nanos_mixed.js
index 0bb6848db4d10..b88ae87601cc5 100644
--- a/test/functional/apps/discover/_date_nanos_mixed.js
+++ b/test/functional/apps/discover/_date_nanos_mixed.js
@@ -23,6 +23,7 @@ export default function({ getService, getPageObjects }) {
const esArchiver = getService('esArchiver');
const PageObjects = getPageObjects(['common', 'timePicker', 'discover']);
const kibanaServer = getService('kibanaServer');
+ const security = getService('security');
const fromTime = 'Jan 1, 2019 @ 00:00:00.000';
const toTime = 'Jan 1, 2019 @ 23:59:59.999';
@@ -30,12 +31,14 @@ export default function({ getService, getPageObjects }) {
before(async function() {
await esArchiver.loadIfNeeded('date_nanos_mixed');
await kibanaServer.uiSettings.replace({ defaultIndex: 'timestamp-*' });
+ await security.testUser.setRoles(['kibana_admin', 'kibana_date_nanos_mixed']);
await PageObjects.common.navigateToApp('discover');
await PageObjects.timePicker.setAbsoluteRange(fromTime, toTime);
});
- after(function unloadMakelogs() {
- return esArchiver.unload('date_nanos_mixed');
+ after(async () => {
+ await security.testUser.restoreDefaults();
+ esArchiver.unload('date_nanos_mixed');
});
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_histogram.js b/test/functional/apps/discover/_discover_histogram.js
index 9310838666256..f815c505a8c27 100644
--- a/test/functional/apps/discover/_discover_histogram.js
+++ b/test/functional/apps/discover/_discover_histogram.js
@@ -25,6 +25,7 @@ export default function({ getService, getPageObjects }) {
const browser = getService('browser');
const elasticChart = getService('elasticChart');
const kibanaServer = getService('kibanaServer');
+ const security = getService('security');
const PageObjects = getPageObjects(['settings', 'common', 'discover', 'header', 'timePicker']);
const defaultSettings = {
defaultIndex: 'long-window-logstash-*',
@@ -35,6 +36,11 @@ export default function({ getService, getPageObjects }) {
before(async function() {
log.debug('load kibana index with default index pattern');
await PageObjects.common.navigateToApp('home');
+ await security.testUser.setRoles([
+ 'kibana_admin',
+ 'test_logstash_reader',
+ 'long_window_logstash',
+ ]);
await esArchiver.loadIfNeeded('logstash_functional');
await esArchiver.load('long_window_logstash');
await esArchiver.load('visualize');
@@ -56,6 +62,7 @@ export default function({ getService, getPageObjects }) {
await esArchiver.unload('long_window_logstash');
await esArchiver.unload('visualize');
await esArchiver.unload('discover');
+ await security.testUser.restoreDefaults();
});
it('should visualize monthly data with different day intervals', async () => {
diff --git a/test/functional/apps/discover/_large_string.js b/test/functional/apps/discover/_large_string.js
index a5052b2403074..5e9048e2bc481 100644
--- a/test/functional/apps/discover/_large_string.js
+++ b/test/functional/apps/discover/_large_string.js
@@ -25,10 +25,12 @@ export default function({ getService, getPageObjects }) {
const retry = getService('retry');
const kibanaServer = getService('kibanaServer');
const queryBar = getService('queryBar');
+ const security = getService('security');
const PageObjects = getPageObjects(['common', 'home', 'settings', 'discover']);
describe('test large strings', function() {
before(async function() {
+ await security.testUser.setRoles(['kibana_admin', 'kibana_large_strings']);
await esArchiver.load('empty_kibana');
await esArchiver.loadIfNeeded('hamlet');
await kibanaServer.uiSettings.replace({ defaultIndex: 'testlargestring' });
@@ -77,6 +79,7 @@ export default function({ getService, getPageObjects }) {
});
after(async () => {
+ await security.testUser.restoreDefaults();
await esArchiver.unload('hamlet');
});
});
diff --git a/test/functional/apps/getting_started/_shakespeare.js b/test/functional/apps/getting_started/_shakespeare.js
index 5af1676cf423f..ded4eca908410 100644
--- a/test/functional/apps/getting_started/_shakespeare.js
+++ b/test/functional/apps/getting_started/_shakespeare.js
@@ -23,6 +23,7 @@ export default function({ getService, getPageObjects }) {
const log = getService('log');
const esArchiver = getService('esArchiver');
const retry = getService('retry');
+ const security = getService('security');
const PageObjects = getPageObjects([
'console',
'common',
@@ -46,11 +47,16 @@ export default function({ getService, getPageObjects }) {
'Load empty_kibana and Shakespeare Getting Started data\n' +
'https://www.elastic.co/guide/en/kibana/current/tutorial-load-dataset.html'
);
+ await security.testUser.setRoles(['kibana_admin', 'test_shakespeare_reader']);
await esArchiver.load('empty_kibana', { skipExisting: true });
log.debug('Load shakespeare data');
await esArchiver.loadIfNeeded('getting_started/shakespeare');
});
+ after(async () => {
+ await security.testUser.restoreDefaults();
+ });
+
it('should create shakespeare index pattern', async function() {
log.debug('Create shakespeare index pattern');
await PageObjects.settings.createIndexPattern('shakes', null);
diff --git a/test/functional/apps/home/_sample_data.ts b/test/functional/apps/home/_sample_data.ts
index 8bc528e045566..5812b9b96e42a 100644
--- a/test/functional/apps/home/_sample_data.ts
+++ b/test/functional/apps/home/_sample_data.ts
@@ -25,6 +25,7 @@ export default function({ getService, getPageObjects }: FtrProviderContext) {
const retry = getService('retry');
const find = getService('find');
const log = getService('log');
+ const security = getService('security');
const pieChart = getService('pieChart');
const renderable = getService('renderable');
const dashboardExpect = getService('dashboardExpect');
@@ -34,10 +35,15 @@ export default function({ getService, getPageObjects }: FtrProviderContext) {
this.tags('smoke');
before(async () => {
+ await security.testUser.setRoles(['kibana_admin', 'kibana_sample_admin']);
await PageObjects.common.navigateToUrl('home', 'tutorial_directory/sampleData');
await PageObjects.header.waitUntilLoadingHasFinished();
});
+ after(async () => {
+ await security.testUser.restoreDefaults();
+ });
+
it('should display registered flights sample data sets', async () => {
await retry.try(async () => {
const exists = await PageObjects.home.doesSampleDataSetExist('flights');
diff --git a/test/functional/apps/management/_handle_alias.js b/test/functional/apps/management/_handle_alias.js
index 55f6b56d9f0d1..4ef02f6c9e873 100644
--- a/test/functional/apps/management/_handle_alias.js
+++ b/test/functional/apps/management/_handle_alias.js
@@ -23,11 +23,13 @@ export default function({ getService, getPageObjects }) {
const esArchiver = getService('esArchiver');
const es = getService('legacyEs');
const retry = getService('retry');
+ const security = getService('security');
const PageObjects = getPageObjects(['common', 'home', 'settings', 'discover', 'timePicker']);
// FLAKY: https://github.com/elastic/kibana/issues/59717
describe.skip('Index patterns on aliases', function() {
before(async function() {
+ await security.testUser.setRoles(['kibana_admin', 'test_alias_reader']);
await esArchiver.loadIfNeeded('alias');
await esArchiver.load('empty_kibana');
await es.indices.updateAliases({
@@ -84,6 +86,7 @@ export default function({ getService, getPageObjects }) {
});
after(async () => {
+ await security.testUser.restoreDefaults();
await esArchiver.unload('alias');
});
});
diff --git a/test/functional/apps/management/_test_huge_fields.js b/test/functional/apps/management/_test_huge_fields.js
index 643cbcbe89482..bc280e51ae048 100644
--- a/test/functional/apps/management/_test_huge_fields.js
+++ b/test/functional/apps/management/_test_huge_fields.js
@@ -21,6 +21,7 @@ import expect from '@kbn/expect';
export default function({ getService, getPageObjects }) {
const esArchiver = getService('esArchiver');
+ const security = getService('security');
const PageObjects = getPageObjects(['common', 'home', 'settings']);
describe('test large number of fields', function() {
@@ -28,6 +29,7 @@ export default function({ getService, getPageObjects }) {
const EXPECTED_FIELD_COUNT = '10006';
before(async function() {
+ await security.testUser.setRoles(['kibana_admin', 'test_testhuge_reader']);
await esArchiver.loadIfNeeded('large_fields');
await PageObjects.settings.createIndexPattern('testhuge', 'date');
});
@@ -38,6 +40,7 @@ export default function({ getService, getPageObjects }) {
});
after(async () => {
+ await security.testUser.restoreDefaults();
await esArchiver.unload('large_fields');
});
});
diff --git a/test/functional/apps/visualize/_area_chart.js b/test/functional/apps/visualize/_area_chart.js
index 101b2d4f547dd..bf836cfe778b4 100644
--- a/test/functional/apps/visualize/_area_chart.js
+++ b/test/functional/apps/visualize/_area_chart.js
@@ -24,6 +24,7 @@ export default function({ getService, getPageObjects }) {
const inspector = getService('inspector');
const browser = getService('browser');
const retry = getService('retry');
+ const security = getService('security');
const PageObjects = getPageObjects([
'common',
'visualize',
@@ -58,7 +59,14 @@ export default function({ getService, getPageObjects }) {
return PageObjects.visEditor.clickGo();
};
- before(initAreaChart);
+ before(async function() {
+ await security.testUser.setRoles([
+ 'kibana_admin',
+ 'long_window_logstash',
+ 'test_logstash_reader',
+ ]);
+ await initAreaChart();
+ });
it('should save and load with special characters', async function() {
const vizNamewithSpecialChars = vizName1 + '/?&=%';
@@ -284,6 +292,7 @@ export default function({ getService, getPageObjects }) {
.pop()
.replace('embed=true', '');
await PageObjects.common.navigateToUrl('visualize', embedUrl);
+ await security.testUser.restoreDefaults();
});
});
diff --git a/test/functional/apps/visualize/_experimental_vis.js b/test/functional/apps/visualize/_experimental_vis.js
index 2ce15cf913eff..c45a95abab86e 100644
--- a/test/functional/apps/visualize/_experimental_vis.js
+++ b/test/functional/apps/visualize/_experimental_vis.js
@@ -23,7 +23,7 @@ export default ({ getService, getPageObjects }) => {
const log = getService('log');
const PageObjects = getPageObjects(['visualize']);
- describe('visualize app', function() {
+ describe('experimental visualizations in visualize app ', function() {
this.tags('smoke');
describe('experimental visualizations', () => {
diff --git a/test/functional/apps/visualize/_linked_saved_searches.ts b/test/functional/apps/visualize/_linked_saved_searches.ts
index 345987a803394..ea42f7c671985 100644
--- a/test/functional/apps/visualize/_linked_saved_searches.ts
+++ b/test/functional/apps/visualize/_linked_saved_searches.ts
@@ -32,7 +32,7 @@ export default function({ getService, getPageObjects }: FtrProviderContext) {
'visChart',
]);
- describe('visualize app', function describeIndexTests() {
+ describe('saved search visualizations from visualize app', function describeIndexTests() {
describe('linked saved searched', () => {
const savedSearchName = 'vis_saved_search';
diff --git a/test/functional/apps/visualize/_markdown_vis.js b/test/functional/apps/visualize/_markdown_vis.js
index fee6c074af5d2..649fe0a8e4c2e 100644
--- a/test/functional/apps/visualize/_markdown_vis.js
+++ b/test/functional/apps/visualize/_markdown_vis.js
@@ -29,7 +29,7 @@ export default function({ getPageObjects, getService }) {
Inline HTML that should not be rendered as html
`;
- describe('visualize app', () => {
+ describe('markdown app in visualize app', () => {
before(async function() {
await PageObjects.visualize.navigateToNewVisualization();
await PageObjects.visualize.clickMarkdownWidget();
diff --git a/test/functional/apps/visualize/_tsvb_chart.ts b/test/functional/apps/visualize/_tsvb_chart.ts
index 6a4bed3ba5892..867db66ac81dc 100644
--- a/test/functional/apps/visualize/_tsvb_chart.ts
+++ b/test/functional/apps/visualize/_tsvb_chart.ts
@@ -25,11 +25,13 @@ export default function({ getService, getPageObjects }: FtrProviderContext) {
const esArchiver = getService('esArchiver');
const log = getService('log');
const inspector = getService('inspector');
+ const security = getService('security');
const PageObjects = getPageObjects(['visualize', 'visualBuilder', 'timePicker', 'visChart']);
describe('visual builder', function describeIndexTests() {
this.tags('smoke');
beforeEach(async () => {
+ await security.testUser.setRoles(['kibana_admin', 'test_logstash_reader']);
await PageObjects.visualize.navigateToNewVisualization();
await PageObjects.visualize.clickVisualBuilder();
await PageObjects.visualBuilder.checkVisualBuilderIsPresent();
@@ -111,8 +113,10 @@ export default function({ getService, getPageObjects }: FtrProviderContext) {
await PageObjects.visualBuilder.resetPage();
await PageObjects.visualBuilder.clickMetric();
await PageObjects.visualBuilder.checkMetricTabIsPresent();
+ await security.testUser.setRoles(['kibana_admin', 'kibana_sample_admin']);
});
after(async () => {
+ await security.testUser.restoreDefaults();
await esArchiver.unload('kibana_sample_data_flights');
});
diff --git a/test/functional/apps/visualize/_vega_chart.js b/test/functional/apps/visualize/_vega_chart.js
index df0603c7f95f5..7a19bde341cdd 100644
--- a/test/functional/apps/visualize/_vega_chart.js
+++ b/test/functional/apps/visualize/_vega_chart.js
@@ -25,7 +25,7 @@ export default function({ getService, getPageObjects }) {
const inspector = getService('inspector');
const log = getService('log');
- describe('visualize app', () => {
+ describe('vega chart in visualize app', () => {
before(async () => {
log.debug('navigateToApp visualize');
await PageObjects.visualize.navigateToNewVisualization();
diff --git a/test/functional/apps/visualize/input_control_vis/input_control_range.ts b/test/functional/apps/visualize/input_control_vis/input_control_range.ts
index f48ba7b54daf1..8f079f5cc430d 100644
--- a/test/functional/apps/visualize/input_control_vis/input_control_range.ts
+++ b/test/functional/apps/visualize/input_control_vis/input_control_range.ts
@@ -25,10 +25,12 @@ export default function({ getService, getPageObjects }: FtrProviderContext) {
const esArchiver = getService('esArchiver');
const kibanaServer = getService('kibanaServer');
const find = getService('find');
+ const security = getService('security');
const { visualize, visEditor } = getPageObjects(['visualize', 'visEditor']);
describe('input control range', () => {
before(async () => {
+ await security.testUser.setRoles(['kibana_admin', 'kibana_sample_admin']);
await esArchiver.load('kibana_sample_data_flights_index_pattern');
await visualize.navigateToNewVisualization();
await visualize.clickInputControlVis();
@@ -63,6 +65,7 @@ export default function({ getService, getPageObjects }: FtrProviderContext) {
await esArchiver.loadIfNeeded('long_window_logstash');
await esArchiver.load('visualize');
await kibanaServer.uiSettings.replace({ defaultIndex: 'logstash-*' });
+ await security.testUser.restoreDefaults();
});
});
}
diff --git a/test/functional/config.js b/test/functional/config.js
index e84b7e0a98a68..11399bd6187c8 100644
--- a/test/functional/config.js
+++ b/test/functional/config.js
@@ -103,5 +103,172 @@ export default async function({ readConfigFile }) {
browser: {
type: 'chrome',
},
+
+ security: {
+ roles: {
+ test_logstash_reader: {
+ elasticsearch: {
+ cluster: [],
+ indices: [
+ {
+ names: ['logstash*'],
+ privileges: ['read', 'view_index_metadata'],
+ field_security: { grant: ['*'], except: [] },
+ },
+ ],
+ run_as: [],
+ },
+ kibana: [],
+ },
+ test_shakespeare_reader: {
+ elasticsearch: {
+ cluster: [],
+ indices: [
+ {
+ names: ['shakes*'],
+ privileges: ['read', 'view_index_metadata'],
+ field_security: { grant: ['*'], except: [] },
+ },
+ ],
+ run_as: [],
+ },
+ kibana: [],
+ },
+ test_testhuge_reader: {
+ elasticsearch: {
+ cluster: [],
+ indices: [
+ {
+ names: ['testhuge*'],
+ privileges: ['read', 'view_index_metadata'],
+ field_security: { grant: ['*'], except: [] },
+ },
+ ],
+ run_as: [],
+ },
+ kibana: [],
+ },
+ test_alias_reader: {
+ elasticsearch: {
+ cluster: [],
+ indices: [
+ {
+ names: ['alias*'],
+ privileges: ['read', 'view_index_metadata'],
+ field_security: { grant: ['*'], except: [] },
+ },
+ ],
+ run_as: [],
+ },
+ kibana: [],
+ },
+ //for sample data - can remove but not add sample data.( not ml)- for ml use built in role.
+ kibana_sample_admin: {
+ elasticsearch: {
+ cluster: [],
+ indices: [
+ {
+ names: ['kibana_sample*'],
+ privileges: ['read', 'view_index_metadata', 'manage', 'create_index', 'index'],
+ field_security: { grant: ['*'], except: [] },
+ },
+ ],
+ run_as: [],
+ },
+ kibana: [],
+ },
+
+ kibana_date_nanos: {
+ elasticsearch: {
+ cluster: [],
+ indices: [
+ {
+ names: ['date-nanos'],
+ privileges: ['read', 'view_index_metadata'],
+ field_security: { grant: ['*'], except: [] },
+ },
+ ],
+ run_as: [],
+ },
+ kibana: [],
+ },
+
+ kibana_date_nanos_custom: {
+ elasticsearch: {
+ cluster: [],
+ indices: [
+ {
+ names: ['date_nanos_custom_timestamp'],
+ privileges: ['read', 'view_index_metadata'],
+ field_security: { grant: ['*'], except: [] },
+ },
+ ],
+ run_as: [],
+ },
+ kibana: [],
+ },
+
+ kibana_date_nanos_mixed: {
+ elasticsearch: {
+ cluster: [],
+ indices: [
+ {
+ names: ['date_nanos_mixed', 'timestamp-*'],
+ privileges: ['read', 'view_index_metadata'],
+ field_security: { grant: ['*'], except: [] },
+ },
+ ],
+ run_as: [],
+ },
+ kibana: [],
+ },
+
+ kibana_large_strings: {
+ elasticsearch: {
+ cluster: [],
+ indices: [
+ {
+ names: ['testlargestring'],
+ privileges: ['read', 'view_index_metadata'],
+ field_security: { grant: ['*'], except: [] },
+ },
+ ],
+ run_as: [],
+ },
+ kibana: [],
+ },
+
+ long_window_logstash: {
+ elasticsearch: {
+ cluster: [],
+ indices: [
+ {
+ names: ['long-window-logstash-*'],
+ privileges: ['read', 'view_index_metadata'],
+ field_security: { grant: ['*'], except: [] },
+ },
+ ],
+ run_as: [],
+ },
+ kibana: [],
+ },
+
+ animals: {
+ elasticsearch: {
+ cluster: [],
+ indices: [
+ {
+ names: ['animals-*'],
+ privileges: ['read', 'view_index_metadata'],
+ field_security: { grant: ['*'], except: [] },
+ },
+ ],
+ run_as: [],
+ },
+ kibana: [],
+ },
+ },
+ defaultRoles: ['test_logstash_reader', 'kibana_admin'],
+ },
};
}
diff --git a/test/functional/page_objects/common_page.ts b/test/functional/page_objects/common_page.ts
index 60966511c1f99..5ee3726ddb44f 100644
--- a/test/functional/page_objects/common_page.ts
+++ b/test/functional/page_objects/common_page.ts
@@ -105,13 +105,16 @@ export function CommonPageProvider({ getService, getPageObjects }: FtrProviderCo
const wantedLoginPage = appUrl.includes('/login') || appUrl.includes('/logout');
if (loginPage && !wantedLoginPage) {
- log.debug(
- `Found login page. Logging in with username = ${config.get('servers.kibana.username')}`
- );
- await PageObjects.shield.login(
- config.get('servers.kibana.username'),
- config.get('servers.kibana.password')
- );
+ log.debug('Found login page');
+ if (config.get('security.disableTestUser')) {
+ await PageObjects.shield.login(
+ config.get('servers.kibana.username'),
+ config.get('servers.kibana.password')
+ );
+ } else {
+ await PageObjects.shield.login('test_user', 'changeme');
+ }
+
await find.byCssSelector(
'[data-test-subj="kibanaChrome"] nav:not(.ng-hide)',
6 * defaultFindTimeout
diff --git a/test/functional/screenshots/baseline/area_chart.png b/test/functional/screenshots/baseline/area_chart.png
index 2c2d599139100..1a381d61dd9f1 100644
Binary files a/test/functional/screenshots/baseline/area_chart.png and b/test/functional/screenshots/baseline/area_chart.png differ
diff --git a/test/functional/screenshots/baseline/tsvb_dashboard.png b/test/functional/screenshots/baseline/tsvb_dashboard.png
index d703be89b7460..f5ebccbcb96c6 100644
Binary files a/test/functional/screenshots/baseline/tsvb_dashboard.png and b/test/functional/screenshots/baseline/tsvb_dashboard.png differ
diff --git a/test/functional/services/browser.ts b/test/functional/services/browser.ts
index 02349b4e6cca2..5017947e95d03 100644
--- a/test/functional/services/browser.ts
+++ b/test/functional/services/browser.ts
@@ -21,6 +21,7 @@ import { cloneDeep } from 'lodash';
import { Key, Origin } from 'selenium-webdriver';
// @ts-ignore internal modules are not typed
import { LegacyActionSequence } from 'selenium-webdriver/lib/actions';
+import { ProvidedType } from '@kbn/test/types/ftr';
import Jimp from 'jimp';
import { modifyUrl } from '../../../src/core/utils';
@@ -28,6 +29,7 @@ import { WebElementWrapper } from './lib/web_element_wrapper';
import { FtrProviderContext } from '../ftr_provider_context';
import { Browsers } from './remote/browsers';
+export type Browser = ProvidedType;
export async function BrowserProvider({ getService }: FtrProviderContext) {
const log = getService('log');
const { driver, browserType } = await getService('__webdriver__').init();
diff --git a/test/functional/services/test_subjects.ts b/test/functional/services/test_subjects.ts
index d47b838c8d72a..e5c2e61c48a0b 100644
--- a/test/functional/services/test_subjects.ts
+++ b/test/functional/services/test_subjects.ts
@@ -19,6 +19,7 @@
import testSubjSelector from '@kbn/test-subj-selector';
import { map as mapAsync } from 'bluebird';
+import { ProvidedType } from '@kbn/test/types/ftr';
import { WebElementWrapper } from './lib/web_element_wrapper';
import { FtrProviderContext } from '../ftr_provider_context';
@@ -32,6 +33,7 @@ interface SetValueOptions {
typeCharByChar?: boolean;
}
+export type TestSubjects = ProvidedType;
export function TestSubjectsProvider({ getService }: FtrProviderContext) {
const log = getService('log');
const retry = getService('retry');
diff --git a/test/plugin_functional/plugins/rendering_plugin/server/plugin.ts b/test/plugin_functional/plugins/rendering_plugin/server/plugin.ts
index fad19728b7514..3f6a8e8773e04 100644
--- a/test/plugin_functional/plugins/rendering_plugin/server/plugin.ts
+++ b/test/plugin_functional/plugins/rendering_plugin/server/plugin.ts
@@ -33,7 +33,7 @@ export class RenderingPlugin implements Plugin {
{
includeUserSettings: schema.boolean({ defaultValue: true }),
},
- { allowUnknowns: true }
+ { unknowns: 'allow' }
),
params: schema.object({
id: schema.maybe(schema.string()),
diff --git a/x-pack/.i18nrc.json b/x-pack/.i18nrc.json
index 60a8d1fcbf229..1564eb94a6903 100644
--- a/x-pack/.i18nrc.json
+++ b/x-pack/.i18nrc.json
@@ -22,7 +22,7 @@
"xpack.infra": "plugins/infra",
"xpack.ingestManager": "plugins/ingest_manager",
"xpack.lens": "legacy/plugins/lens",
- "xpack.licenseMgmt": "legacy/plugins/license_management",
+ "xpack.licenseMgmt": "plugins/license_management",
"xpack.licensing": "plugins/licensing",
"xpack.logstash": "legacy/plugins/logstash",
"xpack.main": "legacy/plugins/xpack_main",
diff --git a/x-pack/index.js b/x-pack/index.js
index ab31d40c5d718..fb14b3dc10a4d 100644
--- a/x-pack/index.js
+++ b/x-pack/index.js
@@ -16,7 +16,6 @@ import { logstash } from './legacy/plugins/logstash';
import { beats } from './legacy/plugins/beats_management';
import { apm } from './legacy/plugins/apm';
import { maps } from './legacy/plugins/maps';
-import { licenseManagement } from './legacy/plugins/license_management';
import { indexManagement } from './legacy/plugins/index_management';
import { indexLifecycleManagement } from './legacy/plugins/index_lifecycle_management';
import { spaces } from './legacy/plugins/spaces';
@@ -52,7 +51,6 @@ module.exports = function(kibana) {
apm(kibana),
maps(kibana),
canvas(kibana),
- licenseManagement(kibana),
indexManagement(kibana),
indexLifecycleManagement(kibana),
infra(kibana),
diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/MachineLearningFlyout/view.tsx b/x-pack/legacy/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/MachineLearningFlyout/view.tsx
index 31fc4db8f1a2f..cff190cd98a11 100644
--- a/x-pack/legacy/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/MachineLearningFlyout/view.tsx
+++ b/x-pack/legacy/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/MachineLearningFlyout/view.tsx
@@ -209,7 +209,7 @@ export function MachineLearningFlyoutView({
{i18n.translate(
'xpack.apm.serviceDetails.enableAnomalyDetectionPanel.createNewJobButtonLabel',
{
- defaultMessage: 'Create new job'
+ defaultMessage: 'Create job'
}
)}
diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/EmptyBanner.test.tsx b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/EmptyBanner.test.tsx
new file mode 100644
index 0000000000000..d61dea80666a0
--- /dev/null
+++ b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/EmptyBanner.test.tsx
@@ -0,0 +1,62 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { act, render, wait } from '@testing-library/react';
+import cytoscape from 'cytoscape';
+import React, { FunctionComponent } from 'react';
+import { MockApmPluginContextWrapper } from '../../../utils/testHelpers';
+import { CytoscapeContext } from './Cytoscape';
+import { EmptyBanner } from './EmptyBanner';
+
+const cy = cytoscape({});
+
+const wrapper: FunctionComponent = ({ children }) => (
+
+ {children}
+
+);
+
+describe('EmptyBanner', () => {
+ describe('when cy is undefined', () => {
+ it('renders null', () => {
+ const noCytoscapeWrapper: FunctionComponent = ({ children }) => (
+
+
+ {children}
+
+
+ );
+ const component = render( , {
+ wrapper: noCytoscapeWrapper
+ });
+
+ expect(component.container.children).toHaveLength(0);
+ });
+ });
+
+ describe('with no nodes', () => {
+ it('renders null', () => {
+ const component = render( , {
+ wrapper
+ });
+
+ expect(component.container.children).toHaveLength(0);
+ });
+ });
+
+ describe('with one node', () => {
+ it('does not render null', async () => {
+ const component = render( , { wrapper });
+
+ await act(async () => {
+ cy.add({ data: { id: 'test id' } });
+ await wait(() => {
+ expect(component.container.children.length).toBeGreaterThan(0);
+ });
+ });
+ });
+ });
+});
diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/EmptyBanner.tsx b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/EmptyBanner.tsx
index 418430e37b21e..464bf166eb80f 100644
--- a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/EmptyBanner.tsx
+++ b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/EmptyBanner.tsx
@@ -7,37 +7,70 @@
import { EuiCallOut } from '@elastic/eui';
import lightTheme from '@elastic/eui/dist/eui_theme_light.json';
import { i18n } from '@kbn/i18n';
-import React from 'react';
+import React, { useContext, useEffect, useState } from 'react';
import styled from 'styled-components';
import { ElasticDocsLink } from '../../shared/Links/ElasticDocsLink';
+import { CytoscapeContext } from './Cytoscape';
-const EmptyBannerCallOut = styled(EuiCallOut)`
+const EmptyBannerContainer = styled.div`
margin: ${lightTheme.gutterTypes.gutterSmall};
/* Add some extra margin so it displays to the right of the controls. */
- margin-left: calc(
- ${lightTheme.gutterTypes.gutterLarge} +
- ${lightTheme.gutterTypes.gutterExtraLarge}
+ left: calc(
+ ${lightTheme.gutterTypes.gutterExtraLarge} +
+ ${lightTheme.gutterTypes.gutterSmall}
);
position: absolute;
z-index: 1;
`;
export function EmptyBanner() {
+ const cy = useContext(CytoscapeContext);
+ const [nodeCount, setNodeCount] = useState(0);
+
+ useEffect(() => {
+ const handler: cytoscape.EventHandler = event =>
+ setNodeCount(event.cy.nodes().length);
+
+ if (cy) {
+ cy.on('add remove', 'node', handler);
+ }
+
+ return () => {
+ if (cy) {
+ cy.removeListener('add remove', 'node', handler);
+ }
+ };
+ }, [cy]);
+
+ // Only show if there's a single node.
+ if (!cy || nodeCount !== 1) {
+ return null;
+ }
+
+ // Since we're absolutely positioned, we need to get the full width and
+ // subtract the space for controls and margins.
+ const width =
+ cy.width() -
+ parseInt(lightTheme.gutterTypes.gutterExtraLarge, 10) -
+ parseInt(lightTheme.gutterTypes.gutterLarge, 10);
+
return (
-
- {i18n.translate('xpack.apm.serviceMap.emptyBanner.message', {
- defaultMessage:
- "We will map out connected services and external requests if we can detect them. Please make sure you're running the latest version of the APM agent."
- })}{' '}
-
- {i18n.translate('xpack.apm.serviceMap.emptyBanner.docsLink', {
- defaultMessage: 'Learn more in the docs'
+
+
-
+ >
+ {i18n.translate('xpack.apm.serviceMap.emptyBanner.message', {
+ defaultMessage:
+ "We will map out connected services and external requests if we can detect them. Please make sure you're running the latest version of the APM agent."
+ })}{' '}
+
+ {i18n.translate('xpack.apm.serviceMap.emptyBanner.docsLink', {
+ defaultMessage: 'Learn more in the docs'
+ })}
+
+
+
);
}
diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/PlatinumLicensePrompt.tsx b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/PlatinumLicensePrompt.tsx
index 9213349a1492b..77f0b64ba0fb1 100644
--- a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/PlatinumLicensePrompt.tsx
+++ b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/PlatinumLicensePrompt.tsx
@@ -6,10 +6,12 @@
import {
EuiButton,
- EuiEmptyPrompt,
+ EuiPanel,
EuiFlexGroup,
EuiFlexItem,
- EuiPanel
+ EuiTitle,
+ EuiText,
+ EuiSpacer
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import React from 'react';
@@ -18,7 +20,8 @@ import { useKibanaUrl } from '../../../hooks/useKibanaUrl';
export function PlatinumLicensePrompt() {
// Set the height to give it some top margin
- const style = { height: '60vh' };
+ const flexGroupStyle = { height: '60vh' };
+ const flexItemStyle = { width: 600, textAlign: 'center' as const };
const licensePageUrl = useKibanaUrl(
'/app/kibana',
@@ -29,30 +32,41 @@ export function PlatinumLicensePrompt() {
-
-
-
- {i18n.translate(
- 'xpack.apm.serviceMap.licensePromptButtonText',
- {
- defaultMessage: 'Start 30-day Platinum trial'
- }
- )}
-
- ]}
- body={{invalidLicenseMessage}
}
- title={
+
+
+
+
+
{i18n.translate('xpack.apm.serviceMap.licensePromptTitle', {
defaultMessage: 'Service maps is available in Platinum.'
})}
- }
- />
+
+
+
+ {invalidLicenseMessage}
+
+
+
+ {i18n.translate('xpack.apm.serviceMap.licensePromptButtonText', {
+ defaultMessage: 'Start 30-day Platinum trial'
+ })}
+
+
diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/dot-net.svg b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/dot-net.svg
index 9f7427f0e1001..da7f1a8fde45d 100644
--- a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/dot-net.svg
+++ b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/dot-net.svg
@@ -1,127 +1,3 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/index.tsx b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/index.tsx
index 7bbb77a49c84b..93aa3d406028c 100644
--- a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/index.tsx
+++ b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/index.tsx
@@ -15,6 +15,8 @@ import React, {
useRef,
useState
} from 'react';
+import { EuiBetaBadge } from '@elastic/eui';
+import styled from 'styled-components';
import { isValidPlatinumLicense } from '../../../../../../../plugins/apm/common/service_map';
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
import { ServiceMapAPIResponse } from '../../../../../../../plugins/apm/server/lib/service_map/get_service_map';
@@ -56,7 +58,12 @@ ${theme.euiColorLightShade}`,
margin: `-${theme.gutterTypes.gutterLarge}`,
marginTop: 0
};
-
+const BetaBadgeContainer = styled.div`
+ right: ${theme.gutterTypes.gutterMedium};
+ position: absolute;
+ top: ${theme.gutterTypes.gutterSmall};
+ z-index: 1; /* The element containing the cytoscape canvas has z-index = 0. */
+`;
const MAX_REQUESTS = 5;
export function ServiceMap({ serviceName }: ServiceMapProps) {
@@ -182,10 +189,22 @@ export function ServiceMap({ serviceName }: ServiceMapProps) {
style={cytoscapeDivStyle}
>
- {serviceName && renderedElements.current.length === 1 && (
-
- )}
+ {serviceName && }
+
+
+
) : (
diff --git a/x-pack/legacy/plugins/canvas/public/components/workpad_header/workpad_export/index.ts b/x-pack/legacy/plugins/canvas/public/components/workpad_header/workpad_export/index.ts
index 7f81adad6bf9b..949264fcc9fdb 100644
--- a/x-pack/legacy/plugins/canvas/public/components/workpad_header/workpad_export/index.ts
+++ b/x-pack/legacy/plugins/canvas/public/components/workpad_header/workpad_export/index.ts
@@ -6,7 +6,7 @@
import { connect } from 'react-redux';
import { compose, withProps } from 'recompose';
-import * as jobCompletionNotifications from '../../../../../reporting/public/lib/job_completion_notifications';
+import { jobCompletionNotifications } from '../../../../../../../plugins/reporting/public';
// @ts-ignore Untyped local
import { getWorkpad, getPages } from '../../../state/selectors/workpad';
// @ts-ignore Untyped local
diff --git a/x-pack/legacy/plugins/cross_cluster_replication/public/app/components/auto_follow_pattern_form.js b/x-pack/legacy/plugins/cross_cluster_replication/public/app/components/auto_follow_pattern_form.js
index ebb731a1b1aca..d4e418a964c8f 100644
--- a/x-pack/legacy/plugins/cross_cluster_replication/public/app/components/auto_follow_pattern_form.js
+++ b/x-pack/legacy/plugins/cross_cluster_replication/public/app/components/auto_follow_pattern_form.js
@@ -29,7 +29,8 @@ import {
EuiTitle,
} from '@elastic/eui';
-import { INDEX_ILLEGAL_CHARACTERS_VISIBLE } from 'ui/indices';
+import { indices } from '../../../../../../../src/plugins/es_ui_shared/public';
+import { indexPatterns } from '../../../../../../../src/plugins/data/public';
import routing from '../services/routing';
import { extractQueryParams } from '../services/query_params';
@@ -44,10 +45,9 @@ import {
} from '../services/auto_follow_pattern_validators';
import { AutoFollowPatternRequestFlyout } from './auto_follow_pattern_request_flyout';
-import { indexPatterns } from '../../../../../../../src/plugins/data/public';
const indexPatternIllegalCharacters = indexPatterns.ILLEGAL_CHARACTERS_VISIBLE.join(' ');
-const indexNameIllegalCharacters = INDEX_ILLEGAL_CHARACTERS_VISIBLE.join(' ');
+const indexNameIllegalCharacters = indices.INDEX_ILLEGAL_CHARACTERS_VISIBLE.join(' ');
const getEmptyAutoFollowPattern = (remoteClusterName = '') => ({
name: '',
diff --git a/x-pack/legacy/plugins/cross_cluster_replication/public/app/components/follower_index_form/follower_index_form.js b/x-pack/legacy/plugins/cross_cluster_replication/public/app/components/follower_index_form/follower_index_form.js
index 329ef4756133d..fc8f9398807e7 100644
--- a/x-pack/legacy/plugins/cross_cluster_replication/public/app/components/follower_index_form/follower_index_form.js
+++ b/x-pack/legacy/plugins/cross_cluster_replication/public/app/components/follower_index_form/follower_index_form.js
@@ -9,7 +9,6 @@ import PropTypes from 'prop-types';
import { debounce } from 'lodash';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
-import { INDEX_ILLEGAL_CHARACTERS_VISIBLE } from 'ui/indices';
import { fatalError } from 'ui/notify';
import {
@@ -30,6 +29,7 @@ import {
EuiTitle,
} from '@elastic/eui';
+import { indices } from '../../../../../../../../src/plugins/es_ui_shared/public';
import { indexNameValidator, leaderIndexValidator } from '../../services/input_validation';
import routing from '../../services/routing';
import { loadIndices } from '../../services/api';
@@ -47,7 +47,7 @@ import { RemoteClustersFormField } from '../remote_clusters_form_field';
import { FollowerIndexRequestFlyout } from './follower_index_request_flyout';
-const indexNameIllegalCharacters = INDEX_ILLEGAL_CHARACTERS_VISIBLE.join(' ');
+const indexNameIllegalCharacters = indices.INDEX_ILLEGAL_CHARACTERS_VISIBLE.join(' ');
const fieldToValidatorMap = advancedSettingsFields.reduce(
(map, advancedSetting) => {
diff --git a/x-pack/legacy/plugins/cross_cluster_replication/public/app/components/follower_index_form/follower_index_form.test.js b/x-pack/legacy/plugins/cross_cluster_replication/public/app/components/follower_index_form/follower_index_form.test.js
index aac0427098813..93da20a8ed93c 100644
--- a/x-pack/legacy/plugins/cross_cluster_replication/public/app/components/follower_index_form/follower_index_form.test.js
+++ b/x-pack/legacy/plugins/cross_cluster_replication/public/app/components/follower_index_form/follower_index_form.test.js
@@ -7,9 +7,6 @@
import { updateFields, updateFormErrors } from './follower_index_form';
jest.mock('ui/new_platform');
-jest.mock('ui/indices', () => ({
- INDEX_ILLEGAL_CHARACTERS_VISIBLE: [],
-}));
describe(' state transitions', () => {
it('updateFormErrors() should merge errors with existing fieldsErrors', () => {
diff --git a/x-pack/legacy/plugins/cross_cluster_replication/public/app/services/auto_follow_pattern_validators.js b/x-pack/legacy/plugins/cross_cluster_replication/public/app/services/auto_follow_pattern_validators.js
index 18610c87c0a51..5186a02383d33 100644
--- a/x-pack/legacy/plugins/cross_cluster_replication/public/app/services/auto_follow_pattern_validators.js
+++ b/x-pack/legacy/plugins/cross_cluster_replication/public/app/services/auto_follow_pattern_validators.js
@@ -8,13 +8,14 @@ import React from 'react';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
-import {
+import { indices } from '../../../../../../../src/plugins/es_ui_shared/public';
+import { indexPatterns } from '../../../../../../../src/plugins/data/public';
+
+const {
indexNameBeginsWithPeriod,
findIllegalCharactersInIndexName,
indexNameContainsSpaces,
-} from 'ui/indices';
-
-import { indexPatterns } from '../../../../../../../src/plugins/data/public';
+} = indices;
export const validateName = (name = '') => {
let errorMsg = null;
diff --git a/x-pack/legacy/plugins/cross_cluster_replication/public/app/services/input_validation.js b/x-pack/legacy/plugins/cross_cluster_replication/public/app/services/input_validation.js
index 22f7d3be2795f..981b3f5929751 100644
--- a/x-pack/legacy/plugins/cross_cluster_replication/public/app/services/input_validation.js
+++ b/x-pack/legacy/plugins/cross_cluster_replication/public/app/services/input_validation.js
@@ -6,7 +6,7 @@
import React from 'react';
import { FormattedMessage } from '@kbn/i18n/react';
-import { INDEX_ILLEGAL_CHARACTERS_VISIBLE } from 'ui/indices';
+import { indices } from '../../../../../../../src/plugins/es_ui_shared/public';
const isEmpty = value => {
return !value || !value.trim().length;
@@ -19,7 +19,7 @@ const beginsWithPeriod = value => {
};
const findIllegalCharacters = value => {
- return INDEX_ILLEGAL_CHARACTERS_VISIBLE.reduce((chars, char) => {
+ return indices.INDEX_ILLEGAL_CHARACTERS_VISIBLE.reduce((chars, char) => {
if (value.includes(char)) {
chars.push(char);
}
diff --git a/x-pack/legacy/plugins/license_management/__jest__/__snapshots__/upload_license.test.tsx.snap b/x-pack/legacy/plugins/license_management/__jest__/__snapshots__/upload_license.test.tsx.snap
deleted file mode 100644
index e19958568b3be..0000000000000
--- a/x-pack/legacy/plugins/license_management/__jest__/__snapshots__/upload_license.test.tsx.snap
+++ /dev/null
@@ -1,2826 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`UploadLicense should display a modal when license requires acknowledgement 1`] = `
-
-
-
-
-
-
-
-
-
-
-
- Upload your license
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Some functionality will be lost if you replace your TRIAL license with a BASIC license. Review the list of features below.
-
-
-
-
- Watcher will be disabled
-
-
-
-
-
-
-
-
-
-
-
-
-
- }
- >
-
- }
- confirmButtonText={
-
- }
- onCancel={[Function]}
- onConfirm={[Function]}
- title={
-
- }
- >
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Some functionality will be lost if you replace your TRIAL license with a BASIC license. Review the list of features below.
-
-
-
-
- Watcher will be disabled
-
-
-
-
-
-
-
-
-
-
-
- }
- onActivation={[Function]}
- onDeactivation={[Function]}
- persistentFocus={false}
- >
-
-
-
-
-
-
-
-
-
-
-
-
- Some functionality will be lost if you replace your TRIAL license with a BASIC license. Review the list of features below.
-
-
-
-
- Watcher will be disabled
-
-
-
-
-
-
-
-
-
-
-
- }
- onActivation={[Function]}
- onDeactivation={[Function]}
- persistentFocus={false}
- />
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Confirm License Upload
-
-
-
-
-
-
-
-
-
-
-
-
-
- Some functionality will be lost if you replace your TRIAL license with a BASIC license. Review the list of features below.
-
-
-
-
-
-
- Watcher will be disabled
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Cancel
-
-
-
-
-
-
-
-
-
-
- Confirm
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Your license key is a JSON file with a signature attached.
-
-
-
-
-
- ,
- }
- }
- >
- Uploading a license will replace your current
-
- license.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- }
- onChange={[Function]}
- >
-
-
-
-
-
-
-
-
-
-
-
-
- Select or drag your license file
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Upload
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-`;
-
-exports[`UploadLicense should display an error when ES says license is expired 1`] = `
-
-
-
-
-
-
-
-
-
-
-
- Upload your license
-
-
-
-
-
-
-
-
-
-
- Your license key is a JSON file with a signature attached.
-
-
-
-
-
- ,
- }
- }
- >
- Uploading a license will replace your current
-
- license.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Please address the errors in your form.
-
-
-
-
-
-
- The supplied license has expired.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- }
- onChange={[Function]}
- >
-
-
-
-
-
-
-
-
-
-
-
-
- Select or drag your license file
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Upload
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-`;
-
-exports[`UploadLicense should display an error when ES says license is invalid 1`] = `
-
-
-
-
-
-
-
-
-
-
-
- Upload your license
-
-
-
-
-
-
-
-
-
-
- Your license key is a JSON file with a signature attached.
-
-
-
-
-
- ,
- }
- }
- >
- Uploading a license will replace your current
-
- license.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Please address the errors in your form.
-
-
-
-
-
-
- The supplied license is not valid for this product.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- }
- onChange={[Function]}
- >
-
-
-
-
-
-
-
-
-
-
-
-
- Select or drag your license file
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Upload
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-`;
-
-exports[`UploadLicense should display an error when submitting invalid JSON 1`] = `
-
-
-
-
-
-
-
-
-
-
-
- Upload your license
-
-
-
-
-
-
-
-
-
-
- Your license key is a JSON file with a signature attached.
-
-
-
-
-
- ,
- }
- }
- >
- Uploading a license will replace your current
-
- license.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Please address the errors in your form.
-
-
-
-
-
-
- Error encountered uploading license: Check your license file.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- }
- onChange={[Function]}
- >
-
-
-
-
-
-
-
-
-
-
-
-
- Select or drag your license file
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Upload
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-`;
-
-exports[`UploadLicense should display error when ES returns error 1`] = `
-
-
-
-
-
-
-
-
-
-
-
- Upload your license
-
-
-
-
-
-
-
-
-
-
- Your license key is a JSON file with a signature attached.
-
-
-
-
-
- ,
- }
- }
- >
- Uploading a license will replace your current
-
- license.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Please address the errors in your form.
-
-
-
-
-
-
- Error encountered uploading license: Can not upgrade to a production license unless TLS is configured or security is disabled
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- }
- onChange={[Function]}
- >
-
-
-
-
-
-
-
-
-
-
-
-
- Select or drag your license file
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Upload
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-`;
diff --git a/x-pack/legacy/plugins/license_management/index.ts b/x-pack/legacy/plugins/license_management/index.ts
deleted file mode 100644
index e9fbb56e9d6ac..0000000000000
--- a/x-pack/legacy/plugins/license_management/index.ts
+++ /dev/null
@@ -1,49 +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;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import { Legacy } from 'kibana';
-import { resolve } from 'path';
-import { PLUGIN } from './common/constants';
-import { plugin } from './server/np_ready';
-
-export function licenseManagement(kibana: any) {
- return new kibana.Plugin({
- id: PLUGIN.ID,
- configPrefix: 'xpack.license_management',
- publicDir: resolve(__dirname, 'public'),
- require: ['kibana', 'elasticsearch'],
- uiExports: {
- styleSheetPaths: resolve(__dirname, 'public/np_ready/application/index.scss'),
- managementSections: ['plugins/license_management/legacy'],
- injectDefaultVars(server: Legacy.Server) {
- const config = server.config();
- return {
- licenseManagementUiEnabled: config.get('xpack.license_management.ui.enabled'),
- };
- },
- },
- config(Joi: any) {
- return Joi.object({
- // display menu item
- ui: Joi.object({
- enabled: Joi.boolean().default(true),
- }).default(),
-
- // enable plugin
- enabled: Joi.boolean().default(true),
- }).default();
- },
- init: (server: Legacy.Server) => {
- plugin({} as any).setup(server.newPlatform.setup.core, {
- ...server.newPlatform.setup.plugins,
- __LEGACY: {
- xpackMain: server.plugins.xpack_main,
- elasticsearch: server.plugins.elasticsearch,
- },
- });
- },
- });
-}
diff --git a/x-pack/legacy/plugins/license_management/public/management_section.ts b/x-pack/legacy/plugins/license_management/public/management_section.ts
deleted file mode 100644
index c7232649857e3..0000000000000
--- a/x-pack/legacy/plugins/license_management/public/management_section.ts
+++ /dev/null
@@ -1,20 +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;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import { management } from 'ui/management';
-import chrome from 'ui/chrome';
-import { BASE_PATH, PLUGIN } from '../common/constants';
-
-const licenseManagementUiEnabled = chrome.getInjected('licenseManagementUiEnabled');
-
-if (licenseManagementUiEnabled) {
- management.getSection('elasticsearch').register('license_management', {
- visible: true,
- display: PLUGIN.TITLE,
- order: 99,
- url: `#${BASE_PATH}home`,
- });
-}
diff --git a/x-pack/legacy/plugins/license_management/public/np_ready/application/boot.tsx b/x-pack/legacy/plugins/license_management/public/np_ready/application/boot.tsx
deleted file mode 100644
index 49bb4ce984e48..0000000000000
--- a/x-pack/legacy/plugins/license_management/public/np_ready/application/boot.tsx
+++ /dev/null
@@ -1,79 +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;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import React from 'react';
-import { Provider } from 'react-redux';
-import { HashRouter } from 'react-router-dom';
-import { render, unmountComponentAtNode } from 'react-dom';
-import * as history from 'history';
-import { DocLinksStart, HttpSetup, ToastsSetup, ChromeStart } from 'src/core/public';
-
-import { TelemetryPluginSetup } from 'src/plugins/telemetry/public';
-// @ts-ignore
-import { App } from './app.container';
-// @ts-ignore
-import { licenseManagementStore } from './store';
-
-import { setDocLinks } from './lib/docs_links';
-import { BASE_PATH } from '../../../common/constants';
-import { Breadcrumb } from './breadcrumbs';
-
-interface AppDependencies {
- element: HTMLElement;
- chrome: ChromeStart;
-
- I18nContext: any;
- legacy: {
- xpackInfo: any;
- refreshXpack: () => void;
- MANAGEMENT_BREADCRUMB: Breadcrumb;
- };
-
- toasts: ToastsSetup;
- docLinks: DocLinksStart;
- http: HttpSetup;
- telemetry?: TelemetryPluginSetup;
-}
-
-export const boot = (deps: AppDependencies) => {
- const { I18nContext, element, legacy, toasts, docLinks, http, chrome, telemetry } = deps;
- const { ELASTIC_WEBSITE_URL, DOC_LINK_VERSION } = docLinks;
- const esBase = `${ELASTIC_WEBSITE_URL}guide/en/elasticsearch/reference/${DOC_LINK_VERSION}`;
- const securityDocumentationLink = `${esBase}/security-settings.html`;
-
- const initialState = { license: legacy.xpackInfo.get('license') };
-
- setDocLinks({ securityDocumentationLink });
-
- const services = {
- legacy: {
- refreshXpack: legacy.refreshXpack,
- xPackInfo: legacy.xpackInfo,
- },
- // So we can imperatively control the hash route
- history: history.createHashHistory({ basename: BASE_PATH }),
- toasts,
- http,
- chrome,
- telemetry,
- MANAGEMENT_BREADCRUMB: legacy.MANAGEMENT_BREADCRUMB,
- };
-
- const store = licenseManagementStore(initialState, services);
-
- render(
-
-
-
-
-
-
- ,
- element
- );
-
- return () => unmountComponentAtNode(element);
-};
diff --git a/x-pack/legacy/plugins/license_management/public/np_ready/application/breadcrumbs.ts b/x-pack/legacy/plugins/license_management/public/np_ready/application/breadcrumbs.ts
deleted file mode 100644
index 2da04b22c0386..0000000000000
--- a/x-pack/legacy/plugins/license_management/public/np_ready/application/breadcrumbs.ts
+++ /dev/null
@@ -1,37 +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;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import { i18n } from '@kbn/i18n';
-
-import { BASE_PATH } from '../../../common/constants';
-
-export interface Breadcrumb {
- text: string;
- href: string;
-}
-
-export function getDashboardBreadcrumbs(root: Breadcrumb) {
- return [
- root,
- {
- text: i18n.translate('xpack.licenseMgmt.dashboard.breadcrumb', {
- defaultMessage: 'License management',
- }),
- href: `#${BASE_PATH}home`,
- },
- ];
-}
-
-export function getUploadBreadcrumbs(root: Breadcrumb) {
- return [
- ...getDashboardBreadcrumbs(root),
- {
- text: i18n.translate('xpack.licenseMgmt.upload.breadcrumb', {
- defaultMessage: 'Upload',
- }),
- },
- ];
-}
diff --git a/x-pack/legacy/plugins/license_management/public/np_ready/application/store/actions/set_breadcrumb.ts b/x-pack/legacy/plugins/license_management/public/np_ready/application/store/actions/set_breadcrumb.ts
deleted file mode 100644
index bcb4a907bdf88..0000000000000
--- a/x-pack/legacy/plugins/license_management/public/np_ready/application/store/actions/set_breadcrumb.ts
+++ /dev/null
@@ -1,22 +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;
- * you may not use this file except in compliance with the Elastic License.
- */
-import { ThunkAction } from 'redux-thunk';
-import { ChromeStart } from 'src/core/public';
-import { getDashboardBreadcrumbs, getUploadBreadcrumbs, Breadcrumb } from '../../breadcrumbs';
-
-export const setBreadcrumb = (
- section: 'dashboard' | 'upload'
-): ThunkAction => (
- dispatch,
- getState,
- { chrome, MANAGEMENT_BREADCRUMB }
-) => {
- if (section === 'upload') {
- chrome.setBreadcrumbs(getUploadBreadcrumbs(MANAGEMENT_BREADCRUMB));
- } else {
- chrome.setBreadcrumbs(getDashboardBreadcrumbs(MANAGEMENT_BREADCRUMB));
- }
-};
diff --git a/x-pack/legacy/plugins/license_management/public/np_ready/plugin.ts b/x-pack/legacy/plugins/license_management/public/np_ready/plugin.ts
deleted file mode 100644
index 60876c9b638d1..0000000000000
--- a/x-pack/legacy/plugins/license_management/public/np_ready/plugin.ts
+++ /dev/null
@@ -1,52 +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;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import { CoreSetup, CoreStart, Plugin } from 'src/core/public';
-import { TelemetryPluginSetup } from 'src/plugins/telemetry/public';
-import { XPackMainPlugin } from '../../../xpack_main/server/xpack_main';
-import { PLUGIN } from '../../common/constants';
-import { Breadcrumb } from './application/breadcrumbs';
-export interface Plugins {
- telemetry: TelemetryPluginSetup;
- __LEGACY: {
- xpackInfo: XPackMainPlugin;
- refreshXpack: () => void;
- MANAGEMENT_BREADCRUMB: Breadcrumb;
- };
-}
-
-export class LicenseManagementUIPlugin implements Plugin {
- setup({ application, notifications, http }: CoreSetup, { __LEGACY, telemetry }: Plugins) {
- application.register({
- id: PLUGIN.ID,
- title: PLUGIN.TITLE,
- async mount(
- {
- core: {
- docLinks,
- i18n: { Context: I18nContext },
- chrome,
- },
- },
- { element }
- ) {
- const { boot } = await import('./application');
- return boot({
- legacy: { ...__LEGACY },
- I18nContext,
- toasts: notifications.toasts,
- docLinks,
- http,
- element,
- chrome,
- telemetry,
- });
- },
- });
- }
- start(core: CoreStart, plugins: any) {}
- stop() {}
-}
diff --git a/x-pack/legacy/plugins/license_management/public/register_route.ts b/x-pack/legacy/plugins/license_management/public/register_route.ts
deleted file mode 100644
index f9258f68c555a..0000000000000
--- a/x-pack/legacy/plugins/license_management/public/register_route.ts
+++ /dev/null
@@ -1,87 +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;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import { App } from 'src/core/public';
-
-/* Legacy Imports */
-import { npSetup, npStart } from 'ui/new_platform';
-import { MANAGEMENT_BREADCRUMB } from 'ui/management';
-import chrome from 'ui/chrome';
-import routes from 'ui/routes';
-// @ts-ignore
-import { xpackInfo } from 'plugins/xpack_main/services/xpack_info';
-
-import { plugin } from './np_ready';
-import { BASE_PATH } from '../common/constants';
-
-const licenseManagementUiEnabled = chrome.getInjected('licenseManagementUiEnabled');
-
-if (licenseManagementUiEnabled) {
- /*
- This method handles the cleanup needed when route is scope is destroyed. It also prevents Angular
- from destroying scope when route changes and both old route and new route are this same route.
- */
- const manageAngularLifecycle = ($scope: any, $route: any, unmount: () => void) => {
- const lastRoute = $route.current;
- const deregister = $scope.$on('$locationChangeSuccess', () => {
- const currentRoute = $route.current;
- // if templates are the same we are on the same route
- if (lastRoute.$$route.template === currentRoute.$$route.template) {
- // this prevents angular from destroying scope
- $route.current = lastRoute;
- }
- });
- $scope.$on('$destroy', () => {
- if (deregister) {
- deregister();
- }
- unmount();
- });
- };
-
- const template = `
-
- `;
-
- routes.when(`${BASE_PATH}:view?`, {
- template,
- controllerAs: 'licenseManagement',
- controller: class LicenseManagementController {
- constructor($injector: any, $rootScope: any, $scope: any, $route: any) {
- $scope.$$postDigest(() => {
- const element = document.getElementById('licenseReactRoot')!;
-
- const refreshXpack = async () => {
- await xpackInfo.refresh($injector);
- };
-
- plugin({} as any).setup(
- {
- ...npSetup.core,
- application: {
- ...npSetup.core.application,
- async register(app: App) {
- const unmountApp = await app.mount({ ...npStart } as any, {
- element,
- appBasePath: '',
- onAppLeave: () => undefined,
- // TODO: adapt to use Core's ScopedHistory
- history: {} as any,
- });
- manageAngularLifecycle($scope, $route, unmountApp as any);
- },
- },
- },
- {
- telemetry: (npSetup.plugins as any).telemetry,
- __LEGACY: { xpackInfo, refreshXpack, MANAGEMENT_BREADCRUMB },
- }
- );
- });
- }
- } as any,
- } as any);
-}
diff --git a/x-pack/legacy/plugins/license_management/server/np_ready/lib/start_trial.ts b/x-pack/legacy/plugins/license_management/server/np_ready/lib/start_trial.ts
deleted file mode 100644
index 3569085d413ca..0000000000000
--- a/x-pack/legacy/plugins/license_management/server/np_ready/lib/start_trial.ts
+++ /dev/null
@@ -1,47 +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;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import { KibanaRequest } from 'src/core/server';
-import { ElasticsearchPlugin } from '../../../../../../../src/legacy/core_plugins/elasticsearch';
-
-export async function canStartTrial(
- req: KibanaRequest,
- elasticsearch: ElasticsearchPlugin
-) {
- const { callWithRequest } = elasticsearch.getCluster('admin');
- const options = {
- method: 'GET',
- path: '/_license/trial_status',
- };
- try {
- const response = await callWithRequest(req as any, 'transport.request', options);
- return response.eligible_to_start_trial;
- } catch (error) {
- return error.body;
- }
-}
-
-export async function startTrial(
- req: KibanaRequest,
- elasticsearch: ElasticsearchPlugin,
- xpackInfo: any
-) {
- const { callWithRequest } = elasticsearch.getCluster('admin');
- const options = {
- method: 'POST',
- path: '/_license/start_trial?acknowledge=true',
- };
- try {
- const response = await callWithRequest(req as any, 'transport.request', options);
- const { trial_was_started: trialWasStarted } = response;
- if (trialWasStarted) {
- await xpackInfo.refreshNow();
- }
- return response;
- } catch (error) {
- return error.body;
- }
-}
diff --git a/x-pack/legacy/plugins/license_management/server/np_ready/plugin.ts b/x-pack/legacy/plugins/license_management/server/np_ready/plugin.ts
deleted file mode 100644
index 9f065cf98d715..0000000000000
--- a/x-pack/legacy/plugins/license_management/server/np_ready/plugin.ts
+++ /dev/null
@@ -1,35 +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;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import { Plugin, CoreSetup } from 'src/core/server';
-import { Dependencies, Server } from './types';
-
-import {
- registerLicenseRoute,
- registerStartTrialRoutes,
- registerStartBasicRoute,
- registerPermissionsRoute,
-} from './routes/api/license';
-
-export class LicenseManagementServerPlugin implements Plugin {
- setup({ http }: CoreSetup, { __LEGACY }: Dependencies) {
- const xpackInfo = __LEGACY.xpackMain.info;
- const router = http.createRouter();
-
- const server: Server = {
- router,
- };
-
- const legacy = { plugins: __LEGACY };
-
- registerLicenseRoute(server, legacy, xpackInfo);
- registerStartTrialRoutes(server, legacy, xpackInfo);
- registerStartBasicRoute(server, legacy, xpackInfo);
- registerPermissionsRoute(server, legacy, xpackInfo);
- }
- start() {}
- stop() {}
-}
diff --git a/x-pack/legacy/plugins/license_management/server/np_ready/routes/api/license/register_license_route.ts b/x-pack/legacy/plugins/license_management/server/np_ready/routes/api/license/register_license_route.ts
deleted file mode 100644
index cdc929a2f3bb3..0000000000000
--- a/x-pack/legacy/plugins/license_management/server/np_ready/routes/api/license/register_license_route.ts
+++ /dev/null
@@ -1,32 +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;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import { schema } from '@kbn/config-schema';
-import { putLicense } from '../../../lib/license';
-import { Legacy, Server } from '../../../types';
-
-export function registerLicenseRoute(server: Server, legacy: Legacy, xpackInfo: any) {
- server.router.put(
- {
- path: '/api/license',
- validate: {
- query: schema.object({ acknowledge: schema.string() }),
- body: schema.object({
- license: schema.object({}, { allowUnknowns: true }),
- }),
- },
- },
- async (ctx, request, response) => {
- try {
- return response.ok({
- body: await putLicense(request, legacy.plugins.elasticsearch, xpackInfo),
- });
- } catch (e) {
- return response.internalError({ body: e });
- }
- }
- );
-}
diff --git a/x-pack/legacy/plugins/license_management/server/np_ready/routes/api/license/register_permissions_route.ts b/x-pack/legacy/plugins/license_management/server/np_ready/routes/api/license/register_permissions_route.ts
deleted file mode 100644
index 0f6c343d04fcd..0000000000000
--- a/x-pack/legacy/plugins/license_management/server/np_ready/routes/api/license/register_permissions_route.ts
+++ /dev/null
@@ -1,29 +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;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import { getPermissions } from '../../../lib/permissions';
-import { Legacy, Server } from '../../../types';
-
-export function registerPermissionsRoute(server: Server, legacy: Legacy, xpackInfo: any) {
- server.router.post(
- { path: '/api/license/permissions', validate: false },
- async (ctx, request, response) => {
- if (!xpackInfo) {
- // xpackInfo is updated via poll, so it may not be available until polling has begun.
- // In this rare situation, tell the client the service is temporarily unavailable.
- return response.customError({ statusCode: 503, body: 'Security info unavailable' });
- }
-
- try {
- return response.ok({
- body: await getPermissions(request, legacy.plugins.elasticsearch, xpackInfo),
- });
- } catch (e) {
- return response.internalError({ body: e });
- }
- }
- );
-}
diff --git a/x-pack/legacy/plugins/license_management/server/np_ready/routes/api/license/register_start_basic_route.ts b/x-pack/legacy/plugins/license_management/server/np_ready/routes/api/license/register_start_basic_route.ts
deleted file mode 100644
index ee7ac8602104b..0000000000000
--- a/x-pack/legacy/plugins/license_management/server/np_ready/routes/api/license/register_start_basic_route.ts
+++ /dev/null
@@ -1,27 +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;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import { schema } from '@kbn/config-schema';
-import { startBasic } from '../../../lib/start_basic';
-import { Legacy, Server } from '../../../types';
-
-export function registerStartBasicRoute(server: Server, legacy: Legacy, xpackInfo: any) {
- server.router.post(
- {
- path: '/api/license/start_basic',
- validate: { query: schema.object({ acknowledge: schema.string() }) },
- },
- async (ctx, request, response) => {
- try {
- return response.ok({
- body: await startBasic(request, legacy.plugins.elasticsearch, xpackInfo),
- });
- } catch (e) {
- return response.internalError({ body: e });
- }
- }
- );
-}
diff --git a/x-pack/legacy/plugins/license_management/server/np_ready/routes/api/license/register_start_trial_routes.ts b/x-pack/legacy/plugins/license_management/server/np_ready/routes/api/license/register_start_trial_routes.ts
deleted file mode 100644
index d93f13eba363a..0000000000000
--- a/x-pack/legacy/plugins/license_management/server/np_ready/routes/api/license/register_start_trial_routes.ts
+++ /dev/null
@@ -1,34 +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;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import { canStartTrial, startTrial } from '../../../lib/start_trial';
-import { Legacy, Server } from '../../../types';
-
-export function registerStartTrialRoutes(server: Server, legacy: Legacy, xpackInfo: any) {
- server.router.get(
- { path: '/api/license/start_trial', validate: false },
- async (ctx, request, response) => {
- try {
- return response.ok({ body: await canStartTrial(request, legacy.plugins.elasticsearch) });
- } catch (e) {
- return response.internalError({ body: e });
- }
- }
- );
-
- server.router.post(
- { path: '/api/license/start_trial', validate: false },
- async (ctx, request, response) => {
- try {
- return response.ok({
- body: await startTrial(request, legacy.plugins.elasticsearch, xpackInfo),
- });
- } catch (e) {
- return response.internalError({ body: e });
- }
- }
- );
-}
diff --git a/x-pack/legacy/plugins/license_management/server/np_ready/types.ts b/x-pack/legacy/plugins/license_management/server/np_ready/types.ts
deleted file mode 100644
index 0e66946ec1cc6..0000000000000
--- a/x-pack/legacy/plugins/license_management/server/np_ready/types.ts
+++ /dev/null
@@ -1,24 +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;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import { IRouter } from 'src/core/server';
-import { XPackMainPlugin } from '../../../xpack_main/server/xpack_main';
-import { ElasticsearchPlugin } from '../../../../../../src/legacy/core_plugins/elasticsearch';
-
-export interface Dependencies {
- __LEGACY: {
- xpackMain: XPackMainPlugin;
- elasticsearch: ElasticsearchPlugin;
- };
-}
-
-export interface Server {
- router: IRouter;
-}
-
-export interface Legacy {
- plugins: Dependencies['__LEGACY'];
-}
diff --git a/x-pack/legacy/plugins/maps/common/data_request_descriptor_types.d.ts b/x-pack/legacy/plugins/maps/common/data_request_descriptor_types.d.ts
new file mode 100644
index 0000000000000..3281fb5892eac
--- /dev/null
+++ b/x-pack/legacy/plugins/maps/common/data_request_descriptor_types.d.ts
@@ -0,0 +1,46 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+/* eslint-disable @typescript-eslint/consistent-type-definitions */
+
+// Global map state passed to every layer.
+export type MapFilters = {
+ buffer: unknown;
+ extent: unknown;
+ filters: unknown[];
+ query: unknown;
+ refreshTimerLastTriggeredAt: string;
+ timeFilters: unknown;
+ zoom: number;
+};
+
+export type VectorLayerRequestMeta = MapFilters & {
+ applyGlobalQuery: boolean;
+ fieldNames: string[];
+ geogridPrecision: number;
+ sourceQuery: unknown;
+ sourceMeta: unknown;
+};
+
+export type ESSearchSourceResponseMeta = {
+ areResultsTrimmed?: boolean;
+ sourceType?: string;
+
+ // top hits meta
+ areEntitiesTrimmed?: boolean;
+ entityCount?: number;
+ totalEntities?: number;
+};
+
+// Partial because objects are justified downstream in constructors
+export type DataMeta = Partial & Partial;
+
+export type DataRequestDescriptor = {
+ dataId: string;
+ dataMetaAtStart?: DataMeta;
+ dataRequestToken?: symbol;
+ data?: object;
+ dataMeta?: DataMeta;
+};
diff --git a/x-pack/legacy/plugins/maps/common/descriptor_types.d.ts b/x-pack/legacy/plugins/maps/common/descriptor_types.d.ts
index ce0743ba2baed..2f45c525828db 100644
--- a/x-pack/legacy/plugins/maps/common/descriptor_types.d.ts
+++ b/x-pack/legacy/plugins/maps/common/descriptor_types.d.ts
@@ -5,7 +5,8 @@
*/
/* eslint-disable @typescript-eslint/consistent-type-definitions */
-import { AGG_TYPE, GRID_RESOLUTION, RENDER_AS, SORT_ORDER } from './constants';
+import { DataRequestDescriptor } from './data_request_descriptor_types';
+import { AGG_TYPE, GRID_RESOLUTION, RENDER_AS, SORT_ORDER, SCALING_TYPES } from './constants';
export type AbstractSourceDescriptor = {
id?: string;
@@ -49,7 +50,7 @@ export type ESSearchSourceDescriptor = AbstractESSourceDescriptor & {
tooltipProperties?: string[];
sortField?: string;
sortOrder?: SORT_ORDER;
- useTopHits?: boolean;
+ scalingType: SCALING_TYPES;
topHitsSplitField?: string;
topHitsSize?: number;
};
@@ -93,14 +94,6 @@ export type JoinDescriptor = {
right: ESTermSourceDescriptor;
};
-export type DataRequestDescriptor = {
- dataId: string;
- dataMetaAtStart: object;
- dataRequestToken: symbol;
- data: object;
- dataMeta: object;
-};
-
export type LayerDescriptor = {
__dataRequests?: DataRequestDescriptor[];
__isInErrorState?: boolean;
diff --git a/x-pack/legacy/plugins/maps/common/migrations/scaling_type.test.ts b/x-pack/legacy/plugins/maps/common/migrations/scaling_type.test.ts
new file mode 100644
index 0000000000000..4fbb1ef4c55ed
--- /dev/null
+++ b/x-pack/legacy/plugins/maps/common/migrations/scaling_type.test.ts
@@ -0,0 +1,74 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { migrateUseTopHitsToScalingType } from './scaling_type';
+
+describe('migrateUseTopHitsToScalingType', () => {
+ test('Should handle missing layerListJSON attribute', () => {
+ const attributes = {
+ title: 'my map',
+ };
+ expect(migrateUseTopHitsToScalingType({ attributes })).toEqual({
+ title: 'my map',
+ });
+ });
+
+ test('Should migrate useTopHits: true to scalingType TOP_HITS for ES documents sources', () => {
+ const layerListJSON = JSON.stringify([
+ {
+ sourceDescriptor: {
+ type: 'ES_SEARCH',
+ useTopHits: true,
+ },
+ },
+ ]);
+ const attributes = {
+ title: 'my map',
+ layerListJSON,
+ };
+ expect(migrateUseTopHitsToScalingType({ attributes })).toEqual({
+ title: 'my map',
+ layerListJSON: '[{"sourceDescriptor":{"type":"ES_SEARCH","scalingType":"TOP_HITS"}}]',
+ });
+ });
+
+ test('Should migrate useTopHits: false to scalingType LIMIT for ES documents sources', () => {
+ const layerListJSON = JSON.stringify([
+ {
+ sourceDescriptor: {
+ type: 'ES_SEARCH',
+ useTopHits: false,
+ },
+ },
+ ]);
+ const attributes = {
+ title: 'my map',
+ layerListJSON,
+ };
+ expect(migrateUseTopHitsToScalingType({ attributes })).toEqual({
+ title: 'my map',
+ layerListJSON: '[{"sourceDescriptor":{"type":"ES_SEARCH","scalingType":"LIMIT"}}]',
+ });
+ });
+
+ test('Should set scalingType to LIMIT when useTopHits is not set', () => {
+ const layerListJSON = JSON.stringify([
+ {
+ sourceDescriptor: {
+ type: 'ES_SEARCH',
+ },
+ },
+ ]);
+ const attributes = {
+ title: 'my map',
+ layerListJSON,
+ };
+ expect(migrateUseTopHitsToScalingType({ attributes })).toEqual({
+ title: 'my map',
+ layerListJSON: '[{"sourceDescriptor":{"type":"ES_SEARCH","scalingType":"LIMIT"}}]',
+ });
+ });
+});
diff --git a/x-pack/legacy/plugins/maps/common/migrations/scaling_type.ts b/x-pack/legacy/plugins/maps/common/migrations/scaling_type.ts
new file mode 100644
index 0000000000000..5823ddd6b42e3
--- /dev/null
+++ b/x-pack/legacy/plugins/maps/common/migrations/scaling_type.ts
@@ -0,0 +1,43 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import _ from 'lodash';
+import { ES_SEARCH, SCALING_TYPES } from '../constants';
+import { LayerDescriptor, ESSearchSourceDescriptor } from '../descriptor_types';
+import { MapSavedObjectAttributes } from '../../../../../plugins/maps/common/map_saved_object_type';
+
+function isEsDocumentSource(layerDescriptor: LayerDescriptor) {
+ const sourceType = _.get(layerDescriptor, 'sourceDescriptor.type');
+ return sourceType === ES_SEARCH;
+}
+
+export function migrateUseTopHitsToScalingType({
+ attributes,
+}: {
+ attributes: MapSavedObjectAttributes;
+}): MapSavedObjectAttributes {
+ if (!attributes || !attributes.layerListJSON) {
+ return attributes;
+ }
+
+ const layerList: LayerDescriptor[] = JSON.parse(attributes.layerListJSON);
+ layerList.forEach((layerDescriptor: LayerDescriptor) => {
+ if (isEsDocumentSource(layerDescriptor)) {
+ const sourceDescriptor = layerDescriptor.sourceDescriptor as ESSearchSourceDescriptor;
+ sourceDescriptor.scalingType = _.get(layerDescriptor, 'sourceDescriptor.useTopHits', false)
+ ? SCALING_TYPES.TOP_HITS
+ : SCALING_TYPES.LIMIT;
+ // @ts-ignore useTopHits no longer in type definition but that does not mean its not in live data
+ // hence the entire point of this method
+ delete sourceDescriptor.useTopHits;
+ }
+ });
+
+ return {
+ ...attributes,
+ layerListJSON: JSON.stringify(layerList),
+ };
+}
diff --git a/x-pack/legacy/plugins/maps/migrations.js b/x-pack/legacy/plugins/maps/migrations.js
index 9622f6ba63fac..6a1f5bc937497 100644
--- a/x-pack/legacy/plugins/maps/migrations.js
+++ b/x-pack/legacy/plugins/maps/migrations.js
@@ -10,6 +10,7 @@ import { topHitsTimeToSort } from './common/migrations/top_hits_time_to_sort';
import { moveApplyGlobalQueryToSources } from './common/migrations/move_apply_global_query';
import { addFieldMetaOptions } from './common/migrations/add_field_meta_options';
import { migrateSymbolStyleDescriptor } from './common/migrations/migrate_symbol_style_descriptor';
+import { migrateUseTopHitsToScalingType } from './common/migrations/scaling_type';
export const migrations = {
map: {
@@ -48,11 +49,12 @@ export const migrations = {
};
},
'7.7.0': doc => {
- const attributes = migrateSymbolStyleDescriptor(doc);
+ const attributesPhase1 = migrateSymbolStyleDescriptor(doc);
+ const attributesPhase2 = migrateUseTopHitsToScalingType({ attributes: attributesPhase1 });
return {
...doc,
- attributes,
+ attributes: attributesPhase2,
};
},
},
diff --git a/x-pack/legacy/plugins/maps/public/actions/map_actions.d.ts b/x-pack/legacy/plugins/maps/public/actions/map_actions.d.ts
new file mode 100644
index 0000000000000..418f2880c1077
--- /dev/null
+++ b/x-pack/legacy/plugins/maps/public/actions/map_actions.d.ts
@@ -0,0 +1,18 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+/* eslint-disable @typescript-eslint/consistent-type-definitions */
+
+import { DataMeta, MapFilters } from '../../common/data_request_descriptor_types';
+
+export type SyncContext = {
+ startLoading(dataId: string, requestToken: symbol, meta: DataMeta): void;
+ stopLoading(dataId: string, requestToken: symbol, data: unknown, meta: DataMeta): void;
+ onLoadError(dataId: string, requestToken: symbol, errorMessage: string): void;
+ updateSourceData(newData: unknown): void;
+ isRequestStillActive(dataId: string, requestToken: symbol): boolean;
+ registerCancelCallback(requestToken: symbol, callback: () => void): void;
+ dataFilters: MapFilters;
+};
diff --git a/x-pack/legacy/plugins/maps/public/actions/map_actions.js b/x-pack/legacy/plugins/maps/public/actions/map_actions.js
index 7a1e5e5266246..415630d9f730b 100644
--- a/x-pack/legacy/plugins/maps/public/actions/map_actions.js
+++ b/x-pack/legacy/plugins/maps/public/actions/map_actions.js
@@ -649,13 +649,14 @@ export function onDataLoadError(layerId, dataId, requestToken, errorMessage) {
};
}
-export function updateSourceProp(layerId, propName, value) {
+export function updateSourceProp(layerId, propName, value, newLayerType) {
return async dispatch => {
dispatch({
type: UPDATE_SOURCE_PROP,
layerId,
propName,
value,
+ newLayerType,
});
await dispatch(clearMissingStyleProperties(layerId));
dispatch(syncDataForLayer(layerId));
diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/filter_editor/filter_editor.js b/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/filter_editor/filter_editor.js
index 94e855fc6708f..60bbaa9825db7 100644
--- a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/filter_editor/filter_editor.js
+++ b/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/filter_editor/filter_editor.js
@@ -16,8 +16,6 @@ import {
EuiTextColor,
EuiTextAlign,
EuiButtonEmpty,
- EuiFormRow,
- EuiSwitch,
} from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
@@ -80,14 +78,6 @@ export class FilterEditor extends Component {
this._close();
};
- _onFilterByMapBoundsChange = event => {
- this.props.updateSourceProp(
- this.props.layer.getId(),
- 'filterByMapBounds',
- event.target.checked
- );
- };
-
_onApplyGlobalQueryChange = applyGlobalQuery => {
this.props.updateSourceProp(this.props.layer.getId(), 'applyGlobalQuery', applyGlobalQuery);
};
@@ -182,22 +172,6 @@ export class FilterEditor extends Component {
}
render() {
- let filterByBoundsSwitch;
- if (this.props.layer.getSource().isFilterByMapBoundsConfigurable()) {
- filterByBoundsSwitch = (
-
-
-
- );
- }
-
return (
@@ -217,8 +191,6 @@ export class FilterEditor extends Component {
- {filterByBoundsSwitch}
-
{
dispatch(fitToLayerExtent(layerId));
},
- updateSourceProp: (id, propName, value) => dispatch(updateSourceProp(id, propName, value)),
+ updateSourceProp: (id, propName, value, newLayerType) =>
+ dispatch(updateSourceProp(id, propName, value, newLayerType)),
};
}
diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/view.js b/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/view.js
index 755d4bb6b323a..1b269e388bea0 100644
--- a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/view.js
+++ b/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/view.js
@@ -99,8 +99,8 @@ export class LayerPanel extends React.Component {
}
}
- _onSourceChange = ({ propName, value }) => {
- this.props.updateSourceProp(this.props.selectedLayer.getId(), propName, value);
+ _onSourceChange = ({ propName, value, newLayerType }) => {
+ this.props.updateSourceProp(this.props.selectedLayer.getId(), propName, value, newLayerType);
};
_renderFilterSection() {
diff --git a/x-pack/legacy/plugins/maps/public/layers/blended_vector_layer.ts b/x-pack/legacy/plugins/maps/public/layers/blended_vector_layer.ts
new file mode 100644
index 0000000000000..b35eeedfa44fa
--- /dev/null
+++ b/x-pack/legacy/plugins/maps/public/layers/blended_vector_layer.ts
@@ -0,0 +1,261 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { i18n } from '@kbn/i18n';
+import { VectorLayer } from './vector_layer';
+import { IVectorStyle, VectorStyle } from './styles/vector/vector_style';
+// @ts-ignore
+import { getDefaultDynamicProperties, VECTOR_STYLES } from './styles/vector/vector_style_defaults';
+import { IDynamicStyleProperty } from './styles/vector/properties/dynamic_style_property';
+import { IStyleProperty } from './styles/vector/properties/style_property';
+import {
+ COUNT_PROP_LABEL,
+ COUNT_PROP_NAME,
+ ES_GEO_GRID,
+ LAYER_TYPE,
+ AGG_TYPE,
+ SOURCE_DATA_ID_ORIGIN,
+ RENDER_AS,
+ STYLE_TYPE,
+} from '../../common/constants';
+import { ESGeoGridSource } from './sources/es_geo_grid_source/es_geo_grid_source';
+// @ts-ignore
+import { canSkipSourceUpdate } from './util/can_skip_fetch';
+import { IVectorLayer, VectorLayerArguments } from './vector_layer';
+import { IESSource } from './sources/es_source';
+import { IESAggSource } from './sources/es_agg_source';
+import { ISource } from './sources/source';
+import { SyncContext } from '../actions/map_actions';
+import { DataRequestAbortError } from './util/data_request';
+
+const ACTIVE_COUNT_DATA_ID = 'ACTIVE_COUNT_DATA_ID';
+
+function getAggType(dynamicProperty: IDynamicStyleProperty): AGG_TYPE {
+ return dynamicProperty.isOrdinal() ? AGG_TYPE.AVG : AGG_TYPE.TERMS;
+}
+
+function getClusterSource(documentSource: IESSource, documentStyle: IVectorStyle): IESAggSource {
+ const clusterSourceDescriptor = ESGeoGridSource.createDescriptor({
+ indexPatternId: documentSource.getIndexPatternId(),
+ geoField: documentSource.getGeoFieldName(),
+ requestType: RENDER_AS.POINT,
+ });
+ clusterSourceDescriptor.metrics = [
+ {
+ type: AGG_TYPE.COUNT,
+ label: COUNT_PROP_LABEL,
+ },
+ ...documentStyle.getDynamicPropertiesArray().map(dynamicProperty => {
+ return {
+ type: getAggType(dynamicProperty),
+ field: dynamicProperty.getFieldName(),
+ };
+ }),
+ ];
+ clusterSourceDescriptor.id = documentSource.getId();
+ return new ESGeoGridSource(clusterSourceDescriptor, documentSource.getInspectorAdapters());
+}
+
+function getClusterStyleDescriptor(
+ documentStyle: IVectorStyle,
+ clusterSource: IESAggSource
+): unknown {
+ const defaultDynamicProperties = getDefaultDynamicProperties();
+ const clusterStyleDescriptor: any = {
+ ...documentStyle.getDescriptor(),
+ properties: {
+ [VECTOR_STYLES.LABEL_TEXT]: {
+ type: STYLE_TYPE.DYNAMIC,
+ options: {
+ ...defaultDynamicProperties[VECTOR_STYLES.LABEL_TEXT].options,
+ field: {
+ name: COUNT_PROP_NAME,
+ origin: SOURCE_DATA_ID_ORIGIN,
+ },
+ },
+ },
+ [VECTOR_STYLES.ICON_SIZE]: {
+ type: STYLE_TYPE.DYNAMIC,
+ options: {
+ ...defaultDynamicProperties[VECTOR_STYLES.ICON_SIZE].options,
+ field: {
+ name: COUNT_PROP_NAME,
+ origin: SOURCE_DATA_ID_ORIGIN,
+ },
+ },
+ },
+ },
+ };
+ documentStyle.getAllStyleProperties().forEach((styleProperty: IStyleProperty) => {
+ const styleName = styleProperty.getStyleName();
+ if (
+ [VECTOR_STYLES.LABEL_TEXT, VECTOR_STYLES.ICON_SIZE].includes(styleName) &&
+ (!styleProperty.isDynamic() || !styleProperty.isComplete())
+ ) {
+ // Do not migrate static label and icon size properties to provide unique cluster styling out of the box
+ return;
+ }
+
+ if (styleProperty.isDynamic()) {
+ const options = (styleProperty as IDynamicStyleProperty).getOptions();
+ const field =
+ options && options.field && options.field.name
+ ? {
+ ...options.field,
+ name: clusterSource.getAggKey(
+ getAggType(styleProperty as IDynamicStyleProperty),
+ options.field.name
+ ),
+ }
+ : undefined;
+ clusterStyleDescriptor.properties[styleName] = {
+ type: STYLE_TYPE.DYNAMIC,
+ options: {
+ ...options,
+ field,
+ },
+ };
+ } else {
+ clusterStyleDescriptor.properties[styleName] = {
+ type: STYLE_TYPE.STATIC,
+ options: { ...styleProperty.getOptions() },
+ };
+ }
+ });
+
+ return clusterStyleDescriptor;
+}
+
+export class BlendedVectorLayer extends VectorLayer implements IVectorLayer {
+ static type = LAYER_TYPE.BLENDED_VECTOR;
+
+ static createDescriptor(options: VectorLayerArguments, mapColors: string[]) {
+ const layerDescriptor = VectorLayer.createDescriptor(options, mapColors);
+ layerDescriptor.type = BlendedVectorLayer.type;
+ return layerDescriptor;
+ }
+
+ private readonly _isClustered: boolean;
+ private readonly _clusterSource: IESAggSource;
+ private readonly _clusterStyle: IVectorStyle;
+ private readonly _documentSource: IESSource;
+ private readonly _documentStyle: IVectorStyle;
+
+ constructor(options: VectorLayerArguments) {
+ super(options);
+
+ this._documentSource = this._source as IESSource; // VectorLayer constructor sets _source as document source
+ this._documentStyle = this._style; // VectorLayer constructor sets _style as document source
+
+ this._clusterSource = getClusterSource(this._documentSource, this._documentStyle);
+ const clusterStyleDescriptor = getClusterStyleDescriptor(
+ this._documentStyle,
+ this._clusterSource
+ );
+ this._clusterStyle = new VectorStyle(clusterStyleDescriptor, this._clusterSource, this);
+
+ let isClustered = false;
+ const sourceDataRequest = this.getSourceDataRequest();
+ if (sourceDataRequest) {
+ const requestMeta = sourceDataRequest.getMeta();
+ if (requestMeta && requestMeta.sourceType && requestMeta.sourceType === ES_GEO_GRID) {
+ isClustered = true;
+ }
+ }
+ this._isClustered = isClustered;
+ }
+
+ destroy() {
+ if (this._documentSource) {
+ this._documentSource.destroy();
+ }
+ if (this._clusterSource) {
+ this._clusterSource.destroy();
+ }
+ }
+
+ async getDisplayName(source: ISource) {
+ const displayName = await super.getDisplayName(source);
+ return this._isClustered
+ ? i18n.translate('xpack.maps.blendedVectorLayer.clusteredLayerName', {
+ defaultMessage: 'Clustered {displayName}',
+ values: { displayName },
+ })
+ : displayName;
+ }
+
+ isJoinable() {
+ return false;
+ }
+
+ getJoins() {
+ return [];
+ }
+
+ getSource() {
+ return this._isClustered ? this._clusterSource : this._documentSource;
+ }
+
+ getSourceForEditing() {
+ // Layer is based on this._documentSource
+ // this._clusterSource is a derived source for rendering only.
+ // Regardless of this._activeSource, this._documentSource should always be displayed in the editor
+ return this._documentSource;
+ }
+
+ getCurrentStyle() {
+ return this._isClustered ? this._clusterStyle : this._documentStyle;
+ }
+
+ getStyleForEditing() {
+ return this._documentStyle;
+ }
+
+ async syncData(syncContext: SyncContext) {
+ const dataRequestId = ACTIVE_COUNT_DATA_ID;
+ const requestToken = Symbol(`layer-active-count:${this.getId()}`);
+ const searchFilters = this._getSearchFilters(
+ syncContext.dataFilters,
+ this.getSource(),
+ this.getCurrentStyle()
+ );
+ const canSkipFetch = await canSkipSourceUpdate({
+ source: this.getSource(),
+ prevDataRequest: this.getDataRequest(dataRequestId),
+ nextMeta: searchFilters,
+ });
+ if (canSkipFetch) {
+ return;
+ }
+
+ let isSyncClustered;
+ try {
+ syncContext.startLoading(dataRequestId, requestToken, searchFilters);
+ const searchSource = await this._documentSource.makeSearchSource(searchFilters, 0);
+ const resp = await searchSource.fetch();
+ const maxResultWindow = await this._documentSource.getMaxResultWindow();
+ isSyncClustered = resp.hits.total > maxResultWindow;
+ syncContext.stopLoading(dataRequestId, requestToken, { isSyncClustered }, searchFilters);
+ } catch (error) {
+ if (!(error instanceof DataRequestAbortError)) {
+ syncContext.onLoadError(dataRequestId, requestToken, error.message);
+ }
+ return;
+ }
+
+ let activeSource;
+ let activeStyle;
+ if (isSyncClustered) {
+ activeSource = this._clusterSource;
+ activeStyle = this._clusterStyle;
+ } else {
+ activeSource = this._documentSource;
+ activeStyle = this._documentStyle;
+ }
+
+ super._syncData(syncContext, activeSource, activeStyle);
+ }
+}
diff --git a/x-pack/legacy/plugins/maps/public/layers/heatmap_layer.js b/x-pack/legacy/plugins/maps/public/layers/heatmap_layer.js
index 29223d6a67c6b..ef78b5afe3a3a 100644
--- a/x-pack/legacy/plugins/maps/public/layers/heatmap_layer.js
+++ b/x-pack/legacy/plugins/maps/public/layers/heatmap_layer.js
@@ -32,7 +32,7 @@ export class HeatmapLayer extends VectorLayer {
}
_getPropKeyOfSelectedMetric() {
- const metricfields = this._source.getMetricFields();
+ const metricfields = this.getSource().getMetricFields();
return metricfields[0].getName();
}
@@ -84,11 +84,11 @@ export class HeatmapLayer extends VectorLayer {
}
this.syncVisibilityWithMb(mbMap, heatmapLayerId);
- this._style.setMBPaintProperties({
+ this.getCurrentStyle().setMBPaintProperties({
mbMap,
layerId: heatmapLayerId,
propertyName: SCALED_PROPERTY_NAME,
- resolution: this._source.getGridResolution(),
+ resolution: this.getSource().getGridResolution(),
});
mbMap.setPaintProperty(heatmapLayerId, 'heatmap-opacity', this.getAlpha());
mbMap.setLayerZoomRange(heatmapLayerId, this._descriptor.minZoom, this._descriptor.maxZoom);
@@ -103,7 +103,7 @@ export class HeatmapLayer extends VectorLayer {
}
renderLegendDetails() {
- const metricFields = this._source.getMetricFields();
- return this._style.renderLegendDetails(metricFields[0]);
+ const metricFields = this.getSource().getMetricFields();
+ return this.getCurrentStyle().renderLegendDetails(metricFields[0]);
}
}
diff --git a/x-pack/legacy/plugins/maps/public/layers/layer.d.ts b/x-pack/legacy/plugins/maps/public/layers/layer.d.ts
index eebbaac7d4f97..777566298e607 100644
--- a/x-pack/legacy/plugins/maps/public/layers/layer.d.ts
+++ b/x-pack/legacy/plugins/maps/public/layers/layer.d.ts
@@ -5,9 +5,17 @@
*/
import { LayerDescriptor } from '../../common/descriptor_types';
import { ISource } from './sources/source';
+import { DataRequest } from './util/data_request';
+import { SyncContext } from '../actions/map_actions';
export interface ILayer {
- getDisplayName(): Promise;
+ getDataRequest(id: string): DataRequest | undefined;
+ getDisplayName(source?: ISource): Promise;
+ getId(): string;
+ getSourceDataRequest(): DataRequest | undefined;
+ getSource(): ISource;
+ getSourceForEditing(): ISource;
+ syncData(syncContext: SyncContext): Promise;
}
export interface ILayerArguments {
@@ -17,5 +25,11 @@ export interface ILayerArguments {
export class AbstractLayer implements ILayer {
constructor(layerArguments: ILayerArguments);
- getDisplayName(): Promise;
+ getDataRequest(id: string): DataRequest | undefined;
+ getDisplayName(source?: ISource): Promise;
+ getId(): string;
+ getSourceDataRequest(): DataRequest | undefined;
+ getSource(): ISource;
+ getSourceForEditing(): ISource;
+ syncData(syncContext: SyncContext): Promise;
}
diff --git a/x-pack/legacy/plugins/maps/public/layers/layer.js b/x-pack/legacy/plugins/maps/public/layers/layer.js
index 5c9532a3841f3..d162e342dfd1a 100644
--- a/x-pack/legacy/plugins/maps/public/layers/layer.js
+++ b/x-pack/legacy/plugins/maps/public/layers/layer.js
@@ -63,7 +63,7 @@ export class AbstractLayer {
clonedDescriptor.id = uuid();
const displayName = await this.getDisplayName();
clonedDescriptor.label = `Clone of ${displayName}`;
- clonedDescriptor.sourceDescriptor = this._source.cloneDescriptor();
+ clonedDescriptor.sourceDescriptor = this.getSource().cloneDescriptor();
if (clonedDescriptor.joins) {
clonedDescriptor.joins.forEach(joinDescriptor => {
// right.id is uuid used to track requests in inspector
@@ -78,28 +78,31 @@ export class AbstractLayer {
}
isJoinable() {
- return this._source.isJoinable();
+ return this.getSource().isJoinable();
}
supportsElasticsearchFilters() {
- return this._source.isESSource();
+ return this.getSource().isESSource();
}
async supportsFitToBounds() {
- return await this._source.supportsFitToBounds();
+ return await this.getSource().supportsFitToBounds();
}
- async getDisplayName() {
+ async getDisplayName(source) {
if (this._descriptor.label) {
return this._descriptor.label;
}
- return (await this._source.getDisplayName()) || `Layer ${this._descriptor.id}`;
+ const sourceDisplayName = source
+ ? await source.getDisplayName()
+ : await this.getSource().getDisplayName();
+ return sourceDisplayName || `Layer ${this._descriptor.id}`;
}
async getAttributions() {
if (!this.hasErrors()) {
- return await this._source.getAttributions();
+ return await this.getSource().getAttributions();
}
return [];
}
@@ -191,6 +194,10 @@ export class AbstractLayer {
return this._source;
}
+ getSourceForEditing() {
+ return this._source;
+ }
+
isVisible() {
return this._descriptor.visible;
}
@@ -226,12 +233,16 @@ export class AbstractLayer {
return this._style;
}
+ getStyleForEditing() {
+ return this._style;
+ }
+
async getImmutableSourceProperties() {
- return this._source.getImmutableProperties();
+ return this.getSource().getImmutableProperties();
}
renderSourceSettingsEditor = ({ onChange }) => {
- return this._source.renderSourceSettingsEditor({ onChange });
+ return this.getSourceForEditing().renderSourceSettingsEditor({ onChange });
};
getPrevRequestToken(dataId) {
@@ -319,10 +330,11 @@ export class AbstractLayer {
}
renderStyleEditor({ onStyleDescriptorChange }) {
- if (!this._style) {
+ const style = this.getStyleForEditing();
+ if (!style) {
return null;
}
- return this._style.renderEditor({ layer: this, onStyleDescriptorChange });
+ return style.renderEditor({ layer: this, onStyleDescriptorChange });
}
getIndexPatternIds() {
@@ -333,10 +345,6 @@ export class AbstractLayer {
return [];
}
- async getFields() {
- return [];
- }
-
syncVisibilityWithMb(mbMap, mbLayerId) {
mbMap.setLayoutProperty(mbLayerId, 'visibility', this.isVisible() ? 'visible' : 'none');
}
diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/es_geo_grid_source/es_geo_grid_source.d.ts b/x-pack/legacy/plugins/maps/public/layers/sources/es_geo_grid_source/es_geo_grid_source.d.ts
index 48e90b6c41d51..3f596cea1ae39 100644
--- a/x-pack/legacy/plugins/maps/public/layers/sources/es_geo_grid_source/es_geo_grid_source.d.ts
+++ b/x-pack/legacy/plugins/maps/public/layers/sources/es_geo_grid_source/es_geo_grid_source.d.ts
@@ -6,10 +6,23 @@
import { AbstractESAggSource } from '../es_agg_source';
import { ESGeoGridSourceDescriptor } from '../../../../common/descriptor_types';
-import { GRID_RESOLUTION } from '../../../../common/constants';
+import { GRID_RESOLUTION, RENDER_AS } from '../../../../common/constants';
export class ESGeoGridSource extends AbstractESAggSource {
+ static createDescriptor({
+ indexPatternId,
+ geoField,
+ requestType,
+ resolution,
+ }: {
+ indexPatternId: string;
+ geoField: string;
+ requestType: RENDER_AS;
+ resolution?: GRID_RESOLUTION;
+ }): ESGeoGridSourceDescriptor;
+
constructor(sourceDescriptor: ESGeoGridSourceDescriptor, inspectorAdapters: unknown);
+
getGridResolution(): GRID_RESOLUTION;
getGeoGridPrecision(zoom: number): number;
}
diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/es_geo_grid_source/es_geo_grid_source.js b/x-pack/legacy/plugins/maps/public/layers/sources/es_geo_grid_source/es_geo_grid_source.js
index 3b3e8004ded05..5ad202a02ae6d 100644
--- a/x-pack/legacy/plugins/maps/public/layers/sources/es_geo_grid_source/es_geo_grid_source.js
+++ b/x-pack/legacy/plugins/maps/public/layers/sources/es_geo_grid_source/es_geo_grid_source.js
@@ -75,7 +75,7 @@ export class ESGeoGridSource extends AbstractESAggSource {
renderSourceSettingsEditor({ onChange }) {
return (
{
@@ -325,6 +325,7 @@ export class ESGeoGridSource extends AbstractESAggSource {
},
meta: {
areResultsTrimmed: false,
+ sourceType: ES_GEO_GRID,
},
};
}
diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/es_pew_pew_source/es_pew_pew_source.js b/x-pack/legacy/plugins/maps/public/layers/sources/es_pew_pew_source/es_pew_pew_source.js
index 53536b11aaca6..8e1145c531f9e 100644
--- a/x-pack/legacy/plugins/maps/public/layers/sources/es_pew_pew_source/es_pew_pew_source.js
+++ b/x-pack/legacy/plugins/maps/public/layers/sources/es_pew_pew_source/es_pew_pew_source.js
@@ -64,7 +64,7 @@ export class ESPewPewSource extends AbstractESAggSource {
renderSourceSettingsEditor({ onChange }) {
return (
-
+
+
+
+
+
+
+
+
+
+
+
@@ -112,7 +152,7 @@ exports[`should enable sort order select when sort field provided 1`] = `
`;
-exports[`should render top hits form when useTopHits is true 1`] = `
+exports[`should render top hits form when scaling type is TOP_HITS 1`] = `
-
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/es_search_source.d.ts b/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/es_search_source.d.ts
index 5d8188f19f4ea..0a4e48a195ec6 100644
--- a/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/es_search_source.d.ts
+++ b/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/es_search_source.d.ts
@@ -8,5 +8,5 @@ import { AbstractESSource } from '../es_source';
import { ESSearchSourceDescriptor } from '../../../../common/descriptor_types';
export class ESSearchSource extends AbstractESSource {
- constructor(sourceDescriptor: ESSearchSourceDescriptor, inspectorAdapters: unknown);
+ constructor(sourceDescriptor: Partial, inspectorAdapters: unknown);
}
diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/es_search_source.js b/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/es_search_source.js
index 7f0e870760512..440b9aa89a945 100644
--- a/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/es_search_source.js
+++ b/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/es_search_source.js
@@ -11,6 +11,8 @@ import uuid from 'uuid/v4';
import { VECTOR_SHAPE_TYPES } from '../vector_feature_types';
import { AbstractESSource } from '../es_source';
import { SearchSource } from '../../../kibana_services';
+import { VectorStyle } from '../../styles/vector/vector_style';
+import { VectorLayer } from '../../vector_layer';
import { hitsToGeoJson } from '../../../elasticsearch_geo_utils';
import { CreateSourceEditor } from './create_source_editor';
import { UpdateSourceEditor } from './update_source_editor';
@@ -19,11 +21,13 @@ import {
ES_GEO_FIELD_TYPE,
DEFAULT_MAX_BUCKETS_LIMIT,
SORT_ORDER,
+ SCALING_TYPES,
} from '../../../../common/constants';
import { i18n } from '@kbn/i18n';
import { getDataSourceLabel } from '../../../../common/i18n_getters';
import { getSourceFields } from '../../../index_pattern_util';
import { loadIndexSettings } from './load_index_settings';
+import { BlendedVectorLayer } from '../../blended_vector_layer';
import { DEFAULT_FILTER_BY_MAP_BOUNDS } from './constants';
import { ESDocField } from '../../fields/es_doc_field';
@@ -99,7 +103,7 @@ export class ESSearchSource extends AbstractESSource {
tooltipProperties: _.get(descriptor, 'tooltipProperties', []),
sortField: _.get(descriptor, 'sortField', ''),
sortOrder: _.get(descriptor, 'sortOrder', SORT_ORDER.DESC),
- useTopHits: _.get(descriptor, 'useTopHits', false),
+ scalingType: _.get(descriptor, 'scalingType', SCALING_TYPES.LIMIT),
topHitsSplitField: descriptor.topHitsSplitField,
topHitsSize: _.get(descriptor, 'topHitsSize', 1),
},
@@ -111,6 +115,32 @@ export class ESSearchSource extends AbstractESSource {
);
}
+ createDefaultLayer(options, mapColors) {
+ if (this._descriptor.scalingType === SCALING_TYPES.CLUSTERS) {
+ const layerDescriptor = BlendedVectorLayer.createDescriptor(
+ {
+ sourceDescriptor: this._descriptor,
+ ...options,
+ },
+ mapColors
+ );
+ const style = new VectorStyle(layerDescriptor.style, this);
+ return new BlendedVectorLayer({
+ layerDescriptor: layerDescriptor,
+ source: this,
+ style,
+ });
+ }
+
+ const layerDescriptor = this._createDefaultLayerDescriptor(options, mapColors);
+ const style = new VectorStyle(layerDescriptor.style, this);
+ return new VectorLayer({
+ layerDescriptor: layerDescriptor,
+ source: this,
+ style,
+ });
+ }
+
createField({ fieldName }) {
return new ESDocField({
fieldName,
@@ -122,12 +152,14 @@ export class ESSearchSource extends AbstractESSource {
return (
@@ -157,7 +189,7 @@ export class ESSearchSource extends AbstractESSource {
}
async getImmutableProperties() {
- let indexPatternTitle = this._descriptor.indexPatternId;
+ let indexPatternTitle = this.getIndexPatternId();
let geoFieldType = '';
try {
const indexPattern = await this.getIndexPattern();
@@ -239,7 +271,7 @@ export class ESSearchSource extends AbstractESSource {
shard_size: DEFAULT_MAX_BUCKETS_LIMIT,
};
- const searchSource = await this._makeSearchSource(searchFilters, 0);
+ const searchSource = await this.makeSearchSource(searchFilters, 0);
searchSource.setField('aggs', {
totalEntities: {
cardinality: addFieldToDSL(cardinalityAgg, topHitsSplitField),
@@ -300,7 +332,7 @@ export class ESSearchSource extends AbstractESSource {
);
const initialSearchContext = { docvalue_fields: docValueFields }; // Request fields in docvalue_fields insted of _source
- const searchSource = await this._makeSearchSource(
+ const searchSource = await this.makeSearchSource(
searchFilters,
maxResultWindow,
initialSearchContext
@@ -332,8 +364,8 @@ export class ESSearchSource extends AbstractESSource {
}
_isTopHits() {
- const { useTopHits, topHitsSplitField } = this._descriptor;
- return !!(useTopHits && topHitsSplitField);
+ const { scalingType, topHitsSplitField } = this._descriptor;
+ return !!(scalingType === SCALING_TYPES.TOP_HITS && topHitsSplitField);
}
_hasSort() {
@@ -341,6 +373,12 @@ export class ESSearchSource extends AbstractESSource {
return !!sortField && !!sortOrder;
}
+ async getMaxResultWindow() {
+ const indexPattern = await this.getIndexPattern();
+ const indexSettings = await loadIndexSettings(indexPattern.title);
+ return indexSettings.maxResultWindow;
+ }
+
async getGeoJsonWithMeta(layerName, searchFilters, registerCancelCallback) {
const indexPattern = await this.getIndexPattern();
@@ -383,7 +421,7 @@ export class ESSearchSource extends AbstractESSource {
return {
data: featureCollection,
- meta,
+ meta: { ...meta, sourceType: ES_SEARCH },
};
}
@@ -442,11 +480,9 @@ export class ESSearchSource extends AbstractESSource {
}
isFilterByMapBounds() {
- return _.get(this._descriptor, 'filterByMapBounds', false);
- }
-
- isFilterByMapBoundsConfigurable() {
- return true;
+ return this._descriptor.scalingType === SCALING_TYPES.CLUSTER
+ ? true
+ : this._descriptor.filterByMapBounds;
}
async getLeftJoinFields() {
@@ -533,7 +569,7 @@ export class ESSearchSource extends AbstractESSource {
return {
sortField: this._descriptor.sortField,
sortOrder: this._descriptor.sortOrder,
- useTopHits: this._descriptor.useTopHits,
+ scalingType: this._descriptor.scalingType,
topHitsSplitField: this._descriptor.topHitsSplitField,
topHitsSize: this._descriptor.topHitsSize,
};
diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/es_search_source.test.ts b/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/es_search_source.test.ts
index 1e10923cea1d0..59120e221ca49 100644
--- a/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/es_search_source.test.ts
+++ b/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/es_search_source.test.ts
@@ -7,7 +7,7 @@ jest.mock('ui/new_platform');
import { ESSearchSource } from './es_search_source';
import { VectorLayer } from '../../vector_layer';
-import { ES_SEARCH } from '../../../../common/constants';
+import { ES_SEARCH, SCALING_TYPES } from '../../../../common/constants';
import { ESSearchSourceDescriptor } from '../../../../common/descriptor_types';
const descriptor: ESSearchSourceDescriptor = {
@@ -15,6 +15,7 @@ const descriptor: ESSearchSourceDescriptor = {
id: '1234',
indexPatternId: 'myIndexPattern',
geoField: 'myLocation',
+ scalingType: SCALING_TYPES.LIMIT,
};
describe('ES Search Source', () => {
diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/update_source_editor.js b/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/update_source_editor.js
index 52702c1f4ecc7..b85cca113cf98 100644
--- a/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/update_source_editor.js
+++ b/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/update_source_editor.js
@@ -14,6 +14,7 @@ import {
EuiPanel,
EuiSpacer,
EuiHorizontalRule,
+ EuiRadioGroup,
} from '@elastic/eui';
import { SingleFieldSelect } from '../../../components/single_field_select';
import { TooltipSelector } from '../../../components/tooltip_selector';
@@ -22,7 +23,13 @@ import { indexPatternService } from '../../../kibana_services';
import { i18n } from '@kbn/i18n';
import { getTermsFields, getSourceFields } from '../../../index_pattern_util';
import { ValidatedRange } from '../../../components/validated_range';
-import { DEFAULT_MAX_INNER_RESULT_WINDOW, SORT_ORDER } from '../../../../common/constants';
+import {
+ DEFAULT_MAX_INNER_RESULT_WINDOW,
+ DEFAULT_MAX_RESULT_WINDOW,
+ SORT_ORDER,
+ SCALING_TYPES,
+ LAYER_TYPE,
+} from '../../../../common/constants';
import { ESDocField } from '../../fields/es_doc_field';
import { FormattedMessage } from '@kbn/i18n/react';
import { loadIndexSettings } from './load_index_settings';
@@ -35,7 +42,7 @@ export class UpdateSourceEditor extends Component {
tooltipFields: PropTypes.arrayOf(PropTypes.object).isRequired,
sortField: PropTypes.string,
sortOrder: PropTypes.string.isRequired,
- useTopHits: PropTypes.bool.isRequired,
+ scalingType: PropTypes.string.isRequired,
topHitsSplitField: PropTypes.string,
topHitsSize: PropTypes.number.isRequired,
source: PropTypes.object,
@@ -46,6 +53,8 @@ export class UpdateSourceEditor extends Component {
termFields: null,
sortFields: null,
maxInnerResultWindow: DEFAULT_MAX_INNER_RESULT_WINDOW,
+ maxResultWindow: DEFAULT_MAX_RESULT_WINDOW,
+ supportsClustering: false,
};
componentDidMount() {
@@ -61,9 +70,9 @@ export class UpdateSourceEditor extends Component {
async loadIndexSettings() {
try {
const indexPattern = await indexPatternService.get(this.props.indexPatternId);
- const { maxInnerResultWindow } = await loadIndexSettings(indexPattern.title);
+ const { maxInnerResultWindow, maxResultWindow } = await loadIndexSettings(indexPattern.title);
if (this._isMounted) {
- this.setState({ maxInnerResultWindow });
+ this.setState({ maxInnerResultWindow, maxResultWindow });
}
} catch (err) {
return;
@@ -88,6 +97,16 @@ export class UpdateSourceEditor extends Component {
return;
}
+ let geoField;
+ try {
+ geoField = await this.props.getGeoField();
+ } catch (err) {
+ if (this._isMounted) {
+ this.setState({ loadError: err.message });
+ }
+ return;
+ }
+
if (!this._isMounted) {
return;
}
@@ -102,6 +121,7 @@ export class UpdateSourceEditor extends Component {
});
this.setState({
+ supportsClustering: geoField.aggregatable,
sourceFields: sourceFields,
termFields: getTermsFields(indexPattern.fields), //todo change term fields to use fields
sortFields: indexPattern.fields.filter(
@@ -113,8 +133,14 @@ export class UpdateSourceEditor extends Component {
this.props.onChange({ propName: 'tooltipProperties', value: propertyNames });
};
- onUseTopHitsChange = event => {
- this.props.onChange({ propName: 'useTopHits', value: event.target.checked });
+ _onScalingTypeChange = optionId => {
+ const layerType =
+ optionId === SCALING_TYPES.CLUSTERS ? LAYER_TYPE.BLENDED_VECTOR : LAYER_TYPE.VECTOR;
+ this.props.onChange({ propName: 'scalingType', value: optionId, newLayerType: layerType });
+ };
+
+ _onFilterByMapBoundsChange = event => {
+ this.props.onChange({ propName: 'filterByMapBounds', value: event.target.checked });
};
onTopHitsSplitFieldChange = topHitsSplitField => {
@@ -133,29 +159,7 @@ export class UpdateSourceEditor extends Component {
this.props.onChange({ propName: 'topHitsSize', value: size });
};
- renderTopHitsForm() {
- const topHitsSwitch = (
-
-
-
- );
-
- if (!this.props.useTopHits) {
- return topHitsSwitch;
- }
-
+ _renderTopHitsForm() {
let sizeSlider;
if (this.props.topHitsSplitField) {
sizeSlider = (
@@ -183,7 +187,6 @@ export class UpdateSourceEditor extends Component {
return (
- {topHitsSwitch}
+
+ );
+ }
+
+ _renderScalingPanel() {
+ const scalingOptions = [
+ {
+ id: SCALING_TYPES.LIMIT,
+ label: i18n.translate('xpack.maps.source.esSearch.limitScalingLabel', {
+ defaultMessage: 'Limit results to {maxResultWindow}.',
+ values: { maxResultWindow: this.state.maxResultWindow },
+ }),
+ },
+ {
+ id: SCALING_TYPES.TOP_HITS,
+ label: i18n.translate('xpack.maps.source.esSearch.useTopHitsLabel', {
+ defaultMessage: 'Show top hits per entity.',
+ }),
+ },
+ ];
+ if (this.state.supportsClustering) {
+ scalingOptions.push({
+ id: SCALING_TYPES.CLUSTERS,
+ label: i18n.translate('xpack.maps.source.esSearch.clusterScalingLabel', {
+ defaultMessage: 'Show clusters when results exceed {maxResultWindow}.',
+ values: { maxResultWindow: this.state.maxResultWindow },
+ }),
+ });
+ }
-
- {this.renderTopHitsForm()}
+ let filterByBoundsSwitch;
+ if (this.props.scalingType !== SCALING_TYPES.CLUSTERS) {
+ filterByBoundsSwitch = (
+
+
+
+ );
+ }
+
+ let scalingForm = null;
+ if (this.props.scalingType === SCALING_TYPES.TOP_HITS) {
+ scalingForm = (
+
+
+ {this._renderTopHitsForm()}
+
+ );
+ }
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {filterByBoundsSwitch}
+
+ {scalingForm}
);
}
@@ -302,6 +379,9 @@ export class UpdateSourceEditor extends Component {
{this._renderSortPanel()}
+
+ {this._renderScalingPanel()}
+
);
}
diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/update_source_editor.test.js b/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/update_source_editor.test.js
index badfba7665dfd..e8a845c4b1669 100644
--- a/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/update_source_editor.test.js
+++ b/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/update_source_editor.test.js
@@ -16,6 +16,7 @@ import React from 'react';
import { shallow } from 'enzyme';
import { UpdateSourceEditor } from './update_source_editor';
+import { SCALING_TYPES } from '../../../../common/constants';
const defaultProps = {
indexPatternId: 'indexPattern1',
@@ -23,7 +24,7 @@ const defaultProps = {
filterByMapBounds: true,
tooltipFields: [],
sortOrder: 'DESC',
- useTopHits: false,
+ scalingType: SCALING_TYPES.LIMIT,
topHitsSplitField: 'trackId',
topHitsSize: 1,
};
@@ -40,8 +41,10 @@ test('should enable sort order select when sort field provided', async () => {
expect(component).toMatchSnapshot();
});
-test('should render top hits form when useTopHits is true', async () => {
- const component = shallow( );
+test('should render top hits form when scaling type is TOP_HITS', async () => {
+ const component = shallow(
+
+ );
expect(component).toMatchSnapshot();
});
diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/es_source.d.ts b/x-pack/legacy/plugins/maps/public/layers/sources/es_source.d.ts
index 25c4fae89f024..963a30c7413e8 100644
--- a/x-pack/legacy/plugins/maps/public/layers/sources/es_source.d.ts
+++ b/x-pack/legacy/plugins/maps/public/layers/sources/es_source.d.ts
@@ -6,12 +6,31 @@
import { AbstractVectorSource } from './vector_source';
import { IVectorSource } from './vector_source';
-import { IndexPattern } from '../../../../../../../src/plugins/data/public';
+import { IndexPattern, SearchSource } from '../../../../../../../src/plugins/data/public';
+import { VectorLayerRequestMeta } from '../../../common/data_request_descriptor_types';
export interface IESSource extends IVectorSource {
+ getId(): string;
getIndexPattern(): Promise;
+ getIndexPatternId(): string;
+ getGeoFieldName(): string;
+ getMaxResultWindow(): Promise;
+ makeSearchSource(
+ searchFilters: VectorLayerRequestMeta,
+ limit: number,
+ initialSearchContext?: object
+ ): Promise;
}
export class AbstractESSource extends AbstractVectorSource implements IESSource {
+ getId(): string;
getIndexPattern(): Promise;
+ getIndexPatternId(): string;
+ getGeoFieldName(): string;
+ getMaxResultWindow(): Promise;
+ makeSearchSource(
+ searchFilters: VectorLayerRequestMeta,
+ limit: number,
+ initialSearchContext?: object
+ ): Promise;
}
diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/es_source.js b/x-pack/legacy/plugins/maps/public/layers/sources/es_source.js
index 1552db277e609..c5bf9a8be75bd 100644
--- a/x-pack/legacy/plugins/maps/public/layers/sources/es_source.js
+++ b/x-pack/legacy/plugins/maps/public/layers/sources/es_source.js
@@ -35,6 +35,10 @@ export class AbstractESSource extends AbstractVectorSource {
);
}
+ getId() {
+ return this._descriptor.id;
+ }
+
isFieldAware() {
return true;
}
@@ -48,12 +52,12 @@ export class AbstractESSource extends AbstractVectorSource {
}
getIndexPatternIds() {
- return [this._descriptor.indexPatternId];
+ return [this.getIndexPatternId()];
}
getQueryableIndexPatternIds() {
if (this.getApplyGlobalQuery()) {
- return [this._descriptor.indexPatternId];
+ return [this.getIndexPatternId()];
}
return [];
}
@@ -106,7 +110,7 @@ export class AbstractESSource extends AbstractVectorSource {
}
}
- async _makeSearchSource(searchFilters, limit, initialSearchContext) {
+ async makeSearchSource(searchFilters, limit, initialSearchContext) {
const indexPattern = await this.getIndexPattern();
const isTimeAware = await this.isTimeAware();
const applyGlobalQuery = _.get(searchFilters, 'applyGlobalQuery', true);
@@ -143,7 +147,7 @@ export class AbstractESSource extends AbstractVectorSource {
}
async getBoundsForFilters({ sourceQuery, query, timeFilters, filters, applyGlobalQuery }) {
- const searchSource = await this._makeSearchSource(
+ const searchSource = await this.makeSearchSource(
{ sourceQuery, query, timeFilters, filters, applyGlobalQuery },
0
);
@@ -190,19 +194,27 @@ export class AbstractESSource extends AbstractVectorSource {
}
}
+ getIndexPatternId() {
+ return this._descriptor.indexPatternId;
+ }
+
+ getGeoFieldName() {
+ return this._descriptor.geoField;
+ }
+
async getIndexPattern() {
if (this.indexPattern) {
return this.indexPattern;
}
try {
- this.indexPattern = await indexPatternService.get(this._descriptor.indexPatternId);
+ this.indexPattern = await indexPatternService.get(this.getIndexPatternId());
return this.indexPattern;
} catch (error) {
throw new Error(
i18n.translate('xpack.maps.source.esSource.noIndexPatternErrorMessage', {
defaultMessage: `Unable to find Index pattern for id: {indexPatternId}`,
- values: { indexPatternId: this._descriptor.indexPatternId },
+ values: { indexPatternId: this.getIndexPatternId() },
})
);
}
@@ -219,7 +231,7 @@ export class AbstractESSource extends AbstractVectorSource {
}
}
- async _getGeoField() {
+ _getGeoField = async () => {
const indexPattern = await this.getIndexPattern();
const geoField = indexPattern.fields.getByName(this._descriptor.geoField);
if (!geoField) {
@@ -231,7 +243,7 @@ export class AbstractESSource extends AbstractVectorSource {
);
}
return geoField;
- }
+ };
async getDisplayName() {
try {
@@ -239,7 +251,7 @@ export class AbstractESSource extends AbstractVectorSource {
return indexPattern.title;
} catch (error) {
// Unable to load index pattern, just return id as display name
- return this._descriptor.indexPatternId;
+ return this.getIndexPatternId();
}
}
diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/es_term_source.js b/x-pack/legacy/plugins/maps/public/layers/sources/es_term_source.js
index c12b4befc0684..3ce0fb58aba19 100644
--- a/x-pack/legacy/plugins/maps/public/layers/sources/es_term_source.js
+++ b/x-pack/legacy/plugins/maps/public/layers/sources/es_term_source.js
@@ -51,10 +51,6 @@ export class ESTermSource extends AbstractESAggSource {
return _.has(this._descriptor, 'indexPatternId') && _.has(this._descriptor, 'term');
}
- getIndexPatternIds() {
- return [this._descriptor.indexPatternId];
- }
-
getTermField() {
return this._termField;
}
@@ -90,7 +86,7 @@ export class ESTermSource extends AbstractESAggSource {
}
const indexPattern = await this.getIndexPattern();
- const searchSource = await this._makeSearchSource(searchFilters, 0);
+ const searchSource = await this.makeSearchSource(searchFilters, 0);
const termsField = getField(indexPattern, this._termField.getName());
const termsAgg = { size: DEFAULT_MAX_BUCKETS_LIMIT };
searchSource.setField('aggs', {
@@ -126,7 +122,7 @@ export class ESTermSource extends AbstractESAggSource {
async getDisplayName() {
//no need to localize. this is never rendered.
- return `es_table ${this._descriptor.indexPatternId}`;
+ return `es_table ${this.getIndexPatternId()}`;
}
async filterAndFormatPropertiesToHtml(properties) {
diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/source.d.ts b/x-pack/legacy/plugins/maps/public/layers/sources/source.d.ts
index b5b34efabda0a..2ca18e47a4bf9 100644
--- a/x-pack/legacy/plugins/maps/public/layers/sources/source.d.ts
+++ b/x-pack/legacy/plugins/maps/public/layers/sources/source.d.ts
@@ -10,10 +10,14 @@ import { ILayer } from '../layer';
export interface ISource {
createDefaultLayer(): ILayer;
getDisplayName(): Promise;
+ destroy(): void;
+ getInspectorAdapters(): object;
}
export class AbstractSource implements ISource {
constructor(sourceDescriptor: AbstractSourceDescriptor, inspectorAdapters: object);
createDefaultLayer(): ILayer;
getDisplayName(): Promise;
+ destroy(): void;
+ getInspectorAdapters(): object;
}
diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/vector_source.d.ts b/x-pack/legacy/plugins/maps/public/layers/sources/vector_source.d.ts
index 7de3fe1823cb7..14fc23751ac1a 100644
--- a/x-pack/legacy/plugins/maps/public/layers/sources/vector_source.d.ts
+++ b/x-pack/legacy/plugins/maps/public/layers/sources/vector_source.d.ts
@@ -7,13 +7,9 @@
import { AbstractSource, ISource } from './source';
import { IField } from '../fields/field';
+import { ESSearchSourceResponseMeta } from '../../../common/data_request_descriptor_types';
-export type GeoJsonFetchMeta = {
- areResultsTrimmed: boolean;
- areEntitiesTrimmed?: boolean;
- entityCount?: number;
- totalEntities?: number;
-};
+export type GeoJsonFetchMeta = ESSearchSourceResponseMeta;
export type GeoJsonWithMeta = {
data: unknown; // geojson feature collection
diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/vector_source.js b/x-pack/legacy/plugins/maps/public/layers/sources/vector_source.js
index 0f74dd605c8f1..7ff1c735c8613 100644
--- a/x-pack/legacy/plugins/maps/public/layers/sources/vector_source.js
+++ b/x-pack/legacy/plugins/maps/public/layers/sources/vector_source.js
@@ -98,10 +98,6 @@ export class AbstractVectorSource extends AbstractSource {
return false;
}
- isFilterByMapBoundsConfigurable() {
- return false;
- }
-
isBoundsAware() {
return false;
}
diff --git a/x-pack/legacy/plugins/maps/public/layers/styles/vector/components/vector_style_editor.js b/x-pack/legacy/plugins/maps/public/layers/styles/vector/components/vector_style_editor.js
index 8e05cf287efa6..acc26e5fce699 100644
--- a/x-pack/legacy/plugins/maps/public/layers/styles/vector/components/vector_style_editor.js
+++ b/x-pack/legacy/plugins/maps/public/layers/styles/vector/components/vector_style_editor.js
@@ -69,7 +69,7 @@ export class VectorStyleEditor extends Component {
};
//These are all fields (only used for text labeling)
- const fields = await this.props.layer.getFields();
+ const fields = await this.props.layer.getStyleEditorFields();
const fieldPromises = fields.map(getFieldMeta);
const fieldsArrayAll = await Promise.all(fieldPromises);
if (!this._isMounted || _.isEqual(fieldsArrayAll, this.state.fields)) {
diff --git a/x-pack/legacy/plugins/maps/public/layers/styles/vector/properties/dynamic_color_property.test.js b/x-pack/legacy/plugins/maps/public/layers/styles/vector/properties/dynamic_color_property.test.js
index f74deb17fff7c..5b5028f68f08c 100644
--- a/x-pack/legacy/plugins/maps/public/layers/styles/vector/properties/dynamic_color_property.test.js
+++ b/x-pack/legacy/plugins/maps/public/layers/styles/vector/properties/dynamic_color_property.test.js
@@ -71,7 +71,7 @@ class MockLayer {
return new MockStyle();
}
- findDataRequestById() {
+ getDataRequest() {
return null;
}
}
diff --git a/x-pack/legacy/plugins/maps/public/layers/styles/vector/properties/dynamic_style_property.d.ts b/x-pack/legacy/plugins/maps/public/layers/styles/vector/properties/dynamic_style_property.d.ts
index f4c487b28757e..25063944b8891 100644
--- a/x-pack/legacy/plugins/maps/public/layers/styles/vector/properties/dynamic_style_property.d.ts
+++ b/x-pack/legacy/plugins/maps/public/layers/styles/vector/properties/dynamic_style_property.d.ts
@@ -7,13 +7,17 @@
import { IStyleProperty } from './style_property';
import { FIELD_ORIGIN } from '../../../../../common/constants';
-import { FieldMetaOptions } from '../../../../../common/style_property_descriptor_types';
+import {
+ FieldMetaOptions,
+ DynamicStylePropertyOptions,
+} from '../../../../../common/style_property_descriptor_types';
import { IField } from '../../../fields/field';
import { IVectorLayer } from '../../../vector_layer';
import { IVectorSource } from '../../../sources/vector_source';
import { CategoryFieldMeta, RangeFieldMeta } from '../../../../../common/descriptor_types';
export interface IDynamicStyleProperty extends IStyleProperty {
+ getOptions(): DynamicStylePropertyOptions;
getFieldMetaOptions(): FieldMetaOptions;
getField(): IField | undefined;
getFieldName(): string;
@@ -22,6 +26,7 @@ export interface IDynamicStyleProperty extends IStyleProperty {
getRangeFieldMeta(): RangeFieldMeta;
getCategoryFieldMeta(): CategoryFieldMeta;
isFieldMetaEnabled(): boolean;
+ isOrdinal(): boolean;
supportsFieldMeta(): boolean;
getFieldMetaRequest(): Promise;
supportsMbFeatureState(): boolean;
diff --git a/x-pack/legacy/plugins/maps/public/layers/styles/vector/properties/dynamic_style_property.js b/x-pack/legacy/plugins/maps/public/layers/styles/vector/properties/dynamic_style_property.js
index 030d3a2a1ef87..68e06bacfa7b7 100644
--- a/x-pack/legacy/plugins/maps/public/layers/styles/vector/properties/dynamic_style_property.js
+++ b/x-pack/legacy/plugins/maps/public/layers/styles/vector/properties/dynamic_style_property.js
@@ -62,7 +62,7 @@ export class DynamicStyleProperty extends AbstractStyleProperty {
return rangeFieldMetaFromLocalFeatures;
}
- const styleMetaDataRequest = this._layer.findDataRequestById(dataRequestId);
+ const styleMetaDataRequest = this._layer.getDataRequest(dataRequestId);
if (!styleMetaDataRequest || !styleMetaDataRequest.hasData()) {
return rangeFieldMetaFromLocalFeatures;
}
@@ -87,7 +87,7 @@ export class DynamicStyleProperty extends AbstractStyleProperty {
return categoryFieldMetaFromLocalFeatures;
}
- const styleMetaDataRequest = this._layer.findDataRequestById(dataRequestId);
+ const styleMetaDataRequest = this._layer.getDataRequest(dataRequestId);
if (!styleMetaDataRequest || !styleMetaDataRequest.hasData()) {
return categoryFieldMetaFromLocalFeatures;
}
diff --git a/x-pack/legacy/plugins/maps/public/layers/styles/vector/vector_style.d.ts b/x-pack/legacy/plugins/maps/public/layers/styles/vector/vector_style.d.ts
new file mode 100644
index 0000000000000..ac84a3b6447d2
--- /dev/null
+++ b/x-pack/legacy/plugins/maps/public/layers/styles/vector/vector_style.d.ts
@@ -0,0 +1,23 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+import { IStyleProperty } from './properties/style_property';
+import { IDynamicStyleProperty } from './properties/dynamic_style_property';
+import { IVectorLayer } from '../../vector_layer';
+import { IVectorSource } from '../../sources/vector_source';
+
+export interface IVectorStyle {
+ getAllStyleProperties(): IStyleProperty[];
+ getDescriptor(): object;
+ getDynamicPropertiesArray(): IDynamicStyleProperty[];
+}
+
+export class VectorStyle implements IVectorStyle {
+ constructor(descriptor: unknown, source: IVectorSource, layer: IVectorLayer);
+
+ getAllStyleProperties(): IStyleProperty[];
+ getDescriptor(): object;
+ getDynamicPropertiesArray(): IDynamicStyleProperty[];
+}
diff --git a/x-pack/legacy/plugins/maps/public/layers/styles/vector/vector_style.js b/x-pack/legacy/plugins/maps/public/layers/styles/vector/vector_style.js
index 1c8ff3e205a38..6ad60e15f10e1 100644
--- a/x-pack/legacy/plugins/maps/public/layers/styles/vector/vector_style.js
+++ b/x-pack/legacy/plugins/maps/public/layers/styles/vector/vector_style.js
@@ -123,7 +123,7 @@ export class VectorStyle extends AbstractStyle {
);
}
- _getAllStyleProperties() {
+ getAllStyleProperties() {
return [
this._symbolizeAsStyleProperty,
this._iconStyleProperty,
@@ -164,7 +164,7 @@ export class VectorStyle extends AbstractStyle {
});
const styleProperties = {};
- this._getAllStyleProperties().forEach(styleProperty => {
+ this.getAllStyleProperties().forEach(styleProperty => {
styleProperties[styleProperty.getStyleName()] = styleProperty;
});
@@ -339,7 +339,7 @@ export class VectorStyle extends AbstractStyle {
}
getDynamicPropertiesArray() {
- const styleProperties = this._getAllStyleProperties();
+ const styleProperties = this.getAllStyleProperties();
return styleProperties.filter(
styleProperty => styleProperty.isDynamic() && styleProperty.isComplete()
);
@@ -390,7 +390,7 @@ export class VectorStyle extends AbstractStyle {
return null;
}
- const formattersDataRequest = this._layer.findDataRequestById(dataRequestId);
+ const formattersDataRequest = this._layer.getDataRequest(dataRequestId);
if (!formattersDataRequest || !formattersDataRequest.hasData()) {
return null;
}
diff --git a/x-pack/legacy/plugins/maps/public/layers/styles/vector/vector_style_defaults.js b/x-pack/legacy/plugins/maps/public/layers/styles/vector/vector_style_defaults.js
index 8bc397dd98b56..dd2cf79318d8e 100644
--- a/x-pack/legacy/plugins/maps/public/layers/styles/vector/vector_style_defaults.js
+++ b/x-pack/legacy/plugins/maps/public/layers/styles/vector/vector_style_defaults.js
@@ -16,7 +16,7 @@ import chrome from 'ui/chrome';
export const MIN_SIZE = 1;
export const MAX_SIZE = 64;
-export const DEFAULT_MIN_SIZE = 4;
+export const DEFAULT_MIN_SIZE = 7; // Make default large enough to fit default label size
export const DEFAULT_MAX_SIZE = 32;
export const DEFAULT_SIGMA = 3;
export const DEFAULT_LABEL_SIZE = 14;
diff --git a/x-pack/legacy/plugins/maps/public/layers/tile_layer.js b/x-pack/legacy/plugins/maps/public/layers/tile_layer.js
index b35adcad976c3..aa2619e96f834 100644
--- a/x-pack/legacy/plugins/maps/public/layers/tile_layer.js
+++ b/x-pack/legacy/plugins/maps/public/layers/tile_layer.js
@@ -30,7 +30,7 @@ export class TileLayer extends AbstractLayer {
const requestToken = Symbol(`layer-source-refresh:${this.getId()} - source`);
startLoading(SOURCE_DATA_ID_ORIGIN, requestToken, dataFilters);
try {
- const url = await this._source.getUrlTemplate();
+ const url = await this.getSource().getUrlTemplate();
stopLoading(SOURCE_DATA_ID_ORIGIN, requestToken, url, {});
} catch (error) {
onLoadError(SOURCE_DATA_ID_ORIGIN, requestToken, error.message);
diff --git a/x-pack/legacy/plugins/maps/public/layers/tile_layer.test.ts b/x-pack/legacy/plugins/maps/public/layers/tile_layer.test.ts
index 065fbd79d9789..0ec9385194cc0 100644
--- a/x-pack/legacy/plugins/maps/public/layers/tile_layer.test.ts
+++ b/x-pack/legacy/plugins/maps/public/layers/tile_layer.test.ts
@@ -32,6 +32,14 @@ class MockTileSource implements ITMSSource {
async getUrlTemplate(): Promise {
return 'template/{x}/{y}/{z}.png';
}
+
+ destroy(): void {
+ // no-op
+ }
+
+ getInspectorAdapters(): object {
+ return {};
+ }
}
describe('TileLayer', () => {
diff --git a/x-pack/legacy/plugins/maps/public/layers/util/data_request.js b/x-pack/legacy/plugins/maps/public/layers/util/data_request.ts
similarity index 61%
rename from x-pack/legacy/plugins/maps/public/layers/util/data_request.js
rename to x-pack/legacy/plugins/maps/public/layers/util/data_request.ts
index 3a6c10a9f07a6..e361574194628 100644
--- a/x-pack/legacy/plugins/maps/public/layers/util/data_request.js
+++ b/x-pack/legacy/plugins/maps/public/layers/util/data_request.ts
@@ -3,42 +3,47 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
+/* eslint-disable max-classes-per-file */
+
import _ from 'lodash';
+import { DataRequestDescriptor, DataMeta } from '../../../common/data_request_descriptor_types';
export class DataRequest {
- constructor(descriptor) {
+ private readonly _descriptor: DataRequestDescriptor;
+
+ constructor(descriptor: DataRequestDescriptor) {
this._descriptor = {
...descriptor,
};
}
- getData() {
+ getData(): object | undefined {
return this._descriptor.data;
}
- isLoading() {
+ isLoading(): boolean {
return !!this._descriptor.dataRequestToken;
}
- getMeta() {
+ getMeta(): DataMeta {
return this.hasData()
? _.get(this._descriptor, 'dataMeta', {})
: _.get(this._descriptor, 'dataMetaAtStart', {});
}
- hasData() {
+ hasData(): boolean {
return !!this._descriptor.data;
}
- hasDataOrRequestInProgress() {
- return this._descriptor.data || this._descriptor.dataRequestToken;
+ hasDataOrRequestInProgress(): boolean {
+ return this.hasData() || this.isLoading();
}
- getDataId() {
+ getDataId(): string {
return this._descriptor.dataId;
}
- getRequestToken() {
+ getRequestToken(): symbol | undefined {
return this._descriptor.dataRequestToken;
}
}
diff --git a/x-pack/legacy/plugins/maps/public/layers/vector_layer.d.ts b/x-pack/legacy/plugins/maps/public/layers/vector_layer.d.ts
index 748b2fd1d782c..77e8ab768cd00 100644
--- a/x-pack/legacy/plugins/maps/public/layers/vector_layer.d.ts
+++ b/x-pack/legacy/plugins/maps/public/layers/vector_layer.d.ts
@@ -8,20 +8,43 @@
import { AbstractLayer } from './layer';
import { IVectorSource } from './sources/vector_source';
import { VectorLayerDescriptor } from '../../common/descriptor_types';
+import { MapFilters, VectorLayerRequestMeta } from '../../common/data_request_descriptor_types';
import { ILayer } from './layer';
import { IJoin } from './joins/join';
+import { IVectorStyle } from './styles/vector/vector_style';
+import { IField } from './fields/field';
+import { SyncContext } from '../actions/map_actions';
type VectorLayerArguments = {
source: IVectorSource;
+ joins: IJoin[];
layerDescriptor: VectorLayerDescriptor;
};
export interface IVectorLayer extends ILayer {
+ getFields(): Promise;
+ getStyleEditorFields(): Promise;
getValidJoins(): IJoin[];
}
export class VectorLayer extends AbstractLayer implements IVectorLayer {
+ static createDescriptor(
+ options: VectorLayerArguments,
+ mapColors: string[]
+ ): VectorLayerDescriptor;
+
+ protected readonly _source: IVectorSource;
+ protected readonly _style: IVectorStyle;
+
constructor(options: VectorLayerArguments);
+ getFields(): Promise;
+ getStyleEditorFields(): Promise;
getValidJoins(): IJoin[];
+ _getSearchFilters(
+ dataFilters: MapFilters,
+ source: IVectorSource,
+ style: IVectorStyle
+ ): VectorLayerRequestMeta;
+ _syncData(syncContext: SyncContext, source: IVectorSource, style: IVectorStyle): Promise;
}
diff --git a/x-pack/legacy/plugins/maps/public/layers/vector_layer.js b/x-pack/legacy/plugins/maps/public/layers/vector_layer.js
index 70bba3d91c723..6b89554546330 100644
--- a/x-pack/legacy/plugins/maps/public/layers/vector_layer.js
+++ b/x-pack/legacy/plugins/maps/public/layers/vector_layer.js
@@ -58,7 +58,7 @@ export class VectorLayer extends AbstractLayer {
constructor({ layerDescriptor, source, joins = [] }) {
super({ layerDescriptor, source });
this._joins = joins;
- this._style = new VectorStyle(this._descriptor.style, this._source, this);
+ this._style = new VectorStyle(this._descriptor.style, source, this);
}
getStyle() {
@@ -66,10 +66,10 @@ export class VectorLayer extends AbstractLayer {
}
destroy() {
- if (this._source) {
- this._source.destroy();
+ if (this.getSource()) {
+ this.getSource().destroy();
}
- this._joins.forEach(joinSource => {
+ this.getJoins().forEach(joinSource => {
joinSource.destroy();
});
}
@@ -79,7 +79,7 @@ export class VectorLayer extends AbstractLayer {
}
getValidJoins() {
- return this._joins.filter(join => {
+ return this.getJoins().filter(join => {
return join.hasCompleteConfig();
});
}
@@ -119,7 +119,7 @@ export class VectorLayer extends AbstractLayer {
}
if (
- this._joins.length &&
+ this.getJoins().length &&
!featureCollection.features.some(feature => feature.properties[FEATURE_VISIBLE_PROPERTY_NAME])
) {
return {
@@ -131,11 +131,11 @@ export class VectorLayer extends AbstractLayer {
}
const sourceDataRequest = this.getSourceDataRequest();
- const { tooltipContent, areResultsTrimmed } = this._source.getSourceTooltipContent(
+ const { tooltipContent, areResultsTrimmed } = this.getSource().getSourceTooltipContent(
sourceDataRequest
);
return {
- icon: this._style.getIcon(),
+ icon: this.getCurrentStyle().getIcon(),
tooltipContent: tooltipContent,
areResultsTrimmed: areResultsTrimmed,
};
@@ -146,11 +146,11 @@ export class VectorLayer extends AbstractLayer {
}
async hasLegendDetails() {
- return this._style.hasLegendDetails();
+ return this.getCurrentStyle().hasLegendDetails();
}
renderLegendDetails() {
- return this._style.renderLegendDetails();
+ return this.getCurrentStyle().renderLegendDetails();
}
_getBoundsBasedOnData() {
@@ -175,17 +175,22 @@ export class VectorLayer extends AbstractLayer {
}
async getBounds(dataFilters) {
- const isStaticLayer = !this._source.isBoundsAware() || !this._source.isFilterByMapBounds();
+ const isStaticLayer =
+ !this.getSource().isBoundsAware() || !this.getSource().isFilterByMapBounds();
if (isStaticLayer) {
return this._getBoundsBasedOnData();
}
- const searchFilters = this._getSearchFilters(dataFilters);
- return await this._source.getBoundsForFilters(searchFilters);
+ const searchFilters = this._getSearchFilters(
+ dataFilters,
+ this.getSource(),
+ this.getCurrentStyle()
+ );
+ return await this.getSource().getBoundsForFilters(searchFilters);
}
async getLeftJoinFields() {
- return await this._source.getLeftJoinFields();
+ return await this.getSource().getLeftJoinFields();
}
_getJoinFields() {
@@ -198,12 +203,17 @@ export class VectorLayer extends AbstractLayer {
}
async getFields() {
- const sourceFields = await this._source.getFields();
+ const sourceFields = await this.getSource().getFields();
+ return [...sourceFields, ...this._getJoinFields()];
+ }
+
+ async getStyleEditorFields() {
+ const sourceFields = await this.getSourceForEditing().getFields();
return [...sourceFields, ...this._getJoinFields()];
}
getIndexPatternIds() {
- const indexPatternIds = this._source.getIndexPatternIds();
+ const indexPatternIds = this.getSource().getIndexPatternIds();
this.getValidJoins().forEach(join => {
indexPatternIds.push(...join.getIndexPatternIds());
});
@@ -211,17 +221,13 @@ export class VectorLayer extends AbstractLayer {
}
getQueryableIndexPatternIds() {
- const indexPatternIds = this._source.getQueryableIndexPatternIds();
+ const indexPatternIds = this.getSource().getQueryableIndexPatternIds();
this.getValidJoins().forEach(join => {
indexPatternIds.push(...join.getQueryableIndexPatternIds());
});
return indexPatternIds;
}
- findDataRequestById(sourceDataId) {
- return this._dataRequests.find(dataRequest => dataRequest.getDataId() === sourceDataId);
- }
-
async _syncJoin({
join,
startLoading,
@@ -239,7 +245,7 @@ export class VectorLayer extends AbstractLayer {
sourceQuery: joinSource.getWhereQuery(),
applyGlobalQuery: joinSource.getApplyGlobalQuery(),
};
- const prevDataRequest = this.findDataRequestById(sourceDataId);
+ const prevDataRequest = this.getDataRequest(sourceDataId);
const canSkipFetch = await canSkipSourceUpdate({
source: joinSource,
@@ -281,30 +287,30 @@ export class VectorLayer extends AbstractLayer {
}
}
- async _syncJoins(syncContext) {
+ async _syncJoins(syncContext, style) {
const joinSyncs = this.getValidJoins().map(async join => {
- await this._syncJoinStyleMeta(syncContext, join);
- await this._syncJoinFormatters(syncContext, join);
+ await this._syncJoinStyleMeta(syncContext, join, style);
+ await this._syncJoinFormatters(syncContext, join, style);
return this._syncJoin({ join, ...syncContext });
});
return await Promise.all(joinSyncs);
}
- _getSearchFilters(dataFilters) {
+ _getSearchFilters(dataFilters, source, style) {
const fieldNames = [
- ...this._source.getFieldNames(),
- ...this._style.getSourceFieldNames(),
+ ...source.getFieldNames(),
+ ...style.getSourceFieldNames(),
...this.getValidJoins().map(join => join.getLeftField().getName()),
];
return {
...dataFilters,
fieldNames: _.uniq(fieldNames).sort(),
- geogridPrecision: this._source.getGeoGridPrecision(dataFilters.zoom),
+ geogridPrecision: source.getGeoGridPrecision(dataFilters.zoom),
sourceQuery: this.getQuery(),
- applyGlobalQuery: this._source.getApplyGlobalQuery(),
- sourceMeta: this._source.getSyncMeta(),
+ applyGlobalQuery: source.getApplyGlobalQuery(),
+ sourceMeta: source.getSyncMeta(),
};
}
@@ -347,20 +353,21 @@ export class VectorLayer extends AbstractLayer {
}
}
- async _syncSource({
- startLoading,
- stopLoading,
- onLoadError,
- registerCancelCallback,
- dataFilters,
- isRequestStillActive,
- }) {
+ async _syncSource(syncContext, source, style) {
+ const {
+ startLoading,
+ stopLoading,
+ onLoadError,
+ registerCancelCallback,
+ dataFilters,
+ isRequestStillActive,
+ } = syncContext;
const dataRequestId = SOURCE_DATA_ID_ORIGIN;
const requestToken = Symbol(`layer-${this.getId()}-${dataRequestId}`);
- const searchFilters = this._getSearchFilters(dataFilters);
+ const searchFilters = this._getSearchFilters(dataFilters, source, style);
const prevDataRequest = this.getSourceDataRequest();
const canSkipFetch = await canSkipSourceUpdate({
- source: this._source,
+ source,
prevDataRequest,
nextMeta: searchFilters,
});
@@ -373,8 +380,8 @@ export class VectorLayer extends AbstractLayer {
try {
startLoading(dataRequestId, requestToken, searchFilters);
- const layerName = await this.getDisplayName();
- const { data: sourceFeatureCollection, meta } = await this._source.getGeoJsonWithMeta(
+ const layerName = await this.getDisplayName(source);
+ const { data: sourceFeatureCollection, meta } = await source.getGeoJsonWithMeta(
layerName,
searchFilters,
registerCancelCallback.bind(null, requestToken),
@@ -398,16 +405,17 @@ export class VectorLayer extends AbstractLayer {
}
}
- async _syncSourceStyleMeta(syncContext) {
- if (this._style.constructor.type !== LAYER_STYLE_TYPE.VECTOR) {
+ async _syncSourceStyleMeta(syncContext, source, style) {
+ if (this.getCurrentStyle().constructor.type !== LAYER_STYLE_TYPE.VECTOR) {
return;
}
return this._syncStyleMeta({
- source: this._source,
+ source,
+ style,
sourceQuery: this.getQuery(),
dataRequestId: SOURCE_META_ID_ORIGIN,
- dynamicStyleProps: this._style.getDynamicPropertiesArray().filter(dynamicStyleProp => {
+ dynamicStyleProps: style.getDynamicPropertiesArray().filter(dynamicStyleProp => {
return (
dynamicStyleProp.getFieldOrigin() === FIELD_ORIGIN.SOURCE &&
dynamicStyleProp.isFieldMetaEnabled()
@@ -417,28 +425,32 @@ export class VectorLayer extends AbstractLayer {
});
}
- async _syncJoinStyleMeta(syncContext, join) {
+ async _syncJoinStyleMeta(syncContext, join, style) {
const joinSource = join.getRightJoinSource();
return this._syncStyleMeta({
source: joinSource,
+ style,
sourceQuery: joinSource.getWhereQuery(),
dataRequestId: join.getSourceMetaDataRequestId(),
- dynamicStyleProps: this._style.getDynamicPropertiesArray().filter(dynamicStyleProp => {
- const matchingField = joinSource.getMetricFieldForName(
- dynamicStyleProp.getField().getName()
- );
- return (
- dynamicStyleProp.getFieldOrigin() === FIELD_ORIGIN.JOIN &&
- !!matchingField &&
- dynamicStyleProp.isFieldMetaEnabled()
- );
- }),
+ dynamicStyleProps: this.getCurrentStyle()
+ .getDynamicPropertiesArray()
+ .filter(dynamicStyleProp => {
+ const matchingField = joinSource.getMetricFieldForName(
+ dynamicStyleProp.getField().getName()
+ );
+ return (
+ dynamicStyleProp.getFieldOrigin() === FIELD_ORIGIN.JOIN &&
+ !!matchingField &&
+ dynamicStyleProp.isFieldMetaEnabled()
+ );
+ }),
...syncContext,
});
}
async _syncStyleMeta({
source,
+ style,
sourceQuery,
dataRequestId,
dynamicStyleProps,
@@ -459,10 +471,10 @@ export class VectorLayer extends AbstractLayer {
const nextMeta = {
dynamicStyleFields: _.uniq(dynamicStyleFields).sort(),
sourceQuery,
- isTimeAware: this._style.isTimeAware() && (await source.isTimeAware()),
+ isTimeAware: this.getCurrentStyle().isTimeAware() && (await source.isTimeAware()),
timeFilters: dataFilters.timeFilters,
};
- const prevDataRequest = this.findDataRequestById(dataRequestId);
+ const prevDataRequest = this.getDataRequest(dataRequestId);
const canSkipFetch = canSkipStyleMetaUpdate({ prevDataRequest, nextMeta });
if (canSkipFetch) {
return;
@@ -471,10 +483,10 @@ export class VectorLayer extends AbstractLayer {
const requestToken = Symbol(`layer-${this.getId()}-${dataRequestId}`);
try {
startLoading(dataRequestId, requestToken, nextMeta);
- const layerName = await this.getDisplayName();
+ const layerName = await this.getDisplayName(source);
const styleMeta = await source.loadStylePropsMeta(
layerName,
- this._style,
+ style,
dynamicStyleProps,
registerCancelCallback,
nextMeta
@@ -487,15 +499,15 @@ export class VectorLayer extends AbstractLayer {
}
}
- async _syncSourceFormatters(syncContext) {
- if (this._style.constructor.type !== LAYER_STYLE_TYPE.VECTOR) {
+ async _syncSourceFormatters(syncContext, source, style) {
+ if (style.constructor.type !== LAYER_STYLE_TYPE.VECTOR) {
return;
}
return this._syncFormatters({
- source: this._source,
+ source,
dataRequestId: SOURCE_FORMATTERS_ID_ORIGIN,
- fields: this._style
+ fields: style
.getDynamicPropertiesArray()
.filter(dynamicStyleProp => {
return dynamicStyleProp.getFieldOrigin() === FIELD_ORIGIN.SOURCE;
@@ -507,12 +519,12 @@ export class VectorLayer extends AbstractLayer {
});
}
- async _syncJoinFormatters(syncContext, join) {
+ async _syncJoinFormatters(syncContext, join, style) {
const joinSource = join.getRightJoinSource();
return this._syncFormatters({
source: joinSource,
dataRequestId: join.getSourceFormattersDataRequestId(),
- fields: this._style
+ fields: style
.getDynamicPropertiesArray()
.filter(dynamicStyleProp => {
const matchingField = joinSource.getMetricFieldForName(
@@ -538,7 +550,7 @@ export class VectorLayer extends AbstractLayer {
const nextMeta = {
fieldNames: _.uniq(fieldNames).sort(),
};
- const prevDataRequest = this.findDataRequestById(dataRequestId);
+ const prevDataRequest = this.getDataRequest(dataRequestId);
const canSkipUpdate = canSkipFormattersUpdate({ prevDataRequest, nextMeta });
if (canSkipUpdate) {
return;
@@ -565,13 +577,27 @@ export class VectorLayer extends AbstractLayer {
}
async syncData(syncContext) {
+ this._syncData(syncContext, this.getSource(), this.getCurrentStyle());
+ }
+
+ // TLDR: Do not call getSource or getCurrentStyle in syncData flow. Use 'source' and 'style' arguments instead.
+ //
+ // 1) State is contained in the redux store. Layer instance state is readonly.
+ // 2) Even though data request descriptor updates trigger new instances for rendering,
+ // syncing data executes on a single object instance. Syncing data can not use updated redux store state.
+ //
+ // Blended layer data syncing branches on the source/style depending on whether clustering is used or not.
+ // Given 1 above, which source/style to use can not be stored in Layer instance state.
+ // Given 2 above, which source/style to use can not be pulled from data request state.
+ // Therefore, source and style are provided as arugments and must be used instead of calling getSource or getCurrentStyle.
+ async _syncData(syncContext, source, style) {
if (!this.isVisible() || !this.showAtZoomLevel(syncContext.dataFilters.zoom)) {
return;
}
- await this._syncSourceStyleMeta(syncContext);
- await this._syncSourceFormatters(syncContext);
- const sourceResult = await this._syncSource(syncContext);
+ await this._syncSourceStyleMeta(syncContext, source, style);
+ await this._syncSourceFormatters(syncContext, source, style);
+ const sourceResult = await this._syncSource(syncContext, source, style);
if (
!sourceResult.featureCollection ||
!sourceResult.featureCollection.features.length ||
@@ -580,7 +606,7 @@ export class VectorLayer extends AbstractLayer {
return;
}
- const joinStates = await this._syncJoins(syncContext);
+ const joinStates = await this._syncJoins(syncContext, style);
await this._performInnerJoins(sourceResult, joinStates, syncContext.updateSourceData);
}
@@ -596,7 +622,7 @@ export class VectorLayer extends AbstractLayer {
if (!featureCollection) {
if (featureCollectionOnMap) {
- this._style.clearFeatureState(featureCollectionOnMap, mbMap, this.getId());
+ this.getCurrentStyle().clearFeatureState(featureCollectionOnMap, mbMap, this.getId());
}
mbGeoJSONSource.setData(EMPTY_FEATURE_COLLECTION);
return;
@@ -605,7 +631,7 @@ export class VectorLayer extends AbstractLayer {
// "feature-state" data expressions are not supported with layout properties.
// To work around this limitation,
// scaled layout properties (like icon-size) must fall back to geojson property values :(
- const hasGeoJsonProperties = this._style.setFeatureStateAndStyleProps(
+ const hasGeoJsonProperties = this.getCurrentStyle().setFeatureStateAndStyleProps(
featureCollection,
mbMap,
this.getId()
@@ -626,7 +652,7 @@ export class VectorLayer extends AbstractLayer {
// Point layers symbolized as icons only contain a single mapbox layer.
let markerLayerId;
let textLayerId;
- if (this._style.arePointsSymbolizedAsCircles()) {
+ if (this.getCurrentStyle().arePointsSymbolizedAsCircles()) {
markerLayerId = pointLayerId;
textLayerId = this._getMbTextLayerId();
if (symbolLayer) {
@@ -680,13 +706,13 @@ export class VectorLayer extends AbstractLayer {
mbMap.setFilter(textLayerId, filterExpr);
}
- this._style.setMBPaintPropertiesForPoints({
+ this.getCurrentStyle().setMBPaintPropertiesForPoints({
alpha: this.getAlpha(),
mbMap,
pointLayerId,
});
- this._style.setMBPropertiesForLabelText({
+ this.getCurrentStyle().setMBPropertiesForLabelText({
alpha: this.getAlpha(),
mbMap,
textLayerId,
@@ -711,13 +737,13 @@ export class VectorLayer extends AbstractLayer {
mbMap.setFilter(symbolLayerId, filterExpr);
}
- this._style.setMBSymbolPropertiesForPoints({
+ this.getCurrentStyle().setMBSymbolPropertiesForPoints({
alpha: this.getAlpha(),
mbMap,
symbolLayerId,
});
- this._style.setMBPropertiesForLabelText({
+ this.getCurrentStyle().setMBPropertiesForLabelText({
alpha: this.getAlpha(),
mbMap,
textLayerId: symbolLayerId,
@@ -745,7 +771,7 @@ export class VectorLayer extends AbstractLayer {
paint: {},
});
}
- this._style.setMBPaintProperties({
+ this.getCurrentStyle().setMBPaintProperties({
alpha: this.getAlpha(),
mbMap,
fillLayerId,
@@ -830,9 +856,13 @@ export class VectorLayer extends AbstractLayer {
for (let i = 0; i < tooltipsFromSource.length; i++) {
const tooltipProperty = tooltipsFromSource[i];
const matchingJoins = [];
- for (let j = 0; j < this._joins.length; j++) {
- if (this._joins[j].getLeftField().getName() === tooltipProperty.getPropertyKey()) {
- matchingJoins.push(this._joins[j]);
+ for (let j = 0; j < this.getJoins().length; j++) {
+ if (
+ this.getJoins()
+ [j].getLeftField()
+ .getName() === tooltipProperty.getPropertyKey()
+ ) {
+ matchingJoins.push(this.getJoins()[j]);
}
}
if (matchingJoins.length) {
@@ -842,18 +872,22 @@ export class VectorLayer extends AbstractLayer {
}
async getPropertiesForTooltip(properties) {
- let allTooltips = await this._source.filterAndFormatPropertiesToHtml(properties);
+ let allTooltips = await this.getSource().filterAndFormatPropertiesToHtml(properties);
this._addJoinsToSourceTooltips(allTooltips);
- for (let i = 0; i < this._joins.length; i++) {
- const propsFromJoin = await this._joins[i].filterAndFormatPropertiesForTooltip(properties);
+ for (let i = 0; i < this.getJoins().length; i++) {
+ const propsFromJoin = await this.getJoins()[i].filterAndFormatPropertiesForTooltip(
+ properties
+ );
allTooltips = [...allTooltips, ...propsFromJoin];
}
return allTooltips;
}
canShowTooltip() {
- return this.isVisible() && (this._source.canFormatFeatureProperties() || this._joins.length);
+ return (
+ this.isVisible() && (this.getSource().canFormatFeatureProperties() || this.getJoins().length)
+ );
}
getFeatureById(id) {
diff --git a/x-pack/legacy/plugins/maps/public/layers/vector_tile_layer.js b/x-pack/legacy/plugins/maps/public/layers/vector_tile_layer.js
index b09ccdc3af8ba..44987fd3e78f0 100644
--- a/x-pack/legacy/plugins/maps/public/layers/vector_tile_layer.js
+++ b/x-pack/legacy/plugins/maps/public/layers/vector_tile_layer.js
@@ -48,7 +48,7 @@ export class VectorTileLayer extends TileLayer {
return;
}
- const nextMeta = { tileLayerId: this._source.getTileLayerId() };
+ const nextMeta = { tileLayerId: this.getSource().getTileLayerId() };
const canSkipSync = this._canSkipSync({
prevDataRequest: this.getSourceDataRequest(),
nextMeta,
@@ -60,7 +60,7 @@ export class VectorTileLayer extends TileLayer {
const requestToken = Symbol(`layer-source-refresh:${this.getId()} - source`);
try {
startLoading(SOURCE_DATA_ID_ORIGIN, requestToken, dataFilters);
- const styleAndSprites = await this._source.getVectorStyleSheetAndSpriteMeta(isRetina());
+ const styleAndSprites = await this.getSource().getVectorStyleSheetAndSpriteMeta(isRetina());
const spriteSheetImageData = await loadSpriteSheetImageData(styleAndSprites.spriteMeta.png);
const data = {
...styleAndSprites,
@@ -78,7 +78,7 @@ export class VectorTileLayer extends TileLayer {
_generateMbSourceIdPrefix() {
const DELIMITTER = '___';
- return `${this.getId()}${DELIMITTER}${this._source.getTileLayerId()}${DELIMITTER}`;
+ return `${this.getId()}${DELIMITTER}${this.getSource().getTileLayerId()}${DELIMITTER}`;
}
_generateMbSourceId(name) {
@@ -141,7 +141,7 @@ export class VectorTileLayer extends TileLayer {
}
_makeNamespacedImageId(imageId) {
- const prefix = this._source.getSpriteNamespacePrefix() + '/';
+ const prefix = this.getSource().getSpriteNamespacePrefix() + '/';
return prefix + imageId;
}
diff --git a/x-pack/legacy/plugins/maps/public/meta.js b/x-pack/legacy/plugins/maps/public/meta.js
index c5cfb582976c1..4d81785ff7a0a 100644
--- a/x-pack/legacy/plugins/maps/public/meta.js
+++ b/x-pack/legacy/plugins/maps/public/meta.js
@@ -9,6 +9,7 @@ import {
EMS_FILES_CATALOGUE_PATH,
EMS_TILES_CATALOGUE_PATH,
EMS_GLYPHS_PATH,
+ EMS_APP_NAME,
} from '../common/constants';
import chrome from 'ui/chrome';
import { i18n } from '@kbn/i18n';
@@ -56,7 +57,8 @@ export function getEMSClient() {
emsClient = new EMSClient({
language: i18n.getLocale(),
- kbnVersion: chrome.getInjected('kbnPkgVersion'),
+ appVersion: chrome.getInjected('kbnPkgVersion'),
+ appName: EMS_APP_NAME,
tileApiUrl,
fileApiUrl,
landingPageUrl: chrome.getInjected('emsLandingPageUrl'),
diff --git a/x-pack/legacy/plugins/maps/public/selectors/map_selectors.js b/x-pack/legacy/plugins/maps/public/selectors/map_selectors.js
index e5eaf8870aa77..79d890bc21f14 100644
--- a/x-pack/legacy/plugins/maps/public/selectors/map_selectors.js
+++ b/x-pack/legacy/plugins/maps/public/selectors/map_selectors.js
@@ -10,6 +10,7 @@ import { TileLayer } from '../layers/tile_layer';
import { VectorTileLayer } from '../layers/vector_tile_layer';
import { VectorLayer } from '../layers/vector_layer';
import { HeatmapLayer } from '../layers/heatmap_layer';
+import { BlendedVectorLayer } from '../layers/blended_vector_layer';
import { ALL_SOURCES } from '../layers/sources/all_sources';
import { timefilter } from 'ui/timefilter';
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
@@ -40,6 +41,8 @@ function createLayerInstance(layerDescriptor, inspectorAdapters) {
return new VectorTileLayer({ layerDescriptor, source });
case HeatmapLayer.type:
return new HeatmapLayer({ layerDescriptor, source });
+ case BlendedVectorLayer.type:
+ return new BlendedVectorLayer({ layerDescriptor, source });
default:
throw new Error(`Unrecognized layerType ${layerDescriptor.type}`);
}
diff --git a/x-pack/legacy/plugins/maps/public/selectors/map_selectors.test.js b/x-pack/legacy/plugins/maps/public/selectors/map_selectors.test.js
index 5ec40a57ebc7f..ef2e23e51a092 100644
--- a/x-pack/legacy/plugins/maps/public/selectors/map_selectors.test.js
+++ b/x-pack/legacy/plugins/maps/public/selectors/map_selectors.test.js
@@ -5,6 +5,7 @@
*/
jest.mock('../layers/vector_layer', () => {});
+jest.mock('../layers/blended_vector_layer', () => {});
jest.mock('../layers/heatmap_layer', () => {});
jest.mock('../layers/vector_tile_layer', () => {});
jest.mock('../layers/sources/all_sources', () => {});
diff --git a/x-pack/legacy/plugins/maps/server/routes.js b/x-pack/legacy/plugins/maps/server/routes.js
index 757750dbb0813..7ca659148449f 100644
--- a/x-pack/legacy/plugins/maps/server/routes.js
+++ b/x-pack/legacy/plugins/maps/server/routes.js
@@ -5,6 +5,7 @@
*/
import {
+ EMS_APP_NAME,
EMS_CATALOGUE_PATH,
EMS_FILES_API_PATH,
EMS_FILES_CATALOGUE_PATH,
@@ -38,7 +39,8 @@ export function initRoutes(server, licenseUid) {
if (mapConfig.includeElasticMapsService) {
emsClient = new EMSClient({
language: i18n.getLocale(),
- kbnVersion: serverConfig.get('pkg.version'),
+ appVersion: serverConfig.get('pkg.version'),
+ appName: EMS_APP_NAME,
fileApiUrl: mapConfig.emsFileApiUrl,
tileApiUrl: mapConfig.emsTileApiUrl,
landingPageUrl: mapConfig.emsLandingPageUrl,
diff --git a/x-pack/legacy/plugins/reporting/index.ts b/x-pack/legacy/plugins/reporting/index.ts
index 9ce4e807f8ef8..89e98302cddc9 100644
--- a/x-pack/legacy/plugins/reporting/index.ts
+++ b/x-pack/legacy/plugins/reporting/index.ts
@@ -10,7 +10,7 @@ import { resolve } from 'path';
import { PLUGIN_ID, UI_SETTINGS_CUSTOM_PDF_LOGO } from './common/constants';
import { config as reportingConfig } from './config';
import { legacyInit } from './server/legacy';
-import { ReportingConfigOptions, ReportingPluginSpecOptions } from './types';
+import { ReportingPluginSpecOptions } from './types';
const kbToBase64Length = (kb: number) => {
return Math.floor((kb * 1024 * 8) / 6);
@@ -25,20 +25,6 @@ export const reporting = (kibana: any) => {
config: reportingConfig,
uiExports: {
- shareContextMenuExtensions: [
- 'plugins/reporting/share_context_menu/register_csv_reporting',
- 'plugins/reporting/share_context_menu/register_reporting',
- ],
- embeddableActions: ['plugins/reporting/panel_actions/get_csv_panel_action'],
- home: ['plugins/reporting/register_feature'],
- managementSections: ['plugins/reporting/views/management'],
- injectDefaultVars(server: Legacy.Server, options?: ReportingConfigOptions) {
- const config = server.config();
- return {
- reportingPollConfig: options ? options.poll : {},
- enablePanelActionDownload: config.get('xpack.reporting.csv.enablePanelActionDownload'),
- };
- },
uiSettingDefaults: {
[UI_SETTINGS_CUSTOM_PDF_LOGO]: {
name: i18n.translate('xpack.reporting.pdfFooterImageLabel', {
diff --git a/x-pack/legacy/plugins/reporting/public/components/report_info_button.test.mocks.ts b/x-pack/legacy/plugins/reporting/public/components/report_info_button.test.mocks.ts
deleted file mode 100644
index 9dd7cbb5fc567..0000000000000
--- a/x-pack/legacy/plugins/reporting/public/components/report_info_button.test.mocks.ts
+++ /dev/null
@@ -1,8 +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;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-export const mockJobQueueClient = { list: jest.fn(), total: jest.fn(), getInfo: jest.fn() };
-jest.mock('../lib/job_queue_client', () => ({ jobQueueClient: mockJobQueueClient }));
diff --git a/x-pack/legacy/plugins/reporting/public/components/report_listing.test.tsx b/x-pack/legacy/plugins/reporting/public/components/report_listing.test.tsx
deleted file mode 100644
index d78eb5c409c1f..0000000000000
--- a/x-pack/legacy/plugins/reporting/public/components/report_listing.test.tsx
+++ /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;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-interface JobData {
- _index: string;
- _id: string;
- _source: {
- browser_type: string;
- created_at: string;
- jobtype: string;
- created_by: string;
- payload: {
- type: string;
- title: string;
- };
- kibana_name?: string; // undefined if job is pending (not yet claimed by an instance)
- kibana_id?: string; // undefined if job is pending (not yet claimed by an instance)
- output?: { content_type: string; size: number }; // undefined if job is incomplete
- completed_at?: string; // undefined if job is incomplete
- };
-}
-
-jest.mock('ui/chrome', () => ({
- getInjected() {
- return {
- jobsRefresh: {
- interval: 10,
- intervalErrorMultiplier: 2,
- },
- };
- },
-}));
-
-jest.mock('ui/kfetch', () => ({
- kfetch: ({ pathname }: { pathname: string }): Promise => {
- if (pathname === '/api/reporting/jobs/list') {
- return Promise.resolve([
- { _index: '.reporting-2019.08.18', _id: 'jzoik8dh1q2i89fb5f19znm6', _source: { payload: { layout: { id: 'preserve_layout', dimensions: { width: 1635, height: 792 } }, type: 'dashboard', title: 'Names', }, max_attempts: 3, browser_type: 'chromium', created_at: '2019-08-23T19:34:24.869Z', jobtype: 'printable_pdf', created_by: 'elastic', attempts: 0, status: 'pending', }, }, // prettier-ignore
- { _index: '.reporting-2019.08.18', _id: 'jzoik7tn1q2i89fb5f60e5ve', _score: null, _source: { payload: { layout: { id: 'preserve_layout', dimensions: { width: 1635, height: 792 } }, type: 'dashboard', title: 'Names', }, max_attempts: 3, browser_type: 'chromium', created_at: '2019-08-23T19:34:24.155Z', jobtype: 'printable_pdf', created_by: 'elastic', attempts: 0, status: 'pending', }, }, // prettier-ignore
- { _index: '.reporting-2019.08.18', _id: 'jzoik5tb1q2i89fb5fckchny', _score: null, _source: { payload: { layout: { id: 'png', dimensions: { width: 1898, height: 876 } }, title: 'cool dashboard', type: 'dashboard', }, max_attempts: 3, browser_type: 'chromium', created_at: '2019-08-23T19:34:21.551Z', jobtype: 'PNG', created_by: 'elastic', attempts: 0, status: 'pending', }, }, // prettier-ignore
- { _index: '.reporting-2019.08.18', _id: 'jzoik5a11q2i89fb5f130t2m', _score: null, _source: { payload: { layout: { id: 'png', dimensions: { width: 1898, height: 876 } }, title: 'cool dashboard', type: 'dashboard', }, max_attempts: 3, browser_type: 'chromium', created_at: '2019-08-23T19:34:20.857Z', jobtype: 'PNG', created_by: 'elastic', attempts: 0, status: 'pending', }, }, // prettier-ignore
- { _index: '.reporting-2019.08.18', _id: 'jzoik3ka1q2i89fb5fdx93g7', _score: null, _source: { payload: { layout: { id: 'preserve_layout', dimensions: { width: 1898, height: 876 } }, type: 'dashboard', title: 'cool dashboard', }, max_attempts: 3, browser_type: 'chromium', created_at: '2019-08-23T19:34:18.634Z', jobtype: 'printable_pdf', created_by: 'elastic', attempts: 0, status: 'pending', }, }, // prettier-ignore
- { _index: '.reporting-2019.08.18', _id: 'jzoik2vt1q2i89fb5ffw723n', _score: null, _source: { payload: { layout: { id: 'preserve_layout', dimensions: { width: 1898, height: 876 } }, type: 'dashboard', title: 'cool dashboard', }, max_attempts: 3, browser_type: 'chromium', created_at: '2019-08-23T19:34:17.753Z', jobtype: 'printable_pdf', created_by: 'elastic', attempts: 0, status: 'pending', }, }, // prettier-ignore
- { _index: '.reporting-2019.08.18', _id: 'jzoik1851q2i89fb5fdge6e7', _score: null, _source: { payload: { layout: { id: 'preserve_layout', dimensions: { width: 1080, height: 720 } }, type: 'canvas workpad', title: 'My Canvas Workpad - Dark', }, max_attempts: 3, browser_type: 'chromium', created_at: '2019-08-23T19:34:15.605Z', jobtype: 'printable_pdf', created_by: 'elastic', attempts: 0, status: 'pending', }, }, // prettier-ignore
- { _index: '.reporting-2019.08.18', _id: 'jzoijyre1q2i89fb5fa7xzvi', _score: null, _source: { payload: { type: 'dashboard', title: 'tests-panels', }, max_attempts: 3, browser_type: 'chromium', created_at: '2019-08-23T19:34:12.410Z', jobtype: 'printable_pdf', created_by: 'elastic', attempts: 0, status: 'pending', }, }, // prettier-ignore
- { _index: '.reporting-2019.08.18', _id: 'jzoijv5h1q2i89fb5ffklnhx', _score: null, _source: { payload: { type: 'dashboard', title: 'tests-panels', }, max_attempts: 3, browser_type: 'chromium', created_at: '2019-08-23T19:34:07.733Z', jobtype: 'printable_pdf', created_by: 'elastic', attempts: 0, status: 'pending', }, }, // prettier-ignore
- { _index: '.reporting-2019.08.18', _id: 'jznhgk7r1bx789fb5f6hxok7', _score: null, _source: { kibana_name: 'spicy.local', browser_type: 'chromium', created_at: '2019-08-23T02:15:47.799Z', jobtype: 'printable_pdf', created_by: 'elastic', kibana_id: 'ca75e26c-2b7d-464f-aef0-babb67c735a0', output: { content_type: 'application/pdf', size: 877114 }, completed_at: '2019-08-23T02:15:57.707Z', payload: { type: 'dashboard (legacy)', title: 'tests-panels', }, max_attempts: 3, started_at: '2019-08-23T02:15:48.794Z', attempts: 1, status: 'completed', }, }, // prettier-ignore
- ]);
- }
-
- // query for jobs count
- return Promise.resolve(18);
- },
-}));
-
-import React from 'react';
-import { mountWithIntl } from 'test_utils/enzyme_helpers';
-import { ReportListing } from './report_listing';
-
-describe('ReportListing', () => {
- it('Report job listing with some items', () => {
- const wrapper = mountWithIntl(
-
- );
- wrapper.update();
- const input = wrapper.find('[data-test-subj="reportJobListing"]');
- expect(input).toMatchSnapshot();
- });
-});
diff --git a/x-pack/legacy/plugins/reporting/public/constants/job_statuses.tsx b/x-pack/legacy/plugins/reporting/public/constants/job_statuses.tsx
deleted file mode 100644
index 29c51217a5c64..0000000000000
--- a/x-pack/legacy/plugins/reporting/public/constants/job_statuses.tsx
+++ /dev/null
@@ -1,13 +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;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-export enum JobStatuses {
- PENDING = 'pending',
- PROCESSING = 'processing',
- COMPLETED = 'completed',
- FAILED = 'failed',
- CANCELLED = 'cancelled',
-}
diff --git a/x-pack/legacy/plugins/reporting/public/lib/download_report.ts b/x-pack/legacy/plugins/reporting/public/lib/download_report.ts
deleted file mode 100644
index 54194c87afabc..0000000000000
--- a/x-pack/legacy/plugins/reporting/public/lib/download_report.ts
+++ /dev/null
@@ -1,23 +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;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import { npStart } from 'ui/new_platform';
-import { API_BASE_URL } from '../../common/constants';
-
-const { core } = npStart;
-
-export function getReportURL(jobId: string) {
- const apiBaseUrl = core.http.basePath.prepend(API_BASE_URL);
- const downloadLink = `${apiBaseUrl}/jobs/download/${jobId}`;
-
- return downloadLink;
-}
-
-export function downloadReport(jobId: string) {
- const location = getReportURL(jobId);
-
- window.open(location);
-}
diff --git a/x-pack/legacy/plugins/reporting/public/lib/job_queue_client.ts b/x-pack/legacy/plugins/reporting/public/lib/job_queue_client.ts
deleted file mode 100644
index 87d4174168b7f..0000000000000
--- a/x-pack/legacy/plugins/reporting/public/lib/job_queue_client.ts
+++ /dev/null
@@ -1,89 +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;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import { npStart } from 'ui/new_platform';
-import { API_LIST_URL } from '../../common/constants';
-
-const { core } = npStart;
-
-export interface JobQueueEntry {
- _id: string;
- _source: any;
-}
-
-export interface JobContent {
- content: string;
- content_type: boolean;
-}
-
-export interface JobInfo {
- kibana_name: string;
- kibana_id: string;
- browser_type: string;
- created_at: string;
- priority: number;
- jobtype: string;
- created_by: string;
- timeout: number;
- output: {
- content_type: string;
- size: number;
- warnings: string[];
- };
- process_expiration: string;
- completed_at: string;
- payload: {
- layout: { id: string; dimensions: { width: number; height: number } };
- objects: Array<{ relativeUrl: string }>;
- type: string;
- title: string;
- forceNow: string;
- browserTimezone: string;
- };
- meta: {
- layout: string;
- objectType: string;
- };
- max_attempts: number;
- started_at: string;
- attempts: number;
- status: string;
-}
-
-class JobQueueClient {
- public list = (page = 0, jobIds: string[] = []): Promise => {
- const query = { page } as any;
- if (jobIds.length > 0) {
- // Only getting the first 10, to prevent URL overflows
- query.ids = jobIds.slice(0, 10).join(',');
- }
-
- return core.http.get(`${API_LIST_URL}/list`, {
- query,
- asSystemRequest: true,
- });
- };
-
- public total(): Promise {
- return core.http.get(`${API_LIST_URL}/count`, {
- asSystemRequest: true,
- });
- }
-
- public getContent(jobId: string): Promise {
- return core.http.get(`${API_LIST_URL}/output/${jobId}`, {
- asSystemRequest: true,
- });
- }
-
- public getInfo(jobId: string): Promise {
- return core.http.get(`${API_LIST_URL}/info/${jobId}`, {
- asSystemRequest: true,
- });
- }
-}
-
-export const jobQueueClient = new JobQueueClient();
diff --git a/x-pack/legacy/plugins/reporting/public/lib/reporting_client.ts b/x-pack/legacy/plugins/reporting/public/lib/reporting_client.ts
deleted file mode 100644
index d471dc57fc9e1..0000000000000
--- a/x-pack/legacy/plugins/reporting/public/lib/reporting_client.ts
+++ /dev/null
@@ -1,37 +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;
- * you may not use this file except in compliance with the Elastic License.
- */
-import { stringify } from 'query-string';
-import { npStart } from 'ui/new_platform';
-// @ts-ignore
-import rison from 'rison-node';
-import { add } from './job_completion_notifications';
-
-const { core } = npStart;
-const API_BASE_URL = '/api/reporting/generate';
-
-interface JobParams {
- [paramName: string]: any;
-}
-
-export const getReportingJobPath = (exportType: string, jobParams: JobParams) => {
- const params = stringify({ jobParams: rison.encode(jobParams) });
-
- return `${core.http.basePath.prepend(API_BASE_URL)}/${exportType}?${params}`;
-};
-
-export const createReportingJob = async (exportType: string, jobParams: any) => {
- const jobParamsRison = rison.encode(jobParams);
- const resp = await core.http.post(`${API_BASE_URL}/${exportType}`, {
- method: 'POST',
- body: JSON.stringify({
- jobParams: jobParamsRison,
- }),
- });
-
- add(resp.job.id);
-
- return resp;
-};
diff --git a/x-pack/legacy/plugins/reporting/public/register_feature.ts b/x-pack/legacy/plugins/reporting/public/register_feature.ts
deleted file mode 100644
index 4e8d32facfcec..0000000000000
--- a/x-pack/legacy/plugins/reporting/public/register_feature.ts
+++ /dev/null
@@ -1,27 +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;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import { i18n } from '@kbn/i18n';
-import { npSetup } from 'ui/new_platform';
-import { FeatureCatalogueCategory } from '../../../../../src/plugins/home/public';
-
-const {
- plugins: { home },
-} = npSetup;
-
-home.featureCatalogue.register({
- id: 'reporting',
- title: i18n.translate('xpack.reporting.registerFeature.reportingTitle', {
- defaultMessage: 'Reporting',
- }),
- description: i18n.translate('xpack.reporting.registerFeature.reportingDescription', {
- defaultMessage: 'Manage your reports generated from Discover, Visualize, and Dashboard.',
- }),
- icon: 'reportingApp',
- path: '/app/kibana#/management/kibana/reporting',
- showOnHomePage: false,
- category: FeatureCatalogueCategory.ADMIN,
-});
diff --git a/x-pack/legacy/plugins/reporting/public/views/management/jobs.html b/x-pack/legacy/plugins/reporting/public/views/management/jobs.html
deleted file mode 100644
index 5471513d64d95..0000000000000
--- a/x-pack/legacy/plugins/reporting/public/views/management/jobs.html
+++ /dev/null
@@ -1,3 +0,0 @@
-
-
-
\ No newline at end of file
diff --git a/x-pack/legacy/plugins/reporting/public/views/management/jobs.js b/x-pack/legacy/plugins/reporting/public/views/management/jobs.js
deleted file mode 100644
index 7205fad8cca53..0000000000000
--- a/x-pack/legacy/plugins/reporting/public/views/management/jobs.js
+++ /dev/null
@@ -1,59 +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;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import React from 'react';
-import { render, unmountComponentAtNode } from 'react-dom';
-import { xpackInfo } from 'plugins/xpack_main/services/xpack_info';
-
-import routes from 'ui/routes';
-import template from 'plugins/reporting/views/management/jobs.html';
-
-import { ReportListing } from '../../components/report_listing';
-import { i18n } from '@kbn/i18n';
-import { I18nContext } from 'ui/i18n';
-import { MANAGEMENT_BREADCRUMB } from 'ui/management';
-
-const REACT_ANCHOR_DOM_ELEMENT_ID = 'reportListingAnchor';
-
-routes.when('/management/kibana/reporting', {
- template,
- k7Breadcrumbs: () => [
- MANAGEMENT_BREADCRUMB,
- {
- text: i18n.translate('xpack.reporting.breadcrumb', {
- defaultMessage: 'Reporting',
- }),
- },
- ],
- controllerAs: 'jobsCtrl',
- controller($scope, kbnUrl) {
- $scope.$$postDigest(() => {
- const node = document.getElementById(REACT_ANCHOR_DOM_ELEMENT_ID);
- if (!node) {
- return;
- }
-
- render(
-
-
- ,
- node
- );
- });
-
- $scope.$on('$destroy', () => {
- const node = document.getElementById(REACT_ANCHOR_DOM_ELEMENT_ID);
- if (node) {
- unmountComponentAtNode(node);
- }
- });
- },
-});
diff --git a/x-pack/legacy/plugins/reporting/public/views/management/management.js b/x-pack/legacy/plugins/reporting/public/views/management/management.js
deleted file mode 100644
index 8643e6fa8b8b4..0000000000000
--- a/x-pack/legacy/plugins/reporting/public/views/management/management.js
+++ /dev/null
@@ -1,44 +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;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import { management } from 'ui/management';
-import { i18n } from '@kbn/i18n';
-import routes from 'ui/routes';
-import { xpackInfo } from 'plugins/xpack_main/services/xpack_info';
-
-import 'plugins/reporting/views/management/jobs';
-
-routes.defaults(/\/management/, {
- resolve: {
- reportingManagementSection: function() {
- const kibanaManagementSection = management.getSection('kibana');
- const showReportingLinks = xpackInfo.get('features.reporting.management.showLinks');
-
- kibanaManagementSection.deregister('reporting');
- if (showReportingLinks) {
- const enableReportingLinks = xpackInfo.get('features.reporting.management.enableLinks');
- const tooltipMessage = xpackInfo.get('features.reporting.management.message');
-
- let url;
- let tooltip;
- if (enableReportingLinks) {
- url = '#/management/kibana/reporting';
- } else {
- tooltip = tooltipMessage;
- }
-
- return kibanaManagementSection.register('reporting', {
- order: 15,
- display: i18n.translate('xpack.reporting.management.reportingTitle', {
- defaultMessage: 'Reporting',
- }),
- url,
- tooltip,
- });
- }
- },
- },
-});
diff --git a/x-pack/legacy/plugins/reporting/types.d.ts b/x-pack/legacy/plugins/reporting/types.d.ts
index b4d49fd21f230..917e9d7daae40 100644
--- a/x-pack/legacy/plugins/reporting/types.d.ts
+++ b/x-pack/legacy/plugins/reporting/types.d.ts
@@ -23,22 +23,6 @@ export type Job = EventEmitter & {
};
};
-export interface ReportingConfigOptions {
- browser: BrowserConfig;
- poll: {
- jobCompletionNotifier: {
- interval: number;
- intervalErrorMultiplier: number;
- };
- jobsRefresh: {
- interval: number;
- intervalErrorMultiplier: number;
- };
- };
- queue: QueueConfig;
- capture: CaptureConfig;
-}
-
export interface NetworkPolicyRule {
allow: boolean;
protocol: string;
diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps/step_logistics.js b/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps/step_logistics.js
index 024001d463240..c3996fe3231b1 100644
--- a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps/step_logistics.js
+++ b/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps/step_logistics.js
@@ -26,14 +26,14 @@ import {
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
import { CronEditor } from '../../../../../../../../../src/plugins/es_ui_shared/public/components/cron_editor';
-import { INDEX_ILLEGAL_CHARACTERS_VISIBLE } from '../../../../legacy_imports';
+import { indexPatterns } from '../../../../../../../../../src/plugins/data/public';
+
+import { indices } from '../../../../shared_imports';
import { getLogisticalDetailsUrl, getCronUrl } from '../../../services';
import { StepError } from './components';
-import { indexPatterns } from '../../../../../../../../../src/plugins/data/public';
-
const indexPatternIllegalCharacters = indexPatterns.ILLEGAL_CHARACTERS_VISIBLE.join(' ');
-const indexIllegalCharacters = INDEX_ILLEGAL_CHARACTERS_VISIBLE.join(' ');
+const indexIllegalCharacters = indices.INDEX_ILLEGAL_CHARACTERS_VISIBLE.join(' ');
export class StepLogistics extends Component {
static propTypes = {
diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps_config/validate_rollup_index.js b/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps_config/validate_rollup_index.js
index 637caa2199c42..ac4bacc291ea3 100644
--- a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps_config/validate_rollup_index.js
+++ b/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps_config/validate_rollup_index.js
@@ -6,7 +6,7 @@
import React from 'react';
import { FormattedMessage } from '@kbn/i18n/react';
-import { findIllegalCharactersInIndexName } from '../../../../legacy_imports';
+import { indices } from '../../../../shared_imports';
export function validateRollupIndex(rollupIndex, indexPattern) {
if (!rollupIndex || !rollupIndex.trim()) {
@@ -27,7 +27,7 @@ export function validateRollupIndex(rollupIndex, indexPattern) {
];
}
- const illegalCharacters = findIllegalCharactersInIndexName(rollupIndex);
+ const illegalCharacters = indices.findIllegalCharactersInIndexName(rollupIndex);
if (illegalCharacters.length) {
return [
diff --git a/x-pack/legacy/plugins/rollup/public/legacy_imports.ts b/x-pack/legacy/plugins/rollup/public/legacy_imports.ts
index 07155a4b0a60e..85fa3022f59ed 100644
--- a/x-pack/legacy/plugins/rollup/public/legacy_imports.ts
+++ b/x-pack/legacy/plugins/rollup/public/legacy_imports.ts
@@ -4,8 +4,5 @@
* you may not use this file except in compliance with the Elastic License.
*/
-// @ts-ignore
-export { findIllegalCharactersInIndexName, INDEX_ILLEGAL_CHARACTERS_VISIBLE } from 'ui/indices';
-
export { AggTypeFilters } from 'ui/agg_types';
export { AggTypeFieldFilters } from 'ui/agg_types';
diff --git a/x-pack/legacy/plugins/reporting/public/views/management/index.js b/x-pack/legacy/plugins/rollup/public/shared_imports.ts
similarity index 76%
rename from x-pack/legacy/plugins/reporting/public/views/management/index.js
rename to x-pack/legacy/plugins/rollup/public/shared_imports.ts
index 0ed6fe09ef80a..6bf74da6db6fe 100644
--- a/x-pack/legacy/plugins/reporting/public/views/management/index.js
+++ b/x-pack/legacy/plugins/rollup/public/shared_imports.ts
@@ -4,4 +4,4 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import './management';
+export { indices } from '../../../../../src/plugins/es_ui_shared/public';
diff --git a/x-pack/legacy/plugins/rollup/server/routes/api/jobs.ts b/x-pack/legacy/plugins/rollup/server/routes/api/jobs.ts
index e58bc95b9a375..e45713e2b807c 100644
--- a/x-pack/legacy/plugins/rollup/server/routes/api/jobs.ts
+++ b/x-pack/legacy/plugins/rollup/server/routes/api/jobs.ts
@@ -127,7 +127,7 @@ export function registerJobsRoute(deps: RouteDependencies, legacy: ServerShim) {
{
id: schema.string(),
},
- { allowUnknowns: true }
+ { unknowns: 'allow' }
),
}),
},
diff --git a/x-pack/legacy/plugins/siem/cypress/integration/detections.spec.ts b/x-pack/legacy/plugins/siem/cypress/integration/detections.spec.ts
index 1624586d4ca14..de17f40a3ac71 100644
--- a/x-pack/legacy/plugins/siem/cypress/integration/detections.spec.ts
+++ b/x-pack/legacy/plugins/siem/cypress/integration/detections.spec.ts
@@ -5,12 +5,14 @@
*/
import {
NUMBER_OF_SIGNALS,
+ OPEN_CLOSE_SIGNALS_BTN,
SELECTED_SIGNALS,
SHOWING_SIGNALS,
SIGNALS,
} from '../screens/detections';
import {
+ closeFirstSignal,
closeSignals,
goToClosedSignals,
goToOpenedSignals,
@@ -26,7 +28,7 @@ import { loginAndWaitForPage } from '../tasks/login';
import { DETECTIONS } from '../urls/navigation';
describe('Detections', () => {
- before(() => {
+ beforeEach(() => {
esArchiverLoad('signals');
loginAndWaitForPage(DETECTIONS);
});
@@ -53,6 +55,7 @@ describe('Detections', () => {
waitForSignals();
cy.reload();
waitForSignals();
+ waitForSignalsToBeLoaded();
const expectedNumberOfSignalsAfterClosing = +numberOfSignals - numberOfSignalsToBeClosed;
cy.get(NUMBER_OF_SIGNALS)
@@ -111,4 +114,43 @@ describe('Detections', () => {
.should('eql', expectedNumberOfOpenedSignals.toString());
});
});
+
+ it('Closes one signal when more than one opened signals are selected', () => {
+ waitForSignalsToBeLoaded();
+
+ cy.get(NUMBER_OF_SIGNALS)
+ .invoke('text')
+ .then(numberOfSignals => {
+ const numberOfSignalsToBeClosed = 1;
+ const numberOfSignalsToBeSelected = 3;
+
+ cy.get(OPEN_CLOSE_SIGNALS_BTN).should('have.attr', 'disabled');
+ selectNumberOfSignals(numberOfSignalsToBeSelected);
+ cy.get(OPEN_CLOSE_SIGNALS_BTN).should('not.have.attr', 'disabled');
+
+ closeFirstSignal();
+ cy.reload();
+ waitForSignalsToBeLoaded();
+ waitForSignals();
+
+ const expectedNumberOfSignals = +numberOfSignals - numberOfSignalsToBeClosed;
+ cy.get(NUMBER_OF_SIGNALS)
+ .invoke('text')
+ .should('eq', expectedNumberOfSignals.toString());
+ cy.get(SHOWING_SIGNALS)
+ .invoke('text')
+ .should('eql', `Showing ${expectedNumberOfSignals.toString()} signals`);
+
+ goToClosedSignals();
+ waitForSignals();
+
+ cy.get(NUMBER_OF_SIGNALS)
+ .invoke('text')
+ .should('eql', numberOfSignalsToBeClosed.toString());
+ cy.get(SHOWING_SIGNALS)
+ .invoke('text')
+ .should('eql', `Showing ${numberOfSignalsToBeClosed.toString()} signal`);
+ cy.get(SIGNALS).should('have.length', numberOfSignalsToBeClosed);
+ });
+ });
});
diff --git a/x-pack/legacy/plugins/siem/cypress/integration/signal_detection_rules.spec.ts b/x-pack/legacy/plugins/siem/cypress/integration/signal_detection_rules.spec.ts
index 8c384c9010665..ce73fe1b7c2a5 100644
--- a/x-pack/legacy/plugins/siem/cypress/integration/signal_detection_rules.spec.ts
+++ b/x-pack/legacy/plugins/siem/cypress/integration/signal_detection_rules.spec.ts
@@ -7,30 +7,30 @@
import { newRule } from '../objects/rule';
import {
- ABOUT_DESCRIPTION,
- ABOUT_EXPECTED_URLS,
ABOUT_FALSE_POSITIVES,
ABOUT_MITRE,
ABOUT_RISK,
- ABOUT_RULE_DESCRIPTION,
ABOUT_SEVERITY,
+ ABOUT_STEP,
ABOUT_TAGS,
ABOUT_TIMELINE,
+ ABOUT_URLS,
DEFINITION_CUSTOM_QUERY,
- DEFINITION_DESCRIPTION,
DEFINITION_INDEX_PATTERNS,
+ DEFINITION_STEP,
RULE_NAME_HEADER,
- SCHEDULE_DESCRIPTION,
SCHEDULE_LOOPBACK,
SCHEDULE_RUNS,
+ SCHEDULE_STEP,
+ ABOUT_RULE_DESCRIPTION,
} from '../screens/rule_details';
import {
CUSTOM_RULES_BTN,
ELASTIC_RULES_BTN,
RISK_SCORE,
RULE_NAME,
- RULES_TABLE,
RULES_ROW,
+ RULES_TABLE,
SEVERITY,
} from '../screens/signal_detection_rules';
@@ -127,10 +127,25 @@ describe('Signal detection rules', () => {
goToRuleDetails();
- cy.get(RULE_NAME_HEADER)
- .invoke('text')
- .should('eql', `${newRule.name} Beta`);
-
+ let expectedUrls = '';
+ newRule.referenceUrls.forEach(url => {
+ expectedUrls = expectedUrls + url;
+ });
+ let expectedFalsePositives = '';
+ newRule.falsePositivesExamples.forEach(falsePositive => {
+ expectedFalsePositives = expectedFalsePositives + falsePositive;
+ });
+ let expectedTags = '';
+ newRule.tags.forEach(tag => {
+ expectedTags = expectedTags + tag;
+ });
+ let expectedMitre = '';
+ newRule.mitre.forEach(mitre => {
+ expectedMitre = expectedMitre + mitre.tactic;
+ mitre.techniques.forEach(technique => {
+ expectedMitre = expectedMitre + technique;
+ });
+ });
const expectedIndexPatterns = [
'apm-*-transaction*',
'auditbeat-*',
@@ -139,77 +154,60 @@ describe('Signal detection rules', () => {
'packetbeat-*',
'winlogbeat-*',
];
- cy.get(DEFINITION_INDEX_PATTERNS).then(patterns => {
- cy.wrap(patterns).each((pattern, index) => {
- cy.wrap(pattern)
- .invoke('text')
- .should('eql', expectedIndexPatterns[index]);
- });
- });
- cy.get(DEFINITION_DESCRIPTION)
- .eq(DEFINITION_CUSTOM_QUERY)
+
+ cy.get(RULE_NAME_HEADER)
.invoke('text')
- .should('eql', `${newRule.customQuery} `);
- cy.get(ABOUT_DESCRIPTION)
- .eq(ABOUT_RULE_DESCRIPTION)
+ .should('eql', `${newRule.name} Beta`);
+
+ cy.get(ABOUT_RULE_DESCRIPTION)
.invoke('text')
.should('eql', newRule.description);
- cy.get(ABOUT_DESCRIPTION)
+ cy.get(ABOUT_STEP)
.eq(ABOUT_SEVERITY)
.invoke('text')
.should('eql', newRule.severity);
- cy.get(ABOUT_DESCRIPTION)
+ cy.get(ABOUT_STEP)
.eq(ABOUT_RISK)
.invoke('text')
.should('eql', newRule.riskScore);
- cy.get(ABOUT_DESCRIPTION)
+ cy.get(ABOUT_STEP)
.eq(ABOUT_TIMELINE)
.invoke('text')
.should('eql', 'Default blank timeline');
-
- let expectedUrls = '';
- newRule.referenceUrls.forEach(url => {
- expectedUrls = expectedUrls + url;
- });
- cy.get(ABOUT_DESCRIPTION)
- .eq(ABOUT_EXPECTED_URLS)
+ cy.get(ABOUT_STEP)
+ .eq(ABOUT_URLS)
.invoke('text')
.should('eql', expectedUrls);
-
- let expectedFalsePositives = '';
- newRule.falsePositivesExamples.forEach(falsePositive => {
- expectedFalsePositives = expectedFalsePositives + falsePositive;
- });
- cy.get(ABOUT_DESCRIPTION)
+ cy.get(ABOUT_STEP)
.eq(ABOUT_FALSE_POSITIVES)
.invoke('text')
.should('eql', expectedFalsePositives);
-
- let expectedMitre = '';
- newRule.mitre.forEach(mitre => {
- expectedMitre = expectedMitre + mitre.tactic;
- mitre.techniques.forEach(technique => {
- expectedMitre = expectedMitre + technique;
- });
- });
- cy.get(ABOUT_DESCRIPTION)
+ cy.get(ABOUT_STEP)
.eq(ABOUT_MITRE)
.invoke('text')
.should('eql', expectedMitre);
-
- let expectedTags = '';
- newRule.tags.forEach(tag => {
- expectedTags = expectedTags + tag;
- });
- cy.get(ABOUT_DESCRIPTION)
+ cy.get(ABOUT_STEP)
.eq(ABOUT_TAGS)
.invoke('text')
.should('eql', expectedTags);
- cy.get(SCHEDULE_DESCRIPTION)
+
+ cy.get(DEFINITION_INDEX_PATTERNS).then(patterns => {
+ cy.wrap(patterns).each((pattern, index) => {
+ cy.wrap(pattern)
+ .invoke('text')
+ .should('eql', expectedIndexPatterns[index]);
+ });
+ });
+ cy.get(DEFINITION_STEP)
+ .eq(DEFINITION_CUSTOM_QUERY)
+ .invoke('text')
+ .should('eql', `${newRule.customQuery} `);
+
+ cy.get(SCHEDULE_STEP)
.eq(SCHEDULE_RUNS)
.invoke('text')
.should('eql', '5m');
- cy.get(SCHEDULE_DESCRIPTION)
+ cy.get(SCHEDULE_STEP)
.eq(SCHEDULE_LOOPBACK)
.invoke('text')
.should('eql', '1m');
diff --git a/x-pack/legacy/plugins/siem/cypress/screens/detections.ts b/x-pack/legacy/plugins/siem/cypress/screens/detections.ts
index 8b5ba23578807..f388ac1215d01 100644
--- a/x-pack/legacy/plugins/siem/cypress/screens/detections.ts
+++ b/x-pack/legacy/plugins/siem/cypress/screens/detections.ts
@@ -12,7 +12,9 @@ export const MANAGE_SIGNAL_DETECTION_RULES_BTN = '[data-test-subj="manage-signal
export const NUMBER_OF_SIGNALS = '[data-test-subj="server-side-event-count"]';
-export const OPEN_CLOSE_SIGNALS_BTN = '[data-test-subj="openCloseSignal"] .siemLinkIcon__label';
+export const OPEN_CLOSE_SIGNAL_BTN = '[data-test-subj="update-signal-status-button"]';
+
+export const OPEN_CLOSE_SIGNALS_BTN = '[data-test-subj="openCloseSignal"] button';
export const OPENED_SIGNALS_BTN = '[data-test-subj="openSignals"]';
diff --git a/x-pack/legacy/plugins/siem/cypress/screens/rule_details.ts b/x-pack/legacy/plugins/siem/cypress/screens/rule_details.ts
index 46da52cd0ddd8..6c16735ba5f24 100644
--- a/x-pack/legacy/plugins/siem/cypress/screens/rule_details.ts
+++ b/x-pack/legacy/plugins/siem/cypress/screens/rule_details.ts
@@ -4,35 +4,35 @@
* you may not use this file except in compliance with the Elastic License.
*/
-export const ABOUT_DESCRIPTION = '[data-test-subj="aboutRule"] .euiDescriptionList__description';
+export const ABOUT_FALSE_POSITIVES = 4;
-export const ABOUT_EXPECTED_URLS = 4;
+export const ABOUT_MITRE = 5;
-export const ABOUT_FALSE_POSITIVES = 5;
+export const ABOUT_RULE_DESCRIPTION = '[data-test-subj=stepAboutRuleDetailsToggleDescriptionText]';
-export const ABOUT_MITRE = 6;
+export const ABOUT_RISK = 1;
-export const ABOUT_RULE_DESCRIPTION = 0;
+export const ABOUT_SEVERITY = 0;
-export const ABOUT_RISK = 2;
+export const ABOUT_STEP = '[data-test-subj="aboutRule"] .euiDescriptionList__description';
-export const ABOUT_SEVERITY = 1;
+export const ABOUT_TAGS = 6;
-export const ABOUT_TAGS = 7;
+export const ABOUT_TIMELINE = 2;
-export const ABOUT_TIMELINE = 3;
+export const ABOUT_URLS = 3;
export const DEFINITION_CUSTOM_QUERY = 1;
-export const DEFINITION_DESCRIPTION =
- '[data-test-subj="definition"] .euiDescriptionList__description';
-
export const DEFINITION_INDEX_PATTERNS =
- '[data-test-subj="definition"] .euiDescriptionList__description .euiBadge__text';
+ '[data-test-subj=definitionRule] [data-test-subj="listItemColumnStepRuleDescription"] .euiDescriptionList__description .euiBadge__text';
+
+export const DEFINITION_STEP =
+ '[data-test-subj=definitionRule] [data-test-subj="listItemColumnStepRuleDescription"] .euiDescriptionList__description';
export const RULE_NAME_HEADER = '[data-test-subj="header-page-title"]';
-export const SCHEDULE_DESCRIPTION = '[data-test-subj="schedule"] .euiDescriptionList__description';
+export const SCHEDULE_STEP = '[data-test-subj="schedule"] .euiDescriptionList__description';
export const SCHEDULE_RUNS = 0;
diff --git a/x-pack/legacy/plugins/siem/cypress/tasks/detections.ts b/x-pack/legacy/plugins/siem/cypress/tasks/detections.ts
index 21a0c136b90df..3416e3eb81de3 100644
--- a/x-pack/legacy/plugins/siem/cypress/tasks/detections.ts
+++ b/x-pack/legacy/plugins/siem/cypress/tasks/detections.ts
@@ -8,6 +8,7 @@ import {
CLOSED_SIGNALS_BTN,
LOADING_SIGNALS_PANEL,
MANAGE_SIGNAL_DETECTION_RULES_BTN,
+ OPEN_CLOSE_SIGNAL_BTN,
OPEN_CLOSE_SIGNALS_BTN,
OPENED_SIGNALS_BTN,
SIGNALS,
@@ -15,6 +16,12 @@ import {
} from '../screens/detections';
import { REFRESH_BUTTON } from '../screens/siem_header';
+export const closeFirstSignal = () => {
+ cy.get(OPEN_CLOSE_SIGNAL_BTN)
+ .first()
+ .click({ force: true });
+};
+
export const closeSignals = () => {
cy.get(OPEN_CLOSE_SIGNALS_BTN).click({ force: true });
};
diff --git a/x-pack/legacy/plugins/siem/dev_tools/circular_deps/run_check_circular_deps_cli.js b/x-pack/legacy/plugins/siem/dev_tools/circular_deps/run_check_circular_deps_cli.js
index 8ca61b2397d8b..f3a97f5b9c9b6 100644
--- a/x-pack/legacy/plugins/siem/dev_tools/circular_deps/run_check_circular_deps_cli.js
+++ b/x-pack/legacy/plugins/siem/dev_tools/circular_deps/run_check_circular_deps_cli.js
@@ -17,6 +17,16 @@ run(
[resolve(__dirname, '../../public'), resolve(__dirname, '../../common')],
{
fileExtensions: ['ts', 'js', 'tsx'],
+ excludeRegExp: [
+ 'test.ts$',
+ 'test.tsx$',
+ 'containers/detection_engine/rules/types.ts$',
+ 'core/public/chrome/chrome_service.tsx$',
+ 'src/core/server/types.ts$',
+ 'src/core/server/saved_objects/types.ts$',
+ 'src/core/public/overlays/banners/banners_service.tsx$',
+ 'src/core/public/saved_objects/saved_objects_client.ts$',
+ ],
}
);
diff --git a/x-pack/legacy/plugins/siem/public/containers/case/configure/api.ts b/x-pack/legacy/plugins/siem/public/containers/case/configure/api.ts
index a6db36d8f64e7..ed47cdc62a1b6 100644
--- a/x-pack/legacy/plugins/siem/public/containers/case/configure/api.ts
+++ b/x-pack/legacy/plugins/siem/public/containers/case/configure/api.ts
@@ -16,7 +16,7 @@ import { KibanaServices } from '../../../lib/kibana';
import { CASES_CONFIGURE_URL } from '../constants';
import { ApiProps } from '../types';
import { convertToCamelCase, decodeCaseConfigureResponse } from '../utils';
-import { CaseConfigure, PatchConnectorProps } from './types';
+import { CaseConfigure } from './types';
export const fetchConnectors = async ({ signal }: ApiProps): Promise => {
const response = await KibanaServices.get().http.fetch(
@@ -79,20 +79,3 @@ export const patchCaseConfigure = async (
decodeCaseConfigureResponse(response)
);
};
-
-export const patchConfigConnector = async ({
- connectorId,
- config,
- signal,
-}: PatchConnectorProps): Promise => {
- const response = await KibanaServices.get().http.fetch(
- `${CASES_CONFIGURE_URL}/connectors/${connectorId}`,
- {
- method: 'PATCH',
- body: JSON.stringify(config),
- signal,
- }
- );
-
- return response;
-};
diff --git a/x-pack/legacy/plugins/siem/public/containers/case/configure/types.ts b/x-pack/legacy/plugins/siem/public/containers/case/configure/types.ts
index 840828307163c..fc7aaa3643d77 100644
--- a/x-pack/legacy/plugins/siem/public/containers/case/configure/types.ts
+++ b/x-pack/legacy/plugins/siem/public/containers/case/configure/types.ts
@@ -4,10 +4,9 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { ElasticUser, ApiProps } from '../types';
+import { ElasticUser } from '../types';
import {
ActionType,
- CasesConnectorConfiguration,
CasesConfigurationMaps,
CaseField,
ClosureType,
@@ -33,11 +32,6 @@ export interface CaseConfigure {
version: string;
}
-export interface PatchConnectorProps extends ApiProps {
- connectorId: string;
- config: CasesConnectorConfiguration;
-}
-
export interface CCMapsCombinedActionAttributes extends CasesConfigurationMaps {
actionType?: ActionType;
}
diff --git a/x-pack/legacy/plugins/siem/public/containers/case/configure/use_connectors.tsx b/x-pack/legacy/plugins/siem/public/containers/case/configure/use_connectors.tsx
index f905ebe756d7d..d31dcdbee2a14 100644
--- a/x-pack/legacy/plugins/siem/public/containers/case/configure/use_connectors.tsx
+++ b/x-pack/legacy/plugins/siem/public/containers/case/configure/use_connectors.tsx
@@ -8,14 +8,13 @@ import { useState, useEffect, useCallback } from 'react';
import { useStateToaster, errorToToaster } from '../../../components/toasters';
import * as i18n from '../translations';
-import { fetchConnectors, patchConfigConnector } from './api';
-import { CasesConfigurationMapping, Connector } from './types';
+import { fetchConnectors } from './api';
+import { Connector } from './types';
export interface ReturnConnectors {
loading: boolean;
connectors: Connector[];
refetchConnectors: () => void;
- updateConnector: (connectorId: string, mappings: CasesConfigurationMapping[]) => unknown;
}
export const useConnectors = (): ReturnConnectors => {
@@ -53,55 +52,6 @@ export const useConnectors = (): ReturnConnectors => {
};
}, []);
- const updateConnector = useCallback(
- (connectorId: string, mappings: CasesConfigurationMapping[]) => {
- if (connectorId === 'none') {
- return;
- }
-
- let didCancel = false;
- const abortCtrl = new AbortController();
- const update = async () => {
- try {
- setLoading(true);
- await patchConfigConnector({
- connectorId,
- config: {
- cases_configuration: {
- mapping: mappings.map(m => ({
- source: m.source,
- target: m.target,
- action_type: m.actionType,
- })),
- },
- },
- signal: abortCtrl.signal,
- });
- if (!didCancel) {
- setLoading(false);
- refetchConnectors();
- }
- } catch (error) {
- if (!didCancel) {
- setLoading(false);
- refetchConnectors();
- errorToToaster({
- title: i18n.ERROR_TITLE,
- error: error.body && error.body.message ? new Error(error.body.message) : error,
- dispatchToaster,
- });
- }
- }
- };
- update();
- return () => {
- didCancel = true;
- abortCtrl.abort();
- };
- },
- []
- );
-
useEffect(() => {
refetchConnectors();
}, []);
@@ -110,6 +60,5 @@ export const useConnectors = (): ReturnConnectors => {
loading,
connectors,
refetchConnectors,
- updateConnector,
};
};
diff --git a/x-pack/legacy/plugins/siem/public/containers/detection_engine/rules/types.ts b/x-pack/legacy/plugins/siem/public/containers/detection_engine/rules/types.ts
index 4d2aec4ee8740..f962204c6b1b4 100644
--- a/x-pack/legacy/plugins/siem/public/containers/detection_engine/rules/types.ts
+++ b/x-pack/legacy/plugins/siem/public/containers/detection_engine/rules/types.ts
@@ -33,6 +33,7 @@ export const NewRuleSchema = t.intersection([
threat: t.array(t.unknown),
to: t.string,
updated_by: t.string,
+ note: t.string,
}),
]);
@@ -86,6 +87,7 @@ export const RuleSchema = t.intersection([
status_date: t.string,
timeline_id: t.string,
timeline_title: t.string,
+ note: t.string,
version: t.number,
}),
]);
diff --git a/x-pack/legacy/plugins/siem/public/lib/connectors/servicenow.tsx b/x-pack/legacy/plugins/siem/public/lib/connectors/servicenow.tsx
index 877757df30fb3..8e947fbc0f9bb 100644
--- a/x-pack/legacy/plugins/siem/public/lib/connectors/servicenow.tsx
+++ b/x-pack/legacy/plugins/siem/public/lib/connectors/servicenow.tsx
@@ -87,6 +87,10 @@ export function getActionType(): ActionTypeModel {
const ServiceNowConnectorFields: React.FunctionComponent> = ({ action, editActionConfig, editActionSecrets, errors }) => {
+ /* We do not provide defaults values to the fields (like empty string for apiUrl) intentionally.
+ * If we do, errors will be shown the first time the flyout is open even though the user did not
+ * interact with the form. Also, we would like to show errors for empty fields provided by the user.
+ /*/
const { apiUrl, casesConfiguration: { mapping = [] } = {} } = action.config;
const { username, password } = action.secrets;
@@ -153,7 +157,7 @@ const ServiceNowConnectorFields: React.FunctionComponent {
sort: { field: queryParams.sortField, direction: queryParams.sortOrder },
};
const euiBasicTableSelectionProps = useMemo>(
- () => ({
- selectable: (item: Case) => true,
- onSelectionChange: setSelectedCases,
- }),
+ () => ({ onSelectionChange: setSelectedCases }),
[selectedCases]
);
const isCasesLoading = useMemo(
@@ -305,6 +302,7 @@ export const AllCases = React.memo(() => {
{i18n.SHOWING_SELECTED_CASES(selectedCases.length)}
{
{
closePopover();
deleteCasesAction(selectedCaseIds);
diff --git a/x-pack/legacy/plugins/siem/public/pages/case/components/case_view/index.test.tsx b/x-pack/legacy/plugins/siem/public/pages/case/components/case_view/index.test.tsx
index 8754c0404d40b..15d6cf7cf7317 100644
--- a/x-pack/legacy/plugins/siem/public/pages/case/components/case_view/index.test.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/case/components/case_view/index.test.tsx
@@ -7,16 +7,30 @@
import React from 'react';
import { mount } from 'enzyme';
import { CaseComponent } from './';
-import * as apiHook from '../../../../containers/case/use_update_case';
+import * as updateHook from '../../../../containers/case/use_update_case';
+import * as deleteHook from '../../../../containers/case/use_delete_cases';
import { caseProps, data } from './__mock__';
import { TestProviders } from '../../../../mock';
describe('CaseView ', () => {
+ const handleOnDeleteConfirm = jest.fn();
+ const handleToggleModal = jest.fn();
+ const dispatchResetIsDeleted = jest.fn();
const updateCaseProperty = jest.fn();
+ /* eslint-disable no-console */
+ // Silence until enzyme fixed to use ReactTestUtils.act()
+ const originalError = console.error;
+ beforeAll(() => {
+ console.error = jest.fn();
+ });
+ afterAll(() => {
+ console.error = originalError;
+ });
+ /* eslint-enable no-console */
beforeEach(() => {
jest.resetAllMocks();
- jest.spyOn(apiHook, 'useUpdateCase').mockReturnValue({
+ jest.spyOn(updateHook, 'useUpdateCase').mockReturnValue({
caseData: data,
isLoading: false,
isError: false,
@@ -119,4 +133,46 @@ describe('CaseView ', () => {
.prop('source')
).toEqual(data.comments[0].comment);
});
+
+ it('toggle delete modal and cancel', () => {
+ const wrapper = mount(
+
+
+
+ );
+
+ expect(wrapper.find('[data-test-subj="confirm-delete-case-modal"]').exists()).toBeFalsy();
+
+ wrapper
+ .find(
+ '[data-test-subj="case-view-actions"] button[data-test-subj="property-actions-ellipses"]'
+ )
+ .first()
+ .simulate('click');
+ wrapper.find('button[data-test-subj="property-actions-trash"]').simulate('click');
+ expect(wrapper.find('[data-test-subj="confirm-delete-case-modal"]').exists()).toBeTruthy();
+ wrapper.find('button[data-test-subj="confirmModalCancelButton"]').simulate('click');
+ expect(wrapper.find('[data-test-subj="confirm-delete-case-modal"]').exists()).toBeFalsy();
+ });
+
+ it('toggle delete modal and confirm', () => {
+ jest.spyOn(deleteHook, 'useDeleteCases').mockReturnValue({
+ dispatchResetIsDeleted,
+ handleToggleModal,
+ handleOnDeleteConfirm,
+ isLoading: false,
+ isError: false,
+ isDeleted: false,
+ isDisplayConfirmDeleteModal: true,
+ });
+ const wrapper = mount(
+
+
+
+ );
+
+ expect(wrapper.find('[data-test-subj="confirm-delete-case-modal"]').exists()).toBeTruthy();
+ wrapper.find('button[data-test-subj="confirmModalConfirmButton"]').simulate('click');
+ expect(handleOnDeleteConfirm.mock.calls[0][0]).toEqual([caseProps.caseId]);
+ });
});
diff --git a/x-pack/legacy/plugins/siem/public/pages/case/components/case_view/index.tsx b/x-pack/legacy/plugins/siem/public/pages/case/components/case_view/index.tsx
index 5ff542d208905..82216e88a091e 100644
--- a/x-pack/legacy/plugins/siem/public/pages/case/components/case_view/index.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/case/components/case_view/index.tsx
@@ -216,7 +216,7 @@ export const CaseComponent = React.memo(({ caseId, initialData }) =>
onChange={toggleStatusCase}
/>
-
+
diff --git a/x-pack/legacy/plugins/siem/public/pages/case/components/configure_cases/connectors.tsx b/x-pack/legacy/plugins/siem/public/pages/case/components/configure_cases/connectors.tsx
index 55b256b66b72b..bb0c50b3b193a 100644
--- a/x-pack/legacy/plugins/siem/public/pages/case/components/configure_cases/connectors.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/case/components/configure_cases/connectors.tsx
@@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import React, { useState, useCallback } from 'react';
+import React from 'react';
import {
EuiDescribedFormGroup,
EuiFormRow,
@@ -18,12 +18,7 @@ import styled from 'styled-components';
import { ConnectorsDropdown } from './connectors_dropdown';
import * as i18n from './translations';
-import {
- ActionsConnectorsContextProvider,
- ConnectorAddFlyout,
-} from '../../../../../../../../plugins/triggers_actions_ui/public';
import { Connector } from '../../../../containers/case/configure/types';
-import { useKibana } from '../../../../lib/kibana';
const EuiFormRowExtended = styled(EuiFormRow)`
.euiFormRow__labelWrapper {
@@ -38,41 +33,26 @@ interface Props {
disabled: boolean;
isLoading: boolean;
onChangeConnector: (id: string) => void;
- refetchConnectors: () => void;
selectedConnector: string;
+ handleShowAddFlyout: () => void;
}
-const actionTypes = [
- {
- id: '.servicenow',
- name: 'ServiceNow',
- enabled: true,
- },
-];
-
const ConnectorsComponent: React.FC = ({
connectors,
disabled,
isLoading,
onChangeConnector,
- refetchConnectors,
selectedConnector,
+ handleShowAddFlyout,
}) => {
- const { http, triggers_actions_ui, notifications, application } = useKibana().services;
- const [addFlyoutVisible, setAddFlyoutVisibility] = useState(false);
-
- const handleShowFlyout = useCallback(() => setAddFlyoutVisibility(true), []);
-
const dropDownLabel = (
{i18n.INCIDENT_MANAGEMENT_SYSTEM_LABEL}
- {i18n.ADD_NEW_CONNECTOR}
+ {i18n.ADD_NEW_CONNECTOR}
);
- const reloadConnectors = useCallback(async () => refetchConnectors(), []);
-
return (
<>
= ({
/>
-
-
-
>
);
};
diff --git a/x-pack/legacy/plugins/siem/public/pages/case/components/configure_cases/index.tsx b/x-pack/legacy/plugins/siem/public/pages/case/components/configure_cases/index.tsx
index da715fb66953f..b3c424bef6a7a 100644
--- a/x-pack/legacy/plugins/siem/public/pages/case/components/configure_cases/index.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/case/components/configure_cases/index.tsx
@@ -9,8 +9,18 @@ import styled, { css } from 'styled-components';
import { EuiFlexGroup, EuiFlexItem, EuiButton, EuiSpacer, EuiCallOut } from '@elastic/eui';
import { noop, isEmpty } from 'lodash/fp';
+import { useKibana } from '../../../../lib/kibana';
import { useConnectors } from '../../../../containers/case/configure/use_connectors';
import { useCaseConfigure } from '../../../../containers/case/configure/use_configure';
+import {
+ ActionsConnectorsContextProvider,
+ ConnectorAddFlyout,
+ ConnectorEditFlyout,
+} from '../../../../../../../../plugins/triggers_actions_ui/public';
+
+// eslint-disable-next-line @kbn/eslint/no-restricted-paths
+import { ActionConnectorTableItem } from '../../../../../../../../plugins/triggers_actions_ui/public/types';
+
import {
ClosureType,
CasesConfigurationMapping,
@@ -40,8 +50,25 @@ const initialState: State = {
mapping: null,
};
+const actionTypes = [
+ {
+ id: '.servicenow',
+ name: 'ServiceNow',
+ enabled: true,
+ },
+];
+
const ConfigureCasesComponent: React.FC = () => {
+ const { http, triggers_actions_ui, notifications, application } = useKibana().services;
+
const [connectorIsValid, setConnectorIsValid] = useState(true);
+ const [addFlyoutVisible, setAddFlyoutVisibility] = useState(false);
+ const [editFlyoutVisible, setEditFlyoutVisibility] = useState(false);
+ const [editedConnectorItem, setEditedConnectorItem] = useState(
+ null
+ );
+
+ const handleShowAddFlyout = useCallback(() => setAddFlyoutVisibility(true), []);
const [{ connectorId, closureType, mapping }, dispatch] = useReducer(
configureCasesReducer(),
@@ -73,20 +100,18 @@ const ConfigureCasesComponent: React.FC = () => {
setConnectorId,
setClosureType,
});
- const {
- loading: isLoadingConnectors,
- connectors,
- refetchConnectors,
- updateConnector,
- } = useConnectors();
+ const { loading: isLoadingConnectors, connectors, refetchConnectors } = useConnectors();
+ // ActionsConnectorsContextProvider reloadConnectors prop expects a Promise.
+ // TODO: Fix it if reloadConnectors type change.
+ const reloadConnectors = useCallback(async () => refetchConnectors(), []);
const isLoadingAny = isLoadingConnectors || persistLoading || loadingCaseConfigure;
+ const updateConnectorDisabled = isLoadingAny || !connectorIsValid || connectorId === 'none';
const handleSubmit = useCallback(
// TO DO give a warning/error to user when field are not mapped so they have chance to do it
() => {
persistCaseConfigure({ connectorId, closureType });
- updateConnector(connectorId, mapping ?? []);
},
[connectorId, closureType, mapping]
);
@@ -124,6 +149,14 @@ const ConfigureCasesComponent: React.FC = () => {
}
}, [connectors, connectorId]);
+ useEffect(() => {
+ if (!isLoadingConnectors && connectorId !== 'none') {
+ setEditedConnectorItem(
+ connectors.find(c => c.id === connectorId) as ActionConnectorTableItem
+ );
+ }
+ }, [connectors, connectorId]);
+
return (
{!connectorIsValid && (
@@ -139,7 +172,7 @@ const ConfigureCasesComponent: React.FC = () => {
disabled={persistLoading || isLoadingConnectors}
isLoading={isLoadingConnectors}
onChangeConnector={setConnectorId}
- refetchConnectors={refetchConnectors}
+ handleShowAddFlyout={handleShowAddFlyout}
selectedConnector={connectorId}
/>
@@ -152,15 +185,11 @@ const ConfigureCasesComponent: React.FC = () => {
@@ -194,6 +223,29 @@ const ConfigureCasesComponent: React.FC = () => {
+
+
+ {editedConnectorItem && (
+
+ )}
+
);
};
diff --git a/x-pack/legacy/plugins/siem/public/pages/case/components/configure_cases/mapping.tsx b/x-pack/legacy/plugins/siem/public/pages/case/components/configure_cases/mapping.tsx
index 10c8f6b938023..2600a9f4e13ac 100644
--- a/x-pack/legacy/plugins/siem/public/pages/case/components/configure_cases/mapping.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/case/components/configure_cases/mapping.tsx
@@ -4,8 +4,16 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import React from 'react';
-import { EuiDescribedFormGroup } from '@elastic/eui';
+import React, { useCallback } from 'react';
+import styled from 'styled-components';
+
+import {
+ EuiDescribedFormGroup,
+ EuiFlexGroup,
+ EuiFlexItem,
+ EuiFormRow,
+ EuiButtonEmpty,
+} from '@elastic/eui';
import * as i18n from './translations';
@@ -14,18 +22,44 @@ import { CasesConfigurationMapping } from '../../../../containers/case/configure
interface MappingProps {
disabled: boolean;
+ updateConnectorDisabled: boolean;
mapping: CasesConfigurationMapping[] | null;
onChangeMapping: (newMapping: CasesConfigurationMapping[]) => void;
+ setEditFlyoutVisibility: React.Dispatch>;
}
-const MappingComponent: React.FC = ({ disabled, mapping, onChangeMapping }) => (
- {i18n.FIELD_MAPPING_TITLE}}
- description={i18n.FIELD_MAPPING_DESC}
- >
-
-
-);
+const EuiButtonEmptyExtended = styled(EuiButtonEmpty)`
+ font-size: 12px;
+ height: 24px;
+`;
+
+const MappingComponent: React.FC = ({
+ disabled,
+ updateConnectorDisabled,
+ mapping,
+ onChangeMapping,
+ setEditFlyoutVisibility,
+}) => {
+ const onClick = useCallback(() => setEditFlyoutVisibility(true), []);
+
+ return (
+ {i18n.FIELD_MAPPING_TITLE}}
+ description={i18n.FIELD_MAPPING_DESC}
+ >
+
+
+
+
+ {i18n.UPDATE_CONNECTOR}
+
+
+
+
+
+
+ );
+};
export const Mapping = React.memo(MappingComponent);
diff --git a/x-pack/legacy/plugins/siem/public/pages/case/components/configure_cases/translations.ts b/x-pack/legacy/plugins/siem/public/pages/case/components/configure_cases/translations.ts
index d24921a636082..dd9bf82fb0b0d 100644
--- a/x-pack/legacy/plugins/siem/public/pages/case/components/configure_cases/translations.ts
+++ b/x-pack/legacy/plugins/siem/public/pages/case/components/configure_cases/translations.ts
@@ -186,3 +186,7 @@ export const FIELD_MAPPING_FIELD_COMMENTS = i18n.translate(
defaultMessage: 'Comments',
}
);
+
+export const UPDATE_CONNECTOR = i18n.translate('xpack.siem.case.configureCases.updateConnector', {
+ defaultMessage: 'Update connector',
+});
diff --git a/x-pack/legacy/plugins/siem/public/pages/case/components/confirm_delete_case/index.tsx b/x-pack/legacy/plugins/siem/public/pages/case/components/confirm_delete_case/index.tsx
index dff36a6dac571..5755258b36388 100644
--- a/x-pack/legacy/plugins/siem/public/pages/case/components/confirm_delete_case/index.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/case/components/confirm_delete_case/index.tsx
@@ -32,6 +32,7 @@ const ConfirmDeleteCaseModalComp: React.FC = ({
buttonColor="danger"
cancelButtonText={i18n.CANCEL}
confirmButtonText={isPlural ? i18n.DELETE_CASES : i18n.DELETE_CASE}
+ data-test-subj="confirm-delete-case-modal"
defaultFocusedButton="confirm"
onCancel={onCancel}
onConfirm={onConfirm}
diff --git a/x-pack/legacy/plugins/siem/public/pages/case/components/create/index.tsx b/x-pack/legacy/plugins/siem/public/pages/case/components/create/index.tsx
index 3b9af8349437e..20712c3c5a815 100644
--- a/x-pack/legacy/plugins/siem/public/pages/case/components/create/index.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/case/components/create/index.tsx
@@ -72,6 +72,10 @@ export const Create = React.memo(() => {
}
}, [form]);
+ const handleSetIsCancel = useCallback(() => {
+ setIsCancel(true);
+ }, [isCancel]);
+
if (caseData != null && caseData.id) {
return ;
}
@@ -137,7 +141,12 @@ export const Create = React.memo(() => {
responsive={false}
>
- setIsCancel(true)} iconType="cross">
+
{i18n.CANCEL}
diff --git a/x-pack/legacy/plugins/siem/public/pages/case/components/property_actions/index.tsx b/x-pack/legacy/plugins/siem/public/pages/case/components/property_actions/index.tsx
index 7fe5b6f5f8794..01ccf3c510b60 100644
--- a/x-pack/legacy/plugins/siem/public/pages/case/components/property_actions/index.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/case/components/property_actions/index.tsx
@@ -13,9 +13,12 @@ export interface PropertyActionButtonProps {
label: string;
}
+const ComponentId = 'property-actions';
+
const PropertyActionButton = React.memo(
({ onClick, iconType, label }) => (
(({ propertyActio
}, []);
return (
-
+
(({ propertyActio
isOpen={showActions}
closePopover={onClosePopover}
>
-
+
{propertyActions.map((action, key) => (
{
+ let mockEcsDataClone = cloneDeep(mockEcsData);
+ beforeEach(() => {
+ mockEcsDataClone = cloneDeep(mockEcsData);
+ });
+ describe('getStringOrStringArray', () => {
+ test('it should correctly return a string array', () => {
+ const value = getStringArray('x', {
+ x: 'The nickname of the developer we all :heart:',
+ });
+ expect(value).toEqual(['The nickname of the developer we all :heart:']);
+ });
+
+ test('it should correctly return a string array with a single element', () => {
+ const value = getStringArray('x', {
+ x: ['The nickname of the developer we all :heart:'],
+ });
+ expect(value).toEqual(['The nickname of the developer we all :heart:']);
+ });
+
+ test('it should correctly return a string array with two elements of strings', () => {
+ const value = getStringArray('x', {
+ x: ['The nickname of the developer we all :heart:', 'We are all made of stars'],
+ });
+ expect(value).toEqual([
+ 'The nickname of the developer we all :heart:',
+ 'We are all made of stars',
+ ]);
+ });
+
+ test('it should correctly return a string array with deep elements', () => {
+ const value = getStringArray('x.y.z', {
+ x: { y: { z: 'zed' } },
+ });
+ expect(value).toEqual(['zed']);
+ });
+
+ test('it should correctly return a string array with a non-existent value', () => {
+ const value = getStringArray('non.existent', {
+ x: { y: { z: 'zed' } },
+ });
+ expect(value).toEqual([]);
+ });
+
+ test('it should trace an error if the value is not a string', () => {
+ const mockConsole: Console = ({ trace: jest.fn() } as unknown) as Console;
+ const value = getStringArray('a', { a: 5 }, mockConsole);
+ expect(value).toEqual([]);
+ expect(
+ mockConsole.trace
+ ).toHaveBeenCalledWith(
+ 'Data type that is not a string or string array detected:',
+ 5,
+ 'when trying to access field:',
+ 'a',
+ 'from data object of:',
+ { a: 5 }
+ );
+ });
+
+ test('it should trace an error if the value is an array of mixed values', () => {
+ const mockConsole: Console = ({ trace: jest.fn() } as unknown) as Console;
+ const value = getStringArray('a', { a: ['hi', 5] }, mockConsole);
+ expect(value).toEqual([]);
+ expect(
+ mockConsole.trace
+ ).toHaveBeenCalledWith(
+ 'Data type that is not a string or string array detected:',
+ ['hi', 5],
+ 'when trying to access field:',
+ 'a',
+ 'from data object of:',
+ { a: ['hi', 5] }
+ );
+ });
+ });
+
+ describe('replaceTemplateFieldFromQuery', () => {
+ test('given an empty query string this returns an empty query string', () => {
+ const replacement = replaceTemplateFieldFromQuery('', mockEcsDataClone[0]);
+ expect(replacement).toEqual('');
+ });
+
+ test('given a query string with spaces this returns an empty query string', () => {
+ const replacement = replaceTemplateFieldFromQuery(' ', mockEcsDataClone[0]);
+ expect(replacement).toEqual('');
+ });
+
+ test('it should replace a query with a template value such as apache from a mock template', () => {
+ const replacement = replaceTemplateFieldFromQuery(
+ 'host.name: placeholdertext',
+ mockEcsDataClone[0]
+ );
+ expect(replacement).toEqual('host.name: apache');
+ });
+
+ test('it should replace a template field with an ECS value that is not an array', () => {
+ mockEcsDataClone[0].host!.name = ('apache' as unknown) as string[]; // very unsafe cast for this test case
+ const replacement = replaceTemplateFieldFromQuery('host.name: *', mockEcsDataClone[0]);
+ expect(replacement).toEqual('host.name: *');
+ });
+
+ test('it should NOT replace a query with a template value that is not part of the template fields array', () => {
+ const replacement = replaceTemplateFieldFromQuery(
+ 'user.id: placeholdertext',
+ mockEcsDataClone[0]
+ );
+ expect(replacement).toEqual('user.id: placeholdertext');
+ });
+ });
+
+ describe('replaceTemplateFieldFromMatchFilters', () => {
+ test('given an empty query filter this will return an empty filter', () => {
+ const replacement = replaceTemplateFieldFromMatchFilters([], mockEcsDataClone[0]);
+ expect(replacement).toEqual([]);
+ });
+
+ test('given a query filter this will return that filter with the placeholder replaced', () => {
+ const filters: Filter[] = [
+ {
+ meta: {
+ type: 'phrase',
+ key: 'host.name',
+ alias: 'alias',
+ disabled: false,
+ negate: false,
+ params: { query: 'Braden' },
+ },
+ query: { match_phrase: { 'host.name': 'Braden' } },
+ },
+ ];
+ const replacement = replaceTemplateFieldFromMatchFilters(filters, mockEcsDataClone[0]);
+ const expected: Filter[] = [
+ {
+ meta: {
+ type: 'phrase',
+ key: 'host.name',
+ alias: 'alias',
+ disabled: false,
+ negate: false,
+ params: { query: 'apache' },
+ },
+ query: { match_phrase: { 'host.name': 'apache' } },
+ },
+ ];
+ expect(replacement).toEqual(expected);
+ });
+
+ test('given a query filter with a value not in the templateFields, this will NOT replace the placeholder value', () => {
+ const filters: Filter[] = [
+ {
+ meta: {
+ type: 'phrase',
+ key: 'user.id',
+ alias: 'alias',
+ disabled: false,
+ negate: false,
+ params: { query: 'Evan' },
+ },
+ query: { match_phrase: { 'user.id': 'Evan' } },
+ },
+ ];
+ const replacement = replaceTemplateFieldFromMatchFilters(filters, mockEcsDataClone[0]);
+ const expected: Filter[] = [
+ {
+ meta: {
+ type: 'phrase',
+ key: 'user.id',
+ alias: 'alias',
+ disabled: false,
+ negate: false,
+ params: { query: 'Evan' },
+ },
+ query: { match_phrase: { 'user.id': 'Evan' } },
+ },
+ ];
+ expect(replacement).toEqual(expected);
+ });
+ });
+
+ describe('reformatDataProviderWithNewValue', () => {
+ test('it should replace a query with a template value such as apache from a mock data provider', () => {
+ const mockDataProvider: DataProvider = mockDataProviders[0];
+ mockDataProvider.queryMatch.field = 'host.name';
+ mockDataProvider.id = 'Braden';
+ mockDataProvider.name = 'Braden';
+ mockDataProvider.queryMatch.value = 'Braden';
+ const replacement = reformatDataProviderWithNewValue(mockDataProvider, mockEcsDataClone[0]);
+ expect(replacement).toEqual({
+ id: 'apache',
+ name: 'apache',
+ enabled: true,
+ excluded: false,
+ kqlQuery: '',
+ queryMatch: {
+ field: 'host.name',
+ value: 'apache',
+ operator: ':',
+ displayField: undefined,
+ displayValue: undefined,
+ },
+ and: [],
+ });
+ });
+
+ test('it should replace a query with a template value such as apache from a mock data provider using a string in the data provider', () => {
+ mockEcsDataClone[0].host!.name = ('apache' as unknown) as string[]; // very unsafe cast for this test case
+ const mockDataProvider: DataProvider = mockDataProviders[0];
+ mockDataProvider.queryMatch.field = 'host.name';
+ mockDataProvider.id = 'Braden';
+ mockDataProvider.name = 'Braden';
+ mockDataProvider.queryMatch.value = 'Braden';
+ const replacement = reformatDataProviderWithNewValue(mockDataProvider, mockEcsDataClone[0]);
+ expect(replacement).toEqual({
+ id: 'apache',
+ name: 'apache',
+ enabled: true,
+ excluded: false,
+ kqlQuery: '',
+ queryMatch: {
+ field: 'host.name',
+ value: 'apache',
+ operator: ':',
+ displayField: undefined,
+ displayValue: undefined,
+ },
+ and: [],
+ });
+ });
+
+ test('it should NOT replace a query with a template value that is not part of a template such as user.id', () => {
+ const mockDataProvider: DataProvider = mockDataProviders[0];
+ mockDataProvider.queryMatch.field = 'user.id';
+ mockDataProvider.id = 'my-id';
+ mockDataProvider.name = 'Rebecca';
+ mockDataProvider.queryMatch.value = 'Rebecca';
+ const replacement = reformatDataProviderWithNewValue(mockDataProvider, mockEcsDataClone[0]);
+ expect(replacement).toEqual({
+ id: 'my-id',
+ name: 'Rebecca',
+ enabled: true,
+ excluded: false,
+ kqlQuery: '',
+ queryMatch: {
+ field: 'user.id',
+ value: 'Rebecca',
+ operator: ':',
+ displayField: undefined,
+ displayValue: undefined,
+ },
+ and: [],
+ });
+ });
+ });
+});
diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/signals/helpers.ts b/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/signals/helpers.ts
index 715d98ed33694..e8c9c2e3cf6c9 100644
--- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/signals/helpers.ts
+++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/signals/helpers.ts
@@ -17,6 +17,11 @@ interface FindValueToChangeInQuery {
valueToChange: string;
}
+/**
+ * Fields that will be replaced with the template strings from a a saved timeline template.
+ * This is used for the signals detection engine feature when you save a timeline template
+ * and are the fields you can replace when creating a template.
+ */
const templateFields = [
'host.name',
'host.hostname',
@@ -32,6 +37,36 @@ const templateFields = [
'process.name',
];
+/**
+ * This will return an unknown as a string array if it exists from an unknown data type and a string
+ * that represents the path within the data object the same as lodash's "get". If the value is non-existent
+ * we will return an empty array. If it is a non string value then this will log a trace to the console
+ * that it encountered an error and return an empty array.
+ * @param field string of the field to access
+ * @param data The unknown data that is typically a ECS value to get the value
+ * @param localConsole The local console which can be sent in to make this pure (for tests) or use the default console
+ */
+export const getStringArray = (field: string, data: unknown, localConsole = console): string[] => {
+ const value: unknown | undefined = get(field, data);
+ if (value == null) {
+ return [];
+ } else if (typeof value === 'string') {
+ return [value];
+ } else if (Array.isArray(value) && value.every(element => typeof element === 'string')) {
+ return value;
+ } else {
+ localConsole.trace(
+ 'Data type that is not a string or string array detected:',
+ value,
+ 'when trying to access field:',
+ field,
+ 'from data object of:',
+ data
+ );
+ return [];
+ }
+};
+
export const findValueToChangeInQuery = (
keuryNode: KueryNode,
valueToChange: FindValueToChangeInQuery[] = []
@@ -66,31 +101,33 @@ export const findValueToChangeInQuery = (
);
};
-export const replaceTemplateFieldFromQuery = (query: string, ecsData: Ecs) => {
+export const replaceTemplateFieldFromQuery = (query: string, ecsData: Ecs): string => {
if (query.trim() !== '') {
const valueToChange = findValueToChangeInQuery(esKuery.fromKueryExpression(query));
return valueToChange.reduce((newQuery, vtc) => {
- const newValue = get(vtc.field, ecsData);
- if (newValue != null) {
- return newQuery.replace(vtc.valueToChange, newValue);
+ const newValue = getStringArray(vtc.field, ecsData);
+ if (newValue.length) {
+ return newQuery.replace(vtc.valueToChange, newValue[0]);
+ } else {
+ return newQuery;
}
- return newQuery;
}, query);
+ } else {
+ return '';
}
- return '';
};
-export const replaceTemplateFieldFromMatchFilters = (filters: Filter[], ecsData: Ecs) =>
+export const replaceTemplateFieldFromMatchFilters = (filters: Filter[], ecsData: Ecs): Filter[] =>
filters.map(filter => {
if (
filter.meta.type === 'phrase' &&
filter.meta.key != null &&
templateFields.includes(filter.meta.key)
) {
- const newValue = get(filter.meta.key, ecsData);
- if (newValue != null) {
- filter.meta.params = { query: newValue };
- filter.query = { match_phrase: { [filter.meta.key]: newValue } };
+ const newValue = getStringArray(filter.meta.key, ecsData);
+ if (newValue.length) {
+ filter.meta.params = { query: newValue[0] };
+ filter.query = { match_phrase: { [filter.meta.key]: newValue[0] } };
}
}
return filter;
@@ -101,11 +138,11 @@ export const reformatDataProviderWithNewValue = {
if (templateFields.includes(dataProvider.queryMatch.field)) {
- const newValue = get(dataProvider.queryMatch.field, ecsData);
- if (newValue != null) {
- dataProvider.id = dataProvider.id.replace(dataProvider.name, newValue);
- dataProvider.name = newValue;
- dataProvider.queryMatch.value = newValue;
+ const newValue = getStringArray(dataProvider.queryMatch.field, ecsData);
+ if (newValue.length) {
+ dataProvider.id = dataProvider.id.replace(dataProvider.name, newValue[0]);
+ dataProvider.name = newValue[0];
+ dataProvider.queryMatch.value = newValue[0];
dataProvider.queryMatch.displayField = undefined;
dataProvider.queryMatch.displayValue = undefined;
}
@@ -116,8 +153,8 @@ export const reformatDataProviderWithNewValue =
- dataProviders.map((dataProvider: DataProvider) => {
+): DataProvider[] =>
+ dataProviders.map(dataProvider => {
const newDataProvider = reformatDataProviderWithNewValue(dataProvider, ecsData);
if (newDataProvider.and != null && !isEmpty(newDataProvider.and)) {
newDataProvider.and = newDataProvider.and.map(andDataProvider =>
diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all/__mocks__/mock.ts b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all/__mocks__/mock.ts
index e2287e5eeeb3f..5627d33818500 100644
--- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all/__mocks__/mock.ts
+++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all/__mocks__/mock.ts
@@ -4,7 +4,40 @@
* you may not use this file except in compliance with the Elastic License.
*/
+import { esFilters } from '../../../../../../../../../../src/plugins/data/public';
import { Rule, RuleError } from '../../../../../containers/detection_engine/rules';
+import { AboutStepRule, DefineStepRule, ScheduleStepRule } from '../../types';
+import { FieldValueQueryBar } from '../../components/query_bar';
+
+export const mockQueryBar: FieldValueQueryBar = {
+ query: {
+ query: 'test query',
+ language: 'kuery',
+ },
+ filters: [
+ {
+ $state: {
+ store: esFilters.FilterStateStore.GLOBAL_STATE,
+ },
+ meta: {
+ alias: null,
+ disabled: false,
+ key: 'event.category',
+ negate: false,
+ params: {
+ query: 'file',
+ },
+ type: 'phrase',
+ },
+ query: {
+ match_phrase: {
+ 'event.category': 'file',
+ },
+ },
+ },
+ ],
+ saved_id: 'test123',
+};
export const mockRule = (id: string): Rule => ({
created_at: '2020-01-10T21:11:45.839Z',
@@ -37,9 +70,129 @@ export const mockRule = (id: string): Rule => ({
to: 'now',
type: 'saved_query',
threat: [],
+ note: '# this is some markdown documentation',
version: 1,
});
+export const mockRuleWithEverything = (id: string): Rule => ({
+ created_at: '2020-01-10T21:11:45.839Z',
+ updated_at: '2020-01-10T21:11:45.839Z',
+ created_by: 'elastic',
+ description: '24/7',
+ enabled: true,
+ false_positives: ['test'],
+ filters: [
+ {
+ $state: {
+ store: esFilters.FilterStateStore.GLOBAL_STATE,
+ },
+ meta: {
+ alias: null,
+ disabled: false,
+ key: 'event.category',
+ negate: false,
+ params: {
+ query: 'file',
+ },
+ type: 'phrase',
+ },
+ query: {
+ match_phrase: {
+ 'event.category': 'file',
+ },
+ },
+ },
+ ],
+ from: 'now-300s',
+ id,
+ immutable: false,
+ index: ['auditbeat-*'],
+ interval: '5m',
+ rule_id: 'b5ba41ab-aaf3-4f43-971b-bdf9434ce0ea',
+ language: 'kuery',
+ output_index: '.siem-signals-default',
+ max_signals: 100,
+ risk_score: 21,
+ name: 'Query with rule-id',
+ query: 'user.name: root or user.name: admin',
+ references: ['www.test.co'],
+ saved_id: 'test123',
+ timeline_id: '86aa74d0-2136-11ea-9864-ebc8cc1cb8c2',
+ timeline_title: 'Titled timeline',
+ meta: { from: '0m' },
+ severity: 'low',
+ updated_by: 'elastic',
+ tags: ['tag1', 'tag2'],
+ to: 'now',
+ type: 'saved_query',
+ threat: [
+ {
+ framework: 'mockFramework',
+ tactic: {
+ id: '1234',
+ name: 'tactic1',
+ reference: 'reference1',
+ },
+ technique: [
+ {
+ id: '456',
+ name: 'technique1',
+ reference: 'technique reference',
+ },
+ ],
+ },
+ ],
+ note: '# this is some markdown documentation',
+ version: 1,
+});
+
+export const mockAboutStepRule = (isNew = false): AboutStepRule => ({
+ isNew,
+ name: 'Query with rule-id',
+ description: '24/7',
+ severity: 'low',
+ riskScore: 21,
+ references: ['www.test.co'],
+ falsePositives: ['test'],
+ tags: ['tag1', 'tag2'],
+ timeline: {
+ id: '86aa74d0-2136-11ea-9864-ebc8cc1cb8c2',
+ title: 'Titled timeline',
+ },
+ threat: [
+ {
+ framework: 'mockFramework',
+ tactic: {
+ id: '1234',
+ name: 'tactic1',
+ reference: 'reference1',
+ },
+ technique: [
+ {
+ id: '456',
+ name: 'technique1',
+ reference: 'technique reference',
+ },
+ ],
+ },
+ ],
+ note: '# this is some markdown documentation',
+});
+
+export const mockDefineStepRule = (isNew = false): DefineStepRule => ({
+ isNew,
+ index: ['filebeat-'],
+ queryBar: mockQueryBar,
+});
+
+export const mockScheduleStepRule = (isNew = false, enabled = false): ScheduleStepRule => ({
+ isNew,
+ enabled,
+ interval: '5m',
+ from: '6m',
+ to: 'now',
+});
+
export const mockRuleError = (id: string): RuleError => ({
rule_id: id,
error: { status_code: 404, message: `id: "${id}" not found` },
diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/description_step/__snapshots__/index.test.tsx.snap b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/description_step/__snapshots__/index.test.tsx.snap
new file mode 100644
index 0000000000000..4d416e70a096c
--- /dev/null
+++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/description_step/__snapshots__/index.test.tsx.snap
@@ -0,0 +1,453 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`description_step StepRuleDescriptionComponent renders correctly against snapshot when columns is "multi" 1`] = `
+
+
+ ,
+ "title": "Severity",
+ },
+ Object {
+ "description": 21,
+ "title": "Risk score",
+ },
+ Object {
+ "description": "Titled timeline",
+ "title": "Timeline template",
+ },
+ ]
+ }
+ />
+
+
+
+
+ ,
+ "title": "Reference URLs",
+ },
+ Object {
+ "description":
+
+ ,
+ "title": "False positive examples",
+ },
+ Object {
+ "description":
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ,
+ "title": "MITRE ATT&CK™",
+ },
+ Object {
+ "description":
+
+
+ tag1
+
+
+
+
+ tag2
+
+
+ ,
+ "title": "Tags",
+ },
+ Object {
+ "description":
+
+ # this is some markdown documentation
+
+ ,
+ "title": "Investigation notes",
+ },
+ ]
+ }
+ />
+
+
+`;
+
+exports[`description_step StepRuleDescriptionComponent renders correctly against snapshot when columns is "single" 1`] = `
+
+
+ ,
+ "title": "Severity",
+ },
+ Object {
+ "description": 21,
+ "title": "Risk score",
+ },
+ Object {
+ "description": "Titled timeline",
+ "title": "Timeline template",
+ },
+ Object {
+ "description":
+
+ ,
+ "title": "Reference URLs",
+ },
+ Object {
+ "description":
+
+ ,
+ "title": "False positive examples",
+ },
+ Object {
+ "description":
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ,
+ "title": "MITRE ATT&CK™",
+ },
+ Object {
+ "description":
+
+
+ tag1
+
+
+
+
+ tag2
+
+
+ ,
+ "title": "Tags",
+ },
+ Object {
+ "description":
+
+ # this is some markdown documentation
+
+ ,
+ "title": "Investigation notes",
+ },
+ ]
+ }
+ />
+
+
+`;
+
+exports[`description_step StepRuleDescriptionComponent renders correctly against snapshot when columns is "singleSplit 1`] = `
+
+
+ ,
+ "title": "Severity",
+ },
+ Object {
+ "description": 21,
+ "title": "Risk score",
+ },
+ Object {
+ "description": "Titled timeline",
+ "title": "Timeline template",
+ },
+ Object {
+ "description":
+
+ ,
+ "title": "Reference URLs",
+ },
+ Object {
+ "description":
+
+ ,
+ "title": "False positive examples",
+ },
+ Object {
+ "description":
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ,
+ "title": "MITRE ATT&CK™",
+ },
+ Object {
+ "description":
+
+
+ tag1
+
+
+
+
+ tag2
+
+
+ ,
+ "title": "Tags",
+ },
+ Object {
+ "description":
+
+ # this is some markdown documentation
+
+ ,
+ "title": "Investigation notes",
+ },
+ ]
+ }
+ type="column"
+ />
+
+
+`;
diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/description_step/helpers.test.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/description_step/helpers.test.tsx
new file mode 100644
index 0000000000000..56c9d6da15607
--- /dev/null
+++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/description_step/helpers.test.tsx
@@ -0,0 +1,403 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import React from 'react';
+import { shallow } from 'enzyme';
+import { EuiLoadingSpinner } from '@elastic/eui';
+
+import { coreMock } from '../../../../../../../../../../src/core/public/mocks';
+import { esFilters, FilterManager } from '../../../../../../../../../../src/plugins/data/public';
+import { SeverityBadge } from '../severity_badge';
+
+import * as i18n from './translations';
+import {
+ isNotEmptyArray,
+ buildQueryBarDescription,
+ buildThreatDescription,
+ buildUnorderedListArrayDescription,
+ buildStringArrayDescription,
+ buildSeverityDescription,
+ buildUrlsDescription,
+ buildNoteDescription,
+} from './helpers';
+import { ListItems } from './types';
+
+const setupMock = coreMock.createSetup();
+const uiSettingsMock = (pinnedByDefault: boolean) => (key: string) => {
+ switch (key) {
+ case 'filters:pinnedByDefault':
+ return pinnedByDefault;
+ default:
+ throw new Error(`Unexpected uiSettings key in FilterManager mock: ${key}`);
+ }
+};
+setupMock.uiSettings.get.mockImplementation(uiSettingsMock(true));
+const mockFilterManager = new FilterManager(setupMock.uiSettings);
+
+const mockQueryBar = {
+ query: {
+ query: 'test query',
+ language: 'kuery',
+ },
+ filters: [
+ {
+ $state: {
+ store: esFilters.FilterStateStore.GLOBAL_STATE,
+ },
+ meta: {
+ alias: null,
+ disabled: false,
+ key: 'event.category',
+ negate: false,
+ params: {
+ query: 'file',
+ },
+ type: 'phrase',
+ },
+ query: {
+ match_phrase: {
+ 'event.category': 'file',
+ },
+ },
+ },
+ ],
+ saved_id: 'test123',
+};
+
+describe('helpers', () => {
+ describe('isNotEmptyArray', () => {
+ test('returns false if empty array', () => {
+ const result = isNotEmptyArray([]);
+ expect(result).toBeFalsy();
+ });
+
+ test('returns false if array of empty strings', () => {
+ const result = isNotEmptyArray(['', '']);
+ expect(result).toBeFalsy();
+ });
+
+ test('returns true if array of string with space', () => {
+ const result = isNotEmptyArray([' ']);
+ expect(result).toBeTruthy();
+ });
+
+ test('returns true if array with at least one non-empty string', () => {
+ const result = isNotEmptyArray(['', 'abc']);
+ expect(result).toBeTruthy();
+ });
+ });
+
+ describe('buildQueryBarDescription', () => {
+ test('returns empty array if no filters, query or savedId exist', () => {
+ const emptyMockQueryBar = {
+ query: {
+ query: '',
+ language: 'kuery',
+ },
+ filters: [],
+ saved_id: '',
+ };
+ const result: ListItems[] = buildQueryBarDescription({
+ field: 'queryBar',
+ filters: emptyMockQueryBar.filters,
+ filterManager: mockFilterManager,
+ query: emptyMockQueryBar.query,
+ savedId: emptyMockQueryBar.saved_id,
+ });
+ expect(result).toEqual([]);
+ });
+
+ test('returns expected array of ListItems when filters exists, but no indexPatterns passed in', () => {
+ const mockQueryBarWithFilters = {
+ ...mockQueryBar,
+ query: {
+ query: '',
+ language: 'kuery',
+ },
+ saved_id: '',
+ };
+ const result: ListItems[] = buildQueryBarDescription({
+ field: 'queryBar',
+ filters: mockQueryBarWithFilters.filters,
+ filterManager: mockFilterManager,
+ query: mockQueryBarWithFilters.query,
+ savedId: mockQueryBarWithFilters.saved_id,
+ });
+ const wrapper = shallow(result[0].description as React.ReactElement);
+
+ expect(result[0].title).toEqual(<>{i18n.FILTERS_LABEL} >);
+ expect(wrapper.find(EuiLoadingSpinner).exists()).toBeTruthy();
+ });
+
+ test('returns expected array of ListItems when filters AND indexPatterns exist', () => {
+ const mockQueryBarWithFilters = {
+ ...mockQueryBar,
+ query: {
+ query: '',
+ language: 'kuery',
+ },
+ saved_id: '',
+ };
+ const result: ListItems[] = buildQueryBarDescription({
+ field: 'queryBar',
+ filters: mockQueryBarWithFilters.filters,
+ filterManager: mockFilterManager,
+ query: mockQueryBarWithFilters.query,
+ savedId: mockQueryBarWithFilters.saved_id,
+ indexPatterns: { fields: [{ name: 'test name', type: 'test type' }], title: 'test title' },
+ });
+ const wrapper = shallow(result[0].description as React.ReactElement);
+ const filterLabelComponent = wrapper.find(esFilters.FilterLabel).at(0);
+
+ expect(result[0].title).toEqual(<>{i18n.FILTERS_LABEL} >);
+ expect(filterLabelComponent.prop('valueLabel')).toEqual('file');
+ expect(filterLabelComponent.prop('filter')).toEqual(mockQueryBar.filters[0]);
+ });
+
+ test('returns expected array of ListItems when "query.query" exists', () => {
+ const mockQueryBarWithQuery = {
+ ...mockQueryBar,
+ filters: [],
+ saved_id: '',
+ };
+ const result: ListItems[] = buildQueryBarDescription({
+ field: 'queryBar',
+ filters: mockQueryBarWithQuery.filters,
+ filterManager: mockFilterManager,
+ query: mockQueryBarWithQuery.query,
+ savedId: mockQueryBarWithQuery.saved_id,
+ });
+ expect(result[0].title).toEqual(<>{i18n.QUERY_LABEL} >);
+ expect(result[0].description).toEqual(<>{mockQueryBarWithQuery.query.query} >);
+ });
+
+ test('returns expected array of ListItems when "savedId" exists', () => {
+ const mockQueryBarWithSavedId = {
+ ...mockQueryBar,
+ query: {
+ query: '',
+ language: 'kuery',
+ },
+ filters: [],
+ };
+ const result: ListItems[] = buildQueryBarDescription({
+ field: 'queryBar',
+ filters: mockQueryBarWithSavedId.filters,
+ filterManager: mockFilterManager,
+ query: mockQueryBarWithSavedId.query,
+ savedId: mockQueryBarWithSavedId.saved_id,
+ });
+ expect(result[0].title).toEqual(<>{i18n.SAVED_ID_LABEL} >);
+ expect(result[0].description).toEqual(<>{mockQueryBarWithSavedId.saved_id} >);
+ });
+ });
+
+ describe('buildThreatDescription', () => {
+ test('returns empty array if no threats', () => {
+ const result: ListItems[] = buildThreatDescription({ label: 'Mitre Attack', threat: [] });
+ expect(result).toHaveLength(0);
+ });
+
+ test('returns empty tactic link if no corresponding tactic id found', () => {
+ const result: ListItems[] = buildThreatDescription({
+ label: 'Mitre Attack',
+ threat: [
+ {
+ framework: 'MITRE ATTACK',
+ technique: [{ reference: 'https://test.com', name: 'Audio Capture', id: 'T1123' }],
+ tactic: { reference: 'https://test.com', name: 'Collection', id: 'TA000999' },
+ },
+ ],
+ });
+ const wrapper = shallow(result[0].description as React.ReactElement);
+ expect(result[0].title).toEqual('Mitre Attack');
+ expect(wrapper.find('[data-test-subj="threatTacticLink"]').text()).toEqual('');
+ expect(wrapper.find('[data-test-subj="threatTechniqueLink"]').text()).toEqual(
+ 'Audio Capture (T1123)'
+ );
+ });
+
+ test('returns empty technique link if no corresponding technique id found', () => {
+ const result: ListItems[] = buildThreatDescription({
+ label: 'Mitre Attack',
+ threat: [
+ {
+ framework: 'MITRE ATTACK',
+ technique: [{ reference: 'https://test.com', name: 'Audio Capture', id: 'T1123456' }],
+ tactic: { reference: 'https://test.com', name: 'Collection', id: 'TA0009' },
+ },
+ ],
+ });
+ const wrapper = shallow(result[0].description as React.ReactElement);
+ expect(result[0].title).toEqual('Mitre Attack');
+ expect(wrapper.find('[data-test-subj="threatTacticLink"]').text()).toEqual(
+ 'Collection (TA0009)'
+ );
+ expect(wrapper.find('[data-test-subj="threatTechniqueLink"]').text()).toEqual('');
+ });
+
+ test('returns with corresponding tactic and technique link text', () => {
+ const result: ListItems[] = buildThreatDescription({
+ label: 'Mitre Attack',
+ threat: [
+ {
+ framework: 'MITRE ATTACK',
+ technique: [{ reference: 'https://test.com', name: 'Audio Capture', id: 'T1123' }],
+ tactic: { reference: 'https://test.com', name: 'Collection', id: 'TA0009' },
+ },
+ ],
+ });
+ const wrapper = shallow(result[0].description as React.ReactElement);
+ expect(result[0].title).toEqual('Mitre Attack');
+ expect(wrapper.find('[data-test-subj="threatTacticLink"]').text()).toEqual(
+ 'Collection (TA0009)'
+ );
+ expect(wrapper.find('[data-test-subj="threatTechniqueLink"]').text()).toEqual(
+ 'Audio Capture (T1123)'
+ );
+ });
+
+ test('returns corresponding number of tactic and technique links', () => {
+ const result: ListItems[] = buildThreatDescription({
+ label: 'Mitre Attack',
+ threat: [
+ {
+ framework: 'MITRE ATTACK',
+ technique: [
+ { reference: 'https://test.com', name: 'Audio Capture', id: 'T1123' },
+ { reference: 'https://test.com', name: 'Clipboard Data', id: 'T1115' },
+ ],
+ tactic: { reference: 'https://test.com', name: 'Collection', id: 'TA0009' },
+ },
+ {
+ framework: 'MITRE ATTACK',
+ technique: [
+ { reference: 'https://test.com', name: 'Automated Collection', id: 'T1119' },
+ ],
+ tactic: { reference: 'https://test.com', name: 'Discovery', id: 'TA0007' },
+ },
+ ],
+ });
+ const wrapper = shallow(result[0].description as React.ReactElement);
+
+ expect(wrapper.find('[data-test-subj="threatTacticLink"]')).toHaveLength(2);
+ expect(wrapper.find('[data-test-subj="threatTechniqueLink"]')).toHaveLength(3);
+ });
+ });
+
+ describe('buildUnorderedListArrayDescription', () => {
+ test('returns empty array if "values" is empty array', () => {
+ const result: ListItems[] = buildUnorderedListArrayDescription(
+ 'Test label',
+ 'falsePositives',
+ []
+ );
+ expect(result).toHaveLength(0);
+ });
+
+ test('returns ListItem with corresponding number of valid values items', () => {
+ const result: ListItems[] = buildUnorderedListArrayDescription(
+ 'Test label',
+ 'falsePositives',
+ ['', 'falsePositive1', 'falsePositive2']
+ );
+ const wrapper = shallow(result[0].description as React.ReactElement);
+
+ expect(result[0].title).toEqual('Test label');
+ expect(wrapper.find('[data-test-subj="unorderedListArrayDescriptionItem"]')).toHaveLength(2);
+ });
+ });
+
+ describe('buildStringArrayDescription', () => {
+ test('returns empty array if "values" is empty array', () => {
+ const result: ListItems[] = buildStringArrayDescription('Test label', 'tags', []);
+ expect(result).toHaveLength(0);
+ });
+
+ test('returns ListItem with corresponding number of valid values items', () => {
+ const result: ListItems[] = buildStringArrayDescription('Test label', 'tags', [
+ '',
+ 'tag1',
+ 'tag2',
+ ]);
+ const wrapper = shallow(result[0].description as React.ReactElement);
+
+ expect(result[0].title).toEqual('Test label');
+ expect(wrapper.find('[data-test-subj="stringArrayDescriptionBadgeItem"]')).toHaveLength(2);
+ expect(
+ wrapper
+ .find('[data-test-subj="stringArrayDescriptionBadgeItem"]')
+ .first()
+ .text()
+ ).toEqual('tag1');
+ expect(
+ wrapper
+ .find('[data-test-subj="stringArrayDescriptionBadgeItem"]')
+ .at(1)
+ .text()
+ ).toEqual('tag2');
+ });
+ });
+
+ describe('buildSeverityDescription', () => {
+ test('returns ListItem with passed in label and SeverityBadge component', () => {
+ const result: ListItems[] = buildSeverityDescription('Test label', 'Test description value');
+
+ expect(result[0].title).toEqual('Test label');
+ expect(result[0].description).toEqual( );
+ });
+ });
+
+ describe('buildUrlsDescription', () => {
+ test('returns empty array if "values" is empty array', () => {
+ const result: ListItems[] = buildUrlsDescription('Test label', []);
+ expect(result).toHaveLength(0);
+ });
+
+ test('returns ListItem with corresponding number of valid values items', () => {
+ const result: ListItems[] = buildUrlsDescription('Test label', [
+ 'www.test.com',
+ 'www.test2.com',
+ ]);
+ const wrapper = shallow(result[0].description as React.ReactElement);
+
+ expect(result[0].title).toEqual('Test label');
+ expect(wrapper.find('[data-test-subj="urlsDescriptionReferenceLinkItem"]')).toHaveLength(2);
+ expect(
+ wrapper
+ .find('[data-test-subj="urlsDescriptionReferenceLinkItem"]')
+ .first()
+ .text()
+ ).toEqual('www.test.com');
+ expect(
+ wrapper
+ .find('[data-test-subj="urlsDescriptionReferenceLinkItem"]')
+ .at(1)
+ .text()
+ ).toEqual('www.test2.com');
+ });
+ });
+
+ describe('buildNoteDescription', () => {
+ test('returns ListItem with passed in label and note content', () => {
+ const noteSample =
+ 'Cras mattism. [Pellentesque](https://elastic.co). ### Malesuada adipiscing tristique';
+ const result: ListItems[] = buildNoteDescription('Test label', noteSample);
+ const wrapper = shallow(result[0].description as React.ReactElement);
+ const noteElement = wrapper.find('[data-test-subj="noteDescriptionItem"]').at(0);
+
+ expect(result[0].title).toEqual('Test label');
+ expect(noteElement.exists()).toBeTruthy();
+ expect(noteElement.text()).toEqual(noteSample);
+ });
+
+ test('returns empty array if passed in note is empty string', () => {
+ const result: ListItems[] = buildNoteDescription('Test label', '');
+
+ expect(result).toHaveLength(0);
+ });
+ });
+});
diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/description_step/helpers.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/description_step/helpers.tsx
index df767fbd4ff8c..bc454ecb1134a 100644
--- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/description_step/helpers.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/description_step/helpers.tsx
@@ -9,9 +9,10 @@ import {
EuiLoadingSpinner,
EuiFlexGroup,
EuiFlexItem,
- EuiLink,
EuiButtonEmpty,
EuiSpacer,
+ EuiLink,
+ EuiText,
} from '@elastic/eui';
import { isEmpty } from 'lodash/fp';
@@ -27,8 +28,12 @@ import { BuildQueryBarDescription, BuildThreatDescription, ListItems } from './t
import { SeverityBadge } from '../severity_badge';
import ListTreeIcon from './assets/list_tree_icon.svg';
-const isNotEmptyArray = (values: string[]) =>
- !isEmpty(values) && values.filter(val => !isEmpty(val)).length > 0;
+const NoteDescriptionContainer = styled(EuiFlexItem)`
+ height: 105px;
+ overflow-y: hidden;
+`;
+
+export const isNotEmptyArray = (values: string[]) => !isEmpty(values.join(''));
const EuiBadgeWrap = styled(EuiBadge)`
.euiBadge__text {
@@ -106,13 +111,6 @@ const TechniqueLinkItem = styled(EuiButtonEmpty)`
}
`;
-const ReferenceLinkItem = styled(EuiButtonEmpty)`
- .euiIcon {
- width: 12px;
- height: 12px;
- }
-`;
-
export const buildThreatDescription = ({ label, threat }: BuildThreatDescription): ListItems[] => {
if (threat.length > 0) {
return [
@@ -124,7 +122,11 @@ export const buildThreatDescription = ({ label, threat }: BuildThreatDescription
const tactic = tacticsOptions.find(t => t.id === singleThreat.tactic.id);
return (
-
+
{tactic != null ? tactic.text : ''}
@@ -133,6 +135,7 @@ export const buildThreatDescription = ({ label, threat }: BuildThreatDescription
return (
- {values.map((val: string) =>
- isEmpty(val) ? null : {val}
- )}
-
+
+
+ {values.map(val =>
+ isEmpty(val) ? null : (
+
+ {val}
+
+ )
+ )}
+
+
),
},
];
@@ -193,7 +202,9 @@ export const buildStringArrayDescription = (
{values.map((val: string) =>
isEmpty(val) ? null : (
- {val}
+
+ {val}
+
)
)}
@@ -218,21 +229,37 @@ export const buildUrlsDescription = (label: string, values: string[]): ListItems
{
title: label,
description: (
-
- {values.map((val: string) => (
-
-
- {val}
-
-
- ))}
-
+
+
+ {values
+ .filter(v => !isEmpty(v))
+ .map((val, index) => (
+
+
+ {val}
+
+
+ ))}
+
+
+ ),
+ },
+ ];
+ }
+ return [];
+};
+
+export const buildNoteDescription = (label: string, note: string): ListItems[] => {
+ if (note.trim() !== '') {
+ return [
+ {
+ title: label,
+ description: (
+
+
+ {note}
+
+
),
},
];
diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/description_step/index.test.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/description_step/index.test.tsx
index 84c662dd00199..2c6f47fd27c44 100644
--- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/description_step/index.test.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/description_step/index.test.tsx
@@ -3,12 +3,88 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
+import React from 'react';
+import { shallow } from 'enzyme';
-import { addFilterStateIfNotThere } from './';
+import {
+ StepRuleDescriptionComponent,
+ addFilterStateIfNotThere,
+ buildListItems,
+ getDescriptionItem,
+} from './';
-import { esFilters, Filter } from '../../../../../../../../../../src/plugins/data/public';
+import {
+ esFilters,
+ Filter,
+ FilterManager,
+} from '../../../../../../../../../../src/plugins/data/public';
+import { mockAboutStepRule } from '../../all/__mocks__/mock';
+import { coreMock } from '../../../../../../../../../../src/core/public/mocks';
+import { DEFAULT_TIMELINE_TITLE } from '../../../../../components/timeline/translations';
+import * as i18n from './translations';
+
+import { schema } from '../step_about_rule/schema';
+import { ListItems } from './types';
+import { AboutStepRule } from '../../types';
describe('description_step', () => {
+ const setupMock = coreMock.createSetup();
+ const uiSettingsMock = (pinnedByDefault: boolean) => (key: string) => {
+ switch (key) {
+ case 'filters:pinnedByDefault':
+ return pinnedByDefault;
+ default:
+ throw new Error(`Unexpected uiSettings key in FilterManager mock: ${key}`);
+ }
+ };
+ let mockFilterManager: FilterManager;
+ let mockAboutStep: AboutStepRule;
+
+ beforeEach(() => {
+ // jest carries state between mocked implementations when using
+ // spyOn. So now we're doing all three of these.
+ // https://github.com/facebook/jest/issues/7136#issuecomment-565976599
+ jest.resetAllMocks();
+ jest.restoreAllMocks();
+ jest.clearAllMocks();
+
+ setupMock.uiSettings.get.mockImplementation(uiSettingsMock(true));
+ mockFilterManager = new FilterManager(setupMock.uiSettings);
+ mockAboutStep = mockAboutStepRule();
+ });
+
+ describe('StepRuleDescriptionComponent', () => {
+ test('renders correctly against snapshot when columns is "multi"', () => {
+ const wrapper = shallow(
+
+ );
+ expect(wrapper).toMatchSnapshot();
+ expect(wrapper.find('[data-test-subj="listItemColumnStepRuleDescription"]')).toHaveLength(2);
+ });
+
+ test('renders correctly against snapshot when columns is "single"', () => {
+ const wrapper = shallow(
+
+ );
+ expect(wrapper).toMatchSnapshot();
+ expect(wrapper.find('[data-test-subj="listItemColumnStepRuleDescription"]')).toHaveLength(1);
+ });
+
+ test('renders correctly against snapshot when columns is "singleSplit', () => {
+ const wrapper = shallow(
+
+ );
+ expect(wrapper).toMatchSnapshot();
+ expect(wrapper.find('[data-test-subj="listItemColumnStepRuleDescription"]')).toHaveLength(1);
+ expect(
+ wrapper
+ .find('[data-test-subj="singleSplitStepRuleDescriptionList"]')
+ .at(0)
+ .prop('type')
+ ).toEqual('column');
+ });
+ });
+
describe('addFilterStateIfNotThere', () => {
test('it does not change the state if it is global', () => {
const filters: Filter[] = [
@@ -182,4 +258,221 @@ describe('description_step', () => {
expect(output).toEqual(expected);
});
});
+
+ describe('buildListItems', () => {
+ test('returns expected ListItems array when given valid inputs', () => {
+ const result: ListItems[] = buildListItems(mockAboutStep, schema, mockFilterManager);
+
+ expect(result.length).toEqual(10);
+ });
+ });
+
+ describe('getDescriptionItem', () => {
+ test('returns ListItem with all values enumerated when value[field] is an array', () => {
+ const result: ListItems[] = getDescriptionItem(
+ 'tags',
+ 'Tags label',
+ mockAboutStep,
+ mockFilterManager
+ );
+
+ expect(result[0].title).toEqual('Tags label');
+ expect(typeof result[0].description).toEqual('object');
+ });
+
+ test('returns ListItem with description of value[field] when value[field] is a string', () => {
+ const result: ListItems[] = getDescriptionItem(
+ 'description',
+ 'Description label',
+ mockAboutStep,
+ mockFilterManager
+ );
+
+ expect(result[0].title).toEqual('Description label');
+ expect(result[0].description).toEqual('24/7');
+ });
+
+ test('returns empty array when "value" is a non-existant property in "field"', () => {
+ const result: ListItems[] = getDescriptionItem(
+ 'jibberjabber',
+ 'JibberJabber label',
+ mockAboutStep,
+ mockFilterManager
+ );
+
+ expect(result.length).toEqual(0);
+ });
+
+ describe('queryBar', () => {
+ test('returns array of ListItems when queryBar exist', () => {
+ const mockQueryBar = {
+ isNew: false,
+ queryBar: {
+ query: {
+ query: 'user.name: root or user.name: admin',
+ language: 'kuery',
+ },
+ filters: null,
+ saved_id: null,
+ },
+ };
+ const result: ListItems[] = getDescriptionItem(
+ 'queryBar',
+ 'Query bar label',
+ mockQueryBar,
+ mockFilterManager
+ );
+
+ expect(result[0].title).toEqual(<>{i18n.QUERY_LABEL} >);
+ expect(result[0].description).toEqual(<>{mockQueryBar.queryBar.query.query} >);
+ });
+ });
+
+ describe('threat', () => {
+ test('returns array of ListItems when threat exist', () => {
+ const result: ListItems[] = getDescriptionItem(
+ 'threat',
+ 'Threat label',
+ mockAboutStep,
+ mockFilterManager
+ );
+
+ expect(result[0].title).toEqual('Threat label');
+ expect(React.isValidElement(result[0].description)).toBeTruthy();
+ });
+
+ test('filters out threats with tactic.name of "none"', () => {
+ const mockStep = {
+ ...mockAboutStep,
+ threat: [
+ {
+ framework: 'mockFramework',
+ tactic: {
+ id: '1234',
+ name: 'none',
+ reference: 'reference1',
+ },
+ technique: [
+ {
+ id: '456',
+ name: 'technique1',
+ reference: 'technique reference',
+ },
+ ],
+ },
+ ],
+ };
+ const result: ListItems[] = getDescriptionItem(
+ 'threat',
+ 'Threat label',
+ mockStep,
+ mockFilterManager
+ );
+
+ expect(result.length).toEqual(0);
+ });
+ });
+
+ describe('references', () => {
+ test('returns array of ListItems when references exist', () => {
+ const result: ListItems[] = getDescriptionItem(
+ 'references',
+ 'Reference label',
+ mockAboutStep,
+ mockFilterManager
+ );
+
+ expect(result[0].title).toEqual('Reference label');
+ expect(React.isValidElement(result[0].description)).toBeTruthy();
+ });
+ });
+
+ describe('falsePositives', () => {
+ test('returns array of ListItems when falsePositives exist', () => {
+ const result: ListItems[] = getDescriptionItem(
+ 'falsePositives',
+ 'False positives label',
+ mockAboutStep,
+ mockFilterManager
+ );
+
+ expect(result[0].title).toEqual('False positives label');
+ expect(React.isValidElement(result[0].description)).toBeTruthy();
+ });
+ });
+
+ describe('severity', () => {
+ test('returns array of ListItems when severity exist', () => {
+ const result: ListItems[] = getDescriptionItem(
+ 'severity',
+ 'Severity label',
+ mockAboutStep,
+ mockFilterManager
+ );
+
+ expect(result[0].title).toEqual('Severity label');
+ expect(React.isValidElement(result[0].description)).toBeTruthy();
+ });
+ });
+
+ describe('riskScore', () => {
+ test('returns array of ListItems when riskScore exist', () => {
+ const result: ListItems[] = getDescriptionItem(
+ 'riskScore',
+ 'Risk score label',
+ mockAboutStep,
+ mockFilterManager
+ );
+
+ expect(result[0].title).toEqual('Risk score label');
+ expect(result[0].description).toEqual(21);
+ });
+ });
+
+ describe('timeline', () => {
+ test('returns timeline title if one exists', () => {
+ const result: ListItems[] = getDescriptionItem(
+ 'timeline',
+ 'Timeline label',
+ mockAboutStep,
+ mockFilterManager
+ );
+
+ expect(result[0].title).toEqual('Timeline label');
+ expect(result[0].description).toEqual('Titled timeline');
+ });
+
+ test('returns default timeline title if none exists', () => {
+ const mockStep = {
+ ...mockAboutStep,
+ timeline: {
+ id: '12345',
+ },
+ };
+ const result: ListItems[] = getDescriptionItem(
+ 'timeline',
+ 'Timeline label',
+ mockStep,
+ mockFilterManager
+ );
+
+ expect(result[0].title).toEqual('Timeline label');
+ expect(result[0].description).toEqual(DEFAULT_TIMELINE_TITLE);
+ });
+ });
+
+ describe('note', () => {
+ test('returns default "note" description', () => {
+ const result: ListItems[] = getDescriptionItem(
+ 'note',
+ 'Investigation notes',
+ mockAboutStep,
+ mockFilterManager
+ );
+
+ expect(result[0].title).toEqual('Investigation notes');
+ expect(React.isValidElement(result[0].description)).toBeTruthy();
+ });
+ });
+ });
});
diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/description_step/index.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/description_step/index.tsx
index cb5c98bb23f07..1d58ef8014899 100644
--- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/description_step/index.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/description_step/index.tsx
@@ -7,6 +7,7 @@
import { EuiDescriptionList, EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
import { isEmpty, chunk, get, pick } from 'lodash/fp';
import React, { memo, useState } from 'react';
+import styled from 'styled-components';
import {
IIndexPattern,
@@ -28,18 +29,28 @@ import {
buildThreatDescription,
buildUnorderedListArrayDescription,
buildUrlsDescription,
+ buildNoteDescription,
} from './helpers';
+const DescriptionListContainer = styled(EuiDescriptionList)`
+ &.euiDescriptionList--column .euiDescriptionList__title {
+ width: 30%;
+ }
+ &.euiDescriptionList--column .euiDescriptionList__description {
+ width: 70%;
+ }
+`;
+
interface StepRuleDescriptionProps {
- direction?: 'row' | 'column';
+ columns?: 'multi' | 'single' | 'singleSplit';
data: unknown;
indexPatterns?: IIndexPattern;
schema: FormSchema;
}
-const StepRuleDescriptionComponent: React.FC = ({
+export const StepRuleDescriptionComponent: React.FC = ({
data,
- direction = 'row',
+ columns = 'multi',
indexPatterns,
schema,
}) => {
@@ -55,11 +66,14 @@ const StepRuleDescriptionComponent: React.FC = ({
[]
);
- if (direction === 'row') {
+ if (columns === 'multi') {
return (
{chunk(Math.ceil(listItems.length / 2), listItems).map((chunkListItems, index) => (
-
+
))}
@@ -69,8 +83,16 @@ const StepRuleDescriptionComponent: React.FC = ({
return (
-
-
+
+ {columns === 'single' ? (
+
+ ) : (
+
+ )}
);
@@ -78,7 +100,7 @@ const StepRuleDescriptionComponent: React.FC = ({
export const StepRuleDescription = memo(StepRuleDescriptionComponent);
-const buildListItems = (
+export const buildListItems = (
data: unknown,
schema: FormSchema,
filterManager: FilterManager,
@@ -108,7 +130,7 @@ export const addFilterStateIfNotThere = (filters: Filter[]): Filter[] => {
});
};
-const getDescriptionItem = (
+export const getDescriptionItem = (
field: string,
label: string,
value: unknown,
@@ -132,13 +154,6 @@ const getDescriptionItem = (
(singleThreat: IMitreEnterpriseAttack) => singleThreat.tactic.name !== 'none'
);
return buildThreatDescription({ label, threat });
- } else if (field === 'description') {
- return [
- {
- title: label,
- description: get(field, value),
- },
- ];
} else if (field === 'references') {
const urls: string[] = get(field, value);
return buildUrlsDescription(label, urls);
@@ -166,14 +181,9 @@ const getDescriptionItem = (
description: timeline.title ?? DEFAULT_TIMELINE_TITLE,
},
];
- } else if (field === 'riskScore') {
- const description: string = get(field, value);
- return [
- {
- title: label,
- description,
- },
- ];
+ } else if (field === 'note') {
+ const val: string = get(field, value);
+ return buildNoteDescription(label, val);
}
const description: string = get(field, value);
if (!isEmpty(description)) {
diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/step_about_rule/default_value.ts b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/step_about_rule/default_value.ts
index d15cce15877b4..417133f230610 100644
--- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/step_about_rule/default_value.ts
+++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/step_about_rule/default_value.ts
@@ -29,4 +29,5 @@ export const stepAboutDefaultValue: AboutStepRule = {
title: DEFAULT_TIMELINE_TITLE,
},
threat: threatDefault,
+ note: '',
};
diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/step_about_rule/index.test.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/step_about_rule/index.test.tsx
new file mode 100644
index 0000000000000..0ed479e235151
--- /dev/null
+++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/step_about_rule/index.test.tsx
@@ -0,0 +1,155 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+import React from 'react';
+import { mount, shallow } from 'enzyme';
+import { ThemeProvider } from 'styled-components';
+import euiDarkVars from '@elastic/eui/dist/eui_theme_light.json';
+
+import { StepAboutRule } from './';
+import { mockAboutStepRule } from '../../all/__mocks__/mock';
+import { StepRuleDescription } from '../description_step';
+import { stepAboutDefaultValue } from './default_value';
+
+const theme = () => ({ eui: euiDarkVars, darkMode: true });
+
+describe('StepAboutRuleComponent', () => {
+ test('it renders StepRuleDescription if isReadOnlyView is true and "name" property exists', () => {
+ const wrapper = shallow(
+
+ );
+
+ expect(wrapper.find(StepRuleDescription).exists()).toBeTruthy();
+ });
+
+ test('it prevents user from clicking continue if no "description" defined', () => {
+ const wrapper = mount(
+
+
+
+ );
+
+ const nameInput = wrapper
+ .find('input[aria-describedby="detectionEngineStepAboutRuleName"]')
+ .at(0);
+ nameInput.simulate('change', { target: { value: 'Test name text' } });
+
+ const descriptionInput = wrapper
+ .find('textarea[aria-describedby="detectionEngineStepAboutRuleDescription"]')
+ .at(0);
+ const nextButton = wrapper.find('button[data-test-subj="about-continue"]').at(0);
+ nextButton.simulate('click');
+
+ expect(
+ wrapper
+ .find('input[aria-describedby="detectionEngineStepAboutRuleName"]')
+ .at(0)
+ .props().value
+ ).toEqual('Test name text');
+ expect(descriptionInput.props().value).toEqual('');
+ expect(
+ wrapper
+ .find('EuiFormRow[data-test-subj="detectionEngineStepAboutRuleDescription"] label')
+ .at(0)
+ .hasClass('euiFormLabel-isInvalid')
+ ).toBeTruthy();
+ expect(
+ wrapper
+ .find('EuiFormRow[data-test-subj="detectionEngineStepAboutRuleDescription"] EuiTextArea')
+ .at(0)
+ .prop('isInvalid')
+ ).toBeTruthy();
+ });
+
+ test('it prevents user from clicking continue if no "name" defined', () => {
+ const wrapper = mount(
+
+
+
+ );
+
+ const descriptionInput = wrapper
+ .find('textarea[aria-describedby="detectionEngineStepAboutRuleDescription"]')
+ .at(0);
+ descriptionInput.simulate('change', { target: { value: 'Test description text' } });
+
+ const nameInput = wrapper
+ .find('input[aria-describedby="detectionEngineStepAboutRuleName"]')
+ .at(0);
+ const nextButton = wrapper.find('button[data-test-subj="about-continue"]').at(0);
+ nextButton.simulate('click');
+
+ expect(
+ wrapper
+ .find('textarea[aria-describedby="detectionEngineStepAboutRuleDescription"]')
+ .at(0)
+ .props().value
+ ).toEqual('Test description text');
+ expect(nameInput.props().value).toEqual('');
+ expect(
+ wrapper
+ .find('EuiFormRow[data-test-subj="detectionEngineStepAboutRuleName"] label')
+ .at(0)
+ .hasClass('euiFormLabel-isInvalid')
+ ).toBeTruthy();
+ expect(
+ wrapper
+ .find('EuiFormRow[data-test-subj="detectionEngineStepAboutRuleName"] EuiFieldText')
+ .at(0)
+ .prop('isInvalid')
+ ).toBeTruthy();
+ });
+
+ test('it allows user to click continue if "name" and "description" are defined', () => {
+ const wrapper = mount(
+
+
+
+ );
+
+ const descriptionInput = wrapper
+ .find('textarea[aria-describedby="detectionEngineStepAboutRuleDescription"]')
+ .at(0);
+ descriptionInput.simulate('change', { target: { value: 'Test description text' } });
+
+ const nameInput = wrapper
+ .find('input[aria-describedby="detectionEngineStepAboutRuleName"]')
+ .at(0);
+ nameInput.simulate('change', { target: { value: 'Test name text' } });
+
+ const nextButton = wrapper.find('button[data-test-subj="about-continue"]').at(0);
+ nextButton.simulate('click');
+ });
+});
diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/step_about_rule/index.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/step_about_rule/index.tsx
index 4f06d4314c1f3..bfb123f3f3204 100644
--- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/step_about_rule/index.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/step_about_rule/index.tsx
@@ -39,6 +39,7 @@ import { schema } from './schema';
import * as I18n from './translations';
import { PickTimeline } from '../pick_timeline';
import { StepContentWrapper } from '../step_content_wrapper';
+import { MarkdownEditorForm } from '../../../../../components/markdown_editor/form';
const CommonUseField = getUseField({ component: Field });
@@ -46,6 +47,12 @@ interface StepAboutRuleProps extends RuleStepProps {
defaultValues?: AboutStepRule | null;
}
+const ThreeQuartersContainer = styled.div`
+ max-width: 740px;
+`;
+
+ThreeQuartersContainer.displayName = 'ThreeQuartersContainer';
+
const TagContainer = styled.div`
margin-top: 16px;
`;
@@ -75,7 +82,7 @@ const AdvancedSettingsAccordionButton = (
const StepAboutRuleComponent: FC = ({
addPadding = false,
defaultValues,
- descriptionDirection = 'row',
+ descriptionColumns = 'singleSplit',
isReadOnlyView,
isUpdateView = false,
isLoading,
@@ -120,68 +127,74 @@ const StepAboutRuleComponent: FC = ({
}, [form]);
return isReadOnlyView && myStepData.name != null ? (
-
-
+
+
) : (
<>
{ruleError}
- {tabs}
- {ruleDetailTab === RuleDetailTabs.signals && (
- <>
-
+
+
+
+
+
+
+
{defineRuleData != null && (
= ({
)}
-
-
-
- {aboutRuleData != null && (
-
- )}
-
-
-
+
{scheduleRuleData != null && (
= ({
-
+
+
+
+ {tabs}
+
+ {ruleDetailTab === RuleDetailTabs.signals && (
+ <>
{
+ describe('getStepsData', () => {
+ test('returns object with about, define, and schedule step properties formatted', () => {
+ const {
+ defineRuleData,
+ modifiedAboutRuleDetailsData,
+ aboutRuleData,
+ scheduleRuleData,
+ }: GetStepsData = getStepsData({
+ rule: mockRuleWithEverything('test-id'),
+ });
+ const defineRuleStepData = {
+ isNew: false,
+ index: ['auditbeat-*'],
+ queryBar: {
+ query: {
+ query: 'user.name: root or user.name: admin',
+ language: 'kuery',
+ },
+ filters: [
+ {
+ $state: {
+ store: esFilters.FilterStateStore.GLOBAL_STATE,
+ },
+ meta: {
+ alias: null,
+ disabled: false,
+ key: 'event.category',
+ negate: false,
+ params: {
+ query: 'file',
+ },
+ type: 'phrase',
+ },
+ query: {
+ match_phrase: {
+ 'event.category': 'file',
+ },
+ },
+ },
+ ],
+ saved_id: 'test123',
+ },
+ };
+ const aboutRuleStepData = {
+ description: '24/7',
+ falsePositives: ['test'],
+ isNew: false,
+ name: 'Query with rule-id',
+ note: '# this is some markdown documentation',
+ references: ['www.test.co'],
+ riskScore: 21,
+ severity: 'low',
+ tags: ['tag1', 'tag2'],
+ threat: [
+ {
+ framework: 'mockFramework',
+ tactic: {
+ id: '1234',
+ name: 'tactic1',
+ reference: 'reference1',
+ },
+ technique: [
+ {
+ id: '456',
+ name: 'technique1',
+ reference: 'technique reference',
+ },
+ ],
+ },
+ ],
+ timeline: {
+ id: '86aa74d0-2136-11ea-9864-ebc8cc1cb8c2',
+ title: 'Titled timeline',
+ },
+ };
+ const scheduleRuleStepData = { enabled: true, from: '0s', interval: '5m', isNew: false };
+ const aboutRuleDataDetailsData = {
+ note: '# this is some markdown documentation',
+ description: '24/7',
+ };
+
+ expect(defineRuleData).toEqual(defineRuleStepData);
+ expect(aboutRuleData).toEqual(aboutRuleStepData);
+ expect(scheduleRuleData).toEqual(scheduleRuleStepData);
+ expect(modifiedAboutRuleDetailsData).toEqual(aboutRuleDataDetailsData);
+ });
+ });
+
+ describe('getAboutStepsData', () => {
+ test('returns timeline id and title of null if they do not exist on rule', () => {
+ const mockedRule = mockRuleWithEverything('test-id');
+ delete mockedRule.timeline_id;
+ delete mockedRule.timeline_title;
+ const result: AboutStepRule = getAboutStepsData(mockedRule, false);
+
+ expect(result.timeline.id).toBeNull();
+ expect(result.timeline.title).toBeNull();
+ });
+
+ test('returns name, description, and note as empty string if detailsView is true', () => {
+ const result: AboutStepRule = getAboutStepsData(mockRuleWithEverything('test-id'), true);
+
+ expect(result.name).toEqual('');
+ expect(result.description).toEqual('');
+ expect(result.note).toEqual('');
+ });
+
+ test('returns note as empty string if property does not exist on rule', () => {
+ const mockedRule = mockRuleWithEverything('test-id');
+ delete mockedRule.note;
+ const result: AboutStepRule = getAboutStepsData(mockedRule, false);
+
+ expect(result.note).toEqual('');
+ });
+ });
+
+ describe('determineDetailsValue', () => {
+ test('returns name, description, and note as empty string if detailsView is true', () => {
+ const result: Pick = determineDetailsValue(
+ mockRuleWithEverything('test-id'),
+ true
+ );
+ const expected = { name: '', description: '', note: '' };
+
+ expect(result).toEqual(expected);
+ });
+
+ test('returns name, description, and note values if detailsView is false', () => {
+ const mockedRule = mockRuleWithEverything('test-id');
+ const result: Pick = determineDetailsValue(
+ mockedRule,
+ false
+ );
+ const expected = {
+ name: mockedRule.name,
+ description: mockedRule.description,
+ note: mockedRule.note,
+ };
+
+ expect(result).toEqual(expected);
+ });
+
+ test('returns note as empty string if property does not exist on rule', () => {
+ const mockedRule = mockRuleWithEverything('test-id');
+ delete mockedRule.note;
+ const result: Pick = determineDetailsValue(
+ mockedRule,
+ false
+ );
+ const expected = { name: mockedRule.name, description: mockedRule.description, note: '' };
+
+ expect(result).toEqual(expected);
+ });
+ });
+
+ describe('getDefineStepsData', () => {
+ test('returns with saved_id if value exists on rule', () => {
+ const result: DefineStepRule = getDefineStepsData(mockRule('test-id'));
+ const expected = {
+ isNew: false,
+ index: ['auditbeat-*'],
+ queryBar: {
+ query: {
+ query: '',
+ language: 'kuery',
+ },
+ filters: [],
+ saved_id: "Garrett's IP",
+ },
+ };
+
+ expect(result).toEqual(expected);
+ });
+
+ test('returns with saved_id of null if value does not exist on rule', () => {
+ const mockedRule = {
+ ...mockRule('test-id'),
+ };
+ delete mockedRule.saved_id;
+ const result: DefineStepRule = getDefineStepsData(mockedRule);
+ const expected = {
+ isNew: false,
+ index: ['auditbeat-*'],
+ queryBar: {
+ query: {
+ query: '',
+ language: 'kuery',
+ },
+ filters: [],
+ saved_id: null,
+ },
+ };
+
+ expect(result).toEqual(expected);
+ });
+ });
+
+ describe('getHumanizedDuration', () => {
+ test('returns from as seconds if from duration is less than a minute', () => {
+ const result = getHumanizedDuration('now-62s', '1m');
+
+ expect(result).toEqual('2s');
+ });
+
+ test('returns from as minutes if from duration is less than an hour', () => {
+ const result = getHumanizedDuration('now-660s', '5m');
+
+ expect(result).toEqual('6m');
+ });
+
+ test('returns from as hours if from duration is more than 60 minutes', () => {
+ const result = getHumanizedDuration('now-7400s', '5m');
+
+ expect(result).toEqual('1h');
+ });
+
+ test('returns from as if from is not parsable as dateMath', () => {
+ const result = getHumanizedDuration('randomstring', '5m');
+
+ expect(result).toEqual('NaNh');
+ });
+
+ test('returns from as 5m if interval is not parsable as dateMath', () => {
+ const result = getHumanizedDuration('now-300s', 'randomstring');
+
+ expect(result).toEqual('5m');
+ });
+ });
+
+ describe('getScheduleStepsData', () => {
+ test('returns expected ScheduleStep rule object', () => {
+ const mockedRule = {
+ ...mockRule('test-id'),
+ };
+ const result: ScheduleStepRule = getScheduleStepsData(mockedRule);
+ const expected = {
+ isNew: false,
+ enabled: mockedRule.enabled,
+ interval: mockedRule.interval,
+ from: '0s',
+ };
+
+ expect(result).toEqual(expected);
+ });
+ });
+
+ describe('getModifiedAboutDetailsData', () => {
+ test('returns object with "note" and "description" being those of passed in rule', () => {
+ const result: AboutStepRuleDetails = getModifiedAboutDetailsData(
+ mockRuleWithEverything('test-id')
+ );
+ const aboutRuleDataDetailsData = {
+ note: '# this is some markdown documentation',
+ description: '24/7',
+ };
+
+ expect(result).toEqual(aboutRuleDataDetailsData);
+ });
+
+ test('returns "note" with empty string if "note" does not exist', () => {
+ const { note, ...mockRuleWithoutNote } = { ...mockRuleWithEverything('test-id') };
+ const result: AboutStepRuleDetails = getModifiedAboutDetailsData(mockRuleWithoutNote);
+
+ const aboutRuleDetailsData = { note: '', description: mockRuleWithoutNote.description };
+
+ expect(result).toEqual(aboutRuleDetailsData);
+ });
+ });
+});
diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/helpers.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/helpers.tsx
index 85f3bcbd236e9..1fc8a86a476f2 100644
--- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/helpers.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/helpers.tsx
@@ -5,19 +5,26 @@
*/
import dateMath from '@elastic/datemath';
-import { get, pick } from 'lodash/fp';
+import { get } from 'lodash/fp';
import moment from 'moment';
import { useLocation } from 'react-router-dom';
import { Filter } from '../../../../../../../../src/plugins/data/public';
import { Rule } from '../../../containers/detection_engine/rules';
import { FormData, FormHook, FormSchema } from '../../../shared_imports';
-import { AboutStepRule, DefineStepRule, IMitreEnterpriseAttack, ScheduleStepRule } from './types';
+import {
+ AboutStepRule,
+ AboutStepRuleDetails,
+ DefineStepRule,
+ IMitreEnterpriseAttack,
+ ScheduleStepRule,
+} from './types';
-interface GetStepsData {
- aboutRuleData: AboutStepRule | null;
- defineRuleData: DefineStepRule | null;
- scheduleRuleData: ScheduleStepRule | null;
+export interface GetStepsData {
+ aboutRuleData: AboutStepRule;
+ modifiedAboutRuleDetailsData: AboutStepRuleDetails;
+ defineRuleData: DefineStepRule;
+ scheduleRuleData: ScheduleStepRule;
}
export const getStepsData = ({
@@ -27,58 +34,107 @@ export const getStepsData = ({
rule: Rule;
detailsView?: boolean;
}): GetStepsData => {
- const defineRuleData: DefineStepRule | null =
- rule != null
- ? {
- isNew: false,
- index: rule.index,
- queryBar: {
- query: { query: rule.query as string, language: rule.language },
- filters: rule.filters as Filter[],
- saved_id: rule.saved_id ?? null,
- },
- }
- : null;
- const aboutRuleData: AboutStepRule | null =
- rule != null
- ? {
- isNew: false,
- ...pick(['description', 'name', 'references', 'severity', 'tags', 'threat'], rule),
- ...(detailsView ? { name: '' } : {}),
- threat: rule.threat as IMitreEnterpriseAttack[],
- falsePositives: rule.false_positives,
- riskScore: rule.risk_score,
- timeline: {
- id: rule.timeline_id ?? null,
- title: rule.timeline_title ?? null,
- },
- }
- : null;
-
- const from = dateMath.parse(rule.from) ?? moment();
- const interval = dateMath.parse(`now-${rule.interval}`) ?? moment();
-
- const fromDuration = moment.duration(interval.diff(from));
- let fromHumanize = `${Math.floor(fromDuration.asHours())}h`;
+ const defineRuleData: DefineStepRule = getDefineStepsData(rule);
+ const aboutRuleData: AboutStepRule = getAboutStepsData(rule, detailsView);
+ const modifiedAboutRuleDetailsData: AboutStepRuleDetails = getModifiedAboutDetailsData(rule);
+ const scheduleRuleData: ScheduleStepRule = getScheduleStepsData(rule);
+
+ return { aboutRuleData, modifiedAboutRuleDetailsData, defineRuleData, scheduleRuleData };
+};
+
+export const getDefineStepsData = (rule: Rule): DefineStepRule => {
+ const { index, query, language, filters, saved_id: savedId } = rule;
+
+ return {
+ isNew: false,
+ index,
+ queryBar: {
+ query: {
+ query,
+ language,
+ },
+ filters: filters as Filter[],
+ saved_id: savedId ?? null,
+ },
+ };
+};
+
+export const getScheduleStepsData = (rule: Rule): ScheduleStepRule => {
+ const { enabled, interval, from } = rule;
+ const fromHumanizedValue = getHumanizedDuration(from, interval);
+
+ return {
+ isNew: false,
+ enabled,
+ interval,
+ from: fromHumanizedValue,
+ };
+};
+
+export const getHumanizedDuration = (from: string, interval: string): string => {
+ const fromValue = dateMath.parse(from) ?? moment();
+ const intervalValue = dateMath.parse(`now-${interval}`) ?? moment();
+
+ const fromDuration = moment.duration(intervalValue.diff(fromValue));
+ const fromHumanize = `${Math.floor(fromDuration.asHours())}h`;
if (fromDuration.asSeconds() < 60) {
- fromHumanize = `${Math.floor(fromDuration.asSeconds())}s`;
+ return `${Math.floor(fromDuration.asSeconds())}s`;
} else if (fromDuration.asMinutes() < 60) {
- fromHumanize = `${Math.floor(fromDuration.asMinutes())}m`;
+ return `${Math.floor(fromDuration.asMinutes())}m`;
}
- const scheduleRuleData: ScheduleStepRule | null =
- rule != null
- ? {
- isNew: false,
- ...pick(['enabled', 'interval'], rule),
- from: fromHumanize,
- }
- : null;
+ return fromHumanize;
+};
+
+export const getAboutStepsData = (rule: Rule, detailsView: boolean): AboutStepRule => {
+ const { name, description, note } = determineDetailsValue(rule, detailsView);
+ const {
+ references,
+ severity,
+ false_positives: falsePositives,
+ risk_score: riskScore,
+ tags,
+ threat,
+ timeline_id: timelineId,
+ timeline_title: timelineTitle,
+ } = rule;
+
+ return {
+ isNew: false,
+ name,
+ description,
+ note: note!,
+ references,
+ severity,
+ tags,
+ riskScore,
+ falsePositives,
+ threat: threat as IMitreEnterpriseAttack[],
+ timeline: {
+ id: timelineId ?? null,
+ title: timelineTitle ?? null,
+ },
+ };
+};
+
+export const determineDetailsValue = (
+ rule: Rule,
+ detailsView: boolean
+): Pick => {
+ const { name, description, note } = rule;
+ if (detailsView) {
+ return { name: '', description: '', note: '' };
+ }
- return { aboutRuleData, defineRuleData, scheduleRuleData };
+ return { name, description, note: note ?? '' };
};
+export const getModifiedAboutDetailsData = (rule: Rule): AboutStepRuleDetails => ({
+ note: rule.note ?? '',
+ description: rule.description,
+});
+
export const useQuery = () => new URLSearchParams(useLocation().search);
export type PrePackagedRuleStatus =
diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/types.ts b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/types.ts
index 34df20de1e461..aa50626a1231a 100644
--- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/types.ts
+++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/types.ts
@@ -36,7 +36,7 @@ export interface RuleStepData {
export interface RuleStepProps {
addPadding?: boolean;
- descriptionDirection?: 'row' | 'column';
+ descriptionColumns?: 'multi' | 'single' | 'singleSplit';
setStepData?: (step: RuleStep, data: unknown, isValid: boolean) => void;
isReadOnlyView: boolean;
isUpdateView?: boolean;
@@ -58,6 +58,12 @@ export interface AboutStepRule extends StepRuleData {
tags: string[];
timeline: FieldValueTimeline;
threat: IMitreEnterpriseAttack[];
+ note: string;
+}
+
+export interface AboutStepRuleDetails {
+ note: string;
+ description: string;
}
export interface DefineStepRule extends StepRuleData {
@@ -91,6 +97,7 @@ export interface AboutStepRuleJson {
timeline_id?: string;
timeline_title?: string;
threat: IMitreEnterpriseAttack[];
+ note?: string;
}
export interface ScheduleStepRuleJson {
diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/translations.ts b/x-pack/legacy/plugins/siem/public/pages/detection_engine/translations.ts
index dd4acaeaf5a02..39277b3d3c77e 100644
--- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/translations.ts
+++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/translations.ts
@@ -19,7 +19,7 @@ export const TOTAL_SIGNAL = i18n.translate('xpack.siem.detectionEngine.totalSign
});
export const SIGNAL = i18n.translate('xpack.siem.detectionEngine.signalTitle', {
- defaultMessage: 'Signals (SIEM Detections)',
+ defaultMessage: 'Detected signals',
});
export const ALERT = i18n.translate('xpack.siem.detectionEngine.alertTitle', {
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/signal_params_schema.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/signal_params_schema.ts
index d1726f93108c7..adbb5fa618957 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/signal_params_schema.ts
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/signal_params_schema.ts
@@ -26,13 +26,13 @@ export const signalParamsSchema = () =>
savedId: schema.nullable(schema.string()),
timelineId: schema.nullable(schema.string()),
timelineTitle: schema.nullable(schema.string()),
- meta: schema.nullable(schema.object({}, { allowUnknowns: true })),
+ meta: schema.nullable(schema.object({}, { unknowns: 'allow' })),
query: schema.nullable(schema.string()),
- filters: schema.nullable(schema.arrayOf(schema.object({}, { allowUnknowns: true }))),
+ filters: schema.nullable(schema.arrayOf(schema.object({}, { unknowns: 'allow' }))),
maxSignals: schema.number({ defaultValue: DEFAULT_MAX_SIGNALS }),
riskScore: schema.number(),
severity: schema.string(),
- threat: schema.nullable(schema.arrayOf(schema.object({}, { allowUnknowns: true }))),
+ threat: schema.nullable(schema.arrayOf(schema.object({}, { unknowns: 'allow' }))),
to: schema.string(),
type: schema.string(),
references: schema.arrayOf(schema.string(), { defaultValue: [] }),
diff --git a/x-pack/legacy/plugins/siem/server/lib/framework/kibana_framework_adapter.ts b/x-pack/legacy/plugins/siem/server/lib/framework/kibana_framework_adapter.ts
index 7d42149223b32..004ac36bad5b4 100644
--- a/x-pack/legacy/plugins/siem/server/lib/framework/kibana_framework_adapter.ts
+++ b/x-pack/legacy/plugins/siem/server/lib/framework/kibana_framework_adapter.ts
@@ -61,7 +61,7 @@ export class KibanaBackendFrameworkAdapter implements FrameworkAdapter {
this.router.post(
{
path: routePath,
- validate: { body: configSchema.object({}, { allowUnknowns: true }) },
+ validate: { body: configSchema.object({}, { unknowns: 'allow' }) },
options: {
tags: ['access:siem'],
},
diff --git a/x-pack/legacy/plugins/triggers_actions_ui/index.ts b/x-pack/legacy/plugins/triggers_actions_ui/index.ts
index e871573b266a7..eb74290c84682 100644
--- a/x-pack/legacy/plugins/triggers_actions_ui/index.ts
+++ b/x-pack/legacy/plugins/triggers_actions_ui/index.ts
@@ -24,18 +24,11 @@ export function triggersActionsUI(kibana: any) {
return Joi.object()
.keys({
enabled: Joi.boolean().default(true),
- createAlertUiEnabled: Joi.boolean().default(false),
})
.default();
},
uiExports: {
styleSheetPaths: resolve(__dirname, 'public/index.scss'),
- injectDefaultVars(server: Legacy.Server) {
- const serverConfig = server.config();
- return {
- createAlertUiEnabled: serverConfig.get('xpack.triggers_actions_ui.createAlertUiEnabled'),
- };
- },
},
});
}
diff --git a/x-pack/legacy/plugins/uptime/common/constants/rest_api.ts b/x-pack/legacy/plugins/uptime/common/constants/rest_api.ts
index f09c795977831..61197d6dc373d 100644
--- a/x-pack/legacy/plugins/uptime/common/constants/rest_api.ts
+++ b/x-pack/legacy/plugins/uptime/common/constants/rest_api.ts
@@ -4,6 +4,16 @@
* you may not use this file except in compliance with the Elastic License.
*/
-export enum REST_API_URLS {
+export enum API_URLS {
+ INDEX_PATTERN = `/api/uptime/index_pattern`,
INDEX_STATUS = '/api/uptime/index_status',
+ MONITOR_LOCATIONS = `/api/uptime/monitor/locations`,
+ MONITOR_DURATION = `/api/uptime/monitor/duration`,
+ MONITOR_DETAILS = `/api/uptime/monitor/details`,
+ MONITOR_SELECTED = `/api/uptime/monitor/selected`,
+ MONITOR_STATUS = `/api/uptime/monitor/status`,
+ PINGS = '/api/uptime/pings',
+ PING_HISTOGRAM = `/api/uptime/ping/histogram`,
+ SNAPSHOT_COUNT = `/api/uptime/snapshot/count`,
+ FILTERS = `/api/uptime/filters`,
}
diff --git a/x-pack/legacy/plugins/uptime/public/components/connected/charts/snapshot_container.tsx b/x-pack/legacy/plugins/uptime/public/components/connected/charts/snapshot_container.tsx
index 08421cb56d14c..ac8ff13d1edce 100644
--- a/x-pack/legacy/plugins/uptime/public/components/connected/charts/snapshot_container.tsx
+++ b/x-pack/legacy/plugins/uptime/public/components/connected/charts/snapshot_container.tsx
@@ -8,9 +8,10 @@ import React, { useEffect } from 'react';
import { connect } from 'react-redux';
import { useUrlParams } from '../../../hooks';
import { AppState } from '../../../state';
-import { fetchSnapshotCount } from '../../../state/actions';
+import { getSnapshotCountAction } from '../../../state/actions';
import { SnapshotComponent } from '../../functional/snapshot';
import { Snapshot as SnapshotType } from '../../../../common/runtime_types';
+import { SnapShotQueryParams } from '../../../state/api';
/**
* Props expected from parent components.
@@ -37,7 +38,7 @@ interface StoreProps {
* for this component's life cycle
*/
interface DispatchProps {
- loadSnapshotCount: typeof fetchSnapshotCount;
+ loadSnapshotCount: typeof getSnapshotCountAction;
}
/**
@@ -57,7 +58,7 @@ export const Container: React.FC = ({
const { dateRangeStart, dateRangeEnd, statusFilter } = getUrlParams();
useEffect(() => {
- loadSnapshotCount(dateRangeStart, dateRangeEnd, esKuery, statusFilter);
+ loadSnapshotCount({ dateRangeStart, dateRangeEnd, filters: esKuery, statusFilter });
}, [dateRangeStart, dateRangeEnd, esKuery, lastRefresh, loadSnapshotCount, statusFilter]);
return ;
};
@@ -81,13 +82,8 @@ const mapStateToProps = ({
* @param dispatch redux-provided action dispatcher
*/
const mapDispatchToProps = (dispatch: any) => ({
- loadSnapshotCount: (
- dateRangeStart: string,
- dateRangeEnd: string,
- filters?: string,
- statusFilter?: string
- ): DispatchProps => {
- return dispatch(fetchSnapshotCount(dateRangeStart, dateRangeEnd, filters, statusFilter));
+ loadSnapshotCount: (params: SnapShotQueryParams): DispatchProps => {
+ return dispatch(getSnapshotCountAction(params));
},
});
diff --git a/x-pack/legacy/plugins/uptime/public/components/connected/monitor/list_drawer_container.tsx b/x-pack/legacy/plugins/uptime/public/components/connected/monitor/list_drawer_container.tsx
index 8c670b485cc56..ceeaa7026059f 100644
--- a/x-pack/legacy/plugins/uptime/public/components/connected/monitor/list_drawer_container.tsx
+++ b/x-pack/legacy/plugins/uptime/public/components/connected/monitor/list_drawer_container.tsx
@@ -7,9 +7,9 @@
import React, { useEffect } from 'react';
import { connect } from 'react-redux';
import { AppState } from '../../../state';
-import { getMonitorDetails } from '../../../state/selectors';
+import { monitorDetailsSelector } from '../../../state/selectors';
import { MonitorDetailsActionPayload } from '../../../state/actions/types';
-import { fetchMonitorDetails } from '../../../state/actions/monitor';
+import { getMonitorDetailsAction } from '../../../state/actions/monitor';
import { MonitorListDrawerComponent } from '../../functional/monitor_list/monitor_list_drawer/monitor_list_drawer';
import { useUrlParams } from '../../../hooks';
import { MonitorSummary } from '../../../../common/graphql/types';
@@ -18,7 +18,7 @@ import { MonitorDetails } from '../../../../common/runtime_types/monitor';
interface ContainerProps {
summary: MonitorSummary;
monitorDetails: MonitorDetails;
- loadMonitorDetails: typeof fetchMonitorDetails;
+ loadMonitorDetails: typeof getMonitorDetailsAction;
}
const Container: React.FC = ({ summary, loadMonitorDetails, monitorDetails }) => {
@@ -38,12 +38,12 @@ const Container: React.FC = ({ summary, loadMonitorDetails, moni
};
const mapStateToProps = (state: AppState, { summary }: any) => ({
- monitorDetails: getMonitorDetails(state, summary),
+ monitorDetails: monitorDetailsSelector(state, summary),
});
const mapDispatchToProps = (dispatch: any) => ({
loadMonitorDetails: (actionPayload: MonitorDetailsActionPayload) =>
- dispatch(fetchMonitorDetails(actionPayload)),
+ dispatch(getMonitorDetailsAction(actionPayload)),
});
export const MonitorListDrawer = connect(mapStateToProps, mapDispatchToProps)(Container);
diff --git a/x-pack/legacy/plugins/uptime/public/components/connected/monitor/status_bar_container.tsx b/x-pack/legacy/plugins/uptime/public/components/connected/monitor/status_bar_container.tsx
index b2b555d32a3c7..456fa2b30bca8 100644
--- a/x-pack/legacy/plugins/uptime/public/components/connected/monitor/status_bar_container.tsx
+++ b/x-pack/legacy/plugins/uptime/public/components/connected/monitor/status_bar_container.tsx
@@ -8,9 +8,9 @@ import React, { useContext, useEffect } from 'react';
import { connect } from 'react-redux';
import { Dispatch } from 'redux';
import { AppState } from '../../../state';
-import { selectMonitorLocations, selectMonitorStatus } from '../../../state/selectors';
+import { monitorLocationsSelector, selectMonitorStatus } from '../../../state/selectors';
import { MonitorStatusBarComponent } from '../../functional/monitor_status_details/monitor_status_bar';
-import { getMonitorStatus, getSelectedMonitor } from '../../../state/actions';
+import { getMonitorStatusAction, getSelectedMonitorAction } from '../../../state/actions';
import { useUrlParams } from '../../../hooks';
import { Ping } from '../../../../common/graphql/types';
import { MonitorLocations } from '../../../../common/runtime_types/monitor';
@@ -57,20 +57,20 @@ const Container: React.FC = ({
const mapStateToProps = (state: AppState, ownProps: OwnProps) => ({
monitorStatus: selectMonitorStatus(state),
- monitorLocations: selectMonitorLocations(state, ownProps.monitorId),
+ monitorLocations: monitorLocationsSelector(state, ownProps.monitorId),
});
const mapDispatchToProps = (dispatch: Dispatch): DispatchProps => ({
loadMonitorStatus: (dateStart: string, dateEnd: string, monitorId: string) => {
dispatch(
- getMonitorStatus({
+ getMonitorStatusAction({
monitorId,
dateStart,
dateEnd,
})
);
dispatch(
- getSelectedMonitor({
+ getSelectedMonitorAction({
monitorId,
})
);
diff --git a/x-pack/legacy/plugins/uptime/public/components/connected/monitor/status_details_container.tsx b/x-pack/legacy/plugins/uptime/public/components/connected/monitor/status_details_container.tsx
index 6929e3bd64c4d..3ced251dfab8c 100644
--- a/x-pack/legacy/plugins/uptime/public/components/connected/monitor/status_details_container.tsx
+++ b/x-pack/legacy/plugins/uptime/public/components/connected/monitor/status_details_container.tsx
@@ -9,8 +9,8 @@ import { connect } from 'react-redux';
import { Dispatch } from 'redux';
import { useUrlParams } from '../../../hooks';
import { AppState } from '../../../state';
-import { selectMonitorLocations } from '../../../state/selectors';
-import { fetchMonitorLocations, MonitorLocationsPayload } from '../../../state/actions/monitor';
+import { monitorLocationsSelector } from '../../../state/selectors';
+import { getMonitorLocationsAction, MonitorLocationsPayload } from '../../../state/actions/monitor';
import { MonitorStatusDetailsComponent } from '../../functional/monitor_status_details';
import { MonitorLocations } from '../../../../common/runtime_types';
import { UptimeRefreshContext } from '../../../contexts';
@@ -24,7 +24,7 @@ interface StoreProps {
}
interface DispatchProps {
- loadMonitorLocations: typeof fetchMonitorLocations;
+ loadMonitorLocations: typeof getMonitorLocationsAction;
}
type Props = OwnProps & StoreProps & DispatchProps;
@@ -48,12 +48,12 @@ export const Container: React.FC = ({
);
};
const mapStateToProps = (state: AppState, { monitorId }: OwnProps) => ({
- monitorLocations: selectMonitorLocations(state, monitorId),
+ monitorLocations: monitorLocationsSelector(state, monitorId),
});
const mapDispatchToProps = (dispatch: Dispatch) => ({
loadMonitorLocations: (params: MonitorLocationsPayload) => {
- dispatch(fetchMonitorLocations(params));
+ dispatch(getMonitorLocationsAction(params));
},
});
diff --git a/x-pack/legacy/plugins/uptime/public/lib/helper/__tests__/__snapshots__/parameterize_values.test.ts.snap b/x-pack/legacy/plugins/uptime/public/lib/helper/__tests__/__snapshots__/parameterize_values.test.ts.snap
deleted file mode 100644
index 39c28a87f5e71..0000000000000
--- a/x-pack/legacy/plugins/uptime/public/lib/helper/__tests__/__snapshots__/parameterize_values.test.ts.snap
+++ /dev/null
@@ -1,5 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`parameterizeValues parameterizes provided values for multiple fields 1`] = `"foo=bar&foo=baz&bar=foo&bar=baz"`;
-
-exports[`parameterizeValues parameterizes the provided values for a given field name 1`] = `"foo=bar&foo=baz"`;
diff --git a/x-pack/legacy/plugins/uptime/public/lib/helper/__tests__/get_api_path.test.ts b/x-pack/legacy/plugins/uptime/public/lib/helper/__tests__/get_api_path.test.ts
deleted file mode 100644
index c111008fdc3d1..0000000000000
--- a/x-pack/legacy/plugins/uptime/public/lib/helper/__tests__/get_api_path.test.ts
+++ /dev/null
@@ -1,24 +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;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import { getApiPath } from '../get_api_path';
-
-describe('getApiPath', () => {
- it('returns a path with basePath when provided', () => {
- const result = getApiPath('/api/foo/bar', '/somebasepath');
- expect(result).toEqual('/somebasepath/api/foo/bar');
- });
-
- it('returns a valid path when no basePath present', () => {
- const result = getApiPath('/api/foo/bar');
- expect(result).toEqual('/api/foo/bar');
- });
-
- it('returns a valid path when an empty string is supplied as basePath', () => {
- const result = getApiPath('/api/foo/bar', '');
- expect(result).toEqual('/api/foo/bar');
- });
-});
diff --git a/x-pack/legacy/plugins/uptime/public/lib/helper/__tests__/parameterize_values.test.ts b/x-pack/legacy/plugins/uptime/public/lib/helper/__tests__/parameterize_values.test.ts
deleted file mode 100644
index e550a1a6397e3..0000000000000
--- a/x-pack/legacy/plugins/uptime/public/lib/helper/__tests__/parameterize_values.test.ts
+++ /dev/null
@@ -1,30 +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;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import { parameterizeValues } from '../parameterize_values';
-
-describe('parameterizeValues', () => {
- let params: URLSearchParams;
-
- beforeEach(() => {
- params = new URLSearchParams();
- });
-
- it('parameterizes the provided values for a given field name', () => {
- parameterizeValues(params, { foo: ['bar', 'baz'] });
- expect(params.toString()).toMatchSnapshot();
- });
-
- it('parameterizes provided values for multiple fields', () => {
- parameterizeValues(params, { foo: ['bar', 'baz'], bar: ['foo', 'baz'] });
- expect(params.toString()).toMatchSnapshot();
- });
-
- it('returns an empty string when there are no values provided', () => {
- parameterizeValues(params, { foo: [] });
- expect(params.toString()).toBe('');
- });
-});
diff --git a/x-pack/legacy/plugins/uptime/public/lib/helper/index.ts b/x-pack/legacy/plugins/uptime/public/lib/helper/index.ts
index ef191ce32e532..e2aa4a2b3d429 100644
--- a/x-pack/legacy/plugins/uptime/public/lib/helper/index.ts
+++ b/x-pack/legacy/plugins/uptime/public/lib/helper/index.ts
@@ -7,9 +7,7 @@
export { combineFiltersAndUserSearch } from './combine_filters_and_user_search';
export { convertMicrosecondsToMilliseconds } from './convert_measurements';
export * from './observability_integration';
-export { getApiPath } from './get_api_path';
export { getChartDateLabel } from './charts';
-export { parameterizeValues } from './parameterize_values';
export { seriesHasDownValues } from './series_has_down_values';
export { stringifyKueries } from './stringify_kueries';
export { UptimeUrlParams, getSupportedUrlParams } from './url_params';
diff --git a/x-pack/legacy/plugins/uptime/public/pages/monitor.tsx b/x-pack/legacy/plugins/uptime/public/pages/monitor.tsx
index 18c4927af0797..b9d29ed017a05 100644
--- a/x-pack/legacy/plugins/uptime/public/pages/monitor.tsx
+++ b/x-pack/legacy/plugins/uptime/public/pages/monitor.tsx
@@ -17,7 +17,7 @@ import { MonitorStatusDetails } from '../components/connected';
import { Ping } from '../../common/graphql/types';
import { AppState } from '../state';
import { selectSelectedMonitor } from '../state/selectors';
-import { getSelectedMonitor } from '../state/actions';
+import { getSelectedMonitorAction } from '../state/actions';
import { PageHeader } from './page_header';
interface StateProps {
@@ -102,7 +102,7 @@ const mapDispatchToProps: MapDispatchToPropsFunction = (dispa
return {
dispatchGetMonitorStatus: (monitorId: string) => {
dispatch(
- getSelectedMonitor({
+ getSelectedMonitorAction({
monitorId,
})
);
diff --git a/x-pack/legacy/plugins/uptime/public/state/actions/monitor.ts b/x-pack/legacy/plugins/uptime/public/state/actions/monitor.ts
index cf4525a08e43c..30ea8e71265e0 100644
--- a/x-pack/legacy/plugins/uptime/public/state/actions/monitor.ts
+++ b/x-pack/legacy/plugins/uptime/public/state/actions/monitor.ts
@@ -4,108 +4,33 @@
* you may not use this file except in compliance with the Elastic License.
*/
+import { createAction } from 'redux-actions';
import { MonitorDetailsActionPayload } from './types';
import { MonitorError } from '../../../common/runtime_types';
import { MonitorLocations } from '../../../common/runtime_types';
import { QueryParams } from './types';
-export const FETCH_MONITOR_DETAILS = 'FETCH_MONITOR_DETAILS';
-export const FETCH_MONITOR_DETAILS_SUCCESS = 'FETCH_MONITOR_DETAILS_SUCCESS';
-export const FETCH_MONITOR_DETAILS_FAIL = 'FETCH_MONITOR_DETAILS_FAIL';
-
-export const FETCH_MONITOR_LOCATIONS = 'FETCH_MONITOR_LOCATIONS';
-export const FETCH_MONITOR_LOCATIONS_SUCCESS = 'FETCH_MONITOR_LOCATIONS_SUCCESS';
-export const FETCH_MONITOR_LOCATIONS_FAIL = 'FETCH_MONITOR_LOCATIONS_FAIL';
-
-export interface MonitorDetailsState {
- monitorId: string;
- error: MonitorError;
-}
-
-interface GetMonitorDetailsAction {
- type: typeof FETCH_MONITOR_DETAILS;
- payload: MonitorDetailsActionPayload;
-}
-
-interface GetMonitorDetailsSuccessAction {
- type: typeof FETCH_MONITOR_DETAILS_SUCCESS;
- payload: MonitorDetailsState;
-}
-
-interface GetMonitorDetailsFailAction {
- type: typeof FETCH_MONITOR_DETAILS_FAIL;
- payload: any;
-}
-
export interface MonitorLocationsPayload extends QueryParams {
monitorId: string;
}
-interface GetMonitorLocationsAction {
- type: typeof FETCH_MONITOR_LOCATIONS;
- payload: MonitorLocationsPayload;
-}
-
-interface GetMonitorLocationsSuccessAction {
- type: typeof FETCH_MONITOR_LOCATIONS_SUCCESS;
- payload: MonitorLocations;
-}
-
-interface GetMonitorLocationsFailAction {
- type: typeof FETCH_MONITOR_LOCATIONS_FAIL;
- payload: any;
-}
-
-export function fetchMonitorDetails(payload: MonitorDetailsActionPayload): GetMonitorDetailsAction {
- return {
- type: FETCH_MONITOR_DETAILS,
- payload,
- };
-}
-
-export function fetchMonitorDetailsSuccess(
- monitorDetailsState: MonitorDetailsState
-): GetMonitorDetailsSuccessAction {
- return {
- type: FETCH_MONITOR_DETAILS_SUCCESS,
- payload: monitorDetailsState,
- };
-}
-
-export function fetchMonitorDetailsFail(error: any): GetMonitorDetailsFailAction {
- return {
- type: FETCH_MONITOR_DETAILS_FAIL,
- payload: error,
- };
-}
-
-export function fetchMonitorLocations(payload: MonitorLocationsPayload): GetMonitorLocationsAction {
- return {
- type: FETCH_MONITOR_LOCATIONS,
- payload,
- };
-}
-
-export function fetchMonitorLocationsSuccess(
- monitorLocationsState: MonitorLocations
-): GetMonitorLocationsSuccessAction {
- return {
- type: FETCH_MONITOR_LOCATIONS_SUCCESS,
- payload: monitorLocationsState,
- };
-}
-
-export function fetchMonitorLocationsFail(error: any): GetMonitorLocationsFailAction {
- return {
- type: FETCH_MONITOR_LOCATIONS_FAIL,
- payload: error,
- };
+export interface MonitorDetailsState {
+ monitorId: string;
+ error: MonitorError;
}
-export type MonitorActionTypes =
- | GetMonitorDetailsAction
- | GetMonitorDetailsSuccessAction
- | GetMonitorDetailsFailAction
- | GetMonitorLocationsAction
- | GetMonitorLocationsSuccessAction
- | GetMonitorLocationsFailAction;
+export const getMonitorDetailsAction = createAction(
+ 'GET_MONITOR_DETAILS'
+);
+export const getMonitorDetailsActionSuccess = createAction(
+ 'GET_MONITOR_DETAILS_SUCCESS'
+);
+export const getMonitorDetailsActionFail = createAction('GET_MONITOR_DETAILS_FAIL');
+
+export const getMonitorLocationsAction = createAction(
+ 'GET_MONITOR_LOCATIONS'
+);
+export const getMonitorLocationsActionSuccess = createAction(
+ 'GET_MONITOR_LOCATIONS_SUCCESS'
+);
+export const getMonitorLocationsActionFail = createAction('GET_MONITOR_LOCATIONS_FAIL');
diff --git a/x-pack/legacy/plugins/uptime/public/state/actions/monitor_status.ts b/x-pack/legacy/plugins/uptime/public/state/actions/monitor_status.ts
index db103f6cb780e..7917628abf7da 100644
--- a/x-pack/legacy/plugins/uptime/public/state/actions/monitor_status.ts
+++ b/x-pack/legacy/plugins/uptime/public/state/actions/monitor_status.ts
@@ -5,11 +5,12 @@
*/
import { createAction } from 'redux-actions';
import { QueryParams } from './types';
+import { Ping } from '../../../common/graphql/types';
-export const getSelectedMonitor = createAction<{ monitorId: string }>('GET_SELECTED_MONITOR');
-export const getSelectedMonitorSuccess = createAction('GET_SELECTED_MONITOR_SUCCESS');
-export const getSelectedMonitorFail = createAction('GET_SELECTED_MONITOR_FAIL');
+export const getSelectedMonitorAction = createAction<{ monitorId: string }>('GET_SELECTED_MONITOR');
+export const getSelectedMonitorActionSuccess = createAction('GET_SELECTED_MONITOR_SUCCESS');
+export const getSelectedMonitorActionFail = createAction('GET_SELECTED_MONITOR_FAIL');
-export const getMonitorStatus = createAction('GET_MONITOR_STATUS');
-export const getMonitorStatusSuccess = createAction('GET_MONITOR_STATUS_SUCCESS');
-export const getMonitorStatusFail = createAction('GET_MONITOR_STATUS_FAIL');
+export const getMonitorStatusAction = createAction('GET_MONITOR_STATUS');
+export const getMonitorStatusActionSuccess = createAction('GET_MONITOR_STATUS_SUCCESS');
+export const getMonitorStatusActionFail = createAction('GET_MONITOR_STATUS_FAIL');
diff --git a/x-pack/legacy/plugins/uptime/public/state/actions/snapshot.ts b/x-pack/legacy/plugins/uptime/public/state/actions/snapshot.ts
index 57d2b4ce38204..e819a553e61f5 100644
--- a/x-pack/legacy/plugins/uptime/public/state/actions/snapshot.ts
+++ b/x-pack/legacy/plugins/uptime/public/state/actions/snapshot.ts
@@ -4,12 +4,9 @@
* you may not use this file except in compliance with the Elastic License.
*/
+import { createAction } from 'redux-actions';
import { Snapshot } from '../../../common/runtime_types';
-export const FETCH_SNAPSHOT_COUNT = 'FETCH_SNAPSHOT_COUNT';
-export const FETCH_SNAPSHOT_COUNT_FAIL = 'FETCH_SNAPSHOT_COUNT_FAIL';
-export const FETCH_SNAPSHOT_COUNT_SUCCESS = 'FETCH_SNAPSHOT_COUNT_SUCCESS';
-
export interface GetSnapshotPayload {
dateRangeStart: string;
dateRangeEnd: string;
@@ -17,47 +14,6 @@ export interface GetSnapshotPayload {
statusFilter?: string;
}
-interface GetSnapshotCountFetchAction {
- type: typeof FETCH_SNAPSHOT_COUNT;
- payload: GetSnapshotPayload;
-}
-
-interface GetSnapshotCountSuccessAction {
- type: typeof FETCH_SNAPSHOT_COUNT_SUCCESS;
- payload: Snapshot;
-}
-
-interface GetSnapshotCountFailAction {
- type: typeof FETCH_SNAPSHOT_COUNT_FAIL;
- payload: Error;
-}
-
-export type SnapshotActionTypes =
- | GetSnapshotCountFetchAction
- | GetSnapshotCountSuccessAction
- | GetSnapshotCountFailAction;
-
-export const fetchSnapshotCount = (
- dateRangeStart: string,
- dateRangeEnd: string,
- filters?: string,
- statusFilter?: string
-): GetSnapshotCountFetchAction => ({
- type: FETCH_SNAPSHOT_COUNT,
- payload: {
- dateRangeStart,
- dateRangeEnd,
- filters,
- statusFilter,
- },
-});
-
-export const fetchSnapshotCountFail = (error: Error): GetSnapshotCountFailAction => ({
- type: FETCH_SNAPSHOT_COUNT_FAIL,
- payload: error,
-});
-
-export const fetchSnapshotCountSuccess = (snapshot: Snapshot) => ({
- type: FETCH_SNAPSHOT_COUNT_SUCCESS,
- payload: snapshot,
-});
+export const getSnapshotCountAction = createAction('GET_SNAPSHOT_COUNT');
+export const getSnapshotCountActionSuccess = createAction('GET_SNAPSHOT_COUNT_SUCCESS');
+export const getSnapshotCountActionFail = createAction('GET_SNAPSHOT_COUNT_FAIL');
diff --git a/x-pack/legacy/plugins/uptime/public/state/api/__tests__/__snapshots__/snapshot.test.ts.snap b/x-pack/legacy/plugins/uptime/public/state/api/__tests__/__snapshots__/snapshot.test.ts.snap
index 0d2392390c7e4..1cd2aae446519 100644
--- a/x-pack/legacy/plugins/uptime/public/state/api/__tests__/__snapshots__/snapshot.test.ts.snap
+++ b/x-pack/legacy/plugins/uptime/public/state/api/__tests__/__snapshots__/snapshot.test.ts.snap
@@ -1,7 +1,7 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`snapshot API throws when server response doesn't correspond to expected type 1`] = `
-[Error: Invalid value undefined supplied to : { down: number, total: number, up: number }/down: number
-Invalid value undefined supplied to : { down: number, total: number, up: number }/total: number
-Invalid value undefined supplied to : { down: number, total: number, up: number }/up: number]
+Object {
+ "foo": "bar",
+}
`;
diff --git a/x-pack/legacy/plugins/uptime/public/state/api/__tests__/snapshot.test.ts b/x-pack/legacy/plugins/uptime/public/state/api/__tests__/snapshot.test.ts
index e9b1391a23e32..66b376c3ac36f 100644
--- a/x-pack/legacy/plugins/uptime/public/state/api/__tests__/snapshot.test.ts
+++ b/x-pack/legacy/plugins/uptime/public/state/api/__tests__/snapshot.test.ts
@@ -5,17 +5,19 @@
*/
import { fetchSnapshotCount } from '../snapshot';
+import { apiService } from '../utils';
+import { HttpFetchError } from '../../../../../../../../src/core/public/http/http_fetch_error';
describe('snapshot API', () => {
- let fetchMock: jest.SpyInstance>>;
- let mockResponse: Partial;
+ let fetchMock: jest.SpyInstance>;
+ let mockResponse: Partial;
beforeEach(() => {
- fetchMock = jest.spyOn(window, 'fetch');
- mockResponse = {
- ok: true,
- json: () => new Promise(r => r({ up: 3, down: 12, total: 15 })),
- };
+ apiService.http = {
+ get: jest.fn(),
+ } as any;
+ fetchMock = jest.spyOn(apiService.http, 'get');
+ mockResponse = { up: 3, down: 12, total: 15 };
});
afterEach(() => {
@@ -25,49 +27,43 @@ describe('snapshot API', () => {
it('calls url with expected params and returns response body on 200', async () => {
fetchMock.mockReturnValue(new Promise(r => r(mockResponse)));
const resp = await fetchSnapshotCount({
- basePath: '',
dateRangeStart: 'now-15m',
dateRangeEnd: 'now',
filters: 'monitor.id:"auto-http-0X21EE76EAC459873F"',
statusFilter: 'up',
});
- expect(fetchMock).toHaveBeenCalledWith(
- '/api/uptime/snapshot/count?dateRangeStart=now-15m&dateRangeEnd=now&filters=monitor.id%3A%22auto-http-0X21EE76EAC459873F%22&statusFilter=up'
- );
+ expect(fetchMock).toHaveBeenCalledWith('/api/uptime/snapshot/count', {
+ query: {
+ dateRangeEnd: 'now',
+ dateRangeStart: 'now-15m',
+ filters: 'monitor.id:"auto-http-0X21EE76EAC459873F"',
+ statusFilter: 'up',
+ },
+ });
expect(resp).toEqual({ up: 3, down: 12, total: 15 });
});
it(`throws when server response doesn't correspond to expected type`, async () => {
- mockResponse = { ok: true, json: () => new Promise(r => r({ foo: 'bar' })) };
+ mockResponse = { foo: 'bar' };
fetchMock.mockReturnValue(new Promise(r => r(mockResponse)));
- let error: Error | undefined;
- try {
- await fetchSnapshotCount({
- basePath: '',
- dateRangeStart: 'now-15m',
- dateRangeEnd: 'now',
- filters: 'monitor.id: baz',
- statusFilter: 'up',
- });
- } catch (e) {
- error = e;
- }
- expect(error).toMatchSnapshot();
+ const result = await fetchSnapshotCount({
+ dateRangeStart: 'now-15m',
+ dateRangeEnd: 'now',
+ filters: 'monitor.id: baz',
+ statusFilter: 'up',
+ });
+
+ expect(result).toMatchSnapshot();
});
it('throws an error when response is not ok', async () => {
- mockResponse = { ok: false, statusText: 'There was an error fetching your data.' };
- fetchMock.mockReturnValue(new Promise(r => r(mockResponse)));
- let error: Error | undefined;
- try {
- await fetchSnapshotCount({
- basePath: '',
- dateRangeStart: 'now-15m',
- dateRangeEnd: 'now',
- });
- } catch (e) {
- error = e;
- }
- expect(error).toEqual(new Error('There was an error fetching your data.'));
+ mockResponse = new HttpFetchError('There was an error fetching your data.', 'error', {} as any);
+ fetchMock.mockReturnValue(mockResponse);
+ const result = await fetchSnapshotCount({
+ dateRangeStart: 'now-15m',
+ dateRangeEnd: 'now',
+ });
+
+ expect(result).toEqual(new Error('There was an error fetching your data.'));
});
});
diff --git a/x-pack/legacy/plugins/uptime/public/state/api/index_pattern.ts b/x-pack/legacy/plugins/uptime/public/state/api/index_pattern.ts
index 2669376d728ab..1eecbc75c5bf4 100644
--- a/x-pack/legacy/plugins/uptime/public/state/api/index_pattern.ts
+++ b/x-pack/legacy/plugins/uptime/public/state/api/index_pattern.ts
@@ -4,18 +4,9 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { getApiPath } from '../../lib/helper';
+import { API_URLS } from '../../../common/constants';
+import { apiService } from './utils';
-interface APIParams {
- basePath: string;
-}
-
-export const fetchIndexPattern = async ({ basePath }: APIParams) => {
- const url = getApiPath(`/api/uptime/index_pattern`, basePath);
-
- const response = await fetch(url);
- if (!response.ok) {
- throw new Error(response.statusText);
- }
- return await response.json();
+export const fetchIndexPattern = async () => {
+ return await apiService.get(API_URLS.INDEX_PATTERN);
};
diff --git a/x-pack/legacy/plugins/uptime/public/state/api/index_status.ts b/x-pack/legacy/plugins/uptime/public/state/api/index_status.ts
index 9c531b3406a7c..0e33ab617777a 100644
--- a/x-pack/legacy/plugins/uptime/public/state/api/index_status.ts
+++ b/x-pack/legacy/plugins/uptime/public/state/api/index_status.ts
@@ -4,28 +4,10 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { PathReporter } from 'io-ts/lib/PathReporter';
-import { isRight } from 'fp-ts/lib/Either';
-import { getApiPath } from '../../lib/helper';
-import { REST_API_URLS } from '../../../common/constants/rest_api';
+import { API_URLS } from '../../../common/constants';
import { StatesIndexStatus, StatesIndexStatusType } from '../../../common/runtime_types';
+import { apiService } from './utils';
-interface ApiRequest {
- basePath: string;
-}
-
-export const fetchIndexStatus = async ({ basePath }: ApiRequest): Promise => {
- const url = getApiPath(REST_API_URLS.INDEX_STATUS, basePath);
-
- const response = await fetch(url);
- if (!response.ok) {
- throw new Error(response.statusText);
- }
- const responseData = await response.json();
- const decoded = StatesIndexStatusType.decode(responseData);
- PathReporter.report(decoded);
- if (isRight(decoded)) {
- return decoded.right;
- }
- throw PathReporter.report(decoded);
+export const fetchIndexStatus = async (): Promise => {
+ return await apiService.get(API_URLS.INDEX_STATUS, undefined, StatesIndexStatusType);
};
diff --git a/x-pack/legacy/plugins/uptime/public/state/api/monitor.ts b/x-pack/legacy/plugins/uptime/public/state/api/monitor.ts
index 80fd311c3ec7e..b36eccca98da9 100644
--- a/x-pack/legacy/plugins/uptime/public/state/api/monitor.ts
+++ b/x-pack/legacy/plugins/uptime/public/state/api/monitor.ts
@@ -4,71 +4,38 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { PathReporter } from 'io-ts/lib/PathReporter';
-import { getApiPath } from '../../lib/helper';
import { BaseParams } from './types';
-import {
- MonitorDetailsType,
- MonitorDetails,
- MonitorLocations,
- MonitorLocationsType,
-} from '../../../common/runtime_types';
+import { MonitorDetailsType, MonitorLocationsType } from '../../../common/runtime_types';
import { QueryParams } from '../actions/types';
+import { apiService } from './utils';
+import { API_URLS } from '../../../common/constants/rest_api';
interface ApiRequest {
monitorId: string;
- basePath: string;
}
export type MonitorQueryParams = BaseParams & ApiRequest;
export const fetchMonitorDetails = async ({
monitorId,
- basePath,
dateStart,
dateEnd,
-}: MonitorQueryParams): Promise => {
- const url = getApiPath(`/api/uptime/monitor/details`, basePath);
+}: MonitorQueryParams) => {
const params = {
monitorId,
dateStart,
dateEnd,
};
- const urlParams = new URLSearchParams(params).toString();
- const response = await fetch(`${url}?${urlParams}`);
-
- if (!response.ok) {
- throw new Error(response.statusText);
- }
- return response.json().then(data => {
- PathReporter.report(MonitorDetailsType.decode(data));
- return data;
- });
+ return await apiService.get(API_URLS.MONITOR_DETAILS, params, MonitorDetailsType);
};
type ApiParams = QueryParams & ApiRequest;
-export const fetchMonitorLocations = async ({
- monitorId,
- basePath,
- dateStart,
- dateEnd,
-}: ApiParams): Promise => {
- const url = getApiPath(`/api/uptime/monitor/locations`, basePath);
-
+export const fetchMonitorLocations = async ({ monitorId, dateStart, dateEnd }: ApiParams) => {
const params = {
dateStart,
dateEnd,
monitorId,
};
- const urlParams = new URLSearchParams(params).toString();
- const response = await fetch(`${url}?${urlParams}`);
-
- if (!response.ok) {
- throw new Error(response.statusText);
- }
- return response.json().then(data => {
- PathReporter.report(MonitorLocationsType.decode(data));
- return data;
- });
+ return await apiService.get(API_URLS.MONITOR_LOCATIONS, params, MonitorLocationsType);
};
diff --git a/x-pack/legacy/plugins/uptime/public/state/api/monitor_duration.ts b/x-pack/legacy/plugins/uptime/public/state/api/monitor_duration.ts
index 44e797457e5fd..daf725119fcf3 100644
--- a/x-pack/legacy/plugins/uptime/public/state/api/monitor_duration.ts
+++ b/x-pack/legacy/plugins/uptime/public/state/api/monitor_duration.ts
@@ -4,29 +4,16 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { stringify } from 'query-string';
-
-import { getApiPath } from '../../lib/helper';
import { BaseParams } from './types';
+import { apiService } from './utils';
+import { API_URLS } from '../../../common/constants/rest_api';
-export const fetchMonitorDuration = async ({
- basePath,
- monitorId,
- dateStart,
- dateEnd,
-}: BaseParams) => {
- const url = getApiPath(`/api/uptime/monitor/duration`, basePath);
-
- const params = {
+export const fetchMonitorDuration = async ({ monitorId, dateStart, dateEnd }: BaseParams) => {
+ const queryParams = {
monitorId,
dateStart,
dateEnd,
};
- const urlParams = stringify(params);
- const response = await fetch(`${url}?${urlParams}`);
- if (!response.ok) {
- throw new Error(response.statusText);
- }
- return await response.json();
+ return await apiService.get(API_URLS.MONITOR_DURATION, queryParams);
};
diff --git a/x-pack/legacy/plugins/uptime/public/state/api/monitor_status.ts b/x-pack/legacy/plugins/uptime/public/state/api/monitor_status.ts
index 936e864b75619..0f7608ba57ea7 100644
--- a/x-pack/legacy/plugins/uptime/public/state/api/monitor_status.ts
+++ b/x-pack/legacy/plugins/uptime/public/state/api/monitor_status.ts
@@ -4,46 +4,33 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { getApiPath } from '../../lib/helper';
import { QueryParams } from '../actions/types';
import { Ping } from '../../../common/graphql/types';
+import { apiService } from './utils';
+import { API_URLS } from '../../../common/constants/rest_api';
export interface APIParams {
- basePath: string;
monitorId: string;
}
-export const fetchSelectedMonitor = async ({ basePath, monitorId }: APIParams): Promise => {
- const url = getApiPath(`/api/uptime/monitor/selected`, basePath);
- const params = {
+export const fetchSelectedMonitor = async ({ monitorId }: APIParams): Promise => {
+ const queryParams = {
monitorId,
};
- const urlParams = new URLSearchParams(params).toString();
- const response = await fetch(`${url}?${urlParams}`);
- if (!response.ok) {
- throw new Error(response.statusText);
- }
- const responseData = await response.json();
- return responseData;
+
+ return await apiService.get(API_URLS.MONITOR_SELECTED, queryParams);
};
export const fetchMonitorStatus = async ({
- basePath,
monitorId,
dateStart,
dateEnd,
-}: QueryParams & APIParams): Promise => {
- const url = getApiPath(`/api/uptime/monitor/status`, basePath);
- const params = {
+}: QueryParams): Promise => {
+ const queryParams = {
monitorId,
dateStart,
dateEnd,
};
- const urlParams = new URLSearchParams(params).toString();
- const response = await fetch(`${url}?${urlParams}`);
- if (!response.ok) {
- throw new Error(response.statusText);
- }
- const responseData = await response.json();
- return responseData;
+
+ return await apiService.get(API_URLS.MONITOR_STATUS, queryParams);
};
diff --git a/x-pack/legacy/plugins/uptime/public/state/api/overview_filters.ts b/x-pack/legacy/plugins/uptime/public/state/api/overview_filters.ts
index c3ef62fa88dcf..9943bc27f11f0 100644
--- a/x-pack/legacy/plugins/uptime/public/state/api/overview_filters.ts
+++ b/x-pack/legacy/plugins/uptime/public/state/api/overview_filters.ts
@@ -4,18 +4,12 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { ThrowReporter } from 'io-ts/lib/ThrowReporter';
-import { isRight } from 'fp-ts/lib/Either';
import { GetOverviewFiltersPayload } from '../actions/overview_filters';
-import { getApiPath, parameterizeValues } from '../../lib/helper';
import { OverviewFiltersType } from '../../../common/runtime_types';
-
-type ApiRequest = GetOverviewFiltersPayload & {
- basePath: string;
-};
+import { apiService } from './utils';
+import { API_URLS } from '../../../common/constants/rest_api';
export const fetchOverviewFilters = async ({
- basePath,
dateRangeStart,
dateRangeEnd,
search,
@@ -23,30 +17,16 @@ export const fetchOverviewFilters = async ({
locations,
ports,
tags,
-}: ApiRequest) => {
- const url = getApiPath(`/api/uptime/filters`, basePath);
-
- const params = new URLSearchParams({
+}: GetOverviewFiltersPayload) => {
+ const queryParams = {
dateRangeStart,
dateRangeEnd,
- });
-
- if (search) {
- params.append('search', search);
- }
-
- parameterizeValues(params, { schemes, locations, ports, tags });
-
- const response = await fetch(`${url}?${params.toString()}`);
- if (!response.ok) {
- throw new Error(response.statusText);
- }
- const responseData = await response.json();
- const decoded = OverviewFiltersType.decode(responseData);
-
- ThrowReporter.report(decoded);
- if (isRight(decoded)) {
- return decoded.right;
- }
- throw new Error('`getOverviewFilters` response did not correspond to expected type');
+ schemes,
+ locations,
+ ports,
+ tags,
+ search,
+ };
+
+ return await apiService.get(API_URLS.FILTERS, queryParams, OverviewFiltersType);
};
diff --git a/x-pack/legacy/plugins/uptime/public/state/api/ping.ts b/x-pack/legacy/plugins/uptime/public/state/api/ping.ts
index c61bf42c8c90e..df71cc8d67bd0 100644
--- a/x-pack/legacy/plugins/uptime/public/state/api/ping.ts
+++ b/x-pack/legacy/plugins/uptime/public/state/api/ping.ts
@@ -4,32 +4,25 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { stringify } from 'query-string';
-import { getApiPath } from '../../lib/helper';
import { APIFn } from './types';
import { GetPingHistogramParams, HistogramResult } from '../../../common/types';
+import { apiService } from './utils';
+import { API_URLS } from '../../../common/constants/rest_api';
export const fetchPingHistogram: APIFn = async ({
- basePath,
monitorId,
dateStart,
dateEnd,
statusFilter,
filters,
}) => {
- const url = getApiPath(`/api/uptime/ping/histogram`, basePath);
- const params = {
+ const queryParams = {
dateStart,
dateEnd,
...(monitorId && { monitorId }),
...(statusFilter && { statusFilter }),
...(filters && { filters }),
};
- const urlParams = stringify(params, { sort: false });
- const response = await fetch(`${url}?${urlParams}`);
- if (!response.ok) {
- throw new Error(response.statusText);
- }
- const responseData = await response.json();
- return responseData;
+
+ return await apiService.get(API_URLS.PING_HISTOGRAM, queryParams);
};
diff --git a/x-pack/legacy/plugins/uptime/public/state/api/snapshot.ts b/x-pack/legacy/plugins/uptime/public/state/api/snapshot.ts
index cbfe00a4a8746..e663d0241d688 100644
--- a/x-pack/legacy/plugins/uptime/public/state/api/snapshot.ts
+++ b/x-pack/legacy/plugins/uptime/public/state/api/snapshot.ts
@@ -4,13 +4,11 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { ThrowReporter } from 'io-ts/lib/ThrowReporter';
-import { isRight } from 'fp-ts/lib/Either';
-import { getApiPath } from '../../lib/helper';
import { SnapshotType, Snapshot } from '../../../common/runtime_types';
+import { apiService } from './utils';
+import { API_URLS } from '../../../common/constants/rest_api';
-interface ApiRequest {
- basePath: string;
+export interface SnapShotQueryParams {
dateRangeStart: string;
dateRangeEnd: string;
filters?: string;
@@ -18,29 +16,17 @@ interface ApiRequest {
}
export const fetchSnapshotCount = async ({
- basePath,
dateRangeStart,
dateRangeEnd,
filters,
statusFilter,
-}: ApiRequest): Promise => {
- const url = getApiPath(`/api/uptime/snapshot/count`, basePath);
- const params = {
+}: SnapShotQueryParams): Promise => {
+ const queryParams = {
dateRangeStart,
dateRangeEnd,
...(filters && { filters }),
...(statusFilter && { statusFilter }),
};
- const urlParams = new URLSearchParams(params).toString();
- const response = await fetch(`${url}?${urlParams}`);
- if (!response.ok) {
- throw new Error(response.statusText);
- }
- const responseData = await response.json();
- const decoded = SnapshotType.decode(responseData);
- ThrowReporter.report(decoded);
- if (isRight(decoded)) {
- return decoded.right;
- }
- throw new Error('`getSnapshotCount` response did not correspond to expected type');
+
+ return await apiService.get(API_URLS.SNAPSHOT_COUNT, queryParams, SnapshotType);
};
diff --git a/x-pack/legacy/plugins/uptime/public/state/api/types.ts b/x-pack/legacy/plugins/uptime/public/state/api/types.ts
index a148f1c7d7ae3..4232751cbc032 100644
--- a/x-pack/legacy/plugins/uptime/public/state/api/types.ts
+++ b/x-pack/legacy/plugins/uptime/public/state/api/types.ts
@@ -5,7 +5,6 @@
*/
export interface BaseParams {
- basePath: string;
dateStart: string;
dateEnd: string;
filters?: string;
@@ -14,4 +13,4 @@ export interface BaseParams {
monitorId?: string;
}
-export type APIFn = (params: { basePath: string } & P) => Promise;
+export type APIFn = (params: P) => Promise;
diff --git a/x-pack/legacy/plugins/uptime/public/state/api/utils.ts b/x-pack/legacy/plugins/uptime/public/state/api/utils.ts
new file mode 100644
index 0000000000000..e67efa8570c11
--- /dev/null
+++ b/x-pack/legacy/plugins/uptime/public/state/api/utils.ts
@@ -0,0 +1,80 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { PathReporter } from 'io-ts/lib/PathReporter';
+import { isRight } from 'fp-ts/lib/Either';
+import { HttpFetchQuery, HttpSetup } from '../../../../../../../target/types/core/public';
+
+class ApiService {
+ private static instance: ApiService;
+ private _http!: HttpSetup;
+
+ public get http() {
+ return this._http;
+ }
+
+ public set http(httpSetup: HttpSetup) {
+ this._http = httpSetup;
+ }
+
+ private constructor() {}
+
+ static getInstance(): ApiService {
+ if (!ApiService.instance) {
+ ApiService.instance = new ApiService();
+ }
+
+ return ApiService.instance;
+ }
+
+ public async get(apiUrl: string, params?: HttpFetchQuery, decodeType?: any) {
+ const response = await this._http!.get(apiUrl, { query: params });
+
+ if (decodeType) {
+ const decoded = decodeType.decode(response);
+ if (isRight(decoded)) {
+ return decoded.right;
+ } else {
+ // eslint-disable-next-line no-console
+ console.error(
+ `API ${apiUrl} is not returning expected response, ${PathReporter.report(decoded)}`
+ );
+ }
+ }
+
+ return response;
+ }
+
+ public async post(apiUrl: string, data?: any, decodeType?: any) {
+ const response = await this._http!.post(apiUrl, {
+ method: 'POST',
+ body: JSON.stringify(data),
+ });
+
+ if (decodeType) {
+ const decoded = decodeType.decode(response);
+ if (isRight(decoded)) {
+ return decoded.right;
+ } else {
+ // eslint-disable-next-line no-console
+ console.warn(
+ `API ${apiUrl} is not returning expected response, ${PathReporter.report(decoded)}`
+ );
+ }
+ }
+ return response;
+ }
+
+ public async delete(apiUrl: string) {
+ const response = await this._http!.delete(apiUrl);
+ if (response instanceof Error) {
+ throw response;
+ }
+ return response;
+ }
+}
+
+export const apiService = ApiService.getInstance();
diff --git a/x-pack/legacy/plugins/uptime/public/state/effects/fetch_effect.ts b/x-pack/legacy/plugins/uptime/public/state/effects/fetch_effect.ts
index ea389ff0a6745..d1d7626b2eab3 100644
--- a/x-pack/legacy/plugins/uptime/public/state/effects/fetch_effect.ts
+++ b/x-pack/legacy/plugins/uptime/public/state/effects/fetch_effect.ts
@@ -4,9 +4,8 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { call, put, select } from 'redux-saga/effects';
+import { call, put } from 'redux-saga/effects';
import { Action } from 'redux-actions';
-import { getBasePath } from '../selectors';
/**
* Factory function for a fetch effect. It expects three action creators,
@@ -25,15 +24,17 @@ export function fetchEffectFactory(
fail: (error: Error) => Action
) {
return function*(action: Action) {
- try {
- const {
- payload: { ...params },
- } = action;
- const basePath = yield select(getBasePath);
- const response = yield call(fetch, { ...params, basePath });
+ const {
+ payload: { ...params },
+ } = action;
+ const response = yield call(fetch, params);
+ if (response instanceof Error) {
+ // eslint-disable-next-line no-console
+ console.error(response);
+
+ yield put(fail(response));
+ } else {
yield put(success(response));
- } catch (error) {
- yield put(fail(error));
}
};
}
diff --git a/x-pack/legacy/plugins/uptime/public/state/effects/monitor.ts b/x-pack/legacy/plugins/uptime/public/state/effects/monitor.ts
index 1cac7424b4e5b..ed21f315476d4 100644
--- a/x-pack/legacy/plugins/uptime/public/state/effects/monitor.ts
+++ b/x-pack/legacy/plugins/uptime/public/state/effects/monitor.ts
@@ -4,48 +4,34 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { call, put, takeLatest, select } from 'redux-saga/effects';
-import { Action } from 'redux-actions';
+import { takeLatest } from 'redux-saga/effects';
import {
- FETCH_MONITOR_DETAILS,
- FETCH_MONITOR_DETAILS_SUCCESS,
- FETCH_MONITOR_DETAILS_FAIL,
- FETCH_MONITOR_LOCATIONS,
- FETCH_MONITOR_LOCATIONS_SUCCESS,
- FETCH_MONITOR_LOCATIONS_FAIL,
+ getMonitorDetailsAction,
+ getMonitorDetailsActionSuccess,
+ getMonitorDetailsActionFail,
+ getMonitorLocationsAction,
+ getMonitorLocationsActionSuccess,
+ getMonitorLocationsActionFail,
} from '../actions/monitor';
import { fetchMonitorDetails, fetchMonitorLocations } from '../api';
-import { getBasePath } from '../selectors';
-import { MonitorDetailsActionPayload } from '../actions/types';
-
-function* monitorDetailsEffect(action: Action) {
- const { monitorId, dateStart, dateEnd }: MonitorDetailsActionPayload = action.payload;
- try {
- const basePath = yield select(getBasePath);
- const response = yield call(fetchMonitorDetails, {
- monitorId,
- basePath,
- dateStart,
- dateEnd,
- });
- yield put({ type: FETCH_MONITOR_DETAILS_SUCCESS, payload: response });
- } catch (error) {
- yield put({ type: FETCH_MONITOR_DETAILS_FAIL, payload: error.message });
- }
-}
-
-function* monitorLocationsEffect(action: Action) {
- const payload = action.payload;
- try {
- const basePath = yield select(getBasePath);
- const response = yield call(fetchMonitorLocations, { basePath, ...payload });
- yield put({ type: FETCH_MONITOR_LOCATIONS_SUCCESS, payload: response });
- } catch (error) {
- yield put({ type: FETCH_MONITOR_LOCATIONS_FAIL, payload: error.message });
- }
-}
+import { fetchEffectFactory } from './fetch_effect';
export function* fetchMonitorDetailsEffect() {
- yield takeLatest(FETCH_MONITOR_DETAILS, monitorDetailsEffect);
- yield takeLatest(FETCH_MONITOR_LOCATIONS, monitorLocationsEffect);
+ yield takeLatest(
+ getMonitorDetailsAction,
+ fetchEffectFactory(
+ fetchMonitorDetails,
+ getMonitorDetailsActionSuccess,
+ getMonitorDetailsActionFail
+ )
+ );
+
+ yield takeLatest(
+ getMonitorLocationsAction,
+ fetchEffectFactory(
+ fetchMonitorLocations,
+ getMonitorLocationsActionSuccess,
+ getMonitorLocationsActionFail
+ )
+ );
}
diff --git a/x-pack/legacy/plugins/uptime/public/state/effects/monitor_status.ts b/x-pack/legacy/plugins/uptime/public/state/effects/monitor_status.ts
index cab32092a14cd..1207ab20bc711 100644
--- a/x-pack/legacy/plugins/uptime/public/state/effects/monitor_status.ts
+++ b/x-pack/legacy/plugins/uptime/public/state/effects/monitor_status.ts
@@ -4,50 +4,34 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { call, put, takeLatest, select } from 'redux-saga/effects';
-import { Action } from 'redux-actions';
+import { takeLatest } from 'redux-saga/effects';
import {
- getSelectedMonitor,
- getSelectedMonitorSuccess,
- getSelectedMonitorFail,
- getMonitorStatus,
- getMonitorStatusSuccess,
- getMonitorStatusFail,
-} from '../actions/monitor_status';
+ getSelectedMonitorAction,
+ getSelectedMonitorActionSuccess,
+ getSelectedMonitorActionFail,
+ getMonitorStatusAction,
+ getMonitorStatusActionSuccess,
+ getMonitorStatusActionFail,
+} from '../actions';
import { fetchSelectedMonitor, fetchMonitorStatus } from '../api';
-import { getBasePath } from '../selectors';
-
-function* selectedMonitorEffect(action: Action) {
- const { monitorId } = action.payload;
- try {
- const basePath = yield select(getBasePath);
- const response = yield call(fetchSelectedMonitor, {
- monitorId,
- basePath,
- });
- yield put({ type: getSelectedMonitorSuccess, payload: response });
- } catch (error) {
- yield put({ type: getSelectedMonitorFail, payload: error.message });
- }
-}
-
-function* monitorStatusEffect(action: Action) {
- const { monitorId, dateStart, dateEnd } = action.payload;
- try {
- const basePath = yield select(getBasePath);
- const response = yield call(fetchMonitorStatus, {
- monitorId,
- basePath,
- dateStart,
- dateEnd,
- });
- yield put({ type: getMonitorStatusSuccess, payload: response });
- } catch (error) {
- yield put({ type: getMonitorStatusFail, payload: error.message });
- }
-}
+import { fetchEffectFactory } from './fetch_effect';
export function* fetchMonitorStatusEffect() {
- yield takeLatest(getMonitorStatus, monitorStatusEffect);
- yield takeLatest(getSelectedMonitor, selectedMonitorEffect);
+ yield takeLatest(
+ getMonitorStatusAction,
+ fetchEffectFactory(
+ fetchMonitorStatus,
+ getMonitorStatusActionSuccess,
+ getMonitorStatusActionFail
+ )
+ );
+
+ yield takeLatest(
+ getSelectedMonitorAction,
+ fetchEffectFactory(
+ fetchSelectedMonitor,
+ getSelectedMonitorActionSuccess,
+ getSelectedMonitorActionFail
+ )
+ );
}
diff --git a/x-pack/legacy/plugins/uptime/public/state/effects/snapshot.ts b/x-pack/legacy/plugins/uptime/public/state/effects/snapshot.ts
index 91df43dd9e826..10010004d47a0 100644
--- a/x-pack/legacy/plugins/uptime/public/state/effects/snapshot.ts
+++ b/x-pack/legacy/plugins/uptime/public/state/effects/snapshot.ts
@@ -6,16 +6,20 @@
import { takeLatest } from 'redux-saga/effects';
import {
- FETCH_SNAPSHOT_COUNT,
- fetchSnapshotCountFail,
- fetchSnapshotCountSuccess,
+ getSnapshotCountAction,
+ getSnapshotCountActionFail,
+ getSnapshotCountActionSuccess,
} from '../actions';
import { fetchSnapshotCount } from '../api';
import { fetchEffectFactory } from './fetch_effect';
export function* fetchSnapshotCountEffect() {
yield takeLatest(
- FETCH_SNAPSHOT_COUNT,
- fetchEffectFactory(fetchSnapshotCount, fetchSnapshotCountSuccess, fetchSnapshotCountFail)
+ getSnapshotCountAction,
+ fetchEffectFactory(
+ fetchSnapshotCount,
+ getSnapshotCountActionSuccess,
+ getSnapshotCountActionFail
+ )
);
}
diff --git a/x-pack/legacy/plugins/uptime/public/state/kibana_service.ts b/x-pack/legacy/plugins/uptime/public/state/kibana_service.ts
new file mode 100644
index 0000000000000..4fd2d446daa17
--- /dev/null
+++ b/x-pack/legacy/plugins/uptime/public/state/kibana_service.ts
@@ -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;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { CoreStart } from 'kibana/public';
+import { apiService } from './api/utils';
+
+class KibanaService {
+ private static instance: KibanaService;
+ private _core!: CoreStart;
+
+ public get core() {
+ return this._core;
+ }
+
+ public set core(coreStart: CoreStart) {
+ this._core = coreStart;
+ apiService.http = this._core.http;
+ }
+
+ private constructor() {}
+
+ static getInstance(): KibanaService {
+ if (!KibanaService.instance) {
+ KibanaService.instance = new KibanaService();
+ }
+
+ return KibanaService.instance;
+ }
+}
+
+export const kibanaService = KibanaService.getInstance();
diff --git a/x-pack/legacy/plugins/uptime/public/state/reducers/__tests__/snapshot.test.ts b/x-pack/legacy/plugins/uptime/public/state/reducers/__tests__/snapshot.test.ts
index 95c576e0fd72e..3650422571ce8 100644
--- a/x-pack/legacy/plugins/uptime/public/state/reducers/__tests__/snapshot.test.ts
+++ b/x-pack/legacy/plugins/uptime/public/state/reducers/__tests__/snapshot.test.ts
@@ -5,19 +5,20 @@
*/
import { snapshotReducer } from '../snapshot';
-import { SnapshotActionTypes } from '../../actions';
+import {
+ getSnapshotCountAction,
+ getSnapshotCountActionSuccess,
+ getSnapshotCountActionFail,
+} from '../../actions';
describe('snapshot reducer', () => {
it('updates existing state', () => {
- const action: SnapshotActionTypes = {
- type: 'FETCH_SNAPSHOT_COUNT',
- payload: {
- dateRangeStart: 'now-15m',
- dateRangeEnd: 'now',
- filters: 'foo: bar',
- statusFilter: 'up',
- },
- };
+ const action = getSnapshotCountAction({
+ dateRangeStart: 'now-15m',
+ dateRangeEnd: 'now',
+ filters: 'foo: bar',
+ statusFilter: 'up',
+ });
expect(
snapshotReducer(
{
@@ -31,33 +32,28 @@ describe('snapshot reducer', () => {
});
it(`sets the state's status to loading during a fetch`, () => {
- const action: SnapshotActionTypes = {
- type: 'FETCH_SNAPSHOT_COUNT',
- payload: {
- dateRangeStart: 'now-15m',
- dateRangeEnd: 'now',
- },
- };
+ const action = getSnapshotCountAction({
+ dateRangeStart: 'now-15m',
+ dateRangeEnd: 'now',
+ });
expect(snapshotReducer(undefined, action)).toMatchSnapshot();
});
it('changes the count when a snapshot fetch succeeds', () => {
- const action: SnapshotActionTypes = {
- type: 'FETCH_SNAPSHOT_COUNT_SUCCESS',
- payload: {
- up: 10,
- down: 15,
- total: 25,
- },
- };
+ const action = getSnapshotCountActionSuccess({
+ up: 10,
+ down: 15,
+ total: 25,
+ });
+
expect(snapshotReducer(undefined, action)).toMatchSnapshot();
});
it('appends a current error to existing errors list', () => {
- const action: SnapshotActionTypes = {
- type: 'FETCH_SNAPSHOT_COUNT_FAIL',
- payload: new Error(`I couldn't get your data because the server denied the request`),
- };
+ const action = getSnapshotCountActionFail(
+ new Error(`I couldn't get your data because the server denied the request`)
+ );
+
expect(snapshotReducer(undefined, action)).toMatchSnapshot();
});
});
diff --git a/x-pack/legacy/plugins/uptime/public/state/reducers/monitor.ts b/x-pack/legacy/plugins/uptime/public/state/reducers/monitor.ts
index aac8a90598d0c..632f3a270e1a1 100644
--- a/x-pack/legacy/plugins/uptime/public/state/reducers/monitor.ts
+++ b/x-pack/legacy/plugins/uptime/public/state/reducers/monitor.ts
@@ -4,15 +4,15 @@
* you may not use this file except in compliance with the Elastic License.
*/
+import { Action } from 'redux-actions';
import {
- MonitorActionTypes,
MonitorDetailsState,
- FETCH_MONITOR_DETAILS,
- FETCH_MONITOR_DETAILS_SUCCESS,
- FETCH_MONITOR_DETAILS_FAIL,
- FETCH_MONITOR_LOCATIONS,
- FETCH_MONITOR_LOCATIONS_SUCCESS,
- FETCH_MONITOR_LOCATIONS_FAIL,
+ getMonitorDetailsAction,
+ getMonitorLocationsAction,
+ getMonitorDetailsActionSuccess,
+ getMonitorDetailsActionFail,
+ getMonitorLocationsActionSuccess,
+ getMonitorLocationsActionFail,
} from '../actions/monitor';
import { MonitorLocations } from '../../../common/runtime_types';
@@ -32,14 +32,14 @@ const initialState: MonitorState = {
errors: [],
};
-export function monitorReducer(state = initialState, action: MonitorActionTypes): MonitorState {
+export function monitorReducer(state = initialState, action: Action): MonitorState {
switch (action.type) {
- case FETCH_MONITOR_DETAILS:
+ case String(getMonitorDetailsAction):
return {
...state,
loading: true,
};
- case FETCH_MONITOR_DETAILS_SUCCESS:
+ case String(getMonitorDetailsActionSuccess):
const { monitorId } = action.payload;
return {
...state,
@@ -49,17 +49,17 @@ export function monitorReducer(state = initialState, action: MonitorActionTypes)
},
loading: false,
};
- case FETCH_MONITOR_DETAILS_FAIL:
+ case String(getMonitorDetailsActionFail):
return {
...state,
errors: [...state.errors, action.payload],
};
- case FETCH_MONITOR_LOCATIONS:
+ case String(getMonitorLocationsAction):
return {
...state,
loading: true,
};
- case FETCH_MONITOR_LOCATIONS_SUCCESS:
+ case String(getMonitorLocationsActionSuccess):
const monLocations = state.monitorLocationsList;
monLocations.set(action.payload.monitorId, action.payload);
return {
@@ -67,7 +67,7 @@ export function monitorReducer(state = initialState, action: MonitorActionTypes)
monitorLocationsList: monLocations,
loading: false,
};
- case FETCH_MONITOR_LOCATIONS_FAIL:
+ case String(getMonitorLocationsActionFail):
return {
...state,
errors: [...state.errors, action.payload],
diff --git a/x-pack/legacy/plugins/uptime/public/state/reducers/monitor_status.ts b/x-pack/legacy/plugins/uptime/public/state/reducers/monitor_status.ts
index 2688a0946dd61..c2dfbd7f90ff2 100644
--- a/x-pack/legacy/plugins/uptime/public/state/reducers/monitor_status.ts
+++ b/x-pack/legacy/plugins/uptime/public/state/reducers/monitor_status.ts
@@ -5,12 +5,12 @@
*/
import { handleActions, Action } from 'redux-actions';
import {
- getSelectedMonitor,
- getSelectedMonitorSuccess,
- getSelectedMonitorFail,
- getMonitorStatus,
- getMonitorStatusSuccess,
- getMonitorStatusFail,
+ getSelectedMonitorAction,
+ getSelectedMonitorActionSuccess,
+ getSelectedMonitorActionFail,
+ getMonitorStatusAction,
+ getMonitorStatusActionSuccess,
+ getMonitorStatusActionFail,
} from '../actions';
import { Ping } from '../../../common/graphql/types';
import { QueryParams } from '../actions/types';
@@ -31,34 +31,34 @@ type MonitorStatusPayload = QueryParams & Ping;
export const monitorStatusReducer = handleActions(
{
- [String(getSelectedMonitor)]: (state, action: Action) => ({
+ [String(getSelectedMonitorAction)]: (state, action: Action) => ({
...state,
loading: true,
}),
- [String(getSelectedMonitorSuccess)]: (state, action: Action) => ({
+ [String(getSelectedMonitorActionSuccess)]: (state, action: Action) => ({
...state,
loading: false,
monitor: { ...action.payload } as Ping,
}),
- [String(getSelectedMonitorFail)]: (state, action: Action) => ({
+ [String(getSelectedMonitorActionFail)]: (state, action: Action) => ({
...state,
loading: false,
}),
- [String(getMonitorStatus)]: (state, action: Action) => ({
+ [String(getMonitorStatusAction)]: (state, action: Action) => ({
...state,
loading: true,
}),
- [String(getMonitorStatusSuccess)]: (state, action: Action) => ({
+ [String(getMonitorStatusActionSuccess)]: (state, action: Action) => ({
...state,
loading: false,
status: { ...action.payload } as Ping,
}),
- [String(getMonitorStatusFail)]: (state, action: Action) => ({
+ [String(getMonitorStatusActionFail)]: (state, action: Action) => ({
...state,
loading: false,
}),
diff --git a/x-pack/legacy/plugins/uptime/public/state/reducers/overview_filters.ts b/x-pack/legacy/plugins/uptime/public/state/reducers/overview_filters.ts
index b219421f4f4dc..0b67d8b0e7689 100644
--- a/x-pack/legacy/plugins/uptime/public/state/reducers/overview_filters.ts
+++ b/x-pack/legacy/plugins/uptime/public/state/reducers/overview_filters.ts
@@ -49,6 +49,7 @@ export function overviewFiltersReducer(
return {
...state,
errors: [...state.errors, action.payload],
+ loading: false,
};
default:
return state;
diff --git a/x-pack/legacy/plugins/uptime/public/state/reducers/snapshot.ts b/x-pack/legacy/plugins/uptime/public/state/reducers/snapshot.ts
index 2155d0e3a74e3..3ba1ef84d41a5 100644
--- a/x-pack/legacy/plugins/uptime/public/state/reducers/snapshot.ts
+++ b/x-pack/legacy/plugins/uptime/public/state/reducers/snapshot.ts
@@ -4,12 +4,12 @@
* you may not use this file except in compliance with the Elastic License.
*/
+import { Action } from 'redux-actions';
import { Snapshot } from '../../../common/runtime_types';
import {
- FETCH_SNAPSHOT_COUNT,
- FETCH_SNAPSHOT_COUNT_FAIL,
- FETCH_SNAPSHOT_COUNT_SUCCESS,
- SnapshotActionTypes,
+ getSnapshotCountAction,
+ getSnapshotCountActionSuccess,
+ getSnapshotCountActionFail,
} from '../actions';
export interface SnapshotState {
@@ -28,20 +28,20 @@ const initialState: SnapshotState = {
loading: false,
};
-export function snapshotReducer(state = initialState, action: SnapshotActionTypes): SnapshotState {
+export function snapshotReducer(state = initialState, action: Action): SnapshotState {
switch (action.type) {
- case FETCH_SNAPSHOT_COUNT:
+ case String(getSnapshotCountAction):
return {
...state,
loading: true,
};
- case FETCH_SNAPSHOT_COUNT_SUCCESS:
+ case String(getSnapshotCountActionSuccess):
return {
...state,
count: action.payload,
loading: false,
};
- case FETCH_SNAPSHOT_COUNT_FAIL:
+ case String(getSnapshotCountActionFail):
return {
...state,
errors: [...state.errors, action.payload],
diff --git a/x-pack/legacy/plugins/uptime/public/state/selectors/index.ts b/x-pack/legacy/plugins/uptime/public/state/selectors/index.ts
index adba288b8b145..4767c25e8f52f 100644
--- a/x-pack/legacy/plugins/uptime/public/state/selectors/index.ts
+++ b/x-pack/legacy/plugins/uptime/public/state/selectors/index.ts
@@ -13,11 +13,11 @@ export const isIntegrationsPopupOpen = ({ ui: { integrationsPopoverOpen } }: App
integrationsPopoverOpen;
// Monitor Selectors
-export const getMonitorDetails = (state: AppState, summary: any) => {
+export const monitorDetailsSelector = (state: AppState, summary: any) => {
return state.monitor.monitorDetailsList[summary.monitor_id];
};
-export const selectMonitorLocations = (state: AppState, monitorId: string) => {
+export const monitorLocationsSelector = (state: AppState, monitorId: string) => {
return state.monitor.monitorLocationsList?.get(monitorId);
};
diff --git a/x-pack/legacy/plugins/uptime/public/uptime_app.tsx b/x-pack/legacy/plugins/uptime/public/uptime_app.tsx
index 427870797a206..09156db9ca7d2 100644
--- a/x-pack/legacy/plugins/uptime/public/uptime_app.tsx
+++ b/x-pack/legacy/plugins/uptime/public/uptime_app.tsx
@@ -23,6 +23,7 @@ import { CommonlyUsedRange } from './components/functional/uptime_date_picker';
import { store } from './state';
import { setBasePath } from './state/actions';
import { PageRouter } from './routes';
+import { kibanaService } from './state/kibana_service';
export interface UptimeAppColors {
danger: string;
@@ -83,6 +84,8 @@ const Application = (props: UptimeAppProps) => {
);
}, [canSave, renderGlobalHelpControls, setBadge]);
+ kibanaService.core = core;
+
// @ts-ignore
store.dispatch(setBasePath(basePath));
diff --git a/x-pack/legacy/plugins/xpack_main/public/components/index.js b/x-pack/legacy/plugins/xpack_main/public/components/index.js
index e57bd6af189f8..871d86e642dec 100644
--- a/x-pack/legacy/plugins/xpack_main/public/components/index.js
+++ b/x-pack/legacy/plugins/xpack_main/public/components/index.js
@@ -4,11 +4,11 @@
* you may not use this file except in compliance with the Elastic License.
*/
-export { LicenseStatus } from '../../../license_management/public/np_ready/application/sections/license_dashboard/license_status/license_status';
+export { LicenseStatus } from '../../../../../plugins/license_management/public/application/sections/license_dashboard/license_status/license_status';
-export { AddLicense } from '../../../license_management/public/np_ready/application/sections/license_dashboard/add_license/add_license';
+export { AddLicense } from '../../../../../plugins/license_management/public/application/sections/license_dashboard/add_license/add_license';
/*
* For to link to management
*/
-export { BASE_PATH as MANAGEMENT_BASE_PATH } from '../../../license_management/common/constants';
+export { BASE_PATH as MANAGEMENT_BASE_PATH } from '../../../../../plugins/license_management/common/constants';
diff --git a/x-pack/package.json b/x-pack/package.json
index 3c8aa435c3e43..192ecd25b582c 100644
--- a/x-pack/package.json
+++ b/x-pack/package.json
@@ -23,7 +23,7 @@
}
},
"resolutions": {
- "**/@types/node": "10.12.27"
+ "**/@types/node": ">=10.17.17 <10.20.0"
},
"devDependencies": {
"@cypress/webpack-preprocessor": "^4.1.0",
@@ -80,7 +80,7 @@
"@types/mime": "^2.0.1",
"@types/mocha": "^5.2.7",
"@types/nock": "^10.0.3",
- "@types/node": "^10.12.27",
+ "@types/node": ">=10.17.17 <10.20.0",
"@types/node-fetch": "^2.5.0",
"@types/nodemailer": "^6.2.1",
"@types/object-hash": "^1.3.0",
@@ -179,7 +179,7 @@
"@babel/runtime": "^7.5.5",
"@elastic/apm-rum-react": "^0.3.2",
"@elastic/datemath": "5.0.2",
- "@elastic/ems-client": "7.6.0",
+ "@elastic/ems-client": "7.7.0",
"@elastic/eui": "20.0.2",
"@elastic/filesaver": "1.1.2",
"@elastic/maki": "6.1.0",
@@ -317,7 +317,7 @@
"react-sticky": "^6.0.3",
"react-syntax-highlighter": "^5.7.0",
"react-tiny-virtual-list": "^2.2.0",
- "react-use": "^13.13.0",
+ "react-use": "^13.27.0",
"react-vis": "^1.8.1",
"react-visibility-sensor": "^5.1.1",
"recompose": "^0.26.0",
diff --git a/x-pack/plugins/actions/server/builtin_action_types/es_index.test.ts b/x-pack/plugins/actions/server/builtin_action_types/es_index.test.ts
index 0be1983477256..7eded9bb40964 100644
--- a/x-pack/plugins/actions/server/builtin_action_types/es_index.test.ts
+++ b/x-pack/plugins/actions/server/builtin_action_types/es_index.test.ts
@@ -43,18 +43,46 @@ describe('actionTypeRegistry.get() works', () => {
describe('config validation', () => {
test('config validation succeeds when config is valid', () => {
- const config: Record = {};
+ const config: Record = {
+ index: 'testing-123',
+ refresh: false,
+ };
expect(validateConfig(actionType, config)).toEqual({
...config,
- index: null,
+ index: 'testing-123',
+ refresh: false,
});
- config.index = 'testing-123';
+ config.executionTimeField = 'field-123';
expect(validateConfig(actionType, config)).toEqual({
...config,
index: 'testing-123',
+ refresh: false,
+ executionTimeField: 'field-123',
});
+
+ delete config.index;
+
+ expect(() => {
+ validateConfig(actionType, { index: 666 });
+ }).toThrowErrorMatchingInlineSnapshot(
+ `"error validating action type config: [index]: expected value of type [string] but got [number]"`
+ );
+ delete config.executionTimeField;
+
+ expect(() => {
+ validateConfig(actionType, { index: 'testing-123', executionTimeField: true });
+ }).toThrowErrorMatchingInlineSnapshot(
+ `"error validating action type config: [executionTimeField]: expected value of type [string] but got [boolean]"`
+ );
+
+ delete config.refresh;
+ expect(() => {
+ validateConfig(actionType, { index: 'testing-123', refresh: 'foo' });
+ }).toThrowErrorMatchingInlineSnapshot(
+ `"error validating action type config: [refresh]: expected value of type [boolean] but got [string]"`
+ );
});
test('config validation fails when config is not valid', () => {
@@ -65,46 +93,16 @@ describe('config validation', () => {
expect(() => {
validateConfig(actionType, baseConfig);
}).toThrowErrorMatchingInlineSnapshot(
- `"error validating action type config: [indeX]: definition for this key is missing"`
+ `"error validating action type config: [index]: expected value of type [string] but got [undefined]"`
);
-
- delete baseConfig.user;
- baseConfig.index = 666;
-
- expect(() => {
- validateConfig(actionType, baseConfig);
- }).toThrowErrorMatchingInlineSnapshot(`
-"error validating action type config: [index]: types that failed validation:
-- [index.0]: expected value of type [string] but got [number]
-- [index.1]: expected value to equal [null]"
-`);
});
});
describe('params validation', () => {
test('params validation succeeds when params is valid', () => {
const params: Record = {
- index: 'testing-123',
- executionTimeField: 'field-used-for-time',
- refresh: true,
documents: [{ rando: 'thing' }],
};
- expect(validateParams(actionType, params)).toMatchInlineSnapshot(`
- Object {
- "documents": Array [
- Object {
- "rando": "thing",
- },
- ],
- "executionTimeField": "field-used-for-time",
- "index": "testing-123",
- "refresh": true,
- }
- `);
-
- delete params.index;
- delete params.refresh;
- delete params.executionTimeField;
expect(validateParams(actionType, params)).toMatchInlineSnapshot(`
Object {
"documents": Array [
@@ -129,24 +127,6 @@ describe('params validation', () => {
`"error validating action params: [documents]: expected value of type [array] but got [undefined]"`
);
- expect(() => {
- validateParams(actionType, { index: 666 });
- }).toThrowErrorMatchingInlineSnapshot(
- `"error validating action params: [index]: expected value of type [string] but got [number]"`
- );
-
- expect(() => {
- validateParams(actionType, { executionTimeField: true });
- }).toThrowErrorMatchingInlineSnapshot(
- `"error validating action params: [executionTimeField]: expected value of type [string] but got [boolean]"`
- );
-
- expect(() => {
- validateParams(actionType, { refresh: 'foo' });
- }).toThrowErrorMatchingInlineSnapshot(
- `"error validating action params: [refresh]: expected value of type [boolean] but got [string]"`
- );
-
expect(() => {
validateParams(actionType, { documents: ['should be an object'] });
}).toThrowErrorMatchingInlineSnapshot(
@@ -162,13 +142,10 @@ describe('execute()', () => {
let params: ActionParamsType;
let executorOptions: ActionTypeExecutorOptions;
- // minimal params, index via param
- config = { index: null };
+ // minimal params
+ config = { index: 'index-value', refresh: false, executionTimeField: undefined };
params = {
- index: 'index-via-param',
documents: [{ jim: 'bob' }],
- executionTimeField: undefined,
- refresh: undefined,
};
const actionId = 'some-id';
@@ -190,19 +167,17 @@ describe('execute()', () => {
"jim": "bob",
},
],
- "index": "index-via-param",
+ "index": "index-value",
+ "refresh": false,
},
],
]
`);
- // full params (except index), index via config
- config = { index: 'index-via-config' };
+ // full params
+ config = { index: 'index-value', executionTimeField: 'field_to_use_for_time', refresh: true };
params = {
- index: undefined,
documents: [{ jimbob: 'jr' }],
- executionTimeField: 'field_to_use_for_time',
- refresh: true,
};
executorOptions = { actionId, config, secrets, params, services };
@@ -226,20 +201,17 @@ describe('execute()', () => {
"jimbob": "jr",
},
],
- "index": "index-via-config",
+ "index": "index-value",
"refresh": true,
},
],
]
`);
- // minimal params, index via config and param
- config = { index: 'index-via-config' };
+ // minimal params
+ config = { index: 'index-value', executionTimeField: undefined, refresh: false };
params = {
- index: 'index-via-param',
documents: [{ jim: 'bob' }],
- executionTimeField: undefined,
- refresh: undefined,
};
executorOptions = { actionId, config, secrets, params, services };
@@ -259,19 +231,17 @@ describe('execute()', () => {
"jim": "bob",
},
],
- "index": "index-via-config",
+ "index": "index-value",
+ "refresh": false,
},
],
]
`);
// multiple documents
- config = { index: null };
+ config = { index: 'index-value', executionTimeField: undefined, refresh: false };
params = {
- index: 'index-via-param',
documents: [{ a: 1 }, { b: 2 }],
- executionTimeField: undefined,
- refresh: undefined,
};
executorOptions = { actionId, config, secrets, params, services };
@@ -297,7 +267,8 @@ describe('execute()', () => {
"b": 2,
},
],
- "index": "index-via-param",
+ "index": "index-value",
+ "refresh": false,
},
],
]
diff --git a/x-pack/plugins/actions/server/builtin_action_types/es_index.ts b/x-pack/plugins/actions/server/builtin_action_types/es_index.ts
index f8217046b2ea5..b1fe5e3af2d11 100644
--- a/x-pack/plugins/actions/server/builtin_action_types/es_index.ts
+++ b/x-pack/plugins/actions/server/builtin_action_types/es_index.ts
@@ -8,7 +8,6 @@ import { curry } from 'lodash';
import { i18n } from '@kbn/i18n';
import { schema, TypeOf } from '@kbn/config-schema';
-import { nullableType } from './lib/nullable';
import { Logger } from '../../../../../src/core/server';
import { ActionType, ActionTypeExecutorOptions, ActionTypeExecutorResult } from '../types';
@@ -17,7 +16,9 @@ import { ActionType, ActionTypeExecutorOptions, ActionTypeExecutorResult } from
export type ActionTypeConfigType = TypeOf;
const ConfigSchema = schema.object({
- index: nullableType(schema.string()),
+ index: schema.string(),
+ refresh: schema.boolean({ defaultValue: false }),
+ executionTimeField: schema.maybe(schema.string()),
});
// params definition
@@ -28,9 +29,6 @@ export type ActionParamsType = TypeOf;
// - timeout not added here, as this seems to be a generic thing we want to do
// eventually: https://github.com/elastic/kibana/projects/26#card-24087404
const ParamsSchema = schema.object({
- index: schema.maybe(schema.string()),
- executionTimeField: schema.maybe(schema.string()),
- refresh: schema.maybe(schema.boolean()),
documents: schema.arrayOf(schema.recordOf(schema.string(), schema.any())),
});
@@ -60,27 +58,12 @@ async function executor(
const params = execOptions.params as ActionParamsType;
const services = execOptions.services;
- if (config.index == null && params.index == null) {
- const message = i18n.translate('xpack.actions.builtin.esIndex.indexParamRequiredErrorMessage', {
- defaultMessage: 'index param needs to be set because not set in config for action',
- });
- return {
- status: 'error',
- actionId,
- message,
- };
- }
-
- if (config.index != null && params.index != null) {
- logger.debug(`index passed in params overridden by index set in config for action ${actionId}`);
- }
-
- const index = config.index || params.index;
+ const index = config.index;
const bulkBody = [];
for (const document of params.documents) {
- if (params.executionTimeField != null) {
- document[params.executionTimeField] = new Date();
+ if (config.executionTimeField != null) {
+ document[config.executionTimeField] = new Date();
}
bulkBody.push({ index: {} });
@@ -92,9 +75,7 @@ async function executor(
body: bulkBody,
};
- if (params.refresh != null) {
- bulkParams.refresh = params.refresh;
- }
+ bulkParams.refresh = config.refresh;
let result;
try {
@@ -103,6 +84,7 @@ async function executor(
const message = i18n.translate('xpack.actions.builtin.esIndex.errorIndexingErrorMessage', {
defaultMessage: 'error indexing documents',
});
+ logger.error(`error indexing documents: ${err.message}`);
return {
status: 'error',
actionId,
diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/action_handlers.test.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/action_handlers.test.ts
index 381b44439033c..be687e33e2201 100644
--- a/x-pack/plugins/actions/server/builtin_action_types/servicenow/action_handlers.test.ts
+++ b/x-pack/plugins/actions/server/builtin_action_types/servicenow/action_handlers.test.ts
@@ -4,68 +4,157 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { handleCreateIncident, handleUpdateIncident } from './action_handlers';
+import {
+ handleCreateIncident,
+ handleUpdateIncident,
+ handleIncident,
+ createComments,
+} from './action_handlers';
import { ServiceNow } from './lib';
-import { finalMapping } from './mock';
-import { Incident } from './lib/types';
+import { Mapping } from './types';
jest.mock('./lib');
const ServiceNowMock = ServiceNow as jest.Mock;
-const incident: Incident = {
- short_description: 'A title',
- description: 'A description',
-};
+const finalMapping: Mapping = new Map();
+
+finalMapping.set('title', {
+ target: 'short_description',
+ actionType: 'overwrite',
+});
-const comments = [
- {
- commentId: '456',
- version: 'WzU3LDFd',
- comment: 'A comment',
- incidentCommentId: undefined,
+finalMapping.set('description', {
+ target: 'description',
+ actionType: 'overwrite',
+});
+
+finalMapping.set('comments', {
+ target: 'comments',
+ actionType: 'append',
+});
+
+finalMapping.set('short_description', {
+ target: 'title',
+ actionType: 'overwrite',
+});
+
+const params = {
+ caseId: '123',
+ title: 'a title',
+ description: 'a description',
+ createdAt: '2020-03-13T08:34:53.450Z',
+ createdBy: { fullName: 'Elastic User', username: 'elastic' },
+ updatedAt: null,
+ updatedBy: null,
+ incidentId: null,
+ incident: {
+ short_description: 'a title',
+ description: 'a description',
},
-];
+ comments: [
+ {
+ commentId: '456',
+ version: 'WzU3LDFd',
+ comment: 'first comment',
+ createdAt: '2020-03-13T08:34:53.450Z',
+ createdBy: { fullName: 'Elastic User', username: 'elastic' },
+ updatedAt: null,
+ updatedBy: null,
+ },
+ ],
+};
-describe('handleCreateIncident', () => {
- beforeAll(() => {
- ServiceNowMock.mockImplementation(() => {
- return {
- serviceNow: {
- getUserID: jest.fn().mockResolvedValue('1234'),
- createIncident: jest.fn().mockResolvedValue({
- incidentId: '123',
- number: 'INC01',
- pushedDate: '2020-03-10T12:24:20.000Z',
- }),
- updateIncident: jest.fn().mockResolvedValue({
- incidentId: '123',
- number: 'INC01',
- pushedDate: '2020-03-10T12:24:20.000Z',
- }),
- batchCreateComments: jest
- .fn()
- .mockResolvedValue([{ commentId: '456', pushedDate: '2020-03-10T12:24:20.000Z' }]),
- batchUpdateComments: jest
- .fn()
- .mockResolvedValue([{ commentId: '456', pushedDate: '2020-03-10T12:24:20.000Z' }]),
+beforeAll(() => {
+ ServiceNowMock.mockImplementation(() => {
+ return {
+ serviceNow: {
+ getUserID: jest.fn().mockResolvedValue('1234'),
+ getIncident: jest.fn().mockResolvedValue({
+ short_description: 'servicenow title',
+ description: 'servicenow desc',
+ }),
+ createIncident: jest.fn().mockResolvedValue({
+ incidentId: '123',
+ number: 'INC01',
+ pushedDate: '2020-03-10T12:24:20.000Z',
+ }),
+ updateIncident: jest.fn().mockResolvedValue({
+ incidentId: '123',
+ number: 'INC01',
+ pushedDate: '2020-03-10T12:24:20.000Z',
+ }),
+ batchCreateComments: jest
+ .fn()
+ .mockResolvedValue([{ commentId: '456', pushedDate: '2020-03-10T12:24:20.000Z' }]),
+ },
+ };
+ });
+});
+
+describe('handleIncident', () => {
+ test('create an incident', async () => {
+ const { serviceNow } = new ServiceNowMock();
+
+ const res = await handleIncident({
+ incidentId: null,
+ serviceNow,
+ params,
+ comments: params.comments,
+ mapping: finalMapping,
+ });
+ expect(res).toEqual({
+ incidentId: '123',
+ number: 'INC01',
+ pushedDate: '2020-03-10T12:24:20.000Z',
+ comments: [
+ {
+ commentId: '456',
+ pushedDate: '2020-03-10T12:24:20.000Z',
},
- };
+ ],
});
});
+ test('update an incident', async () => {
+ const { serviceNow } = new ServiceNowMock();
+ const res = await handleIncident({
+ incidentId: '123',
+ serviceNow,
+ params,
+ comments: params.comments,
+ mapping: finalMapping,
+ });
+ expect(res).toEqual({
+ incidentId: '123',
+ number: 'INC01',
+ pushedDate: '2020-03-10T12:24:20.000Z',
+ comments: [
+ {
+ commentId: '456',
+ pushedDate: '2020-03-10T12:24:20.000Z',
+ },
+ ],
+ });
+ });
+});
+
+describe('handleCreateIncident', () => {
test('create an incident without comments', async () => {
const { serviceNow } = new ServiceNowMock();
const res = await handleCreateIncident({
serviceNow,
- params: incident,
+ params,
comments: [],
mapping: finalMapping,
});
expect(serviceNow.createIncident).toHaveBeenCalled();
- expect(serviceNow.createIncident).toHaveBeenCalledWith(incident);
+ expect(serviceNow.createIncident).toHaveBeenCalledWith({
+ short_description: 'a title (created at 2020-03-13T08:34:53.450Z by Elastic User)',
+ description: 'a description (created at 2020-03-13T08:34:53.450Z by Elastic User)',
+ });
expect(serviceNow.createIncident).toHaveReturned();
expect(serviceNow.batchCreateComments).not.toHaveBeenCalled();
expect(res).toEqual({
@@ -80,16 +169,36 @@ describe('handleCreateIncident', () => {
const res = await handleCreateIncident({
serviceNow,
- params: incident,
- comments,
+ params,
+ comments: params.comments,
mapping: finalMapping,
});
expect(serviceNow.createIncident).toHaveBeenCalled();
- expect(serviceNow.createIncident).toHaveBeenCalledWith(incident);
+ expect(serviceNow.createIncident).toHaveBeenCalledWith({
+ description: 'a description (created at 2020-03-13T08:34:53.450Z by Elastic User)',
+ short_description: 'a title (created at 2020-03-13T08:34:53.450Z by Elastic User)',
+ });
expect(serviceNow.createIncident).toHaveReturned();
expect(serviceNow.batchCreateComments).toHaveBeenCalled();
- expect(serviceNow.batchCreateComments).toHaveBeenCalledWith('123', comments, 'comments');
+ expect(serviceNow.batchCreateComments).toHaveBeenCalledWith(
+ '123',
+ [
+ {
+ comment: 'first comment (added at 2020-03-13T08:34:53.450Z by Elastic User)',
+ commentId: '456',
+ createdAt: '2020-03-13T08:34:53.450Z',
+ createdBy: {
+ fullName: 'Elastic User',
+ username: 'elastic',
+ },
+ updatedAt: null,
+ updatedBy: null,
+ version: 'WzU3LDFd',
+ },
+ ],
+ 'comments'
+ );
expect(res).toEqual({
incidentId: '123',
number: 'INC01',
@@ -102,22 +211,27 @@ describe('handleCreateIncident', () => {
],
});
});
+});
+describe('handleUpdateIncident', () => {
test('update an incident without comments', async () => {
const { serviceNow } = new ServiceNowMock();
const res = await handleUpdateIncident({
incidentId: '123',
serviceNow,
- params: incident,
+ params,
comments: [],
mapping: finalMapping,
});
expect(serviceNow.updateIncident).toHaveBeenCalled();
- expect(serviceNow.updateIncident).toHaveBeenCalledWith('123', incident);
+ expect(serviceNow.updateIncident).toHaveBeenCalledWith('123', {
+ short_description: 'a title (updated at 2020-03-13T08:34:53.450Z by Elastic User)',
+ description: 'a description (updated at 2020-03-13T08:34:53.450Z by Elastic User)',
+ });
expect(serviceNow.updateIncident).toHaveReturned();
- expect(serviceNow.batchUpdateComments).not.toHaveBeenCalled();
+ expect(serviceNow.batchCreateComments).not.toHaveBeenCalled();
expect(res).toEqual({
incidentId: '123',
number: 'INC01',
@@ -125,23 +239,89 @@ describe('handleCreateIncident', () => {
});
});
- test('update an incident and create new comments', async () => {
+ test('update an incident with comments', async () => {
const { serviceNow } = new ServiceNowMock();
+ serviceNow.batchCreateComments.mockResolvedValue([
+ { commentId: '456', pushedDate: '2020-03-10T12:24:20.000Z' },
+ { commentId: '789', pushedDate: '2020-03-10T12:24:20.000Z' },
+ ]);
const res = await handleUpdateIncident({
incidentId: '123',
serviceNow,
- params: incident,
- comments,
+ params,
+ comments: [
+ {
+ comment: 'first comment',
+ commentId: '456',
+ createdAt: '2020-03-13T08:34:53.450Z',
+ createdBy: {
+ fullName: 'Elastic User',
+ username: 'elastic',
+ },
+ updatedAt: null,
+ updatedBy: null,
+ version: 'WzU3LDFd',
+ },
+ {
+ comment: 'second comment',
+ commentId: '789',
+ createdAt: '2020-03-13T08:34:53.450Z',
+ createdBy: {
+ fullName: 'Elastic User',
+ username: 'elastic',
+ },
+ updatedAt: '2020-03-13T08:34:53.450Z',
+ updatedBy: {
+ fullName: 'Elastic User',
+ username: 'elastic',
+ },
+ version: 'WzU3LDFd',
+ },
+ ],
mapping: finalMapping,
});
expect(serviceNow.updateIncident).toHaveBeenCalled();
- expect(serviceNow.updateIncident).toHaveBeenCalledWith('123', incident);
+ expect(serviceNow.updateIncident).toHaveBeenCalledWith('123', {
+ description: 'a description (updated at 2020-03-13T08:34:53.450Z by Elastic User)',
+ short_description: 'a title (updated at 2020-03-13T08:34:53.450Z by Elastic User)',
+ });
expect(serviceNow.updateIncident).toHaveReturned();
- expect(serviceNow.batchUpdateComments).not.toHaveBeenCalled();
- expect(serviceNow.batchCreateComments).toHaveBeenCalledWith('123', comments, 'comments');
-
+ expect(serviceNow.batchCreateComments).toHaveBeenCalled();
+ expect(serviceNow.batchCreateComments).toHaveBeenCalledWith(
+ '123',
+ [
+ {
+ comment: 'first comment (added at 2020-03-13T08:34:53.450Z by Elastic User)',
+ commentId: '456',
+ createdAt: '2020-03-13T08:34:53.450Z',
+ createdBy: {
+ fullName: 'Elastic User',
+ username: 'elastic',
+ },
+ updatedAt: null,
+ updatedBy: null,
+ version: 'WzU3LDFd',
+ },
+ {
+ comment: 'second comment (added at 2020-03-13T08:34:53.450Z by Elastic User)',
+ commentId: '789',
+ createdAt: '2020-03-13T08:34:53.450Z',
+ createdBy: {
+ fullName: 'Elastic User',
+ username: 'elastic',
+ },
+ updatedAt: '2020-03-13T08:34:53.450Z',
+ updatedBy: {
+ fullName: 'Elastic User',
+ username: 'elastic',
+ },
+ version: 'WzU3LDFd',
+ },
+ ],
+ 'comments'
+ );
expect(res).toEqual({
incidentId: '123',
number: 'INC01',
@@ -151,7 +331,487 @@ describe('handleCreateIncident', () => {
commentId: '456',
pushedDate: '2020-03-10T12:24:20.000Z',
},
+ {
+ commentId: '789',
+ pushedDate: '2020-03-10T12:24:20.000Z',
+ },
],
});
});
});
+
+describe('handleUpdateIncident: different action types', () => {
+ test('overwrite & append', async () => {
+ const { serviceNow } = new ServiceNowMock();
+ finalMapping.set('title', {
+ target: 'short_description',
+ actionType: 'overwrite',
+ });
+
+ finalMapping.set('description', {
+ target: 'description',
+ actionType: 'append',
+ });
+
+ finalMapping.set('comments', {
+ target: 'comments',
+ actionType: 'append',
+ });
+
+ finalMapping.set('short_description', {
+ target: 'title',
+ actionType: 'overwrite',
+ });
+
+ const res = await handleUpdateIncident({
+ incidentId: '123',
+ serviceNow,
+ params,
+ comments: [],
+ mapping: finalMapping,
+ });
+
+ expect(serviceNow.updateIncident).toHaveBeenCalled();
+ expect(serviceNow.updateIncident).toHaveBeenCalledWith('123', {
+ short_description: 'a title (updated at 2020-03-13T08:34:53.450Z by Elastic User)',
+ description:
+ 'servicenow desc \r\na description (updated at 2020-03-13T08:34:53.450Z by Elastic User)',
+ });
+ expect(serviceNow.updateIncident).toHaveReturned();
+ expect(serviceNow.batchCreateComments).not.toHaveBeenCalled();
+ expect(res).toEqual({
+ incidentId: '123',
+ number: 'INC01',
+ pushedDate: '2020-03-10T12:24:20.000Z',
+ });
+ });
+ test('nothing & append', async () => {
+ const { serviceNow } = new ServiceNowMock();
+ finalMapping.set('title', {
+ target: 'short_description',
+ actionType: 'nothing',
+ });
+
+ finalMapping.set('description', {
+ target: 'description',
+ actionType: 'append',
+ });
+
+ finalMapping.set('comments', {
+ target: 'comments',
+ actionType: 'append',
+ });
+
+ finalMapping.set('short_description', {
+ target: 'title',
+ actionType: 'nothing',
+ });
+
+ const res = await handleUpdateIncident({
+ incidentId: '123',
+ serviceNow,
+ params,
+ comments: [],
+ mapping: finalMapping,
+ });
+
+ expect(serviceNow.updateIncident).toHaveBeenCalled();
+ expect(serviceNow.updateIncident).toHaveBeenCalledWith('123', {
+ description:
+ 'servicenow desc \r\na description (updated at 2020-03-13T08:34:53.450Z by Elastic User)',
+ });
+ expect(serviceNow.updateIncident).toHaveReturned();
+ expect(serviceNow.batchCreateComments).not.toHaveBeenCalled();
+ expect(res).toEqual({
+ incidentId: '123',
+ number: 'INC01',
+ pushedDate: '2020-03-10T12:24:20.000Z',
+ });
+ });
+ test('append & append', async () => {
+ const { serviceNow } = new ServiceNowMock();
+ finalMapping.set('title', {
+ target: 'short_description',
+ actionType: 'append',
+ });
+
+ finalMapping.set('description', {
+ target: 'description',
+ actionType: 'append',
+ });
+
+ finalMapping.set('comments', {
+ target: 'comments',
+ actionType: 'append',
+ });
+
+ finalMapping.set('short_description', {
+ target: 'title',
+ actionType: 'append',
+ });
+
+ const res = await handleUpdateIncident({
+ incidentId: '123',
+ serviceNow,
+ params,
+ comments: [],
+ mapping: finalMapping,
+ });
+
+ expect(serviceNow.updateIncident).toHaveBeenCalled();
+ expect(serviceNow.updateIncident).toHaveBeenCalledWith('123', {
+ short_description:
+ 'servicenow title \r\na title (updated at 2020-03-13T08:34:53.450Z by Elastic User)',
+ description:
+ 'servicenow desc \r\na description (updated at 2020-03-13T08:34:53.450Z by Elastic User)',
+ });
+ expect(serviceNow.updateIncident).toHaveReturned();
+ expect(serviceNow.batchCreateComments).not.toHaveBeenCalled();
+ expect(res).toEqual({
+ incidentId: '123',
+ number: 'INC01',
+ pushedDate: '2020-03-10T12:24:20.000Z',
+ });
+ });
+ test('nothing & nothing', async () => {
+ const { serviceNow } = new ServiceNowMock();
+ finalMapping.set('title', {
+ target: 'short_description',
+ actionType: 'nothing',
+ });
+
+ finalMapping.set('description', {
+ target: 'description',
+ actionType: 'nothing',
+ });
+
+ finalMapping.set('comments', {
+ target: 'comments',
+ actionType: 'append',
+ });
+
+ finalMapping.set('short_description', {
+ target: 'title',
+ actionType: 'nothing',
+ });
+
+ const res = await handleUpdateIncident({
+ incidentId: '123',
+ serviceNow,
+ params,
+ comments: [],
+ mapping: finalMapping,
+ });
+
+ expect(serviceNow.updateIncident).toHaveBeenCalled();
+ expect(serviceNow.updateIncident).toHaveBeenCalledWith('123', {});
+ expect(serviceNow.updateIncident).toHaveReturned();
+ expect(serviceNow.batchCreateComments).not.toHaveBeenCalled();
+ expect(res).toEqual({
+ incidentId: '123',
+ number: 'INC01',
+ pushedDate: '2020-03-10T12:24:20.000Z',
+ });
+ });
+ test('overwrite & nothing', async () => {
+ const { serviceNow } = new ServiceNowMock();
+ finalMapping.set('title', {
+ target: 'short_description',
+ actionType: 'overwrite',
+ });
+
+ finalMapping.set('description', {
+ target: 'description',
+ actionType: 'nothing',
+ });
+
+ finalMapping.set('comments', {
+ target: 'comments',
+ actionType: 'append',
+ });
+
+ finalMapping.set('short_description', {
+ target: 'title',
+ actionType: 'overwrite',
+ });
+
+ const res = await handleUpdateIncident({
+ incidentId: '123',
+ serviceNow,
+ params,
+ comments: [],
+ mapping: finalMapping,
+ });
+
+ expect(serviceNow.updateIncident).toHaveBeenCalled();
+ expect(serviceNow.updateIncident).toHaveBeenCalledWith('123', {
+ short_description: 'a title (updated at 2020-03-13T08:34:53.450Z by Elastic User)',
+ });
+ expect(serviceNow.updateIncident).toHaveReturned();
+ expect(serviceNow.batchCreateComments).not.toHaveBeenCalled();
+ expect(res).toEqual({
+ incidentId: '123',
+ number: 'INC01',
+ pushedDate: '2020-03-10T12:24:20.000Z',
+ });
+ });
+ test('overwrite & overwrite', async () => {
+ const { serviceNow } = new ServiceNowMock();
+ finalMapping.set('title', {
+ target: 'short_description',
+ actionType: 'overwrite',
+ });
+
+ finalMapping.set('description', {
+ target: 'description',
+ actionType: 'overwrite',
+ });
+
+ finalMapping.set('comments', {
+ target: 'comments',
+ actionType: 'append',
+ });
+
+ finalMapping.set('short_description', {
+ target: 'title',
+ actionType: 'overwrite',
+ });
+
+ const res = await handleUpdateIncident({
+ incidentId: '123',
+ serviceNow,
+ params,
+ comments: [],
+ mapping: finalMapping,
+ });
+
+ expect(serviceNow.updateIncident).toHaveBeenCalled();
+ expect(serviceNow.updateIncident).toHaveBeenCalledWith('123', {
+ short_description: 'a title (updated at 2020-03-13T08:34:53.450Z by Elastic User)',
+ description: 'a description (updated at 2020-03-13T08:34:53.450Z by Elastic User)',
+ });
+ expect(serviceNow.updateIncident).toHaveReturned();
+ expect(serviceNow.batchCreateComments).not.toHaveBeenCalled();
+ expect(res).toEqual({
+ incidentId: '123',
+ number: 'INC01',
+ pushedDate: '2020-03-10T12:24:20.000Z',
+ });
+ });
+ test('nothing & overwrite', async () => {
+ const { serviceNow } = new ServiceNowMock();
+ finalMapping.set('title', {
+ target: 'short_description',
+ actionType: 'nothing',
+ });
+
+ finalMapping.set('description', {
+ target: 'description',
+ actionType: 'overwrite',
+ });
+
+ finalMapping.set('comments', {
+ target: 'comments',
+ actionType: 'append',
+ });
+
+ finalMapping.set('short_description', {
+ target: 'title',
+ actionType: 'nothing',
+ });
+
+ const res = await handleUpdateIncident({
+ incidentId: '123',
+ serviceNow,
+ params,
+ comments: [],
+ mapping: finalMapping,
+ });
+
+ expect(serviceNow.updateIncident).toHaveBeenCalled();
+ expect(serviceNow.updateIncident).toHaveBeenCalledWith('123', {
+ description: 'a description (updated at 2020-03-13T08:34:53.450Z by Elastic User)',
+ });
+ expect(serviceNow.updateIncident).toHaveReturned();
+ expect(serviceNow.batchCreateComments).not.toHaveBeenCalled();
+ expect(res).toEqual({
+ incidentId: '123',
+ number: 'INC01',
+ pushedDate: '2020-03-10T12:24:20.000Z',
+ });
+ });
+ test('append & overwrite', async () => {
+ const { serviceNow } = new ServiceNowMock();
+ finalMapping.set('title', {
+ target: 'short_description',
+ actionType: 'append',
+ });
+
+ finalMapping.set('description', {
+ target: 'description',
+ actionType: 'overwrite',
+ });
+
+ finalMapping.set('comments', {
+ target: 'comments',
+ actionType: 'append',
+ });
+
+ finalMapping.set('short_description', {
+ target: 'title',
+ actionType: 'append',
+ });
+
+ const res = await handleUpdateIncident({
+ incidentId: '123',
+ serviceNow,
+ params,
+ comments: [],
+ mapping: finalMapping,
+ });
+
+ expect(serviceNow.updateIncident).toHaveBeenCalled();
+ expect(serviceNow.updateIncident).toHaveBeenCalledWith('123', {
+ short_description:
+ 'servicenow title \r\na title (updated at 2020-03-13T08:34:53.450Z by Elastic User)',
+ description: 'a description (updated at 2020-03-13T08:34:53.450Z by Elastic User)',
+ });
+ expect(serviceNow.updateIncident).toHaveReturned();
+ expect(serviceNow.batchCreateComments).not.toHaveBeenCalled();
+ expect(res).toEqual({
+ incidentId: '123',
+ number: 'INC01',
+ pushedDate: '2020-03-10T12:24:20.000Z',
+ });
+ });
+ test('append & nothing', async () => {
+ const { serviceNow } = new ServiceNowMock();
+ finalMapping.set('title', {
+ target: 'short_description',
+ actionType: 'append',
+ });
+
+ finalMapping.set('description', {
+ target: 'description',
+ actionType: 'nothing',
+ });
+
+ finalMapping.set('comments', {
+ target: 'comments',
+ actionType: 'append',
+ });
+
+ finalMapping.set('short_description', {
+ target: 'title',
+ actionType: 'append',
+ });
+
+ const res = await handleUpdateIncident({
+ incidentId: '123',
+ serviceNow,
+ params,
+ comments: [],
+ mapping: finalMapping,
+ });
+
+ expect(serviceNow.updateIncident).toHaveBeenCalled();
+ expect(serviceNow.updateIncident).toHaveBeenCalledWith('123', {
+ short_description:
+ 'servicenow title \r\na title (updated at 2020-03-13T08:34:53.450Z by Elastic User)',
+ });
+ expect(serviceNow.updateIncident).toHaveReturned();
+ expect(serviceNow.batchCreateComments).not.toHaveBeenCalled();
+ expect(res).toEqual({
+ incidentId: '123',
+ number: 'INC01',
+ pushedDate: '2020-03-10T12:24:20.000Z',
+ });
+ });
+});
+
+describe('createComments', () => {
+ test('create comments correctly', async () => {
+ const { serviceNow } = new ServiceNowMock();
+ serviceNow.batchCreateComments.mockResolvedValue([
+ { commentId: '456', pushedDate: '2020-03-10T12:24:20.000Z' },
+ { commentId: '789', pushedDate: '2020-03-10T12:24:20.000Z' },
+ ]);
+
+ const comments = [
+ {
+ comment: 'first comment',
+ commentId: '456',
+ createdAt: '2020-03-13T08:34:53.450Z',
+ createdBy: {
+ fullName: 'Elastic User',
+ username: 'elastic',
+ },
+ updatedAt: null,
+ updatedBy: null,
+ version: 'WzU3LDFd',
+ },
+ {
+ comment: 'second comment',
+ commentId: '789',
+ createdAt: '2020-03-13T08:34:53.450Z',
+ createdBy: {
+ fullName: 'Elastic User',
+ username: 'elastic',
+ },
+ updatedAt: '2020-03-13T08:34:53.450Z',
+ updatedBy: {
+ fullName: 'Elastic User',
+ username: 'elastic',
+ },
+ version: 'WzU3LDFd',
+ },
+ ];
+
+ const res = await createComments(serviceNow, '123', 'comments', comments);
+
+ expect(serviceNow.batchCreateComments).toHaveBeenCalled();
+ expect(serviceNow.batchCreateComments).toHaveBeenCalledWith(
+ '123',
+ [
+ {
+ comment: 'first comment',
+ commentId: '456',
+ createdAt: '2020-03-13T08:34:53.450Z',
+ createdBy: {
+ fullName: 'Elastic User',
+ username: 'elastic',
+ },
+ updatedAt: null,
+ updatedBy: null,
+ version: 'WzU3LDFd',
+ },
+ {
+ comment: 'second comment',
+ commentId: '789',
+ createdAt: '2020-03-13T08:34:53.450Z',
+ createdBy: {
+ fullName: 'Elastic User',
+ username: 'elastic',
+ },
+ updatedAt: '2020-03-13T08:34:53.450Z',
+ updatedBy: {
+ fullName: 'Elastic User',
+ username: 'elastic',
+ },
+ version: 'WzU3LDFd',
+ },
+ ],
+ 'comments'
+ );
+ expect(res).toEqual([
+ {
+ commentId: '456',
+ pushedDate: '2020-03-10T12:24:20.000Z',
+ },
+ {
+ commentId: '789',
+ pushedDate: '2020-03-10T12:24:20.000Z',
+ },
+ ]);
+ });
+});
diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/action_handlers.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/action_handlers.ts
index 47120c5da096d..6439a68813fd5 100644
--- a/x-pack/plugins/actions/server/builtin_action_types/servicenow/action_handlers.ts
+++ b/x-pack/plugins/actions/server/builtin_action_types/servicenow/action_handlers.ts
@@ -5,26 +5,27 @@
*/
import { zipWith } from 'lodash';
-import { Incident, CommentResponse } from './lib/types';
+import { CommentResponse } from './lib/types';
import {
- ActionHandlerArguments,
- UpdateParamsType,
- UpdateActionHandlerArguments,
- IncidentCreationResponse,
- CommentType,
- CommentsZipped,
+ HandlerResponse,
+ Comment,
+ SimpleComment,
+ CreateHandlerArguments,
+ UpdateHandlerArguments,
+ IncidentHandlerArguments,
} from './types';
import { ServiceNow } from './lib';
+import { transformFields, prepareFieldsForTransformation, transformComments } from './helpers';
-const createComments = async (
+export const createComments = async (
serviceNow: ServiceNow,
incidentId: string,
key: string,
- comments: CommentType[]
-): Promise => {
+ comments: Comment[]
+): Promise => {
const createdComments = await serviceNow.batchCreateComments(incidentId, comments, key);
- return zipWith(comments, createdComments, (a: CommentType, b: CommentResponse) => ({
+ return zipWith(comments, createdComments, (a: Comment, b: CommentResponse) => ({
commentId: a.commentId,
pushedDate: b.pushedDate,
}));
@@ -35,16 +36,30 @@ export const handleCreateIncident = async ({
params,
comments,
mapping,
-}: ActionHandlerArguments): Promise => {
- const paramsAsIncident = params as Incident;
+}: CreateHandlerArguments): Promise => {
+ const fields = prepareFieldsForTransformation({
+ params,
+ mapping,
+ });
+
+ const incident = transformFields({
+ params,
+ fields,
+ });
const { incidentId, number, pushedDate } = await serviceNow.createIncident({
- ...paramsAsIncident,
+ ...incident,
});
- const res: IncidentCreationResponse = { incidentId, number, pushedDate };
+ const res: HandlerResponse = { incidentId, number, pushedDate };
- if (comments && Array.isArray(comments) && comments.length > 0) {
+ if (
+ comments &&
+ Array.isArray(comments) &&
+ comments.length > 0 &&
+ mapping.get('comments').actionType !== 'nothing'
+ ) {
+ comments = transformComments(comments, params, ['informationAdded']);
res.comments = [
...(await createComments(serviceNow, incidentId, mapping.get('comments').target, comments)),
];
@@ -59,16 +74,33 @@ export const handleUpdateIncident = async ({
params,
comments,
mapping,
-}: UpdateActionHandlerArguments): Promise => {
- const paramsAsIncident = params as UpdateParamsType;
+}: UpdateHandlerArguments): Promise => {
+ const currentIncident = await serviceNow.getIncident(incidentId);
+ const fields = prepareFieldsForTransformation({
+ params,
+ mapping,
+ defaultPipes: ['informationUpdated'],
+ });
+
+ const incident = transformFields({
+ params,
+ fields,
+ currentIncident,
+ });
const { number, pushedDate } = await serviceNow.updateIncident(incidentId, {
- ...paramsAsIncident,
+ ...incident,
});
- const res: IncidentCreationResponse = { incidentId, number, pushedDate };
+ const res: HandlerResponse = { incidentId, number, pushedDate };
- if (comments && Array.isArray(comments) && comments.length > 0) {
+ if (
+ comments &&
+ Array.isArray(comments) &&
+ comments.length > 0 &&
+ mapping.get('comments').actionType !== 'nothing'
+ ) {
+ comments = transformComments(comments, params, ['informationAdded']);
res.comments = [
...(await createComments(serviceNow, incidentId, mapping.get('comments').target, comments)),
];
@@ -76,3 +108,17 @@ export const handleUpdateIncident = async ({
return { ...res };
};
+
+export const handleIncident = async ({
+ incidentId,
+ serviceNow,
+ params,
+ comments,
+ mapping,
+}: IncidentHandlerArguments): Promise => {
+ if (!incidentId) {
+ return await handleCreateIncident({ serviceNow, params, comments, mapping });
+ } else {
+ return await handleUpdateIncident({ incidentId, serviceNow, params, comments, mapping });
+ }
+};
diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/helpers.test.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/helpers.test.ts
index 96962b41b3c68..ce8c3542ab69f 100644
--- a/x-pack/plugins/actions/server/builtin_action_types/servicenow/helpers.test.ts
+++ b/x-pack/plugins/actions/server/builtin_action_types/servicenow/helpers.test.ts
@@ -4,18 +4,62 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { normalizeMapping, buildMap, mapParams } from './helpers';
+import {
+ normalizeMapping,
+ buildMap,
+ mapParams,
+ appendField,
+ appendInformationToField,
+ prepareFieldsForTransformation,
+ transformFields,
+ transformComments,
+} from './helpers';
import { mapping, finalMapping } from './mock';
import { SUPPORTED_SOURCE_FIELDS } from './constants';
-import { MapsType } from './types';
+import { MapEntry, Params, Comment } from './types';
-const maliciousMapping: MapsType[] = [
+const maliciousMapping: MapEntry[] = [
{ source: '__proto__', target: 'short_description', actionType: 'nothing' },
{ source: 'description', target: '__proto__', actionType: 'nothing' },
{ source: 'comments', target: 'comments', actionType: 'nothing' },
{ source: 'unsupportedSource', target: 'comments', actionType: 'nothing' },
];
+const fullParams: Params = {
+ caseId: 'd4387ac5-0899-4dc2-bbfa-0dd605c934aa',
+ title: 'a title',
+ description: 'a description',
+ createdAt: '2020-03-13T08:34:53.450Z',
+ createdBy: { fullName: 'Elastic User', username: 'elastic' },
+ updatedAt: null,
+ updatedBy: null,
+ incidentId: null,
+ incident: {
+ short_description: 'a title',
+ description: 'a description',
+ },
+ comments: [
+ {
+ commentId: 'b5b4c4d0-574e-11ea-9e2e-21b90f8a9631',
+ version: 'WzU3LDFd',
+ comment: 'first comment',
+ createdAt: '2020-03-13T08:34:53.450Z',
+ createdBy: { fullName: 'Elastic User', username: 'elastic' },
+ updatedAt: null,
+ updatedBy: null,
+ },
+ {
+ commentId: 'b5b4c4d0-574e-11ea-9e2e-21b90f8a9631',
+ version: 'WzU3LDFd',
+ comment: 'second comment',
+ createdAt: '2020-03-13T08:34:53.450Z',
+ createdBy: { fullName: 'Elastic User', username: 'elastic' },
+ updatedAt: null,
+ updatedBy: null,
+ },
+ ],
+};
+
describe('sanitizeMapping', () => {
test('remove malicious fields', () => {
const sanitizedMapping = normalizeMapping(SUPPORTED_SOURCE_FIELDS, maliciousMapping);
@@ -81,3 +125,251 @@ describe('mapParams', () => {
expect(fields).not.toEqual(expect.objectContaining(unexpectedFields));
});
});
+
+describe('prepareFieldsForTransformation', () => {
+ test('prepare fields with defaults', () => {
+ const res = prepareFieldsForTransformation({
+ params: fullParams,
+ mapping: finalMapping,
+ });
+ expect(res).toEqual([
+ {
+ key: 'short_description',
+ value: 'a title',
+ actionType: 'overwrite',
+ pipes: ['informationCreated'],
+ },
+ {
+ key: 'description',
+ value: 'a description',
+ actionType: 'append',
+ pipes: ['informationCreated', 'append'],
+ },
+ ]);
+ });
+
+ test('prepare fields with default pipes', () => {
+ const res = prepareFieldsForTransformation({
+ params: fullParams,
+ mapping: finalMapping,
+ defaultPipes: ['myTestPipe'],
+ });
+ expect(res).toEqual([
+ {
+ key: 'short_description',
+ value: 'a title',
+ actionType: 'overwrite',
+ pipes: ['myTestPipe'],
+ },
+ {
+ key: 'description',
+ value: 'a description',
+ actionType: 'append',
+ pipes: ['myTestPipe', 'append'],
+ },
+ ]);
+ });
+});
+
+describe('transformFields', () => {
+ test('transform fields for creation correctly', () => {
+ const fields = prepareFieldsForTransformation({
+ params: fullParams,
+ mapping: finalMapping,
+ });
+
+ const res = transformFields({
+ params: fullParams,
+ fields,
+ });
+
+ expect(res).toEqual({
+ short_description: 'a title (created at 2020-03-13T08:34:53.450Z by Elastic User)',
+ description: 'a description (created at 2020-03-13T08:34:53.450Z by Elastic User)',
+ });
+ });
+
+ test('transform fields for update correctly', () => {
+ const fields = prepareFieldsForTransformation({
+ params: fullParams,
+ mapping: finalMapping,
+ defaultPipes: ['informationUpdated'],
+ });
+
+ const res = transformFields({
+ params: fullParams,
+ fields,
+ currentIncident: {
+ short_description: 'first title (created at 2020-03-13T08:34:53.450Z by Elastic User)',
+ description: 'first description (created at 2020-03-13T08:34:53.450Z by Elastic User)',
+ },
+ });
+ expect(res).toEqual({
+ short_description: 'a title (updated at 2020-03-13T08:34:53.450Z by Elastic User)',
+ description:
+ 'first description (created at 2020-03-13T08:34:53.450Z by Elastic User) \r\na description (updated at 2020-03-13T08:34:53.450Z by Elastic User)',
+ });
+ });
+
+ test('add newline character to descripton', () => {
+ const fields = prepareFieldsForTransformation({
+ params: fullParams,
+ mapping: finalMapping,
+ defaultPipes: ['informationUpdated'],
+ });
+
+ const res = transformFields({
+ params: fullParams,
+ fields,
+ currentIncident: {
+ short_description: 'first title',
+ description: 'first description',
+ },
+ });
+ expect(res.description?.includes('\r\n')).toBe(true);
+ });
+
+ test('append username if fullname is undefined', () => {
+ const fields = prepareFieldsForTransformation({
+ params: fullParams,
+ mapping: finalMapping,
+ });
+
+ const res = transformFields({
+ params: { ...fullParams, createdBy: { fullName: null, username: 'elastic' } },
+ fields,
+ });
+
+ expect(res).toEqual({
+ short_description: 'a title (created at 2020-03-13T08:34:53.450Z by elastic)',
+ description: 'a description (created at 2020-03-13T08:34:53.450Z by elastic)',
+ });
+ });
+});
+
+describe('appendField', () => {
+ test('prefix correctly', () => {
+ expect('my_prefixmy_value ').toEqual(appendField({ value: 'my_value', prefix: 'my_prefix' }));
+ });
+
+ test('suffix correctly', () => {
+ expect('my_value my_suffix').toEqual(appendField({ value: 'my_value', suffix: 'my_suffix' }));
+ });
+
+ test('prefix and suffix correctly', () => {
+ expect('my_prefixmy_value my_suffix').toEqual(
+ appendField({ value: 'my_value', prefix: 'my_prefix', suffix: 'my_suffix' })
+ );
+ });
+});
+
+describe('appendInformationToField', () => {
+ test('creation mode', () => {
+ const res = appendInformationToField({
+ value: 'my value',
+ user: 'Elastic Test User',
+ date: '2020-03-13T08:34:53.450Z',
+ mode: 'create',
+ });
+ expect(res).toEqual('my value (created at 2020-03-13T08:34:53.450Z by Elastic Test User)');
+ });
+
+ test('update mode', () => {
+ const res = appendInformationToField({
+ value: 'my value',
+ user: 'Elastic Test User',
+ date: '2020-03-13T08:34:53.450Z',
+ mode: 'update',
+ });
+ expect(res).toEqual('my value (updated at 2020-03-13T08:34:53.450Z by Elastic Test User)');
+ });
+
+ test('add mode', () => {
+ const res = appendInformationToField({
+ value: 'my value',
+ user: 'Elastic Test User',
+ date: '2020-03-13T08:34:53.450Z',
+ mode: 'add',
+ });
+ expect(res).toEqual('my value (added at 2020-03-13T08:34:53.450Z by Elastic Test User)');
+ });
+});
+
+describe('transformComments', () => {
+ test('transform creation comments', () => {
+ const comments: Comment[] = [
+ {
+ commentId: 'b5b4c4d0-574e-11ea-9e2e-21b90f8a9631',
+ version: 'WzU3LDFd',
+ comment: 'first comment',
+ createdAt: '2020-03-13T08:34:53.450Z',
+ createdBy: { fullName: 'Elastic User', username: 'elastic' },
+ updatedAt: null,
+ updatedBy: null,
+ },
+ ];
+ const res = transformComments(comments, fullParams, ['informationCreated']);
+ expect(res).toEqual([
+ {
+ commentId: 'b5b4c4d0-574e-11ea-9e2e-21b90f8a9631',
+ version: 'WzU3LDFd',
+ comment: 'first comment (created at 2020-03-13T08:34:53.450Z by Elastic User)',
+ createdAt: '2020-03-13T08:34:53.450Z',
+ createdBy: { fullName: 'Elastic User', username: 'elastic' },
+ updatedAt: null,
+ updatedBy: null,
+ },
+ ]);
+ });
+
+ test('transform update comments', () => {
+ const comments: Comment[] = [
+ {
+ commentId: 'b5b4c4d0-574e-11ea-9e2e-21b90f8a9631',
+ version: 'WzU3LDFd',
+ comment: 'first comment',
+ createdAt: '2020-03-13T08:34:53.450Z',
+ createdBy: { fullName: 'Elastic User', username: 'elastic' },
+ updatedAt: null,
+ updatedBy: null,
+ },
+ ];
+ const res = transformComments(comments, fullParams, ['informationUpdated']);
+ expect(res).toEqual([
+ {
+ commentId: 'b5b4c4d0-574e-11ea-9e2e-21b90f8a9631',
+ version: 'WzU3LDFd',
+ comment: 'first comment (updated at 2020-03-13T08:34:53.450Z by Elastic User)',
+ createdAt: '2020-03-13T08:34:53.450Z',
+ createdBy: { fullName: 'Elastic User', username: 'elastic' },
+ updatedAt: null,
+ updatedBy: null,
+ },
+ ]);
+ });
+ test('transform added comments', () => {
+ const comments: Comment[] = [
+ {
+ commentId: 'b5b4c4d0-574e-11ea-9e2e-21b90f8a9631',
+ version: 'WzU3LDFd',
+ comment: 'first comment',
+ createdAt: '2020-03-13T08:34:53.450Z',
+ createdBy: { fullName: 'Elastic User', username: 'elastic' },
+ updatedAt: null,
+ updatedBy: null,
+ },
+ ];
+ const res = transformComments(comments, fullParams, ['informationAdded']);
+ expect(res).toEqual([
+ {
+ commentId: 'b5b4c4d0-574e-11ea-9e2e-21b90f8a9631',
+ version: 'WzU3LDFd',
+ comment: 'first comment (added at 2020-03-13T08:34:53.450Z by Elastic User)',
+ createdAt: '2020-03-13T08:34:53.450Z',
+ createdBy: { fullName: 'Elastic User', username: 'elastic' },
+ updatedAt: null,
+ updatedBy: null,
+ },
+ ]);
+ });
+});
diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/helpers.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/helpers.ts
index 99e67c1c43f35..46d4789e0bd53 100644
--- a/x-pack/plugins/actions/server/builtin_action_types/servicenow/helpers.ts
+++ b/x-pack/plugins/actions/server/builtin_action_types/servicenow/helpers.ts
@@ -3,18 +3,34 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
+import { flow } from 'lodash';
import { SUPPORTED_SOURCE_FIELDS } from './constants';
-import { MapsType, FinalMapping } from './types';
+import {
+ MapEntry,
+ Mapping,
+ AppendFieldArgs,
+ AppendInformationFieldArgs,
+ Params,
+ Comment,
+ TransformFieldsArgs,
+ PipedField,
+ PrepareFieldsForTransformArgs,
+ KeyAny,
+} from './types';
+import { Incident } from './lib/types';
-export const normalizeMapping = (fields: string[], mapping: MapsType[]): MapsType[] => {
+import * as transformers from './transformers';
+import * as i18n from './translations';
+
+export const normalizeMapping = (supportedFields: string[], mapping: MapEntry[]): MapEntry[] => {
// Prevent prototype pollution and remove unsupported fields
return mapping.filter(
- m => m.source !== '__proto__' && m.target !== '__proto__' && fields.includes(m.source)
+ m => m.source !== '__proto__' && m.target !== '__proto__' && supportedFields.includes(m.source)
);
};
-export const buildMap = (mapping: MapsType[]): FinalMapping => {
+export const buildMap = (mapping: MapEntry[]): Mapping => {
return normalizeMapping(SUPPORTED_SOURCE_FIELDS, mapping).reduce((fieldsMap, field) => {
const { source, target, actionType } = field;
fieldsMap.set(source, { target, actionType });
@@ -23,11 +39,7 @@ export const buildMap = (mapping: MapsType[]): FinalMapping => {
}, new Map());
};
-interface KeyAny {
- [key: string]: unknown;
-}
-
-export const mapParams = (params: any, mapping: FinalMapping) => {
+export const mapParams = (params: any, mapping: Mapping) => {
return Object.keys(params).reduce((prev: KeyAny, curr: string): KeyAny => {
const field = mapping.get(curr);
if (field) {
@@ -36,3 +48,72 @@ export const mapParams = (params: any, mapping: FinalMapping) => {
return prev;
}, {});
};
+
+export const appendField = ({ value, prefix = '', suffix = '' }: AppendFieldArgs): string => {
+ return `${prefix}${value} ${suffix}`;
+};
+
+const t = { ...transformers } as { [index: string]: Function }; // TODO: Find a better solution exists.
+
+export const prepareFieldsForTransformation = ({
+ params,
+ mapping,
+ defaultPipes = ['informationCreated'],
+}: PrepareFieldsForTransformArgs): PipedField[] => {
+ return Object.keys(params.incident)
+ .filter(p => mapping.get(p).actionType !== 'nothing')
+ .map(p => ({
+ key: p,
+ value: params.incident[p],
+ actionType: mapping.get(p).actionType,
+ pipes: [...defaultPipes],
+ }))
+ .map(p => ({
+ ...p,
+ pipes: p.actionType === 'append' ? [...p.pipes, 'append'] : p.pipes,
+ }));
+};
+
+export const transformFields = ({
+ params,
+ fields,
+ currentIncident,
+}: TransformFieldsArgs): Incident => {
+ return fields.reduce((prev: Incident, cur) => {
+ const transform = flow(...cur.pipes.map(p => t[p]));
+ prev[cur.key] = transform({
+ value: cur.value,
+ date: params.createdAt,
+ user: params.createdBy.fullName ?? params.createdBy.username,
+ previousValue: currentIncident ? currentIncident[cur.key] : '',
+ }).value;
+ return prev;
+ }, {} as Incident);
+};
+
+export const appendInformationToField = ({
+ value,
+ user,
+ date,
+ mode = 'create',
+}: AppendInformationFieldArgs): string => {
+ return appendField({
+ value,
+ suffix: i18n.FIELD_INFORMATION(mode, date, user),
+ });
+};
+
+export const transformComments = (
+ comments: Comment[],
+ params: Params,
+ pipes: string[]
+): Comment[] => {
+ return comments.map(c => ({
+ ...c,
+ comment: flow(...pipes.map(p => t[p]))({
+ value: c.comment,
+ date: params.createdAt,
+ user: params.createdBy.fullName ?? '',
+ }).value,
+ }));
+};
diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/index.test.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/index.test.ts
index a1df243b0ee7c..8ee81c5e76451 100644
--- a/x-pack/plugins/actions/server/builtin_action_types/servicenow/index.test.ts
+++ b/x-pack/plugins/actions/server/builtin_action_types/servicenow/index.test.ts
@@ -14,13 +14,12 @@ import { configUtilsMock } from '../../actions_config.mock';
import { ACTION_TYPE_ID } from './constants';
import * as i18n from './translations';
-import { handleCreateIncident, handleUpdateIncident } from './action_handlers';
+import { handleIncident } from './action_handlers';
import { incidentResponse } from './mock';
jest.mock('./action_handlers');
-const handleCreateIncidentMock = handleCreateIncident as jest.Mock;
-const handleUpdateIncidentMock = handleUpdateIncident as jest.Mock;
+const handleIncidentMock = handleIncident as jest.Mock;
const services: Services = {
callCluster: async (path: string, opts: any) => {},
@@ -63,12 +62,19 @@ const mockOptions = {
incidentId: 'ceb5986e079f00100e48fbbf7c1ed06d',
title: 'Incident title',
description: 'Incident description',
+ createdAt: '2020-03-13T08:34:53.450Z',
+ createdBy: { fullName: 'Elastic User', username: 'elastic' },
+ updatedAt: null,
+ updatedBy: null,
comments: [
{
commentId: 'b5b4c4d0-574e-11ea-9e2e-21b90f8a9631',
version: 'WzU3LDFd',
comment: 'A comment',
- incidentCommentId: '315e1ece071300100e48fbbf7c1ed0d0',
+ createdAt: '2020-03-13T08:34:53.450Z',
+ createdBy: { fullName: 'Elastic User', username: 'elastic' },
+ updatedAt: null,
+ updatedBy: null,
},
],
},
@@ -169,8 +175,7 @@ describe('validateParams()', () => {
describe('execute()', () => {
beforeEach(() => {
- handleCreateIncidentMock.mockReset();
- handleUpdateIncidentMock.mockReset();
+ handleIncidentMock.mockReset();
});
test('should create an incident', async () => {
@@ -185,7 +190,7 @@ describe('execute()', () => {
services,
};
- handleCreateIncidentMock.mockImplementation(() => incidentResponse);
+ handleIncidentMock.mockImplementation(() => incidentResponse);
const actionResponse = await actionType.executor(executorOptions);
expect(actionResponse).toEqual({ actionId, status: 'ok', data: incidentResponse });
@@ -205,7 +210,7 @@ describe('execute()', () => {
};
const errorMessage = 'Failed to create incident';
- handleCreateIncidentMock.mockImplementation(() => {
+ handleIncidentMock.mockImplementation(() => {
throw new Error(errorMessage);
});
@@ -243,7 +248,7 @@ describe('execute()', () => {
};
const errorMessage = 'Failed to update incident';
- handleUpdateIncidentMock.mockImplementation(() => {
+ handleIncidentMock.mockImplementation(() => {
throw new Error(errorMessage);
});
diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/index.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/index.ts
index 01e566af17d08..f844bef6441ee 100644
--- a/x-pack/plugins/actions/server/builtin_action_types/servicenow/index.ts
+++ b/x-pack/plugins/actions/server/builtin_action_types/servicenow/index.ts
@@ -18,12 +18,12 @@ import { ServiceNow } from './lib';
import * as i18n from './translations';
import { ACTION_TYPE_ID } from './constants';
-import { ConfigType, SecretsType, ParamsType, CommentType } from './types';
+import { ConfigType, SecretsType, Comment, ExecutorParams } from './types';
import { ConfigSchemaProps, SecretsSchemaProps, ParamsSchema } from './schema';
import { buildMap, mapParams } from './helpers';
-import { handleCreateIncident, handleUpdateIncident } from './action_handlers';
+import { handleIncident } from './action_handlers';
function validateConfig(
configurationUtilities: ActionsConfigurationUtilities,
@@ -77,21 +77,22 @@ async function serviceNowExecutor(
const actionId = execOptions.actionId;
const {
apiUrl,
- casesConfiguration: { mapping },
+ casesConfiguration: { mapping: configurationMapping },
} = execOptions.config as ConfigType;
const { username, password } = execOptions.secrets as SecretsType;
- const params = execOptions.params as ParamsType;
+ const params = execOptions.params as ExecutorParams;
const { comments, incidentId, ...restParams } = params;
- const finalMap = buildMap(mapping);
- const restParamsMapped = mapParams(restParams, finalMap);
+ const mapping = buildMap(configurationMapping);
+ const incident = mapParams(restParams, mapping);
const serviceNow = new ServiceNow({ url: apiUrl, username, password });
const handlerInput = {
+ incidentId,
serviceNow,
- params: restParamsMapped,
- comments: comments as CommentType[],
- mapping: finalMap,
+ params: { ...params, incident },
+ comments: comments as Comment[],
+ mapping,
};
const res: Pick &
@@ -100,13 +101,7 @@ async function serviceNowExecutor(
actionId,
};
- let data = {};
-
- if (!incidentId) {
- data = await handleCreateIncident(handlerInput);
- } else {
- data = await handleUpdateIncident({ incidentId, ...handlerInput });
- }
+ const data = await handleIncident(handlerInput);
return {
...res,
diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/lib/index.test.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/lib/index.test.ts
index 22be625611e85..17c8bce651403 100644
--- a/x-pack/plugins/actions/server/builtin_action_types/servicenow/lib/index.test.ts
+++ b/x-pack/plugins/actions/server/builtin_action_types/servicenow/lib/index.test.ts
@@ -132,7 +132,10 @@ describe('ServiceNow lib', () => {
commentId: '456',
version: 'WzU3LDFd',
comment: 'A comment',
- incidentCommentId: undefined,
+ createdAt: '2020-03-13T08:34:53.450Z',
+ createdBy: { fullName: 'Elastic User', username: 'elastic' },
+ updatedAt: null,
+ updatedBy: null,
};
const res = await serviceNow.createComment('123', comment, 'comments');
@@ -173,13 +176,19 @@ describe('ServiceNow lib', () => {
commentId: '123',
version: 'WzU3LDFd',
comment: 'A comment',
- incidentCommentId: undefined,
+ createdAt: '2020-03-13T08:34:53.450Z',
+ createdBy: { fullName: 'Elastic User', username: 'elastic' },
+ updatedAt: null,
+ updatedBy: null,
},
{
commentId: '456',
version: 'WzU3LDFd',
comment: 'A second comment',
- incidentCommentId: undefined,
+ createdAt: '2020-03-13T08:34:53.450Z',
+ createdBy: { fullName: 'Elastic User', username: 'elastic' },
+ updatedAt: null,
+ updatedBy: null,
},
];
const res = await serviceNow.batchCreateComments('000', comments, 'comments');
@@ -210,7 +219,9 @@ describe('ServiceNow lib', () => {
try {
await serviceNow.getUserID();
} catch (error) {
- expect(error.message).toEqual('[ServiceNow]: Instance is not alive.');
+ expect(error.message).toEqual(
+ '[Action][ServiceNow]: Unable to get user id. Error: [ServiceNow]: Instance is not alive.'
+ );
}
});
@@ -226,7 +237,96 @@ describe('ServiceNow lib', () => {
try {
await serviceNow.getUserID();
} catch (error) {
- expect(error.message).toEqual('[ServiceNow]: Instance is not alive.');
+ expect(error.message).toEqual(
+ '[Action][ServiceNow]: Unable to get user id. Error: [ServiceNow]: Instance is not alive.'
+ );
+ }
+ });
+
+ test('check error when getting user', async () => {
+ expect.assertions(1);
+
+ axiosMock.mockImplementationOnce(() => {
+ throw new Error('Bad request.');
+ });
+ try {
+ await serviceNow.getUserID();
+ } catch (error) {
+ expect(error.message).toEqual(
+ '[Action][ServiceNow]: Unable to get user id. Error: Bad request.'
+ );
+ }
+ });
+
+ test('check error when getting incident', async () => {
+ expect.assertions(1);
+
+ axiosMock.mockImplementationOnce(() => {
+ throw new Error('Bad request.');
+ });
+ try {
+ await serviceNow.getIncident('123');
+ } catch (error) {
+ expect(error.message).toEqual(
+ '[Action][ServiceNow]: Unable to get incident with id 123. Error: Bad request.'
+ );
+ }
+ });
+
+ test('check error when creating incident', async () => {
+ expect.assertions(1);
+
+ axiosMock.mockImplementationOnce(() => {
+ throw new Error('Bad request.');
+ });
+ try {
+ await serviceNow.createIncident({ short_description: 'title' });
+ } catch (error) {
+ expect(error.message).toEqual(
+ '[Action][ServiceNow]: Unable to create incident. Error: Bad request.'
+ );
+ }
+ });
+
+ test('check error when updating incident', async () => {
+ expect.assertions(1);
+
+ axiosMock.mockImplementationOnce(() => {
+ throw new Error('Bad request.');
+ });
+ try {
+ await serviceNow.updateIncident('123', { short_description: 'title' });
+ } catch (error) {
+ expect(error.message).toEqual(
+ '[Action][ServiceNow]: Unable to update incident with id 123. Error: Bad request.'
+ );
+ }
+ });
+
+ test('check error when creating comment', async () => {
+ expect.assertions(1);
+
+ axiosMock.mockImplementationOnce(() => {
+ throw new Error('Bad request.');
+ });
+ try {
+ await serviceNow.createComment(
+ '123',
+ {
+ commentId: '456',
+ version: 'WzU3LDFd',
+ comment: 'A second comment',
+ createdAt: '2020-03-13T08:34:53.450Z',
+ createdBy: { fullName: 'Elastic User', username: 'elastic' },
+ updatedAt: null,
+ updatedBy: null,
+ },
+ 'comment'
+ );
+ } catch (error) {
+ expect(error.message).toEqual(
+ '[Action][ServiceNow]: Unable to create comment at incident with id 123. Error: Bad request.'
+ );
}
});
});
diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/lib/index.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/lib/index.ts
index b3d17affb14c2..2d1d8975c9efc 100644
--- a/x-pack/plugins/actions/server/builtin_action_types/servicenow/lib/index.ts
+++ b/x-pack/plugins/actions/server/builtin_action_types/servicenow/lib/index.ts
@@ -8,7 +8,7 @@ import axios, { AxiosInstance, Method, AxiosResponse } from 'axios';
import { INCIDENT_URL, USER_URL, COMMENT_URL } from './constants';
import { Instance, Incident, IncidentResponse, UpdateIncident, CommentResponse } from './types';
-import { CommentType } from '../types';
+import { Comment } from '../types';
const validStatusCodes = [200, 201];
@@ -68,41 +68,77 @@ class ServiceNow {
return `${date} GMT`;
}
+ private _getErrorMessage(msg: string) {
+ return `[Action][ServiceNow]: ${msg}`;
+ }
+
async getUserID(): Promise {
- const res = await this._request({ url: `${this.userUrl}${this.instance.username}` });
- return res.data.result[0].sys_id;
+ try {
+ const res = await this._request({ url: `${this.userUrl}${this.instance.username}` });
+ return res.data.result[0].sys_id;
+ } catch (error) {
+ throw new Error(this._getErrorMessage(`Unable to get user id. Error: ${error.message}`));
+ }
}
- async createIncident(incident: Incident): Promise {
- const res = await this._request({
- url: `${this.incidentUrl}`,
- method: 'post',
- data: { ...incident },
- });
+ async getIncident(incidentId: string) {
+ try {
+ const res = await this._request({
+ url: `${this.incidentUrl}/${incidentId}`,
+ });
+
+ return { ...res.data.result };
+ } catch (error) {
+ throw new Error(
+ this._getErrorMessage(
+ `Unable to get incident with id ${incidentId}. Error: ${error.message}`
+ )
+ );
+ }
+ }
- return {
- number: res.data.result.number,
- incidentId: res.data.result.sys_id,
- pushedDate: new Date(this._addTimeZoneToDate(res.data.result.sys_created_on)).toISOString(),
- };
+ async createIncident(incident: Incident): Promise {
+ try {
+ const res = await this._request({
+ url: `${this.incidentUrl}`,
+ method: 'post',
+ data: { ...incident },
+ });
+
+ return {
+ number: res.data.result.number,
+ incidentId: res.data.result.sys_id,
+ pushedDate: new Date(this._addTimeZoneToDate(res.data.result.sys_created_on)).toISOString(),
+ };
+ } catch (error) {
+ throw new Error(this._getErrorMessage(`Unable to create incident. Error: ${error.message}`));
+ }
}
async updateIncident(incidentId: string, incident: UpdateIncident): Promise {
- const res = await this._patch({
- url: `${this.incidentUrl}/${incidentId}`,
- data: { ...incident },
- });
-
- return {
- number: res.data.result.number,
- incidentId: res.data.result.sys_id,
- pushedDate: new Date(this._addTimeZoneToDate(res.data.result.sys_updated_on)).toISOString(),
- };
+ try {
+ const res = await this._patch({
+ url: `${this.incidentUrl}/${incidentId}`,
+ data: { ...incident },
+ });
+
+ return {
+ number: res.data.result.number,
+ incidentId: res.data.result.sys_id,
+ pushedDate: new Date(this._addTimeZoneToDate(res.data.result.sys_updated_on)).toISOString(),
+ };
+ } catch (error) {
+ throw new Error(
+ this._getErrorMessage(
+ `Unable to update incident with id ${incidentId}. Error: ${error.message}`
+ )
+ );
+ }
}
async batchCreateComments(
incidentId: string,
- comments: CommentType[],
+ comments: Comment[],
field: string
): Promise {
const res = await Promise.all(comments.map(c => this.createComment(incidentId, c, field)));
@@ -111,18 +147,26 @@ class ServiceNow {
async createComment(
incidentId: string,
- comment: CommentType,
+ comment: Comment,
field: string
): Promise {
- const res = await this._patch({
- url: `${this.commentUrl}/${incidentId}`,
- data: { [field]: comment.comment },
- });
-
- return {
- commentId: comment.commentId,
- pushedDate: new Date(this._addTimeZoneToDate(res.data.result.sys_updated_on)).toISOString(),
- };
+ try {
+ const res = await this._patch({
+ url: `${this.commentUrl}/${incidentId}`,
+ data: { [field]: comment.comment },
+ });
+
+ return {
+ commentId: comment.commentId,
+ pushedDate: new Date(this._addTimeZoneToDate(res.data.result.sys_updated_on)).toISOString(),
+ };
+ } catch (error) {
+ throw new Error(
+ this._getErrorMessage(
+ `Unable to create comment at incident with id ${incidentId}. Error: ${error.message}`
+ )
+ );
+ }
}
}
diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/lib/types.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/lib/types.ts
index 4a3c5c42fcb44..3c245bf3f688f 100644
--- a/x-pack/plugins/actions/server/builtin_action_types/servicenow/lib/types.ts
+++ b/x-pack/plugins/actions/server/builtin_action_types/servicenow/lib/types.ts
@@ -11,9 +11,10 @@ export interface Instance {
}
export interface Incident {
- short_description?: string;
+ short_description: string;
description?: string;
caller_id?: string;
+ [index: string]: string | undefined;
}
export interface IncidentResponse {
diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/mock.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/mock.ts
index 9a150bbede5f8..b9608511159b6 100644
--- a/x-pack/plugins/actions/server/builtin_action_types/servicenow/mock.ts
+++ b/x-pack/plugins/actions/server/builtin_action_types/servicenow/mock.ts
@@ -4,40 +4,44 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { MapsType, FinalMapping, ParamsType } from './types';
+import { MapEntry, Mapping, ExecutorParams } from './types';
import { Incident } from './lib/types';
-const mapping: MapsType[] = [
- { source: 'title', target: 'short_description', actionType: 'nothing' },
- { source: 'description', target: 'description', actionType: 'nothing' },
- { source: 'comments', target: 'comments', actionType: 'nothing' },
+const mapping: MapEntry[] = [
+ { source: 'title', target: 'short_description', actionType: 'overwrite' },
+ { source: 'description', target: 'description', actionType: 'append' },
+ { source: 'comments', target: 'comments', actionType: 'append' },
];
-const finalMapping: FinalMapping = new Map();
+const finalMapping: Mapping = new Map();
finalMapping.set('title', {
target: 'short_description',
- actionType: 'nothing',
+ actionType: 'overwrite',
});
finalMapping.set('description', {
target: 'description',
- actionType: 'nothing',
+ actionType: 'append',
});
finalMapping.set('comments', {
target: 'comments',
- actionType: 'nothing',
+ actionType: 'append',
});
finalMapping.set('short_description', {
target: 'title',
- actionType: 'nothing',
+ actionType: 'overwrite',
});
-const params: ParamsType = {
+const params: ExecutorParams = {
caseId: 'd4387ac5-0899-4dc2-bbfa-0dd605c934aa',
incidentId: 'ceb5986e079f00100e48fbbf7c1ed06d',
+ createdAt: '2020-03-13T08:34:53.450Z',
+ createdBy: { fullName: 'Elastic User', username: 'elastic' },
+ updatedAt: '2020-03-13T08:34:53.450Z',
+ updatedBy: { fullName: 'Elastic User', username: 'elastic' },
title: 'Incident title',
description: 'Incident description',
comments: [
@@ -45,13 +49,19 @@ const params: ParamsType = {
commentId: 'b5b4c4d0-574e-11ea-9e2e-21b90f8a9631',
version: 'WzU3LDFd',
comment: 'A comment',
- incidentCommentId: '263ede42075300100e48fbbf7c1ed047',
+ createdAt: '2020-03-13T08:34:53.450Z',
+ createdBy: { fullName: 'Elastic User', username: 'elastic' },
+ updatedAt: '2020-03-13T08:34:53.450Z',
+ updatedBy: { fullName: 'Elastic User', username: 'elastic' },
},
{
commentId: 'e3db587f-ca27-4ae9-ad2e-31f2dcc9bd0d',
version: 'WlK3LDFd',
comment: 'Another comment',
- incidentCommentId: '315e1ece071300100e48fbbf7c1ed0d0',
+ createdAt: '2020-03-13T08:34:53.450Z',
+ createdBy: { fullName: 'Elastic User', username: 'elastic' },
+ updatedAt: '2020-03-13T08:34:53.450Z',
+ updatedBy: { fullName: 'Elastic User', username: 'elastic' },
},
],
};
diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/schema.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/schema.ts
index 0bb4f50819665..889b57c8e92e2 100644
--- a/x-pack/plugins/actions/server/builtin_action_types/servicenow/schema.ts
+++ b/x-pack/plugins/actions/server/builtin_action_types/servicenow/schema.ts
@@ -6,7 +6,7 @@
import { schema } from '@kbn/config-schema';
-export const MapsSchema = schema.object({
+export const MapEntrySchema = schema.object({
source: schema.string(),
target: schema.string(),
actionType: schema.oneOf([
@@ -17,7 +17,7 @@ export const MapsSchema = schema.object({
});
export const CasesConfigurationSchema = schema.object({
- mapping: schema.arrayOf(MapsSchema),
+ mapping: schema.arrayOf(MapEntrySchema),
});
export const ConfigSchemaProps = {
@@ -34,11 +34,25 @@ export const SecretsSchemaProps = {
export const SecretsSchema = schema.object(SecretsSchemaProps);
+export const UserSchema = schema.object({
+ fullName: schema.nullable(schema.string()),
+ username: schema.string(),
+});
+
+const EntityInformationSchemaProps = {
+ createdAt: schema.string(),
+ createdBy: UserSchema,
+ updatedAt: schema.nullable(schema.string()),
+ updatedBy: schema.nullable(UserSchema),
+};
+
+export const EntityInformationSchema = schema.object(EntityInformationSchemaProps);
+
export const CommentSchema = schema.object({
commentId: schema.string(),
comment: schema.string(),
version: schema.maybe(schema.string()),
- incidentCommentId: schema.maybe(schema.string()),
+ ...EntityInformationSchemaProps,
});
export const ExecutorAction = schema.oneOf([
@@ -48,8 +62,9 @@ export const ExecutorAction = schema.oneOf([
export const ParamsSchema = schema.object({
caseId: schema.string(),
+ title: schema.string(),
comments: schema.maybe(schema.arrayOf(CommentSchema)),
description: schema.maybe(schema.string()),
- title: schema.maybe(schema.string()),
- incidentId: schema.maybe(schema.string()),
+ incidentId: schema.nullable(schema.string()),
+ ...EntityInformationSchemaProps,
});
diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/transformers.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/transformers.ts
new file mode 100644
index 0000000000000..dc0a03fab8c71
--- /dev/null
+++ b/x-pack/plugins/actions/server/builtin_action_types/servicenow/transformers.ts
@@ -0,0 +1,43 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { TransformerArgs } from './types';
+import * as i18n from './translations';
+
+export const informationCreated = ({
+ value,
+ date,
+ user,
+ ...rest
+}: TransformerArgs): TransformerArgs => ({
+ value: `${value} ${i18n.FIELD_INFORMATION('create', date, user)}`,
+ ...rest,
+});
+
+export const informationUpdated = ({
+ value,
+ date,
+ user,
+ ...rest
+}: TransformerArgs): TransformerArgs => ({
+ value: `${value} ${i18n.FIELD_INFORMATION('update', date, user)}`,
+ ...rest,
+});
+
+export const informationAdded = ({
+ value,
+ date,
+ user,
+ ...rest
+}: TransformerArgs): TransformerArgs => ({
+ value: `${value} ${i18n.FIELD_INFORMATION('add', date, user)}`,
+ ...rest,
+});
+
+export const append = ({ value, previousValue, ...rest }: TransformerArgs): TransformerArgs => ({
+ value: previousValue ? `${previousValue} \r\n${value}` : `${value}`,
+ ...rest,
+});
diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/translations.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/translations.ts
index 8601c5ce772db..3b216a6c3260a 100644
--- a/x-pack/plugins/actions/server/builtin_action_types/servicenow/translations.ts
+++ b/x-pack/plugins/actions/server/builtin_action_types/servicenow/translations.ts
@@ -51,3 +51,32 @@ export const UNEXPECTED_STATUS = (status: number) =>
status,
},
});
+
+export const FIELD_INFORMATION = (
+ mode: string,
+ date: string | undefined,
+ user: string | undefined
+) => {
+ switch (mode) {
+ case 'create':
+ return i18n.translate('xpack.actions.builtin.servicenow.informationCreated', {
+ values: { date, user },
+ defaultMessage: '(created at {date} by {user})',
+ });
+ case 'update':
+ return i18n.translate('xpack.actions.builtin.servicenow.informationUpdated', {
+ values: { date, user },
+ defaultMessage: '(updated at {date} by {user})',
+ });
+ case 'add':
+ return i18n.translate('xpack.actions.builtin.servicenow.informationAdded', {
+ values: { date, user },
+ defaultMessage: '(added at {date} by {user})',
+ });
+ default:
+ return i18n.translate('xpack.actions.builtin.servicenow.informationDefault', {
+ values: { date, user },
+ defaultMessage: '(created at {date} by {user})',
+ });
+ }
+};
diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/types.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/types.ts
index 7442f14fed064..418b78add2429 100644
--- a/x-pack/plugins/actions/server/builtin_action_types/servicenow/types.ts
+++ b/x-pack/plugins/actions/server/builtin_action_types/servicenow/types.ts
@@ -11,11 +11,12 @@ import {
SecretsSchema,
ParamsSchema,
CasesConfigurationSchema,
- MapsSchema,
+ MapEntrySchema,
CommentSchema,
} from './schema';
import { ServiceNow } from './lib';
+import { Incident } from './lib/types';
// config definition
export type ConfigType = TypeOf