;
```
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 b3dcfb2aa3b0a..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",
@@ -314,6 +314,7 @@
"@types/cheerio": "^0.22.10",
"@types/chromedriver": "^2.38.0",
"@types/classnames": "^2.2.9",
+ "@types/color": "^3.0.0",
"@types/d3": "^3.5.43",
"@types/dedent": "^0.7.0",
"@types/deep-freeze-strict": "^1.1.0",
@@ -349,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 11b9450f2af6e..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';
@@ -48,12 +49,15 @@ export function runFtrCli() {
kbnTestServer: {
installDir: parseInstallDir(flags),
},
+ suiteFiles: {
+ include: toArray(flags.include as string | string[]).map(makeAbsolutePath),
+ exclude: toArray(flags.exclude as string | string[]).map(makeAbsolutePath),
+ },
suiteTags: {
include: toArray(flags['include-tag'] as string | string[]),
exclude: toArray(flags['exclude-tag'] as string | string[]),
},
updateBaselines: flags.updateBaselines,
- excludeTestFiles: flags.exclude || undefined,
}
);
@@ -83,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());
@@ -104,7 +112,15 @@ export function runFtrCli() {
},
{
flags: {
- string: ['config', 'grep', 'exclude', 'include-tag', 'exclude-tag', 'kibana-install-dir'],
+ string: [
+ 'config',
+ 'grep',
+ 'include',
+ 'exclude',
+ 'include-tag',
+ 'exclude-tag',
+ 'kibana-install-dir',
+ ],
boolean: ['bail', 'invert', 'test-stats', 'updateBaselines', 'throttle', 'headless'],
default: {
config: 'test/functional/config.js',
@@ -115,7 +131,8 @@ export function runFtrCli() {
--bail stop tests after the first failure
--grep pattern used to select which tests to run
--invert invert grep to exclude tests
- --exclude=file path to a test file that should not be loaded
+ --include=file a test file to be included, pass multiple times for multiple files
+ --exclude=file a test file to be excluded, pass multiple times for multiple files
--include-tag=tag a tag to be included, pass multiple times for multiple tags
--exclude-tag=tag a tag to be excluded, pass multiple times for multiple tags
--test-stats print the number of tests (included and excluded) to STDERR
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 75623d6c08890..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
@@ -64,9 +64,16 @@ export const schema = Joi.object()
testFiles: Joi.array().items(Joi.string()),
testRunner: Joi.func(),
- excludeTestFiles: Joi.array()
- .items(Joi.string())
- .default([]),
+ suiteFiles: Joi.object()
+ .keys({
+ include: Joi.array()
+ .items(Joi.string())
+ .default([]),
+ exclude: Joi.array()
+ .items(Joi.string())
+ .default([]),
+ })
+ .default(),
suiteTags: Joi.object()
.keys({
@@ -248,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/packages/kbn-test/src/functional_test_runner/lib/mocha/decorate_mocha_ui.js b/packages/kbn-test/src/functional_test_runner/lib/mocha/decorate_mocha_ui.js
index 64fc51a04aac9..1cac852a7e713 100644
--- a/packages/kbn-test/src/functional_test_runner/lib/mocha/decorate_mocha_ui.js
+++ b/packages/kbn-test/src/functional_test_runner/lib/mocha/decorate_mocha_ui.js
@@ -16,7 +16,8 @@
* specific language governing permissions and limitations
* under the License.
*/
-
+import { relative } from 'path';
+import { REPO_ROOT } from '@kbn/dev-utils';
import { createAssignmentProxy } from './assignment_proxy';
import { wrapFunction } from './wrap_function';
import { wrapRunnableArgs } from './wrap_runnable_args';
@@ -65,6 +66,10 @@ export function decorateMochaUi(lifecycle, context) {
this._tags = [].concat(this._tags || [], tags);
};
+ const relativeFilePath = relative(REPO_ROOT, this.file);
+ this.tags(relativeFilePath);
+ this.suiteTag = relativeFilePath; // The tag that uniquely targets this suite/file
+
provider.call(this);
after(async () => {
diff --git a/packages/kbn-test/src/functional_test_runner/lib/mocha/load_test_files.js b/packages/kbn-test/src/functional_test_runner/lib/mocha/load_test_files.js
index 70b0c0874e5e9..6ee65b1b7e394 100644
--- a/packages/kbn-test/src/functional_test_runner/lib/mocha/load_test_files.js
+++ b/packages/kbn-test/src/functional_test_runner/lib/mocha/load_test_files.js
@@ -31,28 +31,12 @@ import { decorateMochaUi } from './decorate_mocha_ui';
* @param {String} path
* @return {undefined} - mutates mocha, no return value
*/
-export const loadTestFiles = ({
- mocha,
- log,
- lifecycle,
- providers,
- paths,
- excludePaths,
- updateBaselines,
-}) => {
- const pendingExcludes = new Set(excludePaths.slice(0));
-
+export const loadTestFiles = ({ mocha, log, lifecycle, providers, paths, updateBaselines }) => {
const innerLoadTestFile = path => {
if (typeof path !== 'string' || !isAbsolute(path)) {
throw new TypeError('loadTestFile() only accepts absolute paths');
}
- if (pendingExcludes.has(path)) {
- pendingExcludes.delete(path);
- log.warning('Skipping test file %s', path);
- return;
- }
-
loadTracer(path, `testFile[${path}]`, () => {
log.verbose('Loading test file %s', path);
@@ -94,13 +78,4 @@ export const loadTestFiles = ({
};
paths.forEach(innerLoadTestFile);
-
- if (pendingExcludes.size) {
- throw new Error(
- `After loading all test files some exclude paths were not consumed:${[
- '',
- ...pendingExcludes,
- ].join('\n -')}`
- );
- }
};
diff --git a/packages/kbn-test/src/functional_test_runner/lib/mocha/setup_mocha.js b/packages/kbn-test/src/functional_test_runner/lib/mocha/setup_mocha.js
index 326877919d985..61851cece0e8f 100644
--- a/packages/kbn-test/src/functional_test_runner/lib/mocha/setup_mocha.js
+++ b/packages/kbn-test/src/functional_test_runner/lib/mocha/setup_mocha.js
@@ -18,6 +18,8 @@
*/
import Mocha from 'mocha';
+import { relative } from 'path';
+import { REPO_ROOT } from '@kbn/dev-utils';
import { loadTestFiles } from './load_test_files';
import { filterSuitesByTags } from './filter_suites_by_tags';
@@ -50,10 +52,20 @@ export async function setupMocha(lifecycle, log, config, providers) {
lifecycle,
providers,
paths: config.get('testFiles'),
- excludePaths: config.get('excludeTestFiles'),
updateBaselines: config.get('updateBaselines'),
});
+ // Each suite has a tag that is the path relative to the root of the repo
+ // So we just need to take input paths, make them relative to the root, and use them as tags
+ // Also, this is a separate filterSuitesByTags() call so that the test suites will be filtered first by
+ // files, then by tags. This way, you can target tags (like smoke) in a specific file.
+ filterSuitesByTags({
+ log,
+ mocha,
+ include: config.get('suiteFiles.include').map(file => relative(REPO_ROOT, file)),
+ exclude: config.get('suiteFiles.exclude').map(file => relative(REPO_ROOT, file)),
+ });
+
filterSuitesByTags({
log,
mocha,
diff --git a/packages/kbn-test/src/functional_tests/cli/run_tests/__snapshots__/args.test.js.snap b/packages/kbn-test/src/functional_tests/cli/run_tests/__snapshots__/args.test.js.snap
index bbf8b38712ac1..434c374d5d23d 100644
--- a/packages/kbn-test/src/functional_tests/cli/run_tests/__snapshots__/args.test.js.snap
+++ b/packages/kbn-test/src/functional_tests/cli/run_tests/__snapshots__/args.test.js.snap
@@ -16,6 +16,8 @@ Options:
--bail Stop the test run at the first failure.
--grep Pattern to select which tests to run.
--updateBaselines Replace baseline screenshots with whatever is generated from the test.
+ --include Files that must included to be run, can be included multiple times.
+ --exclude Files that must NOT be included to be run, can be included multiple times.
--include-tag Tags that suites must include to be run, can be included multiple times.
--exclude-tag Tags that suites must NOT include to be run, can be included multiple times.
--assert-none-excluded Exit with 1/0 based on if any test is excluded with the current set of tags.
@@ -34,6 +36,10 @@ Object {
"createLogger": [Function],
"esFrom": "snapshot",
"extraKbnOpts": undefined,
+ "suiteFiles": Object {
+ "exclude": Array [],
+ "include": Array [],
+ },
"suiteTags": Object {
"exclude": Array [],
"include": Array [],
@@ -52,6 +58,10 @@ Object {
"debug": true,
"esFrom": "snapshot",
"extraKbnOpts": undefined,
+ "suiteFiles": Object {
+ "exclude": Array [],
+ "include": Array [],
+ },
"suiteTags": Object {
"exclude": Array [],
"include": Array [],
@@ -69,6 +79,10 @@ Object {
"createLogger": [Function],
"esFrom": "snapshot",
"extraKbnOpts": undefined,
+ "suiteFiles": Object {
+ "exclude": Array [],
+ "include": Array [],
+ },
"suiteTags": Object {
"exclude": Array [],
"include": Array [],
@@ -90,6 +104,10 @@ Object {
"extraKbnOpts": Object {
"server.foo": "bar",
},
+ "suiteFiles": Object {
+ "exclude": Array [],
+ "include": Array [],
+ },
"suiteTags": Object {
"exclude": Array [],
"include": Array [],
@@ -107,6 +125,10 @@ Object {
"esFrom": "snapshot",
"extraKbnOpts": undefined,
"quiet": true,
+ "suiteFiles": Object {
+ "exclude": Array [],
+ "include": Array [],
+ },
"suiteTags": Object {
"exclude": Array [],
"include": Array [],
@@ -124,6 +146,10 @@ Object {
"esFrom": "snapshot",
"extraKbnOpts": undefined,
"silent": true,
+ "suiteFiles": Object {
+ "exclude": Array [],
+ "include": Array [],
+ },
"suiteTags": Object {
"exclude": Array [],
"include": Array [],
@@ -140,6 +166,10 @@ Object {
"createLogger": [Function],
"esFrom": "source",
"extraKbnOpts": undefined,
+ "suiteFiles": Object {
+ "exclude": Array [],
+ "include": Array [],
+ },
"suiteTags": Object {
"exclude": Array [],
"include": Array [],
@@ -156,6 +186,10 @@ Object {
"createLogger": [Function],
"esFrom": "source",
"extraKbnOpts": undefined,
+ "suiteFiles": Object {
+ "exclude": Array [],
+ "include": Array [],
+ },
"suiteTags": Object {
"exclude": Array [],
"include": Array [],
@@ -173,6 +207,10 @@ Object {
"esFrom": "snapshot",
"extraKbnOpts": undefined,
"installDir": "foo",
+ "suiteFiles": Object {
+ "exclude": Array [],
+ "include": Array [],
+ },
"suiteTags": Object {
"exclude": Array [],
"include": Array [],
@@ -190,6 +228,10 @@ Object {
"esFrom": "snapshot",
"extraKbnOpts": undefined,
"grep": "management",
+ "suiteFiles": Object {
+ "exclude": Array [],
+ "include": Array [],
+ },
"suiteTags": Object {
"exclude": Array [],
"include": Array [],
@@ -206,6 +248,10 @@ Object {
"createLogger": [Function],
"esFrom": "snapshot",
"extraKbnOpts": undefined,
+ "suiteFiles": Object {
+ "exclude": Array [],
+ "include": Array [],
+ },
"suiteTags": Object {
"exclude": Array [],
"include": Array [],
@@ -223,6 +269,10 @@ Object {
"createLogger": [Function],
"esFrom": "snapshot",
"extraKbnOpts": undefined,
+ "suiteFiles": Object {
+ "exclude": Array [],
+ "include": Array [],
+ },
"suiteTags": Object {
"exclude": Array [],
"include": Array [],
diff --git a/packages/kbn-test/src/functional_tests/cli/run_tests/__snapshots__/cli.test.js.snap b/packages/kbn-test/src/functional_tests/cli/run_tests/__snapshots__/cli.test.js.snap
index b12739b3b5df5..6ede71a6c3940 100644
--- a/packages/kbn-test/src/functional_tests/cli/run_tests/__snapshots__/cli.test.js.snap
+++ b/packages/kbn-test/src/functional_tests/cli/run_tests/__snapshots__/cli.test.js.snap
@@ -16,6 +16,8 @@ Options:
--bail Stop the test run at the first failure.
--grep Pattern to select which tests to run.
--updateBaselines Replace baseline screenshots with whatever is generated from the test.
+ --include Files that must included to be run, can be included multiple times.
+ --exclude Files that must NOT be included to be run, can be included multiple times.
--include-tag Tags that suites must include to be run, can be included multiple times.
--exclude-tag Tags that suites must NOT include to be run, can be included multiple times.
--assert-none-excluded Exit with 1/0 based on if any test is excluded with the current set of tags.
diff --git a/packages/kbn-test/src/functional_tests/cli/run_tests/args.js b/packages/kbn-test/src/functional_tests/cli/run_tests/args.js
index b34006a38a45d..7d2414305de8e 100644
--- a/packages/kbn-test/src/functional_tests/cli/run_tests/args.js
+++ b/packages/kbn-test/src/functional_tests/cli/run_tests/args.js
@@ -46,6 +46,14 @@ const options = {
updateBaselines: {
desc: 'Replace baseline screenshots with whatever is generated from the test.',
},
+ include: {
+ arg: '',
+ desc: 'Files that must included to be run, can be included multiple times.',
+ },
+ exclude: {
+ arg: '',
+ desc: 'Files that must NOT be included to be run, can be included multiple times.',
+ },
'include-tag': {
arg: '',
desc: 'Tags that suites must include to be run, can be included multiple times.',
@@ -115,6 +123,13 @@ export function processOptions(userOptions, defaultConfigPaths) {
delete userOptions['kibana-install-dir'];
}
+ userOptions.suiteFiles = {
+ include: [].concat(userOptions.include || []),
+ exclude: [].concat(userOptions.exclude || []),
+ };
+ delete userOptions.include;
+ delete userOptions.exclude;
+
userOptions.suiteTags = {
include: [].concat(userOptions['include-tag'] || []),
exclude: [].concat(userOptions['exclude-tag'] || []),
diff --git a/packages/kbn-test/src/functional_tests/lib/run_ftr.js b/packages/kbn-test/src/functional_tests/lib/run_ftr.js
index 9b631e33f3b24..14883ac977c43 100644
--- a/packages/kbn-test/src/functional_tests/lib/run_ftr.js
+++ b/packages/kbn-test/src/functional_tests/lib/run_ftr.js
@@ -22,7 +22,7 @@ import { CliError } from './run_cli';
async function createFtr({
configPath,
- options: { installDir, log, bail, grep, updateBaselines, suiteTags },
+ options: { installDir, log, bail, grep, updateBaselines, suiteFiles, suiteTags },
}) {
const config = await readConfigFile(log, configPath);
@@ -37,6 +37,10 @@ async function createFtr({
installDir,
},
updateBaselines,
+ suiteFiles: {
+ include: [...suiteFiles.include, ...config.get('suiteFiles.include')],
+ exclude: [...suiteFiles.exclude, ...config.get('suiteFiles.exclude')],
+ },
suiteTags: {
include: [...suiteTags.include, ...config.get('suiteTags.include')],
exclude: [...suiteTags.exclude, ...config.get('suiteTags.exclude')],
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/public/dashboard/legacy_imports.ts b/src/legacy/core_plugins/kibana/public/dashboard/legacy_imports.ts
index 0c5329d8b259f..3f81bfe5aadf2 100644
--- a/src/legacy/core_plugins/kibana/public/dashboard/legacy_imports.ts
+++ b/src/legacy/core_plugins/kibana/public/dashboard/legacy_imports.ts
@@ -28,12 +28,11 @@ export { npSetup, npStart } from 'ui/new_platform';
export { KbnUrl } from 'ui/url/kbn_url';
// @ts-ignore
-export { KbnUrlProvider, RedirectWhenMissingProvider } from 'ui/url/index';
+export { KbnUrlProvider } from 'ui/url/index';
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/application.ts b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/application.ts
index fe0e7a1d3e6d0..9447b5384d172 100644
--- a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/application.ts
+++ b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/application.ts
@@ -35,7 +35,6 @@ import {
KbnUrlProvider,
PrivateProvider,
PromiseServiceCreator,
- RedirectWhenMissingProvider,
} from '../legacy_imports';
// @ts-ignore
import { initDashboardApp } from './legacy_app';
@@ -146,8 +145,7 @@ function createLocalIconModule() {
function createLocalKbnUrlModule() {
angular
.module('app/dashboard/KbnUrl', ['app/dashboard/Private', 'ngRoute'])
- .service('kbnUrl', (Private: IPrivate) => Private(KbnUrlProvider))
- .service('redirectWhenMissing', (Private: IPrivate) => Private(RedirectWhenMissingProvider));
+ .service('kbnUrl', (Private: IPrivate) => Private(KbnUrlProvider));
}
function createLocalConfigModule(core: AppMountContext['core']) {
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 35b510894179d..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,12 @@ 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,
} from '../../../../../../plugins/kibana_utils/public';
@@ -136,8 +137,8 @@ export function initDashboardApp(app, deps) {
});
},
resolve: {
- dash: function($rootScope, $route, redirectWhenMissing, 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) {
@@ -171,17 +172,18 @@ export function initDashboardApp(app, deps) {
controller: createNewDashboardCtrl,
requireUICapability: 'dashboard.createNew',
resolve: {
- dash: function(redirectWhenMissing, $rootScope, kbnUrl) {
- 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({
- dashboard: DashboardConstants.LANDING_PAGE_PATH,
+ history,
+ mapping: {
+ dashboard: DashboardConstants.LANDING_PAGE_PATH,
+ },
+ toastNotifications: deps.core.notifications.toasts,
})
- );
- },
+ ),
},
})
.when(createDashboardEditUrl(':id'), {
@@ -189,13 +191,11 @@ export function initDashboardApp(app, deps) {
template: dashboardTemplate,
controller: createNewDashboardCtrl,
resolve: {
- dash: function($rootScope, $route, redirectWhenMissing, 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(),
@@ -207,7 +207,7 @@ export function initDashboardApp(app, deps) {
.catch(error => {
// A corrupt dashboard was detected (e.g. with invalid JSON properties)
if (error instanceof InvalidJSONProperty) {
- deps.toastNotifications.addDanger(error.message);
+ deps.core.notifications.toasts.addDanger(error.message);
kbnUrl.redirect(DashboardConstants.LANDING_PAGE_PATH);
return;
}
@@ -221,7 +221,7 @@ export function initDashboardApp(app, deps) {
pathname: DashboardConstants.CREATE_NEW_DASHBOARD_URL,
});
- deps.toastNotifications.addWarning(
+ deps.core.notifications.toasts.addWarning(
i18n.translate('kbn.dashboard.urlWasRemovedInSixZeroWarningMessage', {
defaultMessage:
'The url "dashboard/create" was removed in 6.0. Please update your bookmarks.',
@@ -234,7 +234,11 @@ export function initDashboardApp(app, deps) {
})
.catch(
redirectWhenMissing({
- dashboard: DashboardConstants.LANDING_PAGE_PATH,
+ history,
+ mapping: {
+ dashboard: DashboardConstants.LANDING_PAGE_PATH,
+ },
+ toastNotifications: deps.core.notifications.toasts,
})
);
},
diff --git a/src/legacy/core_plugins/kibana/public/discover/build_services.ts b/src/legacy/core_plugins/kibana/public/discover/build_services.ts
index c58307adaf38c..282eef0c983eb 100644
--- a/src/legacy/core_plugins/kibana/public/discover/build_services.ts
+++ b/src/legacy/core_plugins/kibana/public/discover/build_services.ts
@@ -16,6 +16,8 @@
* specific language governing permissions and limitations
* under the License.
*/
+import { createHashHistory, History } from 'history';
+
import {
Capabilities,
ChromeStart,
@@ -46,6 +48,7 @@ export interface DiscoverServices {
data: DataPublicPluginStart;
docLinks: DocLinksStart;
docViewsRegistry: DocViewsRegistry;
+ history: History;
theme: ChartsPluginStart['theme'];
filterManager: FilterManager;
indexPatterns: IndexPatternsContract;
@@ -79,6 +82,7 @@ export async function buildServices(
data: plugins.data,
docLinks: core.docLinks,
docViewsRegistry,
+ history: createHashHistory(),
theme: plugins.charts.theme,
filterManager: plugins.data.query.filterManager,
getSavedSearchById: async (id: string) => savedObjectService.get(id),
diff --git a/src/legacy/core_plugins/kibana/public/discover/get_inner_angular.ts b/src/legacy/core_plugins/kibana/public/discover/get_inner_angular.ts
index 76d475c4f7f96..4d871bcb7a858 100644
--- a/src/legacy/core_plugins/kibana/public/discover/get_inner_angular.ts
+++ b/src/legacy/core_plugins/kibana/public/discover/get_inner_angular.ts
@@ -27,7 +27,7 @@ import { CoreStart, LegacyCoreStart, IUiSettingsClient } from 'kibana/public';
// @ts-ignore
import { StateManagementConfigProvider } from 'ui/state_management/config_provider';
// @ts-ignore
-import { KbnUrlProvider, RedirectWhenMissingProvider } from 'ui/url';
+import { KbnUrlProvider } from 'ui/url';
import { DataPublicPluginStart } from '../../../../../plugins/data/public';
import { Storage } from '../../../../../plugins/kibana_utils/public';
import { NavigationPublicPluginStart as NavigationStart } from '../../../../../plugins/navigation/public';
@@ -173,8 +173,7 @@ export function initializeInnerAngularModule(
function createLocalKbnUrlModule() {
angular
.module('discoverKbnUrl', ['discoverPrivate', 'ngRoute'])
- .service('kbnUrl', (Private: IPrivate) => Private(KbnUrlProvider))
- .service('redirectWhenMissing', (Private: IPrivate) => Private(RedirectWhenMissingProvider));
+ .service('kbnUrl', (Private: IPrivate) => Private(KbnUrlProvider));
}
function createLocalConfigModule(uiSettings: IUiSettingsClient) {
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 57a9e4966d6d6..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 } 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 f3334c9211e4b..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
@@ -50,6 +50,7 @@ import {
tabifyAggResponse,
getAngularModule,
ensureDefaultIndexPattern,
+ redirectWhenMissing,
} from '../../kibana_services';
const {
@@ -57,6 +58,7 @@ const {
chrome,
data,
docTitle,
+ history,
indexPatterns,
filterManager,
share,
@@ -113,10 +115,10 @@ app.config($routeProvider => {
template: indexTemplate,
reloadOnSearch: false,
resolve: {
- savedObjects: function(redirectWhenMissing, $route, kbnUrl, Promise, $rootScope) {
+ savedObjects: function($route, Promise) {
const savedSearchId = $route.current.params.id;
- return ensureDefaultIndexPattern(core, data, $rootScope, kbnUrl).then(() => {
- const { appStateContainer } = getState({});
+ return ensureDefaultIndexPattern(core, data, history).then(() => {
+ const { appStateContainer } = getState({ history });
const { index } = appStateContainer.getState();
return Promise.props({
ip: indexPatterns.getCache().then(indexPatternList => {
@@ -151,9 +153,13 @@ app.config($routeProvider => {
})
.catch(
redirectWhenMissing({
- search: '/discover',
- 'index-pattern':
- '/management/kibana/objects/savedSearches/' + $route.current.params.id,
+ history,
+ mapping: {
+ search: '/discover',
+ 'index-pattern':
+ '/management/kibana/objects/savedSearches/' + $route.current.params.id,
+ },
+ toastNotifications,
})
),
});
@@ -207,6 +213,7 @@ function discoverController(
} = getState({
defaultAppState: getStateDefaults(),
storeInSessionStorage: config.get('state:storeInSessionStorage'),
+ history,
});
if (appStateContainer.getState().index !== $scope.indexPattern.id) {
//used index pattern is different than the given by url/state which is invalid
diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover_state.test.ts b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover_state.test.ts
index af772cb5c76f1..3840fd0c2e3be 100644
--- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover_state.test.ts
+++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover_state.test.ts
@@ -30,7 +30,7 @@ describe('Test discover state', () => {
history.push('/');
state = getState({
defaultAppState: { index: 'test' },
- hashHistory: history,
+ history,
});
await state.replaceUrlAppState({});
await state.startSync();
diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover_state.ts b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover_state.ts
index 10e7cd1d0c49d..981855d1ee774 100644
--- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover_state.ts
+++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover_state.ts
@@ -17,7 +17,7 @@
* under the License.
*/
import { isEqual } from 'lodash';
-import { createHashHistory, History } from 'history';
+import { History } from 'history';
import {
createStateContainer,
createKbnUrlStateStorage,
@@ -65,9 +65,9 @@ interface GetStateParams {
*/
storeInSessionStorage?: boolean;
/**
- * Browser history used for testing
+ * Browser history
*/
- hashHistory?: History;
+ history: History;
}
export interface GetStateReturn {
@@ -121,11 +121,11 @@ const APP_STATE_URL_KEY = '_a';
export function getState({
defaultAppState = {},
storeInSessionStorage = false,
- hashHistory,
+ history,
}: GetStateParams): GetStateReturn {
const stateStorage = createKbnUrlStateStorage({
useHash: storeInSessionStorage,
- history: hashHistory ? hashHistory : createHashHistory(),
+ history,
});
const appStateFromUrl = stateStorage.get(APP_STATE_URL_KEY) as AppState;
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 0ddf3ee67aa94..e6b7a29e28d89 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/legacy_imports.ts
+++ b/src/legacy/core_plugins/kibana/public/visualize/legacy_imports.ts
@@ -25,7 +25,7 @@
*/
// @ts-ignore
-export { KbnUrlProvider, RedirectWhenMissingProvider } from 'ui/url';
+export { KbnUrlProvider } from 'ui/url';
export { absoluteToParsedUrl } from 'ui/url/absolute_to_parsed_url';
export { KibanaParsedUrl } from 'ui/url/kibana_parsed_url';
export { wrapInI18nContext } from 'ui/i18n';
@@ -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/application.ts b/src/legacy/core_plugins/kibana/public/visualize/np_ready/application.ts
index 8ef63ec5778e2..c7c3286bb5c71 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/np_ready/application.ts
+++ b/src/legacy/core_plugins/kibana/public/visualize/np_ready/application.ts
@@ -24,7 +24,6 @@ import { AppMountContext } from 'kibana/public';
import {
configureAppAngularModule,
KbnUrlProvider,
- RedirectWhenMissingProvider,
IPrivate,
PrivateProvider,
PromiseServiceCreator,
@@ -102,8 +101,7 @@ function createLocalAngularModule(core: AppMountContext['core'], navigation: Nav
function createLocalKbnUrlModule() {
angular
.module('app/visualize/KbnUrl', ['app/visualize/Private', 'ngRoute'])
- .service('kbnUrl', (Private: IPrivate) => Private(KbnUrlProvider))
- .service('redirectWhenMissing', (Private: IPrivate) => Private(RedirectWhenMissingProvider));
+ .service('kbnUrl', (Private: IPrivate) => Private(KbnUrlProvider));
}
function createLocalPromiseModule() {
diff --git a/src/legacy/core_plugins/kibana/public/visualize/np_ready/editor/editor.js b/src/legacy/core_plugins/kibana/public/visualize/np_ready/editor/editor.js
index c023c402f5fea..1fab38027f65b 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/np_ready/editor/editor.js
+++ b/src/legacy/core_plugins/kibana/public/visualize/np_ready/editor/editor.js
@@ -31,6 +31,7 @@ import { getEditBreadcrumbs } from '../breadcrumbs';
import { addHelpMenuToAppChrome } from '../help_menu/help_menu_util';
import { unhashUrl } from '../../../../../../../plugins/kibana_utils/public';
+import { MarkdownSimple, toMountPoint } from '../../../../../../../plugins/kibana_react/public';
import { addFatalError, kbnBaseUrl } from '../../../../../../../plugins/kibana_legacy/public';
import {
SavedObjectSaveModal,
@@ -75,7 +76,6 @@ function VisualizeAppController(
$injector,
$timeout,
kbnUrl,
- redirectWhenMissing,
kbnUrlStateStorage,
history
) {
@@ -313,16 +313,33 @@ function VisualizeAppController(
}
);
+ const stopAllSyncing = () => {
+ stopStateSync();
+ stopSyncingQueryServiceStateWithUrl();
+ stopSyncingAppFilters();
+ };
+
// The savedVis is pulled from elasticsearch, but the appState is pulled from the url, with the
// defaults applied. If the url was from a previous session which included modifications to the
// appState then they won't be equal.
if (!_.isEqual(stateContainer.getState().vis, stateDefaults.vis)) {
try {
vis.setState(stateContainer.getState().vis);
- } catch {
- redirectWhenMissing({
- 'index-pattern-field': '/visualize',
+ } catch (error) {
+ // stop syncing url updtes with the state to prevent extra syncing
+ stopAllSyncing();
+
+ toastNotifications.addWarning({
+ title: i18n.translate('kbn.visualize.visualizationTypeInvalidNotificationMessage', {
+ defaultMessage: 'Invalid visualization type',
+ }),
+ text: toMountPoint({error.message} ),
});
+
+ history.replace(`${VisualizeConstants.LANDING_PAGE_PATH}?notFound=visualization`);
+
+ // prevent further controller execution
+ return;
}
}
@@ -529,9 +546,8 @@ function VisualizeAppController(
unsubscribePersisted();
unsubscribeStateUpdates();
- stopStateSync();
- stopSyncingQueryServiceStateWithUrl();
- stopSyncingAppFilters();
+
+ stopAllSyncing();
});
$timeout(() => {
diff --git a/src/legacy/core_plugins/kibana/public/visualize/np_ready/editor/visualization.js b/src/legacy/core_plugins/kibana/public/visualize/np_ready/editor/visualization.js
index 6acdb0abdd0b5..c8acea168444f 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/np_ready/editor/visualization.js
+++ b/src/legacy/core_plugins/kibana/public/visualize/np_ready/editor/visualization.js
@@ -59,7 +59,9 @@ export function initVisualizationDirective(app, deps) {
});
$scope.$on('$destroy', () => {
- $scope._handler.destroy();
+ if ($scope._handler) {
+ $scope._handler.destroy();
+ }
});
},
};
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 b9409445166bc..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
@@ -21,7 +21,11 @@ import { find } from 'lodash';
import { i18n } from '@kbn/i18n';
import { createHashHistory } from 'history';
-import { createKbnUrlStateStorage } from '../../../../../../plugins/kibana_utils/public';
+import {
+ createKbnUrlStateStorage,
+ redirectWhenMissing,
+ ensureDefaultIndexPattern,
+} from '../../../../../../plugins/kibana_utils/public';
import editorTemplate from './editor/editor.html';
import visualizeListingTemplate from './listing/visualize_listing.html';
@@ -29,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,
@@ -79,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, {
@@ -91,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, {
@@ -100,8 +101,8 @@ export function initVisualizeApp(app, deps) {
template: editorTemplate,
k7Breadcrumbs: getCreateBreadcrumbs,
resolve: {
- savedVis: function(redirectWhenMissing, $route, $rootScope, kbnUrl) {
- const { core, data, savedVisualizations, visualizations } = deps;
+ savedVis: function($route, history) {
+ const { core, data, savedVisualizations, visualizations, toastNotifications } = deps;
const visTypes = visualizations.all();
const visType = find(visTypes, { name: $route.current.params.type });
const shouldHaveIndex = visType.requiresSearch && visType.options.showIndexSelection;
@@ -118,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) {
@@ -128,7 +129,9 @@ export function initVisualizeApp(app, deps) {
})
.catch(
redirectWhenMissing({
- '*': '/visualize',
+ history,
+ mapping: VisualizeConstants.LANDING_PAGE_PATH,
+ toastNotifications,
})
);
},
@@ -139,9 +142,9 @@ export function initVisualizeApp(app, deps) {
template: editorTemplate,
k7Breadcrumbs: getEditBreadcrumbs,
resolve: {
- savedVis: function(redirectWhenMissing, $route, $rootScope, kbnUrl) {
- const { chrome, core, data, savedVisualizations } = deps;
- return ensureDefaultIndexPattern(core, data, $rootScope, kbnUrl)
+ savedVis: function($route, history) {
+ const { chrome, core, data, savedVisualizations, toastNotifications } = deps;
+ return ensureDefaultIndexPattern(core, data, history)
.then(() => savedVisualizations.get($route.current.params.id))
.then(savedVis => {
chrome.recentlyAccessed.add(savedVis.getFullPath(), savedVis.title, savedVis.id);
@@ -155,13 +158,17 @@ export function initVisualizeApp(app, deps) {
})
.catch(
redirectWhenMissing({
- visualization: '/visualize',
- search:
- '/management/kibana/objects/savedVisualizations/' + $route.current.params.id,
- 'index-pattern':
- '/management/kibana/objects/savedVisualizations/' + $route.current.params.id,
- 'index-pattern-field':
- '/management/kibana/objects/savedVisualizations/' + $route.current.params.id,
+ history,
+ mapping: {
+ visualization: VisualizeConstants.LANDING_PAGE_PATH,
+ search:
+ '/management/kibana/objects/savedVisualizations/' + $route.current.params.id,
+ 'index-pattern':
+ '/management/kibana/objects/savedVisualizations/' + $route.current.params.id,
+ 'index-pattern-field':
+ '/management/kibana/objects/savedVisualizations/' + $route.current.params.id,
+ },
+ toastNotifications,
})
);
},
diff --git a/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_editor.js b/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_editor.js
index 0263f5b2c851c..ff2546f75c51a 100644
--- a/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_editor.js
+++ b/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_editor.js
@@ -50,7 +50,7 @@ export class VisEditor extends Component {
visFields: props.visFields,
extractedIndexPatterns: [''],
};
- this.onBrush = createBrushHandler(getDataStart().query.timefilter);
+ this.onBrush = createBrushHandler(getDataStart().query.timefilter.timefilter);
this.visDataSubject = new Rx.BehaviorSubject(this.props.visData);
this.visData$ = this.visDataSubject.asObservable().pipe(share());
diff --git a/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_types/_vis_types.scss b/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_types/_vis_types.scss
index 90c2007b1c94a..3db09bace079f 100644
--- a/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_types/_vis_types.scss
+++ b/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_types/_vis_types.scss
@@ -7,4 +7,21 @@
.tvbVisTimeSeries {
overflow: hidden;
}
+ .tvbVisTimeSeriesDark {
+ .echReactiveChart_unavailable {
+ color: #DFE5EF;
+ }
+ .echLegendItem {
+ color: #DFE5EF;
+ }
+ }
+ .tvbVisTimeSeriesLight {
+ .echReactiveChart_unavailable {
+ color: #343741;
+ }
+ .echLegendItem {
+ color: #343741;
+ }
+ }
}
+
diff --git a/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_types/timeseries/vis.js b/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_types/timeseries/vis.js
index 954d3d174bb8c..356ba08ac2427 100644
--- a/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_types/timeseries/vis.js
+++ b/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_types/timeseries/vis.js
@@ -33,9 +33,8 @@ import { getAxisLabelString } from '../../lib/get_axis_label_string';
import { getInterval } from '../../lib/get_interval';
import { areFieldsDifferent } from '../../lib/charts';
import { createXaxisFormatter } from '../../lib/create_xaxis_formatter';
-import { isBackgroundDark } from '../../../lib/set_is_reversed';
import { STACKED_OPTIONS } from '../../../visualizations/constants';
-import { getCoreStart } from '../../../services';
+import { getCoreStart, getUISettings } from '../../../services';
export class TimeseriesVisualization extends Component {
static propTypes = {
@@ -238,6 +237,7 @@ export class TimeseriesVisualization extends Component {
}
});
+ const darkMode = getUISettings().get('theme:darkMode');
return (
null;
export const AreaSeries = () => null;
+
+export { LIGHT_THEME, DARK_THEME } from '@elastic/charts';
diff --git a/src/legacy/core_plugins/vis_type_timeseries/public/visualizations/views/timeseries/index.js b/src/legacy/core_plugins/vis_type_timeseries/public/visualizations/views/timeseries/index.js
index 986111b462b35..75554a476bdea 100644
--- a/src/legacy/core_plugins/vis_type_timeseries/public/visualizations/views/timeseries/index.js
+++ b/src/legacy/core_plugins/vis_type_timeseries/public/visualizations/views/timeseries/index.js
@@ -19,14 +19,13 @@
import React, { useEffect, useRef } from 'react';
import PropTypes from 'prop-types';
+import classNames from 'classnames';
import {
Axis,
Chart,
Position,
Settings,
- DARK_THEME,
- LIGHT_THEME,
AnnotationDomainTypes,
LineAnnotation,
TooltipType,
@@ -40,6 +39,7 @@ import { GRID_LINE_CONFIG, ICON_TYPES_MAP, STACKED_OPTIONS } from '../../constan
import { AreaSeriesDecorator } from './decorators/area_decorator';
import { BarSeriesDecorator } from './decorators/bar_decorator';
import { getStackAccessors } from './utils/stack_format';
+import { getTheme, getChartClasses } from './utils/theme';
const generateAnnotationData = (values, formatter) =>
values.map(({ key, docs }) => ({
@@ -57,7 +57,8 @@ const handleCursorUpdate = cursor => {
};
export const TimeSeries = ({
- isDarkMode,
+ darkMode,
+ backgroundColor,
showGrid,
legend,
legendPosition,
@@ -89,8 +90,13 @@ export const TimeSeries = ({
const timeZone = timezoneProvider(uiSettings)();
const hasBarChart = series.some(({ bars }) => bars.show);
+ // compute the theme based on the bg color
+ const theme = getTheme(darkMode, backgroundColor);
+ // apply legend style change if bgColor is configured
+ const classes = classNames('tvbVisTimeSeries', getChartClasses(backgroundColor));
+
return (
-
+
{
+ it('should return the basic themes if no bg color is specified', () => {
+ // use original dark/light theme
+ expect(getTheme(false)).toEqual(LIGHT_THEME);
+ expect(getTheme(true)).toEqual(DARK_THEME);
+
+ // discard any wrong/missing bg color
+ expect(getTheme(true, null)).toEqual(DARK_THEME);
+ expect(getTheme(true, '')).toEqual(DARK_THEME);
+ expect(getTheme(true, undefined)).toEqual(DARK_THEME);
+ });
+ it('should return a highcontrast color theme for a different background', () => {
+ // red use a near full-black color
+ expect(getTheme(false, 'red').axes.axisTitleStyle.fill).toEqual('rgb(23,23,23)');
+
+ // violet increased the text color to full white for higer contrast
+ expect(getTheme(false, '#ba26ff').axes.axisTitleStyle.fill).toEqual('rgb(255,255,255)');
+
+ // light yellow, prefer the LIGHT_THEME fill color because already with a good contrast
+ expect(getTheme(false, '#fff49f').axes.axisTitleStyle.fill).toEqual('#333');
+ });
+});
diff --git a/src/legacy/core_plugins/vis_type_timeseries/public/visualizations/views/timeseries/utils/theme.ts b/src/legacy/core_plugins/vis_type_timeseries/public/visualizations/views/timeseries/utils/theme.ts
new file mode 100644
index 0000000000000..a25d5e1ce1d35
--- /dev/null
+++ b/src/legacy/core_plugins/vis_type_timeseries/public/visualizations/views/timeseries/utils/theme.ts
@@ -0,0 +1,139 @@
+/*
+ * 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 colorJS from 'color';
+import { Theme, LIGHT_THEME, DARK_THEME } from '@elastic/charts';
+
+function computeRelativeLuminosity(rgb: string) {
+ return colorJS(rgb).luminosity();
+}
+
+function computeContrast(rgb1: string, rgb2: string) {
+ return colorJS(rgb1).contrast(colorJS(rgb2));
+}
+
+function getAAARelativeLum(bgColor: string, fgColor: string, ratio = 7) {
+ const relLum1 = computeRelativeLuminosity(bgColor);
+ const relLum2 = computeRelativeLuminosity(fgColor);
+ if (relLum1 > relLum2) {
+ // relLum1 is brighter, relLum2 is darker
+ return (relLum1 + 0.05 - ratio * 0.05) / ratio;
+ } else {
+ // relLum1 is darker, relLum2 is brighter
+ return Math.min(ratio * (relLum1 + 0.05) - 0.05, 1);
+ }
+}
+
+function getGrayFromRelLum(relLum: number) {
+ if (relLum <= 0.0031308) {
+ return relLum * 12.92;
+ } else {
+ return (1.0 + 0.055) * Math.pow(relLum, 1.0 / 2.4) - 0.055;
+ }
+}
+
+function getGrayRGBfromGray(gray: number) {
+ const g = Math.round(gray * 255);
+ return `rgb(${g},${g},${g})`;
+}
+
+function getAAAGray(bgColor: string, fgColor: string, ratio = 7) {
+ const relLum = getAAARelativeLum(bgColor, fgColor, ratio);
+ const gray = getGrayFromRelLum(relLum);
+ return getGrayRGBfromGray(gray);
+}
+
+function findBestContrastColor(
+ bgColor: string,
+ lightFgColor: string,
+ darkFgColor: string,
+ ratio = 4.5
+) {
+ const lc = computeContrast(bgColor, lightFgColor);
+ const dc = computeContrast(bgColor, darkFgColor);
+ if (lc >= dc) {
+ if (lc >= ratio) {
+ return lightFgColor;
+ }
+ return getAAAGray(bgColor, lightFgColor, ratio);
+ }
+ if (dc >= ratio) {
+ return darkFgColor;
+ }
+ return getAAAGray(bgColor, darkFgColor, ratio);
+}
+
+function isValidColor(color: string | null | undefined): color is string {
+ if (typeof color !== 'string') {
+ return false;
+ }
+ if (color.length === 0) {
+ return false;
+ }
+ try {
+ colorJS(color);
+ return true;
+ } catch {
+ return false;
+ }
+}
+
+export function getTheme(darkMode: boolean, bgColor?: string | null): Theme {
+ if (!isValidColor(bgColor)) {
+ return darkMode ? DARK_THEME : LIGHT_THEME;
+ }
+
+ const bgLuminosity = computeRelativeLuminosity(bgColor);
+ const mainTheme = bgLuminosity <= 0.179 ? DARK_THEME : LIGHT_THEME;
+ const color = findBestContrastColor(
+ bgColor,
+ LIGHT_THEME.axes.axisTitleStyle.fill,
+ DARK_THEME.axes.axisTitleStyle.fill
+ );
+ return {
+ ...mainTheme,
+ axes: {
+ ...mainTheme.axes,
+ axisTitleStyle: {
+ ...mainTheme.axes.axisTitleStyle,
+ fill: color,
+ },
+ tickLabelStyle: {
+ ...mainTheme.axes.tickLabelStyle,
+ fill: color,
+ },
+ axisLineStyle: {
+ ...mainTheme.axes.axisLineStyle,
+ stroke: color,
+ },
+ tickLineStyle: {
+ ...mainTheme.axes.tickLineStyle,
+ stroke: color,
+ },
+ },
+ };
+}
+
+export function getChartClasses(bgColor?: string) {
+ // keep the original theme color if no bg color is specified
+ if (typeof bgColor !== 'string') {
+ return;
+ }
+ const bgLuminosity = computeRelativeLuminosity(bgColor);
+ return bgLuminosity <= 0.179 ? 'tvbVisTimeSeriesDark' : 'tvbVisTimeSeriesLight';
+}
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/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/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/core_plugins/kibana/common/utils/__tests__/shorten_dotted_string.js b/src/plugins/console/server/lib/spec_definitions/js/shared.js
similarity index 60%
rename from src/legacy/core_plugins/kibana/common/utils/__tests__/shorten_dotted_string.js
rename to src/plugins/console/server/lib/spec_definitions/js/shared.js
index 267ca74c7c42a..ace189e2d0913 100644
--- a/src/legacy/core_plugins/kibana/common/utils/__tests__/shorten_dotted_string.js
+++ b/src/plugins/console/server/lib/spec_definitions/js/shared.js
@@ -17,18 +17,6 @@
* 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);
- });
+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/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/legacy/ui/public/chrome/services/global_nav_state.js b/src/plugins/data/common/query/filter_manager/index.ts
similarity index 54%
rename from src/legacy/ui/public/chrome/services/global_nav_state.js
rename to src/plugins/data/common/query/filter_manager/index.ts
index 5a67806852fe8..315c124f083a8 100644
--- a/src/legacy/ui/public/chrome/services/global_nav_state.js
+++ b/src/plugins/data/common/query/filter_manager/index.ts
@@ -17,29 +17,6 @@
* 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);
- },
- };
-});
+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/index_patterns/index_patterns/index_pattern.test.ts b/src/plugins/data/public/index_patterns/index_patterns/index_pattern.test.ts
index b6ca91169a933..305aa8575e4d7 100644
--- a/src/plugins/data/public/index_patterns/index_patterns/index_pattern.test.ts
+++ b/src/plugins/data/public/index_patterns/index_patterns/index_pattern.test.ts
@@ -18,6 +18,8 @@
*/
import { defaults, pluck, last, get } from 'lodash';
+
+jest.mock('../../../../kibana_utils/public/history');
import { IndexPattern } from './index_pattern';
import { DuplicateField } from '../../../../kibana_utils/public';
diff --git a/src/plugins/data/public/public.api.md b/src/plugins/data/public/public.api.md
index 783411bbf27e2..07d8d302bc18c 100644
--- a/src/plugins/data/public/public.api.md
+++ b/src/plugins/data/public/public.api.md
@@ -362,8 +362,8 @@ export const 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;
@@ -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/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 b4b5658c1c886..1a73bbb6b04a1 100644
--- a/src/plugins/kibana_utils/public/history/index.ts
+++ b/src/plugins/kibana_utils/public/history/index.ts
@@ -18,3 +18,5 @@
*/
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/history/redirect_when_missing.tsx b/src/plugins/kibana_utils/public/history/redirect_when_missing.tsx
new file mode 100644
index 0000000000000..cbdeef6fbe96c
--- /dev/null
+++ b/src/plugins/kibana_utils/public/history/redirect_when_missing.tsx
@@ -0,0 +1,80 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import React from 'react';
+import { History } from 'history';
+import { i18n } from '@kbn/i18n';
+
+import { ToastsSetup } from 'kibana/public';
+import { MarkdownSimple, toMountPoint } from '../../../kibana_react/public';
+import { SavedObjectNotFound } from '../errors';
+
+interface Mapping {
+ [key: string]: string;
+}
+
+/**
+ * Creates an error handler that will redirect to a url when a SavedObjectNotFound
+ * error is thrown
+ */
+export function redirectWhenMissing({
+ history,
+ mapping,
+ toastNotifications,
+}: {
+ history: History;
+ /**
+ * a mapping of url's to redirect to based on the saved object that
+ * couldn't be found, or just a string that will be used for all types
+ */
+ mapping: string | Mapping;
+ /**
+ * Toast notifications service to show toasts in error cases.
+ */
+ toastNotifications: ToastsSetup;
+}) {
+ let localMappingObject: Mapping;
+
+ if (typeof mapping === 'string') {
+ localMappingObject = { '*': mapping };
+ } else {
+ localMappingObject = mapping;
+ }
+
+ return (error: SavedObjectNotFound) => {
+ // if this error is not "404", rethrow
+ // we can't check "error instanceof SavedObjectNotFound" since this class can live in a separate bundle
+ // and the error will be an instance of other class with the same interface (actually the copy of SavedObjectNotFound class)
+ if (!error.savedObjectType) {
+ throw error;
+ }
+
+ let url = localMappingObject[error.savedObjectType] || localMappingObject['*'] || '/';
+ url += (url.indexOf('?') >= 0 ? '&' : '?') + `notFound=${error.savedObjectType}`;
+
+ toastNotifications.addWarning({
+ title: i18n.translate('kibana_utils.history.savedObjectIsMissingNotificationMessage', {
+ defaultMessage: 'Saved object is missing',
+ }),
+ text: toMountPoint({error.message} ),
+ });
+
+ history.replace(url);
+ };
+}
diff --git a/src/plugins/kibana_utils/public/index.ts b/src/plugins/kibana_utils/public/index.ts
index ee38d5e8111c9..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 } 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/src/setup_node_env/exit_on_warning.js b/src/setup_node_env/exit_on_warning.js
index 5be5ccd72bd02..6321cd7ba8db0 100644
--- a/src/setup_node_env/exit_on_warning.js
+++ b/src/setup_node_env/exit_on_warning.js
@@ -35,4 +35,16 @@ if (process.noProcessWarnings !== true) {
process.exit(1);
});
+
+ // While the above warning listener would also be called on
+ // unhandledRejection warnings, we can give a better error message if we
+ // handle them separately:
+ process.on('unhandledRejection', function(reason) {
+ console.error('Unhandled Promise rejection detected:');
+ console.error();
+ console.error(reason);
+ console.error();
+ console.error('Terminating process...');
+ process.exit(1);
+ });
}
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 15f525620d503..589720f1052dc 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/lens/public/_config_panel.scss b/x-pack/legacy/plugins/lens/public/_config_panel.scss
deleted file mode 100644
index 5c6d25bf10818..0000000000000
--- a/x-pack/legacy/plugins/lens/public/_config_panel.scss
+++ /dev/null
@@ -1,21 +0,0 @@
-.lnsConfigPanel__panel {
- margin-bottom: $euiSizeS;
-}
-
-.lnsConfigPanel__axis {
- background: $euiColorLightestShade;
- padding: $euiSizeS;
- border-radius: $euiBorderRadius;
-
- // Add margin to the top of the next same panel
- & + & {
- margin-top: $euiSizeS;
- }
-}
-
-.lnsConfigPanel__addLayerBtn {
- color: transparentize($euiColorMediumShade, .3);
- // sass-lint:disable-block no-important
- box-shadow: none !important;
- border: 1px dashed currentColor;
-}
diff --git a/x-pack/legacy/plugins/lens/public/datatable_visualization/visualization.test.tsx b/x-pack/legacy/plugins/lens/public/datatable_visualization/visualization.test.tsx
index 0cba22170df1f..e18190b6c2d69 100644
--- a/x-pack/legacy/plugins/lens/public/datatable_visualization/visualization.test.tsx
+++ b/x-pack/legacy/plugins/lens/public/datatable_visualization/visualization.test.tsx
@@ -4,18 +4,9 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import React from 'react';
import { createMockDatasource } from '../editor_frame_service/mocks';
-import {
- DatatableVisualizationState,
- datatableVisualization,
- DataTableLayer,
-} from './visualization';
-import { mount } from 'enzyme';
+import { DatatableVisualizationState, datatableVisualization } from './visualization';
import { Operation, DataType, FramePublicAPI, TableSuggestionColumn } from '../types';
-import { generateId } from '../id_generator';
-
-jest.mock('../id_generator');
function mockFrame(): FramePublicAPI {
return {
@@ -34,12 +25,11 @@ function mockFrame(): FramePublicAPI {
describe('Datatable Visualization', () => {
describe('#initialize', () => {
it('should initialize from the empty state', () => {
- (generateId as jest.Mock).mockReturnValueOnce('id');
expect(datatableVisualization.initialize(mockFrame(), undefined)).toEqual({
layers: [
{
layerId: 'aaa',
- columns: ['id'],
+ columns: [],
},
],
});
@@ -88,7 +78,6 @@ describe('Datatable Visualization', () => {
describe('#clearLayer', () => {
it('should reset the layer', () => {
- (generateId as jest.Mock).mockReturnValueOnce('testid');
const state: DatatableVisualizationState = {
layers: [
{
@@ -101,7 +90,7 @@ describe('Datatable Visualization', () => {
layers: [
{
layerId: 'baz',
- columns: ['testid'],
+ columns: [],
},
],
});
@@ -214,29 +203,35 @@ describe('Datatable Visualization', () => {
});
});
- describe('DataTableLayer', () => {
- it('allows all kinds of operations', () => {
- const setState = jest.fn();
- const datasource = createMockDatasource();
- const layer = { layerId: 'a', columns: ['b', 'c'] };
+ describe('#getConfiguration', () => {
+ it('returns a single layer option', () => {
+ const datasource = createMockDatasource('test');
const frame = mockFrame();
- frame.datasourceLayers = { a: datasource.publicAPIMock };
+ frame.datasourceLayers = { first: datasource.publicAPIMock };
- mount(
- {} }}
- frame={frame}
- layer={layer}
- setState={setState}
- state={{ layers: [layer] }}
- />
- );
+ expect(
+ datatableVisualization.getConfiguration({
+ layerId: 'first',
+ state: {
+ layers: [{ layerId: 'first', columns: [] }],
+ },
+ frame,
+ }).groups
+ ).toHaveLength(1);
+ });
- expect(datasource.publicAPIMock.renderDimensionPanel).toHaveBeenCalled();
+ it('allows all kinds of operations', () => {
+ const datasource = createMockDatasource('test');
+ const frame = mockFrame();
+ frame.datasourceLayers = { first: datasource.publicAPIMock };
- const filterOperations =
- datasource.publicAPIMock.renderDimensionPanel.mock.calls[0][1].filterOperations;
+ const filterOperations = datatableVisualization.getConfiguration({
+ layerId: 'first',
+ state: {
+ layers: [{ layerId: 'first', columns: [] }],
+ },
+ frame,
+ }).groups[0].filterOperations;
const baseOperation: Operation = {
dataType: 'string',
@@ -253,108 +248,80 @@ describe('Datatable Visualization', () => {
);
});
- it('allows columns to be removed', () => {
- const setState = jest.fn();
- const datasource = createMockDatasource();
+ it('reorders the rendered colums based on the order from the datasource', () => {
+ const datasource = createMockDatasource('test');
const layer = { layerId: 'a', columns: ['b', 'c'] };
const frame = mockFrame();
frame.datasourceLayers = { a: datasource.publicAPIMock };
- const component = mount(
- {} }}
- frame={frame}
- layer={layer}
- setState={setState}
- state={{ layers: [layer] }}
- />
- );
-
- const onRemove = component
- .find('[data-test-subj="datatable_multicolumnEditor"]')
- .first()
- .prop('onRemove') as (k: string) => {};
-
- onRemove('b');
+ datasource.publicAPIMock.getTableSpec.mockReturnValue([{ columnId: 'c' }, { columnId: 'b' }]);
+
+ expect(
+ datatableVisualization.getConfiguration({
+ layerId: 'a',
+ state: { layers: [layer] },
+ frame,
+ }).groups[0].accessors
+ ).toEqual(['c', 'b']);
+ });
+ });
- expect(setState).toHaveBeenCalledWith({
+ describe('#removeDimension', () => {
+ it('allows columns to be removed', () => {
+ const layer = { layerId: 'layer1', columns: ['b', 'c'] };
+ expect(
+ datatableVisualization.removeDimension({
+ prevState: { layers: [layer] },
+ layerId: 'layer1',
+ columnId: 'b',
+ })
+ ).toEqual({
layers: [
{
- layerId: 'a',
+ layerId: 'layer1',
columns: ['c'],
},
],
});
});
+ });
+ describe('#setDimension', () => {
it('allows columns to be added', () => {
- (generateId as jest.Mock).mockReturnValueOnce('d');
- const setState = jest.fn();
- const datasource = createMockDatasource();
- const layer = { layerId: 'a', columns: ['b', 'c'] };
- const frame = mockFrame();
- frame.datasourceLayers = { a: datasource.publicAPIMock };
- const component = mount(
- {} }}
- frame={frame}
- layer={layer}
- setState={setState}
- state={{ layers: [layer] }}
- />
- );
-
- const onAdd = component
- .find('[data-test-subj="datatable_multicolumnEditor"]')
- .first()
- .prop('onAdd') as () => {};
-
- onAdd();
-
- expect(setState).toHaveBeenCalledWith({
+ const layer = { layerId: 'layer1', columns: ['b', 'c'] };
+ expect(
+ datatableVisualization.setDimension({
+ prevState: { layers: [layer] },
+ layerId: 'layer1',
+ columnId: 'd',
+ groupId: '',
+ })
+ ).toEqual({
layers: [
{
- layerId: 'a',
+ layerId: 'layer1',
columns: ['b', 'c', 'd'],
},
],
});
});
- it('reorders the rendered colums based on the order from the datasource', () => {
- const datasource = createMockDatasource();
- const layer = { layerId: 'a', columns: ['b', 'c'] };
- const frame = mockFrame();
- frame.datasourceLayers = { a: datasource.publicAPIMock };
- const component = mount(
- {} }}
- frame={frame}
- layer={layer}
- setState={jest.fn()}
- state={{ layers: [layer] }}
- />
- );
-
- const accessors = component
- .find('[data-test-subj="datatable_multicolumnEditor"]')
- .first()
- .prop('accessors') as string[];
-
- expect(accessors).toEqual(['b', 'c']);
-
- component.setProps({
- layer: { layerId: 'a', columns: ['c', 'b'] },
+ it('does not set a duplicate dimension', () => {
+ const layer = { layerId: 'layer1', columns: ['b', 'c'] };
+ expect(
+ datatableVisualization.setDimension({
+ prevState: { layers: [layer] },
+ layerId: 'layer1',
+ columnId: 'b',
+ groupId: '',
+ })
+ ).toEqual({
+ layers: [
+ {
+ layerId: 'layer1',
+ columns: ['b', 'c'],
+ },
+ ],
});
-
- const newAccessors = component
- .find('[data-test-subj="datatable_multicolumnEditor"]')
- .first()
- .prop('accessors') as string[];
-
- expect(newAccessors).toEqual(['c', 'b']);
});
});
});
diff --git a/x-pack/legacy/plugins/lens/public/datatable_visualization/visualization.tsx b/x-pack/legacy/plugins/lens/public/datatable_visualization/visualization.tsx
index 79a018635134f..4248d722d5540 100644
--- a/x-pack/legacy/plugins/lens/public/datatable_visualization/visualization.tsx
+++ b/x-pack/legacy/plugins/lens/public/datatable_visualization/visualization.tsx
@@ -4,20 +4,8 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import React from 'react';
-import { render } from 'react-dom';
-import { EuiFormRow } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
-import { I18nProvider } from '@kbn/i18n/react';
-import { MultiColumnEditor } from '../multi_column_editor';
-import {
- SuggestionRequest,
- Visualization,
- VisualizationLayerConfigProps,
- VisualizationSuggestion,
- Operation,
-} from '../types';
-import { generateId } from '../id_generator';
+import { SuggestionRequest, Visualization, VisualizationSuggestion, Operation } from '../types';
import chartTableSVG from '../assets/chart_datatable.svg';
export interface LayerState {
@@ -32,58 +20,10 @@ export interface DatatableVisualizationState {
function newLayerState(layerId: string): LayerState {
return {
layerId,
- columns: [generateId()],
+ columns: [],
};
}
-function updateColumns(
- state: DatatableVisualizationState,
- layer: LayerState,
- fn: (columns: string[]) => string[]
-) {
- const columns = fn(layer.columns);
- const updatedLayer = { ...layer, columns };
- const layers = state.layers.map(l => (l.layerId === layer.layerId ? updatedLayer : l));
- return { ...state, layers };
-}
-
-const allOperations = () => true;
-
-export function DataTableLayer({
- layer,
- frame,
- state,
- setState,
- dragDropContext,
-}: { layer: LayerState } & VisualizationLayerConfigProps) {
- const datasource = frame.datasourceLayers[layer.layerId];
-
- const originalOrder = datasource.getTableSpec().map(({ columnId }) => columnId);
- // When we add a column it could be empty, and therefore have no order
- const sortedColumns = Array.from(new Set(originalOrder.concat(layer.columns)));
-
- return (
-
- setState(updateColumns(state, layer, columns => [...columns, generateId()]))}
- onRemove={column =>
- setState(updateColumns(state, layer, columns => columns.filter(c => c !== column)))
- }
- testSubj="datatable_columns"
- data-test-subj="datatable_multicolumnEditor"
- />
-
- );
-}
-
export const datatableVisualization: Visualization<
DatatableVisualizationState,
DatatableVisualizationState
@@ -188,17 +128,56 @@ export const datatableVisualization: Visualization<
];
},
- renderLayerConfigPanel(domElement, props) {
- const layer = props.state.layers.find(l => l.layerId === props.layerId);
-
- if (layer) {
- render(
-
-
- ,
- domElement
- );
+ getConfiguration({ state, frame, layerId }) {
+ const layer = state.layers.find(l => l.layerId === layerId);
+ if (!layer) {
+ return { groups: [] };
}
+
+ const datasource = frame.datasourceLayers[layer.layerId];
+ const originalOrder = datasource.getTableSpec().map(({ columnId }) => columnId);
+ // When we add a column it could be empty, and therefore have no order
+ const sortedColumns = Array.from(new Set(originalOrder.concat(layer.columns)));
+
+ return {
+ groups: [
+ {
+ groupId: 'columns',
+ groupLabel: i18n.translate('xpack.lens.datatable.columns', {
+ defaultMessage: 'Columns',
+ }),
+ layerId: state.layers[0].layerId,
+ accessors: sortedColumns,
+ supportsMoreColumns: true,
+ filterOperations: () => true,
+ },
+ ],
+ };
+ },
+
+ setDimension({ prevState, layerId, columnId }) {
+ return {
+ ...prevState,
+ layers: prevState.layers.map(l => {
+ if (l.layerId !== layerId || l.columns.includes(columnId)) {
+ return l;
+ }
+ return { ...l, columns: [...l.columns, columnId] };
+ }),
+ };
+ },
+ removeDimension({ prevState, layerId, columnId }) {
+ return {
+ ...prevState,
+ layers: prevState.layers.map(l =>
+ l.layerId === layerId
+ ? {
+ ...l,
+ columns: l.columns.filter(c => c !== columnId),
+ }
+ : l
+ ),
+ };
},
toExpression(state, frame) {
diff --git a/x-pack/legacy/plugins/lens/public/editor_frame_service/editor_frame/_config_panel_wrapper.scss b/x-pack/legacy/plugins/lens/public/editor_frame_service/editor_frame/_config_panel_wrapper.scss
new file mode 100644
index 0000000000000..62a7f6b023f31
--- /dev/null
+++ b/x-pack/legacy/plugins/lens/public/editor_frame_service/editor_frame/_config_panel_wrapper.scss
@@ -0,0 +1,50 @@
+.lnsConfigPanel__panel {
+ margin-bottom: $euiSizeS;
+}
+
+.lnsConfigPanel__row {
+ background: $euiColorLightestShade;
+ padding: $euiSizeS;
+ border-radius: $euiBorderRadius;
+
+ // Add margin to the top of the next same panel
+ & + & {
+ margin-top: $euiSizeS;
+ }
+}
+
+.lnsConfigPanel__addLayerBtn {
+ color: transparentize($euiColorMediumShade, .3);
+ // Remove EuiButton's default shadow to make button more subtle
+ // sass-lint:disable-block no-important
+ box-shadow: none !important;
+ border: 1px dashed currentColor;
+}
+
+.lnsConfigPanel__dimension {
+ @include euiFontSizeS;
+ background: lightOrDarkTheme($euiColorEmptyShade, $euiColorLightestShade);
+ border-radius: $euiBorderRadius;
+ display: flex;
+ align-items: center;
+ margin-top: $euiSizeXS;
+ overflow: hidden;
+}
+
+.lnsConfigPanel__trigger {
+ max-width: 100%;
+ display: block;
+}
+
+.lnsConfigPanel__triggerLink {
+ padding: $euiSizeS;
+ width: 100%;
+ display: flex;
+ align-items: center;
+ min-height: $euiSizeXXL;
+}
+
+.lnsConfigPanel__popover {
+ line-height: 0;
+ flex-grow: 1;
+}
diff --git a/x-pack/legacy/plugins/lens/public/editor_frame_service/editor_frame/chart_switch.test.tsx b/x-pack/legacy/plugins/lens/public/editor_frame_service/editor_frame/chart_switch.test.tsx
index 1b60098fd45ad..6698c9e68b98c 100644
--- a/x-pack/legacy/plugins/lens/public/editor_frame_service/editor_frame/chart_switch.test.tsx
+++ b/x-pack/legacy/plugins/lens/public/editor_frame_service/editor_frame/chart_switch.test.tsx
@@ -84,7 +84,7 @@ describe('chart_switch', () => {
}
function mockDatasourceMap() {
- const datasource = createMockDatasource();
+ const datasource = createMockDatasource('testDatasource');
datasource.getDatasourceSuggestionsFromCurrentState.mockReturnValue([
{
state: {},
diff --git a/x-pack/legacy/plugins/lens/public/editor_frame_service/editor_frame/config_panel_wrapper.tsx b/x-pack/legacy/plugins/lens/public/editor_frame_service/editor_frame/config_panel_wrapper.tsx
index 1422ee86be3e9..c2cd0485de67e 100644
--- a/x-pack/legacy/plugins/lens/public/editor_frame_service/editor_frame/config_panel_wrapper.tsx
+++ b/x-pack/legacy/plugins/lens/public/editor_frame_service/editor_frame/config_panel_wrapper.tsx
@@ -16,17 +16,21 @@ import {
EuiToolTip,
EuiButton,
EuiForm,
+ EuiFormRow,
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
+import { FormattedMessage } from '@kbn/i18n/react';
import { NativeRenderer } from '../../native_renderer';
import { Action } from './state_management';
import {
Visualization,
FramePublicAPI,
Datasource,
- VisualizationLayerConfigProps,
+ VisualizationLayerWidgetProps,
+ DatasourceDimensionEditorProps,
+ StateSetter,
} from '../../types';
-import { DragContext } from '../../drag_drop';
+import { DragContext, DragDrop, ChildDragDropProvider } from '../../drag_drop';
import { ChartSwitch } from './chart_switch';
import { trackUiEvent } from '../../lens_ui_telemetry';
import { generateId } from '../../id_generator';
@@ -47,6 +51,7 @@ interface ConfigPanelWrapperProps {
state: unknown;
}
>;
+ core: DatasourceDimensionEditorProps['core'];
}
export const ConfigPanelWrapper = memo(function ConfigPanelWrapper(props: ConfigPanelWrapperProps) {
@@ -86,8 +91,7 @@ function LayerPanels(
activeDatasourceId,
datasourceMap,
} = props;
- const dragDropContext = useContext(DragContext);
- const setState = useMemo(
+ const setVisualizationState = useMemo(
() => (newState: unknown) => {
props.dispatch({
type: 'UPDATE_VISUALIZATION_STATE',
@@ -98,6 +102,43 @@ function LayerPanels(
},
[props.dispatch, activeVisualization]
);
+ const updateDatasource = useMemo(
+ () => (datasourceId: string, newState: unknown) => {
+ props.dispatch({
+ type: 'UPDATE_DATASOURCE_STATE',
+ updater: () => newState,
+ datasourceId,
+ clearStagedPreview: false,
+ });
+ },
+ [props.dispatch]
+ );
+ const updateAll = useMemo(
+ () => (datasourceId: string, newDatasourceState: unknown, newVisualizationState: unknown) => {
+ props.dispatch({
+ type: 'UPDATE_STATE',
+ subType: 'UPDATE_ALL_STATES',
+ updater: prevState => {
+ return {
+ ...prevState,
+ datasourceStates: {
+ ...prevState.datasourceStates,
+ [datasourceId]: {
+ state: newDatasourceState,
+ isLoading: false,
+ },
+ },
+ visualization: {
+ activeId: activeVisualization.id,
+ state: newVisualizationState,
+ },
+ stagedPreview: undefined,
+ };
+ },
+ });
+ },
+ [props.dispatch]
+ );
const layerIds = activeVisualization.getLayerIds(visualizationState);
return (
@@ -108,12 +149,13 @@ function LayerPanels(
key={layerId}
layerId={layerId}
activeVisualization={activeVisualization}
- dragDropContext={dragDropContext}
- state={setState}
- setState={setState}
+ visualizationState={visualizationState}
+ updateVisualization={setVisualizationState}
+ updateDatasource={updateDatasource}
+ updateAll={updateAll}
frame={framePublicAPI}
isOnlyLayer={layerIds.length === 1}
- onRemove={() => {
+ onRemoveLayer={() => {
dispatch({
type: 'UPDATE_STATE',
subType: 'REMOVE_OR_CLEAR_LAYER',
@@ -143,7 +185,7 @@ function LayerPanels(
className="lnsConfigPanel__addLayerBtn"
fullWidth
size="s"
- data-test-subj={`lnsXY_layer_add`}
+ data-test-subj="lnsXY_layer_add"
aria-label={i18n.translate('xpack.lens.xyChart.addLayerButton', {
defaultMessage: 'Add layer',
})}
@@ -174,85 +216,399 @@ function LayerPanels(
}
function LayerPanel(
- props: ConfigPanelWrapperProps &
- VisualizationLayerConfigProps & {
- isOnlyLayer: boolean;
- activeVisualization: Visualization;
- onRemove: () => void;
- }
+ props: Exclude & {
+ frame: FramePublicAPI;
+ layerId: string;
+ isOnlyLayer: boolean;
+ activeVisualization: Visualization;
+ visualizationState: unknown;
+ updateVisualization: StateSetter;
+ updateDatasource: (datasourceId: string, newState: unknown) => void;
+ updateAll: (
+ datasourceId: string,
+ newDatasourcestate: unknown,
+ newVisualizationState: unknown
+ ) => void;
+ onRemoveLayer: () => void;
+ }
) {
- const { framePublicAPI, layerId, activeVisualization, isOnlyLayer, onRemove } = props;
+ const dragDropContext = useContext(DragContext);
+ const { framePublicAPI, layerId, activeVisualization, isOnlyLayer, onRemoveLayer } = props;
const datasourcePublicAPI = framePublicAPI.datasourceLayers[layerId];
- const layerConfigProps = {
+ if (!datasourcePublicAPI) {
+ return null;
+ }
+ const layerVisualizationConfigProps = {
layerId,
- dragDropContext: props.dragDropContext,
+ dragDropContext,
state: props.visualizationState,
- setState: props.setState,
frame: props.framePublicAPI,
+ dateRange: props.framePublicAPI.dateRange,
};
+ const datasourceId = datasourcePublicAPI.datasourceId;
+ const layerDatasourceState = props.datasourceStates[datasourceId].state;
+ const layerDatasource = props.datasourceMap[datasourceId];
- return (
-
-
-
-
-
+ const layerDatasourceDropProps = {
+ layerId,
+ dragDropContext,
+ state: layerDatasourceState,
+ setState: (newState: unknown) => {
+ props.updateDatasource(datasourceId, newState);
+ },
+ };
- {datasourcePublicAPI && (
-
- ({
+ isOpen: false,
+ openId: null,
+ addingToGroupId: null,
+ });
+
+ const { groups } = activeVisualization.getConfiguration(layerVisualizationConfigProps);
+ const isEmptyLayer = !groups.some(d => d.accessors.length > 0);
+
+ function wrapInPopover(
+ id: string,
+ groupId: string,
+ trigger: React.ReactElement,
+ panel: React.ReactElement
+ ) {
+ const noMatch = popoverState.isOpen ? !groups.some(d => d.accessors.includes(id)) : false;
+ return (
+ {
+ setPopoverState({ isOpen: false, openId: null, addingToGroupId: null });
+ }}
+ button={trigger}
+ anchorPosition="leftUp"
+ withTitle
+ panelPaddingSize="s"
+ >
+ {panel}
+
+ );
+ }
+
+ return (
+
+
+
+
+
- )}
-
-
-
-
+ {layerDatasource && (
+
+ {
+ const newState =
+ typeof updater === 'function' ? updater(layerDatasourceState) : updater;
+ // Look for removed columns
+ const nextPublicAPI = layerDatasource.getPublicAPI({
+ state: newState,
+ layerId,
+ dateRange: props.framePublicAPI.dateRange,
+ });
+ const nextTable = new Set(
+ nextPublicAPI.getTableSpec().map(({ columnId }) => columnId)
+ );
+ const removed = datasourcePublicAPI
+ .getTableSpec()
+ .map(({ columnId }) => columnId)
+ .filter(columnId => !nextTable.has(columnId));
+ let nextVisState = props.visualizationState;
+ removed.forEach(columnId => {
+ nextVisState = activeVisualization.removeDimension({
+ layerId,
+ columnId,
+ prevState: nextVisState,
+ });
+ });
-
+ props.updateAll(datasourceId, newState, nextVisState);
+ },
+ }}
+ />
+
+ )}
+
-
-
- {
- // If we don't blur the remove / clear button, it remains focused
- // which is a strange UX in this case. e.target.blur doesn't work
- // due to who knows what, but probably event re-writing. Additionally,
- // activeElement does not have blur so, we need to do some casting + safeguards.
- const el = (document.activeElement as unknown) as { blur: () => void };
+
- if (el && el.blur) {
- el.blur();
+ {groups.map((group, index) => {
+ const newId = generateId();
+ const isMissing = !isEmptyLayer && group.required && group.accessors.length === 0;
+ return (
+
+ <>
+ {group.accessors.map(accessor => (
+ {
+ layerDatasource.onDrop({
+ ...layerDatasourceDropProps,
+ droppedItem,
+ columnId: accessor,
+ filterOperations: group.filterOperations,
+ });
+ }}
+ >
+ {wrapInPopover(
+ accessor,
+ group.groupId,
+ {
+ if (popoverState.isOpen) {
+ setPopoverState({
+ isOpen: false,
+ openId: null,
+ addingToGroupId: null,
+ });
+ } else {
+ setPopoverState({
+ isOpen: true,
+ openId: accessor,
+ addingToGroupId: null, // not set for existing dimension
+ });
+ }
+ },
+ }}
+ />,
+
+ )}
- onRemove();
- }}
- >
- {isOnlyLayer
- ? i18n.translate('xpack.lens.resetLayer', {
- defaultMessage: 'Reset layer',
- })
- : i18n.translate('xpack.lens.deleteLayer', {
- defaultMessage: 'Delete layer',
- })}
-
-
-
-
+ {
+ trackUiEvent('indexpattern_dimension_removed');
+ props.updateAll(
+ datasourceId,
+ layerDatasource.removeColumn({
+ layerId,
+ columnId: accessor,
+ prevState: layerDatasourceState,
+ }),
+ props.activeVisualization.removeDimension({
+ layerId,
+ columnId: accessor,
+ prevState: props.visualizationState,
+ })
+ );
+ }}
+ />
+
+ ))}
+ {group.supportsMoreColumns ? (
+ {
+ const dropSuccess = layerDatasource.onDrop({
+ ...layerDatasourceDropProps,
+ droppedItem,
+ columnId: newId,
+ filterOperations: group.filterOperations,
+ });
+ if (dropSuccess) {
+ props.updateVisualization(
+ activeVisualization.setDimension({
+ layerId,
+ groupId: group.groupId,
+ columnId: newId,
+ prevState: props.visualizationState,
+ })
+ );
+ }
+ }}
+ >
+ {wrapInPopover(
+ newId,
+ group.groupId,
+
+ {
+ if (popoverState.isOpen) {
+ setPopoverState({
+ isOpen: false,
+ openId: null,
+ addingToGroupId: null,
+ });
+ } else {
+ setPopoverState({
+ isOpen: true,
+ openId: newId,
+ addingToGroupId: group.groupId,
+ });
+ }
+ }}
+ size="xs"
+ >
+
+
+
,
+ {
+ props.updateAll(
+ datasourceId,
+ newState,
+ activeVisualization.setDimension({
+ layerId,
+ groupId: group.groupId,
+ columnId: newId,
+ prevState: props.visualizationState,
+ })
+ );
+ setPopoverState({
+ isOpen: true,
+ openId: newId,
+ addingToGroupId: null, // clear now that dimension exists
+ });
+ },
+ }}
+ />
+ )}
+
+ ) : null}
+ >
+
+ );
+ })}
+
+
+
+
+
+ {
+ // If we don't blur the remove / clear button, it remains focused
+ // which is a strange UX in this case. e.target.blur doesn't work
+ // due to who knows what, but probably event re-writing. Additionally,
+ // activeElement does not have blur so, we need to do some casting + safeguards.
+ const el = (document.activeElement as unknown) as { blur: () => void };
+
+ if (el?.blur) {
+ el.blur();
+ }
+
+ onRemoveLayer();
+ }}
+ >
+ {isOnlyLayer
+ ? i18n.translate('xpack.lens.resetLayer', {
+ defaultMessage: 'Reset layer',
+ })
+ : i18n.translate('xpack.lens.deleteLayer', {
+ defaultMessage: 'Delete layer',
+ })}
+
+
+
+
+
);
}
@@ -263,7 +619,7 @@ function LayerSettings({
}: {
layerId: string;
activeVisualization: Visualization;
- layerConfigProps: VisualizationLayerConfigProps;
+ layerConfigProps: VisualizationLayerWidgetProps;
}) {
const [isOpen, setIsOpen] = useState(false);
diff --git a/x-pack/legacy/plugins/lens/public/editor_frame_service/editor_frame/editor_frame.test.tsx b/x-pack/legacy/plugins/lens/public/editor_frame_service/editor_frame/editor_frame.test.tsx
index dd591b3992fe5..8d8d38944e18a 100644
--- a/x-pack/legacy/plugins/lens/public/editor_frame_service/editor_frame/editor_frame.test.tsx
+++ b/x-pack/legacy/plugins/lens/public/editor_frame_service/editor_frame/editor_frame.test.tsx
@@ -87,14 +87,15 @@ describe('editor_frame', () => {
mockVisualization.getLayerIds.mockReturnValue(['first']);
mockVisualization2.getLayerIds.mockReturnValue(['second']);
- mockDatasource = createMockDatasource();
- mockDatasource2 = createMockDatasource();
+ mockDatasource = createMockDatasource('testDatasource');
+ mockDatasource2 = createMockDatasource('testDatasource2');
expressionRendererMock = createExpressionRendererMock();
});
describe('initialization', () => {
it('should initialize initial datasource', async () => {
+ mockVisualization.getLayerIds.mockReturnValue([]);
await act(async () => {
mount(
{
});
it('should initialize all datasources with state from doc', async () => {
- const mockDatasource3 = createMockDatasource();
+ const mockDatasource3 = createMockDatasource('testDatasource3');
const datasource1State = { datasource1: '' };
const datasource2State = { datasource2: '' };
@@ -198,9 +199,9 @@ describe('editor_frame', () => {
ExpressionRenderer={expressionRendererMock}
/>
);
- expect(mockVisualization.renderLayerConfigPanel).not.toHaveBeenCalled();
expect(mockDatasource.renderDataPanel).not.toHaveBeenCalled();
});
+ expect(mockDatasource.renderDataPanel).toHaveBeenCalled();
});
it('should not initialize visualization before datasource is initialized', async () => {
@@ -289,6 +290,7 @@ describe('editor_frame', () => {
mockDatasource2.initialize.mockReturnValue(Promise.resolve(initialState));
mockDatasource2.getLayers.mockReturnValue(['abc', 'def']);
mockDatasource2.removeLayer.mockReturnValue({ removed: true });
+ mockVisualization.getLayerIds.mockReturnValue(['first', 'abc', 'def']);
await act(async () => {
mount(
{
);
});
- expect(mockVisualization.renderLayerConfigPanel).toHaveBeenCalledWith(
- expect.any(Element),
+ expect(mockVisualization.getConfiguration).toHaveBeenCalledWith(
expect.objectContaining({ state: initialState })
);
});
@@ -614,15 +615,14 @@ describe('editor_frame', () => {
);
});
const updatedState = {};
- const setVisualizationState = (mockVisualization.renderLayerConfigPanel as jest.Mock).mock
- .calls[0][1].setState;
+ const setDatasourceState = (mockDatasource.renderDataPanel as jest.Mock).mock.calls[0][1]
+ .setState;
act(() => {
- setVisualizationState(updatedState);
+ setDatasourceState(updatedState);
});
- expect(mockVisualization.renderLayerConfigPanel).toHaveBeenCalledTimes(2);
- expect(mockVisualization.renderLayerConfigPanel).toHaveBeenLastCalledWith(
- expect.any(Element),
+ expect(mockVisualization.getConfiguration).toHaveBeenCalledTimes(2);
+ expect(mockVisualization.getConfiguration).toHaveBeenLastCalledWith(
expect.objectContaining({
state: updatedState,
})
@@ -688,8 +688,7 @@ describe('editor_frame', () => {
});
const updatedPublicAPI: DatasourcePublicAPI = {
- renderLayerPanel: jest.fn(),
- renderDimensionPanel: jest.fn(),
+ datasourceId: 'testDatasource',
getOperationForColumnId: jest.fn(),
getTableSpec: jest.fn(),
};
@@ -701,9 +700,8 @@ describe('editor_frame', () => {
setDatasourceState({});
});
- expect(mockVisualization.renderLayerConfigPanel).toHaveBeenCalledTimes(2);
- expect(mockVisualization.renderLayerConfigPanel).toHaveBeenLastCalledWith(
- expect.any(Element),
+ expect(mockVisualization.getConfiguration).toHaveBeenCalledTimes(2);
+ expect(mockVisualization.getConfiguration).toHaveBeenLastCalledWith(
expect.objectContaining({
frame: expect.objectContaining({
datasourceLayers: {
@@ -719,6 +717,7 @@ describe('editor_frame', () => {
it('should pass the datasource api for each layer to the visualization', async () => {
mockDatasource.getLayers.mockReturnValue(['first']);
mockDatasource2.getLayers.mockReturnValue(['second', 'third']);
+ mockVisualization.getLayerIds.mockReturnValue(['first', 'second', 'third']);
await act(async () => {
mount(
@@ -755,10 +754,10 @@ describe('editor_frame', () => {
);
});
- expect(mockVisualization.renderLayerConfigPanel).toHaveBeenCalled();
+ expect(mockVisualization.getConfiguration).toHaveBeenCalled();
const datasourceLayers =
- mockVisualization.renderLayerConfigPanel.mock.calls[0][1].frame.datasourceLayers;
+ mockVisualization.getConfiguration.mock.calls[0][0].frame.datasourceLayers;
expect(datasourceLayers.first).toBe(mockDatasource.publicAPIMock);
expect(datasourceLayers.second).toBe(mockDatasource2.publicAPIMock);
expect(datasourceLayers.third).toBe(mockDatasource2.publicAPIMock);
@@ -811,21 +810,18 @@ describe('editor_frame', () => {
expect(mockDatasource.getPublicAPI).toHaveBeenCalledWith(
expect.objectContaining({
state: datasource1State,
- setState: expect.anything(),
layerId: 'first',
})
);
expect(mockDatasource2.getPublicAPI).toHaveBeenCalledWith(
expect.objectContaining({
state: datasource2State,
- setState: expect.anything(),
layerId: 'second',
})
);
expect(mockDatasource2.getPublicAPI).toHaveBeenCalledWith(
expect.objectContaining({
state: datasource2State,
- setState: expect.anything(),
layerId: 'third',
})
);
@@ -858,45 +854,9 @@ describe('editor_frame', () => {
expect(mockDatasource.getPublicAPI).toHaveBeenCalledWith({
dateRange,
state: datasourceState,
- setState: expect.any(Function),
layerId: 'first',
});
});
-
- it('should re-create the public api after state has been set', async () => {
- mockDatasource.getLayers.mockReturnValue(['first']);
-
- await act(async () => {
- mount(
-
- );
- });
-
- const updatedState = {};
- const setDatasourceState = mockDatasource.getPublicAPI.mock.calls[0][0].setState;
- act(() => {
- setDatasourceState(updatedState);
- });
-
- expect(mockDatasource.getPublicAPI).toHaveBeenLastCalledWith(
- expect.objectContaining({
- state: updatedState,
- setState: expect.any(Function),
- layerId: 'first',
- })
- );
- });
});
describe('switching', () => {
@@ -1021,8 +981,7 @@ describe('editor_frame', () => {
expect(mockVisualization2.getSuggestions).toHaveBeenCalled();
expect(mockVisualization2.initialize).toHaveBeenCalledWith(expect.anything(), initialState);
- expect(mockVisualization2.renderLayerConfigPanel).toHaveBeenCalledWith(
- expect.any(Element),
+ expect(mockVisualization2.getConfiguration).toHaveBeenCalledWith(
expect.objectContaining({ state: { initial: true } })
);
});
@@ -1039,8 +998,7 @@ describe('editor_frame', () => {
datasourceLayers: expect.objectContaining({ first: mockDatasource.publicAPIMock }),
})
);
- expect(mockVisualization2.renderLayerConfigPanel).toHaveBeenCalledWith(
- expect.any(Element),
+ expect(mockVisualization2.getConfiguration).toHaveBeenCalledWith(
expect.objectContaining({ state: { initial: true } })
);
});
@@ -1239,9 +1197,8 @@ describe('editor_frame', () => {
.simulate('click');
});
- expect(mockVisualization.renderLayerConfigPanel).toHaveBeenCalledTimes(1);
- expect(mockVisualization.renderLayerConfigPanel).toHaveBeenCalledWith(
- expect.any(Element),
+ expect(mockVisualization.getConfiguration).toHaveBeenCalledTimes(1);
+ expect(mockVisualization.getConfiguration).toHaveBeenCalledWith(
expect.objectContaining({
state: suggestionVisState,
})
@@ -1306,8 +1263,7 @@ describe('editor_frame', () => {
.simulate('drop');
});
- expect(mockVisualization.renderLayerConfigPanel).toHaveBeenCalledWith(
- expect.any(Element),
+ expect(mockVisualization.getConfiguration).toHaveBeenCalledWith(
expect.objectContaining({
state: suggestionVisState,
})
@@ -1375,14 +1331,16 @@ describe('editor_frame', () => {
instance.update();
act(() => {
- instance.find(DragDrop).prop('onDrop')!({
+ instance
+ .find(DragDrop)
+ .filter('[data-test-subj="mockVisA"]')
+ .prop('onDrop')!({
indexPatternId: '1',
field: {},
});
});
- expect(mockVisualization2.renderLayerConfigPanel).toHaveBeenCalledWith(
- expect.any(Element),
+ expect(mockVisualization2.getConfiguration).toHaveBeenCalledWith(
expect.objectContaining({
state: suggestionVisState,
})
@@ -1472,14 +1430,16 @@ describe('editor_frame', () => {
instance.update();
act(() => {
- instance.find(DragDrop).prop('onDrop')!({
+ instance
+ .find(DragDrop)
+ .filter('[data-test-subj="lnsWorkspace"]')
+ .prop('onDrop')!({
indexPatternId: '1',
field: {},
});
});
- expect(mockVisualization3.renderLayerConfigPanel).toHaveBeenCalledWith(
- expect.any(Element),
+ expect(mockVisualization3.getConfiguration).toHaveBeenCalledWith(
expect.objectContaining({
state: suggestionVisState,
})
diff --git a/x-pack/legacy/plugins/lens/public/editor_frame_service/editor_frame/editor_frame.tsx b/x-pack/legacy/plugins/lens/public/editor_frame_service/editor_frame/editor_frame.tsx
index a456372c99c01..082519d9a8feb 100644
--- a/x-pack/legacy/plugins/lens/public/editor_frame_service/editor_frame/editor_frame.tsx
+++ b/x-pack/legacy/plugins/lens/public/editor_frame_service/editor_frame/editor_frame.tsx
@@ -21,6 +21,7 @@ import { FrameLayout } from './frame_layout';
import { SuggestionPanel } from './suggestion_panel';
import { WorkspacePanel } from './workspace_panel';
import { Document } from '../../persistence/saved_object_store';
+import { RootDragDropProvider } from '../../drag_drop';
import { getSavedObjectFormat } from './save';
import { WorkspacePanelWrapper } from './workspace_panel_wrapper';
import { generateId } from '../../id_generator';
@@ -90,21 +91,11 @@ export function EditorFrame(props: EditorFrameProps) {
const layers = datasource.getLayers(datasourceState);
layers.forEach(layer => {
- const publicAPI = props.datasourceMap[id].getPublicAPI({
+ datasourceLayers[layer] = props.datasourceMap[id].getPublicAPI({
state: datasourceState,
- setState: (newState: unknown) => {
- dispatch({
- type: 'UPDATE_DATASOURCE_STATE',
- datasourceId: id,
- updater: newState,
- clearStagedPreview: true,
- });
- },
layerId: layer,
dateRange: props.dateRange,
});
-
- datasourceLayers[layer] = publicAPI;
});
});
@@ -235,74 +226,79 @@ export function EditorFrame(props: EditorFrameProps) {
]);
return (
-
- }
- configPanel={
- allLoaded && (
-
+
- )
- }
- workspacePanel={
- allLoaded && (
-
-
+ )
+ }
+ workspacePanel={
+ allLoaded && (
+
+
+
+ )
+ }
+ suggestionsPanel={
+ allLoaded && (
+
-
- )
- }
- suggestionsPanel={
- allLoaded && (
-
- )
- }
- />
+ )
+ }
+ />
+
);
}
diff --git a/x-pack/legacy/plugins/lens/public/editor_frame_service/editor_frame/frame_layout.tsx b/x-pack/legacy/plugins/lens/public/editor_frame_service/editor_frame/frame_layout.tsx
index a69da8b49e233..56afe3ed69a73 100644
--- a/x-pack/legacy/plugins/lens/public/editor_frame_service/editor_frame/frame_layout.tsx
+++ b/x-pack/legacy/plugins/lens/public/editor_frame_service/editor_frame/frame_layout.tsx
@@ -6,7 +6,6 @@
import React from 'react';
import { EuiPage, EuiPageSideBar, EuiPageBody } from '@elastic/eui';
-import { RootDragDropProvider } from '../../drag_drop';
export interface FrameLayoutProps {
dataPanel: React.ReactNode;
@@ -17,19 +16,17 @@ export interface FrameLayoutProps {
export function FrameLayout(props: FrameLayoutProps) {
return (
-
-
-
- {props.dataPanel}
-
- {props.workspacePanel}
- {props.suggestionsPanel}
-
-
- {props.configPanel}
-
-
-
-
+
+
+ {props.dataPanel}
+
+ {props.workspacePanel}
+ {props.suggestionsPanel}
+
+
+ {props.configPanel}
+
+
+
);
}
diff --git a/x-pack/legacy/plugins/lens/public/editor_frame_service/editor_frame/index.scss b/x-pack/legacy/plugins/lens/public/editor_frame_service/editor_frame/index.scss
index fee28c374ef7e..6c6a63c8c7eb6 100644
--- a/x-pack/legacy/plugins/lens/public/editor_frame_service/editor_frame/index.scss
+++ b/x-pack/legacy/plugins/lens/public/editor_frame_service/editor_frame/index.scss
@@ -1,4 +1,5 @@
@import './chart_switch';
+@import './config_panel_wrapper';
@import './data_panel_wrapper';
@import './expression_renderer';
@import './frame_layout';
diff --git a/x-pack/legacy/plugins/lens/public/editor_frame_service/editor_frame/save.test.ts b/x-pack/legacy/plugins/lens/public/editor_frame_service/editor_frame/save.test.ts
index 158a6cb8c979a..60bfbc493f61c 100644
--- a/x-pack/legacy/plugins/lens/public/editor_frame_service/editor_frame/save.test.ts
+++ b/x-pack/legacy/plugins/lens/public/editor_frame_service/editor_frame/save.test.ts
@@ -11,7 +11,7 @@ import { esFilters, IIndexPattern, IFieldType } from '../../../../../../../src/p
describe('save editor frame state', () => {
const mockVisualization = createMockVisualization();
mockVisualization.getPersistableState.mockImplementation(x => x);
- const mockDatasource = createMockDatasource();
+ const mockDatasource = createMockDatasource('a');
const mockIndexPattern = ({ id: 'indexpattern' } as unknown) as IIndexPattern;
const mockField = ({ name: '@timestamp' } as unknown) as IFieldType;
@@ -45,7 +45,7 @@ describe('save editor frame state', () => {
};
it('transforms from internal state to persisted doc format', async () => {
- const datasource = createMockDatasource();
+ const datasource = createMockDatasource('a');
datasource.getPersistableState.mockImplementation(state => ({
stuff: `${state}_datasource_persisted`,
}));
diff --git a/x-pack/legacy/plugins/lens/public/editor_frame_service/editor_frame/suggestion_helpers.test.ts b/x-pack/legacy/plugins/lens/public/editor_frame_service/editor_frame/suggestion_helpers.test.ts
index 487a91c22b5d5..63b8b1f048296 100644
--- a/x-pack/legacy/plugins/lens/public/editor_frame_service/editor_frame/suggestion_helpers.test.ts
+++ b/x-pack/legacy/plugins/lens/public/editor_frame_service/editor_frame/suggestion_helpers.test.ts
@@ -30,7 +30,7 @@ let datasourceStates: Record<
beforeEach(() => {
datasourceMap = {
- mock: createMockDatasource(),
+ mock: createMockDatasource('a'),
};
datasourceStates = {
@@ -147,9 +147,9 @@ describe('suggestion helpers', () => {
},
};
const multiDatasourceMap = {
- mock: createMockDatasource(),
- mock2: createMockDatasource(),
- mock3: createMockDatasource(),
+ mock: createMockDatasource('a'),
+ mock2: createMockDatasource('a'),
+ mock3: createMockDatasource('a'),
};
const droppedField = {};
getSuggestions({
diff --git a/x-pack/legacy/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.test.tsx b/x-pack/legacy/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.test.tsx
index 9729d6259f84a..b146f2467c46c 100644
--- a/x-pack/legacy/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.test.tsx
+++ b/x-pack/legacy/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.test.tsx
@@ -39,7 +39,7 @@ describe('suggestion_panel', () => {
beforeEach(() => {
mockVisualization = createMockVisualization();
- mockDatasource = createMockDatasource();
+ mockDatasource = createMockDatasource('a');
expressionRendererMock = createExpressionRendererMock();
dispatchMock = jest.fn();
diff --git a/x-pack/legacy/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.tsx b/x-pack/legacy/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.tsx
index 1115126792c86..93f6ea6ea67ac 100644
--- a/x-pack/legacy/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.tsx
+++ b/x-pack/legacy/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.tsx
@@ -373,7 +373,6 @@ function getPreviewExpression(
layerId,
dateRange: frame.dateRange,
state: datasourceState,
- setState: () => {},
});
}
});
diff --git a/x-pack/legacy/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel.test.tsx b/x-pack/legacy/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel.test.tsx
index a51091d39f84c..748e5b876da95 100644
--- a/x-pack/legacy/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel.test.tsx
+++ b/x-pack/legacy/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel.test.tsx
@@ -36,7 +36,7 @@ describe('workspace_panel', () => {
mockVisualization = createMockVisualization();
mockVisualization2 = createMockVisualization();
- mockDatasource = createMockDatasource();
+ mockDatasource = createMockDatasource('a');
expressionRendererMock = createExpressionRendererMock();
});
@@ -199,7 +199,7 @@ describe('workspace_panel', () => {
});
it('should include data fetching for each layer in the expression', () => {
- const mockDatasource2 = createMockDatasource();
+ const mockDatasource2 = createMockDatasource('a');
const framePublicAPI = createMockFramePublicAPI();
framePublicAPI.datasourceLayers = {
first: mockDatasource.publicAPIMock,
diff --git a/x-pack/legacy/plugins/lens/public/editor_frame_service/mocks.tsx b/x-pack/legacy/plugins/lens/public/editor_frame_service/mocks.tsx
index e606c69c8c386..5d2f68a5567eb 100644
--- a/x-pack/legacy/plugins/lens/public/editor_frame_service/mocks.tsx
+++ b/x-pack/legacy/plugins/lens/public/editor_frame_service/mocks.tsx
@@ -33,9 +33,24 @@ export function createMockVisualization(): jest.Mocked {
getPersistableState: jest.fn(_state => _state),
getSuggestions: jest.fn(_options => []),
initialize: jest.fn((_frame, _state?) => ({})),
- renderLayerConfigPanel: jest.fn(),
+ getConfiguration: jest.fn(props => ({
+ groups: [
+ {
+ groupId: 'a',
+ groupLabel: 'a',
+ layerId: 'layer1',
+ supportsMoreColumns: true,
+ accessors: [],
+ filterOperations: jest.fn(() => true),
+ dataTestSubj: 'mockVisA',
+ },
+ ],
+ })),
toExpression: jest.fn((_state, _frame) => null),
toPreviewExpression: jest.fn((_state, _frame) => null),
+
+ setDimension: jest.fn(),
+ removeDimension: jest.fn(),
};
}
@@ -43,12 +58,11 @@ export type DatasourceMock = jest.Mocked & {
publicAPIMock: jest.Mocked;
};
-export function createMockDatasource(): DatasourceMock {
+export function createMockDatasource(id: string): DatasourceMock {
const publicAPIMock: jest.Mocked = {
+ datasourceId: id,
getTableSpec: jest.fn(() => []),
getOperationForColumnId: jest.fn(),
- renderDimensionPanel: jest.fn(),
- renderLayerPanel: jest.fn(),
};
return {
@@ -60,12 +74,19 @@ export function createMockDatasource(): DatasourceMock {
getPublicAPI: jest.fn().mockReturnValue(publicAPIMock),
initialize: jest.fn((_state?) => Promise.resolve()),
renderDataPanel: jest.fn(),
+ renderLayerPanel: jest.fn(),
toExpression: jest.fn((_frame, _state) => null),
insertLayer: jest.fn((_state, _newLayerId) => {}),
removeLayer: jest.fn((_state, _layerId) => {}),
+ removeColumn: jest.fn(props => {}),
getLayers: jest.fn(_state => []),
getMetaData: jest.fn(_state => ({ filterableIndexPatterns: [] })),
+ renderDimensionTrigger: jest.fn(),
+ renderDimensionEditor: jest.fn(),
+ canHandleDrop: jest.fn(),
+ onDrop: jest.fn(),
+
// this is an additional property which doesn't exist on real datasources
// but can be used to validate whether specific API mock functions are called
publicAPIMock,
diff --git a/x-pack/legacy/plugins/lens/public/editor_frame_service/service.test.tsx b/x-pack/legacy/plugins/lens/public/editor_frame_service/service.test.tsx
index 6b9dc88e7ed12..47fd810bb4c53 100644
--- a/x-pack/legacy/plugins/lens/public/editor_frame_service/service.test.tsx
+++ b/x-pack/legacy/plugins/lens/public/editor_frame_service/service.test.tsx
@@ -47,7 +47,7 @@ describe('editor_frame service', () => {
pluginSetupDependencies
);
const publicAPI = pluginInstance.start(coreMock.createStart(), pluginStartDependencies);
- const instance = await publicAPI.createInstance({});
+ const instance = await publicAPI.createInstance();
instance.mount(mountpoint, {
onError: jest.fn(),
onChange: jest.fn(),
@@ -66,7 +66,7 @@ describe('editor_frame service', () => {
pluginSetupDependencies
);
const publicAPI = pluginInstance.start(coreMock.createStart(), pluginStartDependencies);
- const instance = await publicAPI.createInstance({});
+ const instance = await publicAPI.createInstance();
instance.mount(mountpoint, {
onError: jest.fn(),
onChange: jest.fn(),
diff --git a/x-pack/legacy/plugins/lens/public/index.scss b/x-pack/legacy/plugins/lens/public/index.scss
index 496573f6a1c9a..2f91d14c397c7 100644
--- a/x-pack/legacy/plugins/lens/public/index.scss
+++ b/x-pack/legacy/plugins/lens/public/index.scss
@@ -4,8 +4,6 @@
@import './variables';
@import './mixins';
-@import './config_panel';
-
@import './app_plugin/index';
@import 'datatable_visualization/index';
@import './drag_drop/index';
diff --git a/x-pack/legacy/plugins/lens/public/indexpattern_datasource/dimension_panel/_dimension_panel.scss b/x-pack/legacy/plugins/lens/public/indexpattern_datasource/dimension_panel/_dimension_panel.scss
deleted file mode 100644
index ddb37505f9985..0000000000000
--- a/x-pack/legacy/plugins/lens/public/indexpattern_datasource/dimension_panel/_dimension_panel.scss
+++ /dev/null
@@ -1,9 +0,0 @@
-.lnsIndexPatternDimensionPanel {
- @include euiFontSizeS;
- background-color: $euiColorEmptyShade;
- border-radius: $euiBorderRadius;
- display: flex;
- align-items: center;
- margin-top: $euiSizeXS;
- overflow: hidden;
-}
diff --git a/x-pack/legacy/plugins/lens/public/indexpattern_datasource/dimension_panel/_index.scss b/x-pack/legacy/plugins/lens/public/indexpattern_datasource/dimension_panel/_index.scss
index 2ce3e11171fc9..26f805fe735f0 100644
--- a/x-pack/legacy/plugins/lens/public/indexpattern_datasource/dimension_panel/_index.scss
+++ b/x-pack/legacy/plugins/lens/public/indexpattern_datasource/dimension_panel/_index.scss
@@ -1,3 +1,2 @@
-@import './dimension_panel';
@import './field_select';
@import './popover';
diff --git a/x-pack/legacy/plugins/lens/public/indexpattern_datasource/dimension_panel/_popover.scss b/x-pack/legacy/plugins/lens/public/indexpattern_datasource/dimension_panel/_popover.scss
index 8f26ab91e0f16..07a72ee1f66fc 100644
--- a/x-pack/legacy/plugins/lens/public/indexpattern_datasource/dimension_panel/_popover.scss
+++ b/x-pack/legacy/plugins/lens/public/indexpattern_datasource/dimension_panel/_popover.scss
@@ -1,37 +1,24 @@
-.lnsPopoverEditor {
+.lnsIndexPatternDimensionEditor {
flex-grow: 1;
line-height: 0;
overflow: hidden;
}
-.lnsPopoverEditor__anchor {
- max-width: 100%;
- display: block;
-}
-
-.lnsPopoverEditor__link {
- width: 100%;
- display: flex;
- align-items: center;
- padding: $euiSizeS;
- min-height: $euiSizeXXL;
-}
-
-.lnsPopoverEditor__left,
-.lnsPopoverEditor__right {
+.lnsIndexPatternDimensionEditor__left,
+.lnsIndexPatternDimensionEditor__right {
padding: $euiSizeS;
}
-.lnsPopoverEditor__left {
+.lnsIndexPatternDimensionEditor__left {
padding-top: 0;
background-color: $euiPageBackgroundColor;
}
-.lnsPopoverEditor__right {
+.lnsIndexPatternDimensionEditor__right {
width: $euiSize * 20;
}
-.lnsPopoverEditor__operation {
+.lnsIndexPatternDimensionEditor__operation {
@include euiFontSizeS;
color: $euiColorPrimary;
@@ -41,11 +28,11 @@
}
}
-.lnsPopoverEditor__operation--selected {
+.lnsIndexPatternDimensionEditor__operation--selected {
font-weight: bold;
color: $euiTextColor;
}
-.lnsPopoverEditor__operation--incompatible {
+.lnsIndexPatternDimensionEditor__operation--incompatible {
color: $euiColorMediumShade;
}
diff --git a/x-pack/legacy/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_panel.test.tsx b/x-pack/legacy/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_panel.test.tsx
index 56f75ae4b17be..41c317ccab290 100644
--- a/x-pack/legacy/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_panel.test.tsx
+++ b/x-pack/legacy/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_panel.test.tsx
@@ -7,27 +7,28 @@
import { ReactWrapper, ShallowWrapper } from 'enzyme';
import React from 'react';
import { act } from 'react-dom/test-utils';
-import {
- EuiComboBox,
- EuiSideNav,
- EuiSideNavItemType,
- EuiPopover,
- EuiFieldNumber,
-} from '@elastic/eui';
+import { EuiComboBox, EuiSideNav, EuiSideNavItemType, EuiFieldNumber } from '@elastic/eui';
import { DataPublicPluginStart } from '../../../../../../../src/plugins/data/public';
import { changeColumn } from '../state_helpers';
import {
- IndexPatternDimensionPanel,
- IndexPatternDimensionPanelComponent,
- IndexPatternDimensionPanelProps,
+ IndexPatternDimensionEditorComponent,
+ IndexPatternDimensionEditorProps,
+ onDrop,
+ canHandleDrop,
} from './dimension_panel';
-import { DropHandler, DragContextState } from '../../drag_drop';
+import { DragContextState } from '../../drag_drop';
import { createMockedDragDropContext } from '../mocks';
import { mountWithIntl as mount, shallowWithIntl as shallow } from 'test_utils/enzyme_helpers';
-import { IUiSettingsClient, SavedObjectsClientContract, HttpSetup } from 'src/core/public';
+import {
+ IUiSettingsClient,
+ SavedObjectsClientContract,
+ HttpSetup,
+ CoreSetup,
+} from 'src/core/public';
import { IStorageWrapper } from 'src/plugins/kibana_utils/public';
import { IndexPatternPrivateState } from '../types';
import { documentField } from '../document_field';
+import { OperationMetadata } from '../../types';
jest.mock('ui/new_platform');
jest.mock('../loader');
@@ -79,20 +80,12 @@ const expectedIndexPatterns = {
},
};
-describe('IndexPatternDimensionPanel', () => {
- let wrapper: ReactWrapper | ShallowWrapper;
+describe('IndexPatternDimensionEditorPanel', () => {
let state: IndexPatternPrivateState;
let setState: jest.Mock;
- let defaultProps: IndexPatternDimensionPanelProps;
+ let defaultProps: IndexPatternDimensionEditorProps;
let dragDropContext: DragContextState;
- function openPopover() {
- wrapper
- .find('[data-test-subj="indexPattern-configure-dimension"]')
- .first()
- .simulate('click');
- }
-
beforeEach(() => {
state = {
indexPatternRefs: [],
@@ -134,7 +127,6 @@ describe('IndexPatternDimensionPanel', () => {
dragDropContext = createMockedDragDropContext();
defaultProps = {
- dragDropContext,
state,
setState,
dateRange: { fromDate: 'now-1d', toDate: 'now' },
@@ -158,475 +150,582 @@ describe('IndexPatternDimensionPanel', () => {
}),
} as unknown) as DataPublicPluginStart['fieldFormats'],
} as unknown) as DataPublicPluginStart,
+ core: {} as CoreSetup,
};
jest.clearAllMocks();
});
- afterEach(() => {
- if (wrapper) {
- wrapper.unmount();
- }
- });
+ describe('Editor component', () => {
+ let wrapper: ReactWrapper | ShallowWrapper;
- it('should display a configure button if dimension has no column yet', () => {
- wrapper = mount( );
- expect(
- wrapper
- .find('[data-test-subj="indexPattern-configure-dimension"]')
- .first()
- .prop('iconType')
- ).toEqual('plusInCircleFilled');
- });
+ afterEach(() => {
+ if (wrapper) {
+ wrapper.unmount();
+ }
+ });
- it('should call the filterOperations function', () => {
- const filterOperations = jest.fn().mockReturnValue(true);
+ it('should call the filterOperations function', () => {
+ const filterOperations = jest.fn().mockReturnValue(true);
- wrapper = shallow(
-
- );
+ wrapper = shallow(
+
+ );
- expect(filterOperations).toBeCalled();
- });
+ expect(filterOperations).toBeCalled();
+ });
- it('should show field select combo box on click', () => {
- wrapper = mount( );
+ it('should show field select combo box on click', () => {
+ wrapper = mount( );
- openPopover();
+ expect(
+ wrapper.find(EuiComboBox).filter('[data-test-subj="indexPattern-dimension-field"]')
+ ).toHaveLength(1);
+ });
- expect(
- wrapper.find(EuiComboBox).filter('[data-test-subj="indexPattern-dimension-field"]')
- ).toHaveLength(1);
- });
+ it('should not show any choices if the filter returns false', () => {
+ wrapper = mount(
+ false}
+ />
+ );
- it('should not show any choices if the filter returns false', () => {
- wrapper = mount(
- false}
- />
- );
+ expect(
+ wrapper
+ .find(EuiComboBox)
+ .filter('[data-test-subj="indexPattern-dimension-field"]')!
+ .prop('options')!
+ ).toHaveLength(0);
+ });
- openPopover();
+ it('should list all field names and document as a whole in prioritized order', () => {
+ wrapper = mount( );
- expect(
- wrapper
+ const options = wrapper
.find(EuiComboBox)
- .filter('[data-test-subj="indexPattern-dimension-field"]')!
- .prop('options')!
- ).toHaveLength(0);
- });
-
- it('should list all field names and document as a whole in prioritized order', () => {
- wrapper = mount( );
-
- openPopover();
-
- const options = wrapper
- .find(EuiComboBox)
- .filter('[data-test-subj="indexPattern-dimension-field"]')
- .prop('options');
+ .filter('[data-test-subj="indexPattern-dimension-field"]')
+ .prop('options');
- expect(options).toHaveLength(2);
+ expect(options).toHaveLength(2);
- expect(options![0].label).toEqual('Records');
+ expect(options![0].label).toEqual('Records');
- expect(options![1].options!.map(({ label }) => label)).toEqual([
- 'timestamp',
- 'bytes',
- 'memory',
- 'source',
- ]);
- });
+ expect(options![1].options!.map(({ label }) => label)).toEqual([
+ 'timestamp',
+ 'bytes',
+ 'memory',
+ 'source',
+ ]);
+ });
- it('should hide fields that have no data', () => {
- const props = {
- ...defaultProps,
- state: {
- ...defaultProps.state,
- existingFields: {
- 'my-fake-index-pattern': {
- timestamp: true,
- source: true,
+ it('should hide fields that have no data', () => {
+ const props = {
+ ...defaultProps,
+ state: {
+ ...defaultProps.state,
+ existingFields: {
+ 'my-fake-index-pattern': {
+ timestamp: true,
+ source: true,
+ },
},
},
- },
- };
- wrapper = mount( );
-
- openPopover();
-
- const options = wrapper
- .find(EuiComboBox)
- .filter('[data-test-subj="indexPattern-dimension-field"]')
- .prop('options');
+ };
+ wrapper = mount( );
- expect(options![1].options!.map(({ label }) => label)).toEqual(['timestamp', 'source']);
- });
+ const options = wrapper
+ .find(EuiComboBox)
+ .filter('[data-test-subj="indexPattern-dimension-field"]')
+ .prop('options');
- it('should indicate fields which are incompatible for the operation of the current column', () => {
- wrapper = mount(
- label)).toEqual(['timestamp', 'source']);
+ });
- // Private
- operationType: 'max',
- sourceField: 'bytes',
+ it('should indicate fields which are incompatible for the operation of the current column', () => {
+ wrapper = mount(
+
- );
-
- openPopover();
-
- const options = wrapper
- .find(EuiComboBox)
- .filter('[data-test-subj="indexPattern-dimension-field"]')
- .prop('options');
+ }}
+ />
+ );
- expect(options![0]['data-test-subj']).toEqual('lns-fieldOptionIncompatible-Records');
+ const options = wrapper
+ .find(EuiComboBox)
+ .filter('[data-test-subj="indexPattern-dimension-field"]')
+ .prop('options');
- expect(
- options![1].options!.filter(({ label }) => label === 'timestamp')[0]['data-test-subj']
- ).toContain('Incompatible');
- expect(
- options![1].options!.filter(({ label }) => label === 'memory')[0]['data-test-subj']
- ).not.toContain('Incompatible');
- });
+ expect(options![0]['data-test-subj']).toEqual('lns-fieldOptionIncompatible-Records');
- it('should indicate operations which are incompatible for the field of the current column', () => {
- wrapper = mount(
- label === 'timestamp')[0]['data-test-subj']
+ ).toContain('Incompatible');
+ expect(
+ options![1].options!.filter(({ label }) => label === 'memory')[0]['data-test-subj']
+ ).not.toContain('Incompatible');
+ });
- // Private
- operationType: 'max',
- sourceField: 'bytes',
+ it('should indicate operations which are incompatible for the field of the current column', () => {
+ wrapper = mount(
+
- );
-
- openPopover();
+ }}
+ />
+ );
- interface ItemType {
- name: string;
- 'data-test-subj': string;
- }
- const items: Array> = wrapper.find(EuiSideNav).prop('items');
- const options = (items[0].items as unknown) as ItemType[];
+ interface ItemType {
+ name: string;
+ 'data-test-subj': string;
+ }
+ const items: Array> = wrapper.find(EuiSideNav).prop('items');
+ const options = (items[0].items as unknown) as ItemType[];
- expect(options.find(({ name }) => name === 'Minimum')!['data-test-subj']).not.toContain(
- 'Incompatible'
- );
+ expect(options.find(({ name }) => name === 'Minimum')!['data-test-subj']).not.toContain(
+ 'Incompatible'
+ );
- expect(options.find(({ name }) => name === 'Date histogram')!['data-test-subj']).toContain(
- 'Incompatible'
- );
- });
+ expect(options.find(({ name }) => name === 'Date histogram')!['data-test-subj']).toContain(
+ 'Incompatible'
+ );
+ });
- it('should keep the operation when switching to another field compatible with this operation', () => {
- const initialState: IndexPatternPrivateState = {
- ...state,
- layers: {
- first: {
- ...state.layers.first,
- columns: {
- ...state.layers.first.columns,
- col1: {
- label: 'Max of bytes',
- dataType: 'number',
- isBucketed: false,
+ it('should keep the operation when switching to another field compatible with this operation', () => {
+ const initialState: IndexPatternPrivateState = {
+ ...state,
+ layers: {
+ first: {
+ ...state.layers.first,
+ columns: {
+ ...state.layers.first.columns,
+ col1: {
+ label: 'Max of bytes',
+ dataType: 'number',
+ isBucketed: false,
- // Private
- operationType: 'max',
- sourceField: 'bytes',
- params: { format: { id: 'bytes' } },
+ // Private
+ operationType: 'max',
+ sourceField: 'bytes',
+ params: { format: { id: 'bytes' } },
+ },
},
},
},
- },
- };
-
- wrapper = mount( );
+ };
- openPopover();
+ wrapper = mount(
+
+ );
- const comboBox = wrapper
- .find(EuiComboBox)
- .filter('[data-test-subj="indexPattern-dimension-field"]')!;
- const option = comboBox.prop('options')![1].options!.find(({ label }) => label === 'memory')!;
+ const comboBox = wrapper
+ .find(EuiComboBox)
+ .filter('[data-test-subj="indexPattern-dimension-field"]')!;
+ const option = comboBox.prop('options')![1].options!.find(({ label }) => label === 'memory')!;
- act(() => {
- comboBox.prop('onChange')!([option]);
- });
+ act(() => {
+ comboBox.prop('onChange')!([option]);
+ });
- expect(setState).toHaveBeenCalledWith({
- ...initialState,
- layers: {
- first: {
- ...state.layers.first,
- columns: {
- ...state.layers.first.columns,
- col1: expect.objectContaining({
- operationType: 'max',
- sourceField: 'memory',
- params: { format: { id: 'bytes' } },
- // Other parts of this don't matter for this test
- }),
+ expect(setState).toHaveBeenCalledWith({
+ ...initialState,
+ layers: {
+ first: {
+ ...state.layers.first,
+ columns: {
+ ...state.layers.first.columns,
+ col1: expect.objectContaining({
+ operationType: 'max',
+ sourceField: 'memory',
+ params: { format: { id: 'bytes' } },
+ // Other parts of this don't matter for this test
+ }),
+ },
},
},
- },
+ });
});
- });
-
- it('should switch operations when selecting a field that requires another operation', () => {
- wrapper = mount( );
- openPopover();
+ it('should switch operations when selecting a field that requires another operation', () => {
+ wrapper = mount( );
- const comboBox = wrapper
- .find(EuiComboBox)
- .filter('[data-test-subj="indexPattern-dimension-field"]')!;
- const option = comboBox.prop('options')![1].options!.find(({ label }) => label === 'source')!;
+ const comboBox = wrapper
+ .find(EuiComboBox)
+ .filter('[data-test-subj="indexPattern-dimension-field"]')!;
+ const option = comboBox.prop('options')![1].options!.find(({ label }) => label === 'source')!;
- act(() => {
- comboBox.prop('onChange')!([option]);
- });
+ act(() => {
+ comboBox.prop('onChange')!([option]);
+ });
- expect(setState).toHaveBeenCalledWith({
- ...state,
- layers: {
- first: {
- ...state.layers.first,
- columns: {
- ...state.layers.first.columns,
- col1: expect.objectContaining({
- operationType: 'terms',
- sourceField: 'source',
- // Other parts of this don't matter for this test
- }),
+ expect(setState).toHaveBeenCalledWith({
+ ...state,
+ layers: {
+ first: {
+ ...state.layers.first,
+ columns: {
+ ...state.layers.first.columns,
+ col1: expect.objectContaining({
+ operationType: 'terms',
+ sourceField: 'source',
+ // Other parts of this don't matter for this test
+ }),
+ },
},
},
- },
+ });
});
- });
-
- it('should keep the field when switching to another operation compatible for this field', () => {
- wrapper = mount(
- {
+ wrapper = mount(
+
- );
-
- openPopover();
+ }}
+ />
+ );
- act(() => {
- wrapper.find('button[data-test-subj="lns-indexPatternDimension-min"]').simulate('click');
- });
+ act(() => {
+ wrapper.find('button[data-test-subj="lns-indexPatternDimension-min"]').simulate('click');
+ });
- expect(setState).toHaveBeenCalledWith({
- ...state,
- layers: {
- first: {
- ...state.layers.first,
- columns: {
- ...state.layers.first.columns,
- col1: expect.objectContaining({
- operationType: 'min',
- sourceField: 'bytes',
- params: { format: { id: 'bytes' } },
- // Other parts of this don't matter for this test
- }),
+ expect(setState).toHaveBeenCalledWith({
+ ...state,
+ layers: {
+ first: {
+ ...state.layers.first,
+ columns: {
+ ...state.layers.first.columns,
+ col1: expect.objectContaining({
+ operationType: 'min',
+ sourceField: 'bytes',
+ params: { format: { id: 'bytes' } },
+ // Other parts of this don't matter for this test
+ }),
+ },
},
},
- },
+ });
});
- });
- it('should not set the state if selecting the currently active operation', () => {
- wrapper = mount( );
+ it('should not set the state if selecting the currently active operation', () => {
+ wrapper = mount( );
- openPopover();
+ act(() => {
+ wrapper
+ .find('button[data-test-subj="lns-indexPatternDimension-date_histogram"]')
+ .simulate('click');
+ });
- act(() => {
- wrapper
- .find('button[data-test-subj="lns-indexPatternDimension-date_histogram"]')
- .simulate('click');
+ expect(setState).not.toHaveBeenCalled();
});
- expect(setState).not.toHaveBeenCalled();
- });
-
- it('should update label on label input changes', () => {
- wrapper = mount( );
+ it('should update label on label input changes', () => {
+ wrapper = mount( );
- openPopover();
-
- act(() => {
- wrapper
- .find('input[data-test-subj="indexPattern-label-edit"]')
- .simulate('change', { target: { value: 'New Label' } });
- });
+ act(() => {
+ wrapper
+ .find('input[data-test-subj="indexPattern-label-edit"]')
+ .simulate('change', { target: { value: 'New Label' } });
+ });
- expect(setState).toHaveBeenCalledWith({
- ...state,
- layers: {
- first: {
- ...state.layers.first,
- columns: {
- ...state.layers.first.columns,
- col1: expect.objectContaining({
- label: 'New Label',
- // Other parts of this don't matter for this test
- }),
+ expect(setState).toHaveBeenCalledWith({
+ ...state,
+ layers: {
+ first: {
+ ...state.layers.first,
+ columns: {
+ ...state.layers.first.columns,
+ col1: expect.objectContaining({
+ label: 'New Label',
+ // Other parts of this don't matter for this test
+ }),
+ },
},
},
- },
+ });
});
- });
- describe('transient invalid state', () => {
- it('should not set the state if selecting an operation incompatible with the current field', () => {
- wrapper = mount( );
+ describe('transient invalid state', () => {
+ it('should not set the state if selecting an operation incompatible with the current field', () => {
+ wrapper = mount( );
- openPopover();
+ act(() => {
+ wrapper
+ .find('button[data-test-subj="lns-indexPatternDimensionIncompatible-terms"]')
+ .simulate('click');
+ });
+
+ expect(setState).not.toHaveBeenCalled();
+ });
+
+ it('should show error message in invalid state', () => {
+ wrapper = mount( );
- act(() => {
wrapper
.find('button[data-test-subj="lns-indexPatternDimensionIncompatible-terms"]')
.simulate('click');
+
+ expect(wrapper.find('[data-test-subj="indexPattern-invalid-operation"]')).not.toHaveLength(
+ 0
+ );
+
+ expect(setState).not.toHaveBeenCalled();
});
- expect(setState).not.toHaveBeenCalled();
- });
+ it('should leave error state if a compatible operation is selected', () => {
+ wrapper = mount( );
- it('should show error message in invalid state', () => {
- wrapper = mount( );
+ wrapper
+ .find('button[data-test-subj="lns-indexPatternDimensionIncompatible-terms"]')
+ .simulate('click');
- openPopover();
+ wrapper
+ .find('button[data-test-subj="lns-indexPatternDimension-date_histogram"]')
+ .simulate('click');
- wrapper
- .find('button[data-test-subj="lns-indexPatternDimensionIncompatible-terms"]')
- .simulate('click');
+ expect(wrapper.find('[data-test-subj="indexPattern-invalid-operation"]')).toHaveLength(0);
+ });
- expect(wrapper.find('[data-test-subj="indexPattern-invalid-operation"]')).not.toHaveLength(0);
+ it('should indicate fields compatible with selected operation', () => {
+ wrapper = mount( );
- expect(setState).not.toHaveBeenCalled();
- });
+ wrapper
+ .find('button[data-test-subj="lns-indexPatternDimensionIncompatible-terms"]')
+ .simulate('click');
- it('should leave error state if a compatible operation is selected', () => {
- wrapper = mount( );
+ const options = wrapper
+ .find(EuiComboBox)
+ .filter('[data-test-subj="indexPattern-dimension-field"]')
+ .prop('options');
- openPopover();
+ expect(options![0]['data-test-subj']).toContain('Incompatible');
- wrapper
- .find('button[data-test-subj="lns-indexPatternDimensionIncompatible-terms"]')
- .simulate('click');
+ expect(
+ options![1].options!.filter(({ label }) => label === 'timestamp')[0]['data-test-subj']
+ ).toContain('Incompatible');
+ expect(
+ options![1].options!.filter(({ label }) => label === 'source')[0]['data-test-subj']
+ ).not.toContain('Incompatible');
+ });
- wrapper
- .find('button[data-test-subj="lns-indexPatternDimension-date_histogram"]')
- .simulate('click');
+ it('should select compatible operation if field not compatible with selected operation', () => {
+ wrapper = mount(
+
+ );
- expect(wrapper.find('[data-test-subj="indexPattern-invalid-operation"]')).toHaveLength(0);
- });
+ wrapper.find('button[data-test-subj="lns-indexPatternDimension-avg"]').simulate('click');
- it('should leave error state if the popover gets closed', () => {
- wrapper = mount( );
+ const comboBox = wrapper
+ .find(EuiComboBox)
+ .filter('[data-test-subj="indexPattern-dimension-field"]');
+ const options = comboBox.prop('options');
- openPopover();
+ // options[1][2] is a `source` field of type `string` which doesn't support `avg` operation
+ act(() => {
+ comboBox.prop('onChange')!([options![1].options![2]]);
+ });
- wrapper
- .find('button[data-test-subj="lns-indexPatternDimensionIncompatible-terms"]')
- .simulate('click');
+ expect(setState).toHaveBeenCalledWith({
+ ...state,
+ layers: {
+ first: {
+ ...state.layers.first,
+ columns: {
+ ...state.layers.first.columns,
+ col2: expect.objectContaining({
+ sourceField: 'source',
+ operationType: 'terms',
+ // Other parts of this don't matter for this test
+ }),
+ },
+ columnOrder: ['col1', 'col2'],
+ },
+ },
+ });
+ });
- act(() => {
- wrapper.find(EuiPopover).prop('closePopover')!();
+ it('should select the Records field when count is selected', () => {
+ const initialState: IndexPatternPrivateState = {
+ ...state,
+ layers: {
+ first: {
+ ...state.layers.first,
+ columns: {
+ ...state.layers.first.columns,
+ col2: {
+ dataType: 'number',
+ isBucketed: false,
+ label: '',
+ operationType: 'avg',
+ sourceField: 'bytes',
+ },
+ },
+ },
+ },
+ };
+ wrapper = mount(
+
+ );
+
+ wrapper
+ .find('button[data-test-subj="lns-indexPatternDimensionIncompatible-count"]')
+ .simulate('click');
+
+ const newColumnState = setState.mock.calls[0][0].layers.first.columns.col2;
+ expect(newColumnState.operationType).toEqual('count');
+ expect(newColumnState.sourceField).toEqual('Records');
});
- openPopover();
+ it('should indicate document and field compatibility with selected document operation', () => {
+ const initialState: IndexPatternPrivateState = {
+ ...state,
+ layers: {
+ first: {
+ ...state.layers.first,
+ columns: {
+ ...state.layers.first.columns,
+ col2: {
+ dataType: 'number',
+ isBucketed: false,
+ label: '',
+ operationType: 'count',
+ sourceField: 'Records',
+ },
+ },
+ },
+ },
+ };
+ wrapper = mount(
+
+ );
+
+ wrapper
+ .find('button[data-test-subj="lns-indexPatternDimensionIncompatible-terms"]')
+ .simulate('click');
- expect(wrapper.find('[data-test-subj="indexPattern-invalid-operation"]')).toHaveLength(0);
- });
+ const options = wrapper
+ .find(EuiComboBox)
+ .filter('[data-test-subj="indexPattern-dimension-field"]')
+ .prop('options');
- it('should indicate fields compatible with selected operation', () => {
- wrapper = mount( );
+ expect(options![0]['data-test-subj']).toContain('Incompatible');
- openPopover();
+ expect(
+ options![1].options!.filter(({ label }) => label === 'timestamp')[0]['data-test-subj']
+ ).toContain('Incompatible');
+ expect(
+ options![1].options!.filter(({ label }) => label === 'source')[0]['data-test-subj']
+ ).not.toContain('Incompatible');
+ });
- wrapper
- .find('button[data-test-subj="lns-indexPatternDimensionIncompatible-terms"]')
- .simulate('click');
+ it('should set datasource state if compatible field is selected for operation', () => {
+ wrapper = mount( );
- const options = wrapper
- .find(EuiComboBox)
- .filter('[data-test-subj="indexPattern-dimension-field"]')
- .prop('options');
+ act(() => {
+ wrapper
+ .find('button[data-test-subj="lns-indexPatternDimensionIncompatible-terms"]')
+ .simulate('click');
+ });
- expect(options![0]['data-test-subj']).toContain('Incompatible');
+ const comboBox = wrapper
+ .find(EuiComboBox)
+ .filter('[data-test-subj="indexPattern-dimension-field"]')!;
+ const option = comboBox
+ .prop('options')![1]
+ .options!.find(({ label }) => label === 'source')!;
- expect(
- options![1].options!.filter(({ label }) => label === 'timestamp')[0]['data-test-subj']
- ).toContain('Incompatible');
- expect(
- options![1].options!.filter(({ label }) => label === 'source')[0]['data-test-subj']
- ).not.toContain('Incompatible');
- });
+ act(() => {
+ comboBox.prop('onChange')!([option]);
+ });
- it('should select compatible operation if field not compatible with selected operation', () => {
- wrapper = mount( );
+ expect(setState).toHaveBeenCalledWith({
+ ...state,
+ layers: {
+ first: {
+ ...state.layers.first,
+ columns: {
+ ...state.layers.first.columns,
+ col1: expect.objectContaining({
+ sourceField: 'source',
+ operationType: 'terms',
+ }),
+ },
+ },
+ },
+ });
+ });
+ });
- openPopover();
+ it('should support selecting the operation before the field', () => {
+ wrapper = mount( );
wrapper.find('button[data-test-subj="lns-indexPatternDimension-avg"]').simulate('click');
@@ -635,9 +734,8 @@ describe('IndexPatternDimensionPanel', () => {
.filter('[data-test-subj="indexPattern-dimension-field"]');
const options = comboBox.prop('options');
- // options[1][2] is a `source` field of type `string` which doesn't support `avg` operation
act(() => {
- comboBox.prop('onChange')!([options![1].options![2]]);
+ comboBox.prop('onChange')!([options![1].options![0]]);
});
expect(setState).toHaveBeenCalledWith({
@@ -648,8 +746,8 @@ describe('IndexPatternDimensionPanel', () => {
columns: {
...state.layers.first.columns,
col2: expect.objectContaining({
- sourceField: 'source',
- operationType: 'terms',
+ sourceField: 'bytes',
+ operationType: 'avg',
// Other parts of this don't matter for this test
}),
},
@@ -659,41 +757,93 @@ describe('IndexPatternDimensionPanel', () => {
});
});
- it('should select the Records field when count is selected', () => {
- const initialState: IndexPatternPrivateState = {
+ it('should select operation directly if only one field is possible', () => {
+ const initialState = {
+ ...state,
+ indexPatterns: {
+ 1: {
+ ...state.indexPatterns['1'],
+ fields: state.indexPatterns['1'].fields.filter(field => field.name !== 'memory'),
+ },
+ },
+ };
+
+ wrapper = mount(
+
+ );
+
+ wrapper.find('button[data-test-subj="lns-indexPatternDimension-avg"]').simulate('click');
+
+ expect(setState).toHaveBeenCalledWith({
+ ...initialState,
+ layers: {
+ first: {
+ ...initialState.layers.first,
+ columns: {
+ ...initialState.layers.first.columns,
+ col2: expect.objectContaining({
+ sourceField: 'bytes',
+ operationType: 'avg',
+ // Other parts of this don't matter for this test
+ }),
+ },
+ columnOrder: ['col1', 'col2'],
+ },
+ },
+ });
+ });
+
+ it('should select operation directly if only document is possible', () => {
+ wrapper = mount( );
+
+ wrapper.find('button[data-test-subj="lns-indexPatternDimension-count"]').simulate('click');
+
+ expect(setState).toHaveBeenCalledWith({
...state,
layers: {
first: {
...state.layers.first,
columns: {
...state.layers.first.columns,
- col2: {
- dataType: 'number',
- isBucketed: false,
- label: '',
- operationType: 'avg',
- sourceField: 'bytes',
- },
+ col2: expect.objectContaining({
+ operationType: 'count',
+ // Other parts of this don't matter for this test
+ }),
},
+ columnOrder: ['col1', 'col2'],
},
},
- };
- wrapper = mount(
-
- );
+ });
+ });
- openPopover();
+ it('should indicate compatible fields when selecting the operation first', () => {
+ wrapper = mount( );
- wrapper
- .find('button[data-test-subj="lns-indexPatternDimensionIncompatible-count"]')
- .simulate('click');
+ wrapper.find('button[data-test-subj="lns-indexPatternDimension-avg"]').simulate('click');
- const newColumnState = setState.mock.calls[0][0].layers.first.columns.col2;
- expect(newColumnState.operationType).toEqual('count');
- expect(newColumnState.sourceField).toEqual('Records');
+ const options = wrapper
+ .find(EuiComboBox)
+ .filter('[data-test-subj="indexPattern-dimension-field"]')
+ .prop('options');
+
+ expect(options![0]['data-test-subj']).toContain('Incompatible');
+
+ expect(
+ options![1].options!.filter(({ label }) => label === 'timestamp')[0]['data-test-subj']
+ ).toContain('Incompatible');
+ expect(
+ options![1].options!.filter(({ label }) => label === 'bytes')[0]['data-test-subj']
+ ).not.toContain('Incompatible');
+ expect(
+ options![1].options!.filter(({ label }) => label === 'memory')[0]['data-test-subj']
+ ).not.toContain('Incompatible');
});
- it('should indicate document and field compatibility with selected document operation', () => {
+ it('should indicate document compatibility when document operation is selected', () => {
const initialState: IndexPatternPrivateState = {
...state,
layers: {
@@ -713,45 +863,56 @@ describe('IndexPatternDimensionPanel', () => {
},
};
wrapper = mount(
-
+
);
- openPopover();
-
- wrapper
- .find('button[data-test-subj="lns-indexPatternDimensionIncompatible-terms"]')
- .simulate('click');
-
const options = wrapper
.find(EuiComboBox)
.filter('[data-test-subj="indexPattern-dimension-field"]')
.prop('options');
- expect(options![0]['data-test-subj']).toContain('Incompatible');
+ expect(options![0]['data-test-subj']).not.toContain('Incompatible');
- expect(
- options![1].options!.filter(({ label }) => label === 'timestamp')[0]['data-test-subj']
- ).toContain('Incompatible');
- expect(
- options![1].options!.filter(({ label }) => label === 'source')[0]['data-test-subj']
- ).not.toContain('Incompatible');
+ options![1].options!.map(operation =>
+ expect(operation['data-test-subj']).toContain('Incompatible')
+ );
});
- it('should set datasource state if compatible field is selected for operation', () => {
- wrapper = mount( );
+ it('should show all operations that are not filtered out', () => {
+ wrapper = mount(
+ !op.isBucketed && op.dataType === 'number'}
+ />
+ );
- openPopover();
+ interface ItemType {
+ name: React.ReactNode;
+ }
+ const items: Array> = wrapper.find(EuiSideNav).prop('items');
+ const options = (items[0].items as unknown) as ItemType[];
+
+ expect(options.map(({ name }: { name: React.ReactNode }) => name)).toEqual([
+ 'Unique count',
+ 'Average',
+ 'Count',
+ 'Maximum',
+ 'Minimum',
+ 'Sum',
+ ]);
+ });
- act(() => {
- wrapper
- .find('button[data-test-subj="lns-indexPatternDimensionIncompatible-terms"]')
- .simulate('click');
- });
+ it('should add a column on selection of a field', () => {
+ wrapper = mount( );
const comboBox = wrapper
.find(EuiComboBox)
.filter('[data-test-subj="indexPattern-dimension-field"]')!;
- const option = comboBox.prop('options')![1].options!.find(({ label }) => label === 'source')!;
+ const option = comboBox.prop('options')![1].options![0];
act(() => {
comboBox.prop('onChange')!([option]);
@@ -764,479 +925,237 @@ describe('IndexPatternDimensionPanel', () => {
...state.layers.first,
columns: {
...state.layers.first.columns,
- col1: expect.objectContaining({
- sourceField: 'source',
- operationType: 'terms',
+ col2: expect.objectContaining({
+ sourceField: 'bytes',
+ // Other parts of this don't matter for this test
}),
},
+ columnOrder: ['col1', 'col2'],
},
},
});
});
- });
-
- it('should support selecting the operation before the field', () => {
- wrapper = mount( );
-
- openPopover();
-
- wrapper.find('button[data-test-subj="lns-indexPatternDimension-avg"]').simulate('click');
-
- const comboBox = wrapper
- .find(EuiComboBox)
- .filter('[data-test-subj="indexPattern-dimension-field"]');
- const options = comboBox.prop('options');
-
- act(() => {
- comboBox.prop('onChange')!([options![1].options![0]]);
- });
-
- expect(setState).toHaveBeenCalledWith({
- ...state,
- layers: {
- first: {
- ...state.layers.first,
- columns: {
- ...state.layers.first.columns,
- col2: expect.objectContaining({
- sourceField: 'bytes',
- operationType: 'avg',
- // Other parts of this don't matter for this test
- }),
- },
- columnOrder: ['col1', 'col2'],
- },
- },
- });
- });
-
- it('should select operation directly if only one field is possible', () => {
- const initialState = {
- ...state,
- indexPatterns: {
- 1: {
- ...state.indexPatterns['1'],
- fields: state.indexPatterns['1'].fields.filter(field => field.name !== 'memory'),
- },
- },
- };
-
- wrapper = mount(
-
- );
-
- openPopover();
-
- wrapper.find('button[data-test-subj="lns-indexPatternDimension-avg"]').simulate('click');
-
- expect(setState).toHaveBeenCalledWith({
- ...initialState,
- layers: {
- first: {
- ...initialState.layers.first,
- columns: {
- ...initialState.layers.first.columns,
- col2: expect.objectContaining({
- sourceField: 'bytes',
- operationType: 'avg',
- // Other parts of this don't matter for this test
- }),
- },
- columnOrder: ['col1', 'col2'],
- },
- },
- });
- });
-
- it('should select operation directly if only document is possible', () => {
- wrapper = mount( );
-
- openPopover();
-
- wrapper.find('button[data-test-subj="lns-indexPatternDimension-count"]').simulate('click');
-
- expect(setState).toHaveBeenCalledWith({
- ...state,
- layers: {
- first: {
- ...state.layers.first,
- columns: {
- ...state.layers.first.columns,
- col2: expect.objectContaining({
- operationType: 'count',
- // Other parts of this don't matter for this test
- }),
- },
- columnOrder: ['col1', 'col2'],
- },
- },
- });
- });
- it('should indicate compatible fields when selecting the operation first', () => {
- wrapper = mount( );
-
- openPopover();
-
- wrapper.find('button[data-test-subj="lns-indexPatternDimension-avg"]').simulate('click');
-
- const options = wrapper
- .find(EuiComboBox)
- .filter('[data-test-subj="indexPattern-dimension-field"]')
- .prop('options');
-
- expect(options![0]['data-test-subj']).toContain('Incompatible');
-
- expect(
- options![1].options!.filter(({ label }) => label === 'timestamp')[0]['data-test-subj']
- ).toContain('Incompatible');
- expect(
- options![1].options!.filter(({ label }) => label === 'bytes')[0]['data-test-subj']
- ).not.toContain('Incompatible');
- expect(
- options![1].options!.filter(({ label }) => label === 'memory')[0]['data-test-subj']
- ).not.toContain('Incompatible');
- });
-
- it('should indicate document compatibility when document operation is selected', () => {
- const initialState: IndexPatternPrivateState = {
- ...state,
- layers: {
- first: {
- ...state.layers.first,
- columns: {
- ...state.layers.first.columns,
- col2: {
- dataType: 'number',
- isBucketed: false,
- label: '',
- operationType: 'count',
- sourceField: 'Records',
- },
- },
- },
- },
- };
- wrapper = mount(
-
- );
-
- openPopover();
-
- const options = wrapper
- .find(EuiComboBox)
- .filter('[data-test-subj="indexPattern-dimension-field"]')
- .prop('options');
-
- expect(options![0]['data-test-subj']).not.toContain('Incompatible');
-
- options![1].options!.map(operation =>
- expect(operation['data-test-subj']).toContain('Incompatible')
- );
- });
-
- it('should show all operations that are not filtered out', () => {
- wrapper = mount(
- !op.isBucketed && op.dataType === 'number'}
- />
- );
-
- openPopover();
-
- interface ItemType {
- name: React.ReactNode;
- }
- const items: Array> = wrapper.find(EuiSideNav).prop('items');
- const options = (items[0].items as unknown) as ItemType[];
-
- expect(options.map(({ name }: { name: React.ReactNode }) => name)).toEqual([
- 'Unique count',
- 'Average',
- 'Count',
- 'Maximum',
- 'Minimum',
- 'Sum',
- ]);
- });
-
- it('should add a column on selection of a field', () => {
- wrapper = mount( );
-
- openPopover();
-
- const comboBox = wrapper
- .find(EuiComboBox)
- .filter('[data-test-subj="indexPattern-dimension-field"]')!;
- const option = comboBox.prop('options')![1].options![0];
-
- act(() => {
- comboBox.prop('onChange')!([option]);
- });
-
- expect(setState).toHaveBeenCalledWith({
- ...state,
- layers: {
- first: {
- ...state.layers.first,
- columns: {
- ...state.layers.first.columns,
- col2: expect.objectContaining({
- sourceField: 'bytes',
- // Other parts of this don't matter for this test
- }),
- },
- columnOrder: ['col1', 'col2'],
- },
- },
- });
- });
-
- it('should use helper function when changing the function', () => {
- const initialState: IndexPatternPrivateState = {
- ...state,
- layers: {
- first: {
- ...state.layers.first,
- columns: {
- ...state.layers.first.columns,
- col1: {
- label: 'Max of bytes',
- dataType: 'number',
- isBucketed: false,
+ it('should use helper function when changing the function', () => {
+ const initialState: IndexPatternPrivateState = {
+ ...state,
+ layers: {
+ first: {
+ ...state.layers.first,
+ columns: {
+ ...state.layers.first.columns,
+ col1: {
+ label: 'Max of bytes',
+ dataType: 'number',
+ isBucketed: false,
- // Private
- operationType: 'max',
- sourceField: 'bytes',
+ // Private
+ operationType: 'max',
+ sourceField: 'bytes',
+ },
},
},
},
- },
- };
- wrapper = mount( );
-
- openPopover();
-
- act(() => {
- wrapper
- .find('[data-test-subj="lns-indexPatternDimension-min"]')
- .first()
- .prop('onClick')!({} as React.MouseEvent<{}, MouseEvent>);
- });
-
- expect(changeColumn).toHaveBeenCalledWith({
- state: initialState,
- columnId: 'col1',
- layerId: 'first',
- newColumn: expect.objectContaining({
- sourceField: 'bytes',
- operationType: 'min',
- }),
- });
- });
-
- it('should clear the dimension with the clear button', () => {
- wrapper = mount( );
-
- const clearButton = wrapper.find(
- 'EuiButtonIcon[data-test-subj="indexPattern-dimensionPopover-remove"]'
- );
+ };
+ wrapper = mount(
+
+ );
- act(() => {
- clearButton.simulate('click');
- });
+ act(() => {
+ wrapper
+ .find('[data-test-subj="lns-indexPatternDimension-min"]')
+ .first()
+ .prop('onClick')!({} as React.MouseEvent<{}, MouseEvent>);
+ });
- expect(setState).toHaveBeenCalledWith({
- ...state,
- layers: {
- first: {
- indexPatternId: '1',
- columns: {},
- columnOrder: [],
- },
- },
+ expect(changeColumn).toHaveBeenCalledWith({
+ state: initialState,
+ columnId: 'col1',
+ layerId: 'first',
+ newColumn: expect.objectContaining({
+ sourceField: 'bytes',
+ operationType: 'min',
+ }),
+ });
});
- });
-
- it('should clear the dimension when removing the selection in field combobox', () => {
- wrapper = mount( );
- openPopover();
+ it('should clear the dimension when removing the selection in field combobox', () => {
+ wrapper = mount( );
- act(() => {
- wrapper
- .find(EuiComboBox)
- .filter('[data-test-subj="indexPattern-dimension-field"]')
- .prop('onChange')!([]);
- });
+ act(() => {
+ wrapper
+ .find(EuiComboBox)
+ .filter('[data-test-subj="indexPattern-dimension-field"]')
+ .prop('onChange')!([]);
+ });
- expect(setState).toHaveBeenCalledWith({
- ...state,
- layers: {
- first: {
- indexPatternId: '1',
- columns: {},
- columnOrder: [],
+ expect(setState).toHaveBeenCalledWith({
+ ...state,
+ layers: {
+ first: {
+ indexPatternId: '1',
+ columns: {},
+ columnOrder: [],
+ },
},
- },
+ });
});
- });
- it('allows custom format', () => {
- const stateWithNumberCol: IndexPatternPrivateState = {
- ...state,
- layers: {
- first: {
- indexPatternId: '1',
- columnOrder: ['col1'],
- columns: {
- col1: {
- label: 'Average of bar',
- dataType: 'number',
- isBucketed: false,
- // Private
- operationType: 'avg',
- sourceField: 'bar',
+ it('allows custom format', () => {
+ const stateWithNumberCol: IndexPatternPrivateState = {
+ ...state,
+ layers: {
+ first: {
+ indexPatternId: '1',
+ columnOrder: ['col1'],
+ columns: {
+ col1: {
+ label: 'Average of bar',
+ dataType: 'number',
+ isBucketed: false,
+ // Private
+ operationType: 'avg',
+ sourceField: 'bar',
+ },
},
},
},
- },
- };
-
- wrapper = mount( );
+ };
- openPopover();
+ wrapper = mount(
+
+ );
- act(() => {
- wrapper
- .find(EuiComboBox)
- .filter('[data-test-subj="indexPattern-dimension-format"]')
- .prop('onChange')!([{ value: 'bytes', label: 'Bytes' }]);
- });
+ act(() => {
+ wrapper
+ .find(EuiComboBox)
+ .filter('[data-test-subj="indexPattern-dimension-format"]')
+ .prop('onChange')!([{ value: 'bytes', label: 'Bytes' }]);
+ });
- expect(setState).toHaveBeenCalledWith({
- ...state,
- layers: {
- first: {
- ...state.layers.first,
- columns: {
- ...state.layers.first.columns,
- col1: expect.objectContaining({
- params: {
- format: { id: 'bytes', params: { decimals: 2 } },
- },
- }),
+ expect(setState).toHaveBeenCalledWith({
+ ...state,
+ layers: {
+ first: {
+ ...state.layers.first,
+ columns: {
+ ...state.layers.first.columns,
+ col1: expect.objectContaining({
+ params: {
+ format: { id: 'bytes', params: { decimals: 2 } },
+ },
+ }),
+ },
},
},
- },
+ });
});
- });
- it('keeps decimal places while switching', () => {
- const stateWithNumberCol: IndexPatternPrivateState = {
- ...state,
- layers: {
- first: {
- indexPatternId: '1',
- columnOrder: ['col1'],
- columns: {
- col1: {
- label: 'Average of bar',
- dataType: 'number',
- isBucketed: false,
- // Private
- operationType: 'avg',
- sourceField: 'bar',
- params: {
- format: { id: 'bytes', params: { decimals: 0 } },
+ it('keeps decimal places while switching', () => {
+ const stateWithNumberCol: IndexPatternPrivateState = {
+ ...state,
+ layers: {
+ first: {
+ indexPatternId: '1',
+ columnOrder: ['col1'],
+ columns: {
+ col1: {
+ label: 'Average of bar',
+ dataType: 'number',
+ isBucketed: false,
+ // Private
+ operationType: 'avg',
+ sourceField: 'bar',
+ params: {
+ format: { id: 'bytes', params: { decimals: 0 } },
+ },
},
},
},
},
- },
- };
+ };
- wrapper = mount( );
+ wrapper = mount(
+
+ );
- openPopover();
+ act(() => {
+ wrapper
+ .find(EuiComboBox)
+ .filter('[data-test-subj="indexPattern-dimension-format"]')
+ .prop('onChange')!([{ value: '', label: 'Default' }]);
+ });
- act(() => {
- wrapper
- .find(EuiComboBox)
- .filter('[data-test-subj="indexPattern-dimension-format"]')
- .prop('onChange')!([{ value: '', label: 'Default' }]);
- });
+ act(() => {
+ wrapper
+ .find(EuiComboBox)
+ .filter('[data-test-subj="indexPattern-dimension-format"]')
+ .prop('onChange')!([{ value: 'number', label: 'Number' }]);
+ });
- act(() => {
- wrapper
- .find(EuiComboBox)
- .filter('[data-test-subj="indexPattern-dimension-format"]')
- .prop('onChange')!([{ value: 'number', label: 'Number' }]);
+ expect(
+ wrapper
+ .find(EuiFieldNumber)
+ .filter('[data-test-subj="indexPattern-dimension-formatDecimals"]')
+ .prop('value')
+ ).toEqual(0);
});
- expect(
- wrapper
- .find(EuiFieldNumber)
- .filter('[data-test-subj="indexPattern-dimension-formatDecimals"]')
- .prop('value')
- ).toEqual(0);
- });
-
- it('allows custom format with number of decimal places', () => {
- const stateWithNumberCol: IndexPatternPrivateState = {
- ...state,
- layers: {
- first: {
- indexPatternId: '1',
- columnOrder: ['col1'],
- columns: {
- col1: {
- label: 'Average of bar',
- dataType: 'number',
- isBucketed: false,
- // Private
- operationType: 'avg',
- sourceField: 'bar',
- params: {
- format: { id: 'bytes', params: { decimals: 2 } },
+ it('allows custom format with number of decimal places', () => {
+ const stateWithNumberCol: IndexPatternPrivateState = {
+ ...state,
+ layers: {
+ first: {
+ indexPatternId: '1',
+ columnOrder: ['col1'],
+ columns: {
+ col1: {
+ label: 'Average of bar',
+ dataType: 'number',
+ isBucketed: false,
+ // Private
+ operationType: 'avg',
+ sourceField: 'bar',
+ params: {
+ format: { id: 'bytes', params: { decimals: 2 } },
+ },
},
},
},
},
- },
- };
-
- wrapper = mount( );
+ };
- openPopover();
+ wrapper = mount(
+
+ );
- act(() => {
- wrapper
- .find(EuiFieldNumber)
- .filter('[data-test-subj="indexPattern-dimension-formatDecimals"]')
- .prop('onChange')!({ target: { value: '0' } });
- });
+ act(() => {
+ wrapper
+ .find(EuiFieldNumber)
+ .filter('[data-test-subj="indexPattern-dimension-formatDecimals"]')
+ .prop('onChange')!({ target: { value: '0' } });
+ });
- expect(setState).toHaveBeenCalledWith({
- ...state,
- layers: {
- first: {
- ...state.layers.first,
- columns: {
- ...state.layers.first.columns,
- col1: expect.objectContaining({
- params: {
- format: { id: 'bytes', params: { decimals: 0 } },
- },
- }),
+ expect(setState).toHaveBeenCalledWith({
+ ...state,
+ layers: {
+ first: {
+ ...state.layers.first,
+ columns: {
+ ...state.layers.first.columns,
+ col1: expect.objectContaining({
+ params: {
+ format: { id: 'bytes', params: { decimals: 0 } },
+ },
+ }),
+ },
},
},
- },
+ });
});
});
- describe('drag and drop', () => {
+ describe('Drag and drop', () => {
function dragDropState(): IndexPatternPrivateState {
return {
indexPatternRefs: [],
@@ -1287,112 +1206,80 @@ describe('IndexPatternDimensionPanel', () => {
}
it('is not droppable if no drag is happening', () => {
- wrapper = mount(
-
- );
-
expect(
- wrapper
- .find('[data-test-subj="indexPattern-dropTarget"]')
- .first()
- .prop('droppable')
- ).toBeFalsy();
+ canHandleDrop({
+ ...defaultProps,
+ dragDropContext,
+ state: dragDropState(),
+ layerId: 'myLayer',
+ })
+ ).toBe(false);
});
it('is not droppable if the dragged item has no field', () => {
- wrapper = shallow(
-
- );
-
- expect(
- wrapper
- .find('[data-test-subj="indexPattern-dropTarget"]')
- .first()
- .prop('droppable')
- ).toBeFalsy();
+ },
+ })
+ ).toBe(false);
});
it('is not droppable if field is not supported by filterOperations', () => {
- wrapper = shallow(
- false}
- layerId="myLayer"
- />
- );
-
- expect(
- wrapper
- .find('[data-test-subj="indexPattern-dropTarget"]')
- .first()
- .prop('droppable')
- ).toBeFalsy();
+ },
+ state: dragDropState(),
+ filterOperations: () => false,
+ layerId: 'myLayer',
+ })
+ ).toBe(false);
});
it('is droppable if the field is supported by filterOperations', () => {
- wrapper = shallow(
- op.dataType === 'number'}
- layerId="myLayer"
- />
- );
-
- expect(
- wrapper
- .find('[data-test-subj="indexPattern-dropTarget"]')
- .first()
- .prop('droppable')
- ).toBeTruthy();
+ },
+ state: dragDropState(),
+ filterOperations: (op: OperationMetadata) => op.dataType === 'number',
+ layerId: 'myLayer',
+ })
+ ).toBe(true);
});
- it('is notdroppable if the field belongs to another index pattern', () => {
- wrapper = shallow(
- {
+ expect(
+ canHandleDrop({
+ ...defaultProps,
+ dragDropContext: {
...dragDropContext,
dragging: {
field: { type: 'number', name: 'bar', aggregatable: true },
indexPatternId: 'foo2',
},
- }}
- state={dragDropState()}
- filterOperations={op => op.dataType === 'number'}
- layerId="myLayer"
- />
- );
-
- expect(
- wrapper
- .find('[data-test-subj="indexPattern-dropTarget"]')
- .first()
- .prop('droppable')
- ).toBeFalsy();
+ },
+ state: dragDropState(),
+ filterOperations: (op: OperationMetadata) => op.dataType === 'number',
+ layerId: 'myLayer',
+ })
+ ).toBe(false);
});
it('appends the dropped column when a field is dropped', () => {
@@ -1401,27 +1288,18 @@ describe('IndexPatternDimensionPanel', () => {
indexPatternId: 'foo',
};
const testState = dragDropState();
- wrapper = shallow(
- op.dataType === 'number'}
- layerId="myLayer"
- />
- );
-
- act(() => {
- const onDrop = wrapper
- .find('[data-test-subj="indexPattern-dropTarget"]')
- .first()
- .prop('onDrop') as DropHandler;
- onDrop(dragging);
+ onDrop({
+ ...defaultProps,
+ dragDropContext: {
+ ...dragDropContext,
+ dragging,
+ },
+ droppedItem: dragging,
+ state: testState,
+ columnId: 'col2',
+ filterOperations: (op: OperationMetadata) => op.dataType === 'number',
+ layerId: 'myLayer',
});
expect(setState).toBeCalledTimes(1);
@@ -1449,27 +1327,17 @@ describe('IndexPatternDimensionPanel', () => {
indexPatternId: 'foo',
};
const testState = dragDropState();
- wrapper = shallow(
- op.isBucketed}
- layerId="myLayer"
- />
- );
-
- act(() => {
- const onDrop = wrapper
- .find('[data-test-subj="indexPattern-dropTarget"]')
- .first()
- .prop('onDrop') as DropHandler;
-
- onDrop(dragging);
+ onDrop({
+ ...defaultProps,
+ dragDropContext: {
+ ...dragDropContext,
+ dragging,
+ },
+ droppedItem: dragging,
+ state: testState,
+ columnId: 'col2',
+ filterOperations: (op: OperationMetadata) => op.isBucketed,
+ layerId: 'myLayer',
});
expect(setState).toBeCalledTimes(1);
@@ -1497,26 +1365,16 @@ describe('IndexPatternDimensionPanel', () => {
indexPatternId: 'foo',
};
const testState = dragDropState();
- wrapper = shallow(
- op.dataType === 'number'}
- layerId="myLayer"
- />
- );
-
- act(() => {
- const onDrop = wrapper
- .find('[data-test-subj="indexPattern-dropTarget"]')
- .first()
- .prop('onDrop') as DropHandler;
-
- onDrop(dragging);
+ onDrop({
+ ...defaultProps,
+ dragDropContext: {
+ ...dragDropContext,
+ dragging,
+ },
+ droppedItem: dragging,
+ state: testState,
+ filterOperations: (op: OperationMetadata) => op.dataType === 'number',
+ layerId: 'myLayer',
});
expect(setState).toBeCalledTimes(1);
diff --git a/x-pack/legacy/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_panel.tsx b/x-pack/legacy/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_panel.tsx
index 59350ff215c27..5d87137db3d39 100644
--- a/x-pack/legacy/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_panel.tsx
+++ b/x-pack/legacy/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_panel.tsx
@@ -5,27 +5,36 @@
*/
import _ from 'lodash';
-import React, { memo, useMemo } from 'react';
-import { EuiButtonIcon } from '@elastic/eui';
+import React, { memo } from 'react';
import { i18n } from '@kbn/i18n';
+import { EuiLink } from '@elastic/eui';
import { IUiSettingsClient, SavedObjectsClientContract, HttpSetup } from 'src/core/public';
import { IStorageWrapper } from 'src/plugins/kibana_utils/public';
+import {
+ DatasourceDimensionTriggerProps,
+ DatasourceDimensionEditorProps,
+ DatasourceDimensionDropProps,
+ DatasourceDimensionDropHandlerProps,
+} from '../../types';
import { DataPublicPluginStart } from '../../../../../../../src/plugins/data/public';
-import { DatasourceDimensionPanelProps, StateSetter } from '../../types';
import { IndexPatternColumn, OperationType } from '../indexpattern';
import { getAvailableOperationsByMetadata, buildColumn, changeField } from '../operations';
import { PopoverEditor } from './popover_editor';
-import { DragContextState, ChildDragDropProvider, DragDrop } from '../../drag_drop';
-import { changeColumn, deleteColumn } from '../state_helpers';
+import { changeColumn } from '../state_helpers';
import { isDraggedField, hasField } from '../utils';
import { IndexPatternPrivateState, IndexPatternField } from '../types';
import { trackUiEvent } from '../../lens_ui_telemetry';
import { DateRange } from '../../../../../../plugins/lens/common';
-export type IndexPatternDimensionPanelProps = DatasourceDimensionPanelProps & {
- state: IndexPatternPrivateState;
- setState: StateSetter;
- dragDropContext: DragContextState;
+export type IndexPatternDimensionTriggerProps = DatasourceDimensionTriggerProps<
+ IndexPatternPrivateState
+> & {
+ uniqueLabel: string;
+};
+
+export type IndexPatternDimensionEditorProps = DatasourceDimensionEditorProps<
+ IndexPatternPrivateState
+> & {
uiSettings: IUiSettingsClient;
storage: IStorageWrapper;
savedObjectsClient: SavedObjectsClientContract;
@@ -41,152 +50,181 @@ export interface OperationFieldSupportMatrix {
fieldByOperation: Partial>;
}
-export const IndexPatternDimensionPanelComponent = function IndexPatternDimensionPanel(
- props: IndexPatternDimensionPanelProps
-) {
+type Props = Pick<
+ DatasourceDimensionDropProps,
+ 'layerId' | 'columnId' | 'state' | 'filterOperations'
+>;
+
+// TODO: This code has historically been memoized, as a potentially performance
+// sensitive task. If we can add memoization without breaking the behavior, we should.
+const getOperationFieldSupportMatrix = (props: Props): OperationFieldSupportMatrix => {
const layerId = props.layerId;
const currentIndexPattern = props.state.indexPatterns[props.state.layers[layerId].indexPatternId];
- const operationFieldSupportMatrix = useMemo(() => {
- const filteredOperationsByMetadata = getAvailableOperationsByMetadata(
- currentIndexPattern
- ).filter(operation => props.filterOperations(operation.operationMetaData));
-
- const supportedOperationsByField: Partial> = {};
- const supportedFieldsByOperation: Partial> = {};
-
- filteredOperationsByMetadata.forEach(({ operations }) => {
- operations.forEach(operation => {
- if (supportedOperationsByField[operation.field]) {
- supportedOperationsByField[operation.field]!.push(operation.operationType);
- } else {
- supportedOperationsByField[operation.field] = [operation.operationType];
- }
-
- if (supportedFieldsByOperation[operation.operationType]) {
- supportedFieldsByOperation[operation.operationType]!.push(operation.field);
- } else {
- supportedFieldsByOperation[operation.operationType] = [operation.field];
- }
- });
+ const filteredOperationsByMetadata = getAvailableOperationsByMetadata(
+ currentIndexPattern
+ ).filter(operation => props.filterOperations(operation.operationMetaData));
+
+ const supportedOperationsByField: Partial> = {};
+ const supportedFieldsByOperation: Partial> = {};
+
+ filteredOperationsByMetadata.forEach(({ operations }) => {
+ operations.forEach(operation => {
+ if (supportedOperationsByField[operation.field]) {
+ supportedOperationsByField[operation.field]!.push(operation.operationType);
+ } else {
+ supportedOperationsByField[operation.field] = [operation.operationType];
+ }
+
+ if (supportedFieldsByOperation[operation.operationType]) {
+ supportedFieldsByOperation[operation.operationType]!.push(operation.field);
+ } else {
+ supportedFieldsByOperation[operation.operationType] = [operation.field];
+ }
});
- return {
- operationByField: _.mapValues(supportedOperationsByField, _.uniq),
- fieldByOperation: _.mapValues(supportedFieldsByOperation, _.uniq),
- };
- }, [currentIndexPattern, props.filterOperations]);
+ });
+ return {
+ operationByField: _.mapValues(supportedOperationsByField, _.uniq),
+ fieldByOperation: _.mapValues(supportedFieldsByOperation, _.uniq),
+ };
+};
- const selectedColumn: IndexPatternColumn | null =
- props.state.layers[layerId].columns[props.columnId] || null;
+export function canHandleDrop(props: DatasourceDimensionDropProps) {
+ const operationFieldSupportMatrix = getOperationFieldSupportMatrix(props);
+
+ const { dragging } = props.dragDropContext;
+ const layerIndexPatternId = props.state.layers[props.layerId].indexPatternId;
function hasOperationForField(field: IndexPatternField) {
return Boolean(operationFieldSupportMatrix.operationByField[field.name]);
}
- function canHandleDrop() {
- const { dragging } = props.dragDropContext;
- const layerIndexPatternId = props.state.layers[props.layerId].indexPatternId;
+ return (
+ isDraggedField(dragging) &&
+ layerIndexPatternId === dragging.indexPatternId &&
+ Boolean(hasOperationForField(dragging.field))
+ );
+}
+
+export function onDrop(
+ props: DatasourceDimensionDropHandlerProps
+): boolean {
+ const operationFieldSupportMatrix = getOperationFieldSupportMatrix(props);
+ const droppedItem = props.droppedItem;
+
+ function hasOperationForField(field: IndexPatternField) {
+ return Boolean(operationFieldSupportMatrix.operationByField[field.name]);
+ }
- return (
- isDraggedField(dragging) &&
- layerIndexPatternId === dragging.indexPatternId &&
- Boolean(hasOperationForField(dragging.field))
- );
+ if (!isDraggedField(droppedItem) || !hasOperationForField(droppedItem.field)) {
+ // TODO: What do we do if we couldn't find a column?
+ return false;
}
+ const operationsForNewField =
+ operationFieldSupportMatrix.operationByField[droppedItem.field.name];
+
+ const layerId = props.layerId;
+ const selectedColumn: IndexPatternColumn | null =
+ props.state.layers[layerId].columns[props.columnId] || null;
+ const currentIndexPattern =
+ props.state.indexPatterns[props.state.layers[layerId]?.indexPatternId];
+
+ // We need to check if dragging in a new field, was just a field change on the same
+ // index pattern and on the same operations (therefore checking if the new field supports
+ // our previous operation)
+ const hasFieldChanged =
+ selectedColumn &&
+ hasField(selectedColumn) &&
+ selectedColumn.sourceField !== droppedItem.field.name &&
+ operationsForNewField &&
+ operationsForNewField.includes(selectedColumn.operationType);
+
+ // If only the field has changed use the onFieldChange method on the operation to get the
+ // new column, otherwise use the regular buildColumn to get a new column.
+ const newColumn = hasFieldChanged
+ ? changeField(selectedColumn, currentIndexPattern, droppedItem.field)
+ : buildColumn({
+ op: operationsForNewField ? operationsForNewField[0] : undefined,
+ columns: props.state.layers[props.layerId].columns,
+ indexPattern: currentIndexPattern,
+ layerId,
+ suggestedPriority: props.suggestedPriority,
+ field: droppedItem.field,
+ previousColumn: selectedColumn,
+ });
+
+ trackUiEvent('drop_onto_dimension');
+ const hasData = Object.values(props.state.layers).some(({ columns }) => columns.length);
+ trackUiEvent(hasData ? 'drop_non_empty' : 'drop_empty');
+
+ props.setState(
+ changeColumn({
+ state: props.state,
+ layerId,
+ columnId: props.columnId,
+ newColumn,
+ // If the field has changed, the onFieldChange method needs to take care of everything including moving
+ // over params. If we create a new column above we want changeColumn to move over params.
+ keepParams: !hasFieldChanged,
+ })
+ );
+
+ return true;
+}
+
+export const IndexPatternDimensionTriggerComponent = function IndexPatternDimensionTrigger(
+ props: IndexPatternDimensionTriggerProps
+) {
+ const layerId = props.layerId;
+
+ const selectedColumn: IndexPatternColumn | null =
+ props.state.layers[layerId].columns[props.columnId] || null;
+
+ const { columnId, uniqueLabel } = props;
+ if (!selectedColumn) {
+ return null;
+ }
+ return (
+ {
+ props.togglePopover();
+ }}
+ data-test-subj="lns-dimensionTrigger"
+ aria-label={i18n.translate('xpack.lens.configure.editConfig', {
+ defaultMessage: 'Edit configuration',
+ })}
+ title={i18n.translate('xpack.lens.configure.editConfig', {
+ defaultMessage: 'Edit configuration',
+ })}
+ >
+ {uniqueLabel}
+
+ );
+};
+
+export const IndexPatternDimensionEditorComponent = function IndexPatternDimensionPanel(
+ props: IndexPatternDimensionEditorProps
+) {
+ const layerId = props.layerId;
+ const currentIndexPattern =
+ props.state.indexPatterns[props.state.layers[layerId]?.indexPatternId];
+ const operationFieldSupportMatrix = getOperationFieldSupportMatrix(props);
+
+ const selectedColumn: IndexPatternColumn | null =
+ props.state.layers[layerId].columns[props.columnId] || null;
+
return (
-
- {
- if (!isDraggedField(droppedItem) || !hasOperationForField(droppedItem.field)) {
- // TODO: What do we do if we couldn't find a column?
- return;
- }
-
- const operationsForNewField =
- operationFieldSupportMatrix.operationByField[droppedItem.field.name];
-
- // We need to check if dragging in a new field, was just a field change on the same
- // index pattern and on the same operations (therefore checking if the new field supports
- // our previous operation)
- const hasFieldChanged =
- selectedColumn &&
- hasField(selectedColumn) &&
- selectedColumn.sourceField !== droppedItem.field.name &&
- operationsForNewField &&
- operationsForNewField.includes(selectedColumn.operationType);
-
- // If only the field has changed use the onFieldChange method on the operation to get the
- // new column, otherwise use the regular buildColumn to get a new column.
- const newColumn = hasFieldChanged
- ? changeField(selectedColumn, currentIndexPattern, droppedItem.field)
- : buildColumn({
- op: operationsForNewField ? operationsForNewField[0] : undefined,
- columns: props.state.layers[props.layerId].columns,
- indexPattern: currentIndexPattern,
- layerId,
- suggestedPriority: props.suggestedPriority,
- field: droppedItem.field,
- previousColumn: selectedColumn,
- });
-
- trackUiEvent('drop_onto_dimension');
- const hasData = Object.values(props.state.layers).some(({ columns }) => columns.length);
- trackUiEvent(hasData ? 'drop_non_empty' : 'drop_empty');
-
- props.setState(
- changeColumn({
- state: props.state,
- layerId,
- columnId: props.columnId,
- newColumn,
- // If the field has changed, the onFieldChange method needs to take care of everything including moving
- // over params. If we create a new column above we want changeColumn to move over params.
- keepParams: !hasFieldChanged,
- })
- );
- }}
- >
-
- {selectedColumn && (
- {
- trackUiEvent('indexpattern_dimension_removed');
- props.setState(
- deleteColumn({
- state: props.state,
- layerId,
- columnId: props.columnId,
- })
- );
- if (props.onRemove) {
- props.onRemove(props.columnId);
- }
- }}
- />
- )}
-
-
+
);
};
-export const IndexPatternDimensionPanel = memo(IndexPatternDimensionPanelComponent);
+export const IndexPatternDimensionTrigger = memo(IndexPatternDimensionTriggerComponent);
+export const IndexPatternDimensionEditor = memo(IndexPatternDimensionEditorComponent);
diff --git a/x-pack/legacy/plugins/lens/public/indexpattern_datasource/dimension_panel/popover_editor.tsx b/x-pack/legacy/plugins/lens/public/indexpattern_datasource/dimension_panel/popover_editor.tsx
index 056a8d177dfe8..e26c338b6e240 100644
--- a/x-pack/legacy/plugins/lens/public/indexpattern_datasource/dimension_panel/popover_editor.tsx
+++ b/x-pack/legacy/plugins/lens/public/indexpattern_datasource/dimension_panel/popover_editor.tsx
@@ -7,22 +7,18 @@
import _ from 'lodash';
import React, { useState, useMemo } from 'react';
import { i18n } from '@kbn/i18n';
-import { FormattedMessage } from '@kbn/i18n/react';
import {
- EuiPopover,
EuiFlexItem,
EuiFlexGroup,
EuiSideNav,
EuiCallOut,
EuiFormRow,
EuiFieldText,
- EuiLink,
- EuiButtonEmpty,
EuiSpacer,
} from '@elastic/eui';
import classNames from 'classnames';
import { IndexPatternColumn, OperationType } from '../indexpattern';
-import { IndexPatternDimensionPanelProps, OperationFieldSupportMatrix } from './dimension_panel';
+import { IndexPatternDimensionEditorProps, OperationFieldSupportMatrix } from './dimension_panel';
import {
operationDefinitionMap,
getOperationDisplay,
@@ -39,7 +35,7 @@ import { FormatSelector } from './format_selector';
const operationPanels = getOperationDisplay();
-export interface PopoverEditorProps extends IndexPatternDimensionPanelProps {
+export interface PopoverEditorProps extends IndexPatternDimensionEditorProps {
selectedColumn?: IndexPatternColumn;
operationFieldSupportMatrix: OperationFieldSupportMatrix;
currentIndexPattern: IndexPattern;
@@ -67,11 +63,9 @@ export function PopoverEditor(props: PopoverEditorProps) {
setState,
layerId,
currentIndexPattern,
- uniqueLabel,
hideGrouping,
} = props;
const { operationByField, fieldByOperation } = operationFieldSupportMatrix;
- const [isPopoverOpen, setPopoverOpen] = useState(false);
const [
incompatibleSelectedOperationType,
setInvalidOperationType,
@@ -115,14 +109,14 @@ export function PopoverEditor(props: PopoverEditorProps) {
items: getOperationTypes().map(({ operationType, compatibleWithCurrentField }) => ({
name: operationPanels[operationType].displayName,
id: operationType as string,
- className: classNames('lnsPopoverEditor__operation', {
- 'lnsPopoverEditor__operation--selected': Boolean(
+ className: classNames('lnsIndexPatternDimensionEditor__operation', {
+ 'lnsIndexPatternDimensionEditor__operation--selected': Boolean(
incompatibleSelectedOperationType === operationType ||
(!incompatibleSelectedOperationType &&
selectedColumn &&
selectedColumn.operationType === operationType)
),
- 'lnsPopoverEditor__operation--incompatible': !compatibleWithCurrentField,
+ 'lnsIndexPatternDimensionEditor__operation--incompatible': !compatibleWithCurrentField,
}),
'data-test-subj': `lns-indexPatternDimension${
compatibleWithCurrentField ? '' : 'Incompatible'
@@ -188,246 +182,193 @@ export function PopoverEditor(props: PopoverEditorProps) {
}
return (
- {
- setPopoverOpen(!isPopoverOpen);
+
+
+
+ {
+ setState(
+ deleteColumn({
+ state,
+ layerId,
+ columnId,
+ })
+ );
}}
- data-test-subj="indexPattern-configure-dimension"
- aria-label={i18n.translate('xpack.lens.configure.editConfig', {
- defaultMessage: 'Edit configuration',
- })}
- title={i18n.translate('xpack.lens.configure.editConfig', {
- defaultMessage: 'Edit configuration',
- })}
- >
- {uniqueLabel}
-
- ) : (
- <>
- setPopoverOpen(!isPopoverOpen)}
- size="xs"
- >
-
-
- >
- )
- }
- isOpen={isPopoverOpen}
- closePopover={() => {
- setPopoverOpen(false);
- setInvalidOperationType(null);
- }}
- anchorPosition="leftUp"
- withTitle
- panelPaddingSize="s"
- >
- {isPopoverOpen && (
-
-
- {
- setState(
- deleteColumn({
- state,
- layerId,
- columnId,
- })
- );
- }}
- onChoose={choice => {
- let column: IndexPatternColumn;
- if (
- !incompatibleSelectedOperationType &&
- selectedColumn &&
- 'field' in choice &&
- choice.operationType === selectedColumn.operationType
- ) {
- // If we just changed the field are not in an error state and the operation didn't change,
- // we use the operations onFieldChange method to calculate the new column.
- column = changeField(selectedColumn, currentIndexPattern, fieldMap[choice.field]);
- } else {
- // Otherwise we'll use the buildColumn method to calculate a new column
- const compatibleOperations =
- ('field' in choice &&
- operationFieldSupportMatrix.operationByField[choice.field]) ||
- [];
- let operation;
- if (compatibleOperations.length > 0) {
- operation =
- incompatibleSelectedOperationType &&
- compatibleOperations.includes(incompatibleSelectedOperationType)
- ? incompatibleSelectedOperationType
- : compatibleOperations[0];
- } else if ('field' in choice) {
- operation = choice.operationType;
- }
- column = buildColumn({
- columns: props.state.layers[props.layerId].columns,
- field: fieldMap[choice.field],
- indexPattern: currentIndexPattern,
- layerId: props.layerId,
- suggestedPriority: props.suggestedPriority,
- op: operation as OperationType,
- previousColumn: selectedColumn,
- });
+ onChoose={choice => {
+ let column: IndexPatternColumn;
+ if (
+ !incompatibleSelectedOperationType &&
+ selectedColumn &&
+ 'field' in choice &&
+ choice.operationType === selectedColumn.operationType
+ ) {
+ // If we just changed the field are not in an error state and the operation didn't change,
+ // we use the operations onFieldChange method to calculate the new column.
+ column = changeField(selectedColumn, currentIndexPattern, fieldMap[choice.field]);
+ } else {
+ // Otherwise we'll use the buildColumn method to calculate a new column
+ const compatibleOperations =
+ ('field' in choice &&
+ operationFieldSupportMatrix.operationByField[choice.field]) ||
+ [];
+ let operation;
+ if (compatibleOperations.length > 0) {
+ operation =
+ incompatibleSelectedOperationType &&
+ compatibleOperations.includes(incompatibleSelectedOperationType)
+ ? incompatibleSelectedOperationType
+ : compatibleOperations[0];
+ } else if ('field' in choice) {
+ operation = choice.operationType;
}
+ column = buildColumn({
+ columns: props.state.layers[props.layerId].columns,
+ field: fieldMap[choice.field],
+ indexPattern: currentIndexPattern,
+ layerId: props.layerId,
+ suggestedPriority: props.suggestedPriority,
+ op: operation as OperationType,
+ previousColumn: selectedColumn,
+ });
+ }
- setState(
- changeColumn({
- state,
- layerId,
- columnId,
- newColumn: column,
- keepParams: false,
- })
- );
- setInvalidOperationType(null);
- }}
- />
-
-
-
-
-
-
-
- {incompatibleSelectedOperationType && selectedColumn && (
-
- )}
- {incompatibleSelectedOperationType && !selectedColumn && (
-
- )}
- {!incompatibleSelectedOperationType && ParamEditor && (
- <>
-
-
- >
- )}
- {!incompatibleSelectedOperationType && selectedColumn && (
-
- {
- setState(
- changeColumn({
- state,
- layerId,
- columnId,
- newColumn: {
- ...selectedColumn,
- label: e.target.value,
- },
- })
- );
- }}
- />
-
- )}
-
- {!hideGrouping && (
- {
- setState({
- ...state,
- layers: {
- ...state.layers,
- [props.layerId]: {
- ...state.layers[props.layerId],
- columnOrder,
- },
- },
- });
- }}
+ setState(
+ changeColumn({
+ state,
+ layerId,
+ columnId,
+ newColumn: column,
+ keepParams: false,
+ })
+ );
+ setInvalidOperationType(null);
+ }}
+ />
+
+
+
+
+
+
+
+ {incompatibleSelectedOperationType && selectedColumn && (
+
+ )}
+ {incompatibleSelectedOperationType && !selectedColumn && (
+
+ )}
+ {!incompatibleSelectedOperationType && ParamEditor && (
+ <>
+
- )}
-
- {selectedColumn && selectedColumn.dataType === 'number' ? (
- {
+
+ >
+ )}
+ {!incompatibleSelectedOperationType && selectedColumn && (
+
+ {
setState(
- updateColumnParam({
+ changeColumn({
state,
layerId,
- currentColumn: selectedColumn,
- paramName: 'format',
- value: newFormat,
+ columnId,
+ newColumn: {
+ ...selectedColumn,
+ label: e.target.value,
+ },
})
);
}}
/>
- ) : null}
-
-
-
-
- )}
-
+
+ )}
+
+ {!hideGrouping && (
+ {
+ setState({
+ ...state,
+ layers: {
+ ...state.layers,
+ [props.layerId]: {
+ ...state.layers[props.layerId],
+ columnOrder,
+ },
+ },
+ });
+ }}
+ />
+ )}
+
+ {selectedColumn && selectedColumn.dataType === 'number' ? (
+ {
+ setState(
+ updateColumnParam({
+ state,
+ layerId,
+ currentColumn: selectedColumn,
+ paramName: 'format',
+ value: newFormat,
+ })
+ );
+ }}
+ />
+ ) : null}
+
+
+
+
+
);
}
diff --git a/x-pack/legacy/plugins/lens/public/indexpattern_datasource/indexpattern.test.ts b/x-pack/legacy/plugins/lens/public/indexpattern_datasource/indexpattern.test.ts
index 25121eec30f2a..76e59a170a9e9 100644
--- a/x-pack/legacy/plugins/lens/public/indexpattern_datasource/indexpattern.test.ts
+++ b/x-pack/legacy/plugins/lens/public/indexpattern_datasource/indexpattern.test.ts
@@ -408,7 +408,6 @@ describe('IndexPattern Data Source', () => {
const initialState = stateFromPersistedState(persistedState);
publicAPI = indexPatternDatasource.getPublicAPI({
state: initialState,
- setState: () => {},
layerId: 'first',
dateRange: {
fromDate: 'now-30d',
diff --git a/x-pack/legacy/plugins/lens/public/indexpattern_datasource/indexpattern.tsx b/x-pack/legacy/plugins/lens/public/indexpattern_datasource/indexpattern.tsx
index 00f52d6a1747f..9c2a9c9bf4a09 100644
--- a/x-pack/legacy/plugins/lens/public/indexpattern_datasource/indexpattern.tsx
+++ b/x-pack/legacy/plugins/lens/public/indexpattern_datasource/indexpattern.tsx
@@ -12,7 +12,8 @@ import { CoreStart } from 'src/core/public';
import { i18n } from '@kbn/i18n';
import { IStorageWrapper } from 'src/plugins/kibana_utils/public';
import {
- DatasourceDimensionPanelProps,
+ DatasourceDimensionEditorProps,
+ DatasourceDimensionTriggerProps,
DatasourceDataPanelProps,
Operation,
DatasourceLayerPanelProps,
@@ -20,7 +21,12 @@ import {
} from '../types';
import { loadInitialState, changeIndexPattern, changeLayerIndexPattern } from './loader';
import { toExpression } from './to_expression';
-import { IndexPatternDimensionPanel } from './dimension_panel';
+import {
+ IndexPatternDimensionTrigger,
+ IndexPatternDimensionEditor,
+ canHandleDrop,
+ onDrop,
+} from './dimension_panel';
import { IndexPatternDataPanel } from './datapanel';
import {
getDatasourceSuggestionsForField,
@@ -38,6 +44,7 @@ import {
} from './types';
import { KibanaContextProvider } from '../../../../../../src/plugins/kibana_react/public';
import { Plugin as DataPlugin } from '../../../../../../src/plugins/data/public';
+import { deleteColumn } from './state_helpers';
import { Datasource, StateSetter } from '..';
export { OperationType, IndexPatternColumn } from './operations';
@@ -80,6 +87,9 @@ export function uniqueLabels(layers: Record) {
};
Object.values(layers).forEach(layer => {
+ if (!layer.columns) {
+ return;
+ }
Object.entries(layer.columns).forEach(([columnId, column]) => {
columnLabelMap[columnId] = makeUnique(column.label);
});
@@ -156,6 +166,14 @@ export function getIndexPatternDatasource({
return Object.keys(state.layers);
},
+ removeColumn({ prevState, layerId, columnId }) {
+ return deleteColumn({
+ state: prevState,
+ layerId,
+ columnId,
+ });
+ },
+
toExpression,
getMetaData(state: IndexPatternPrivateState) {
@@ -198,15 +216,97 @@ export function getIndexPatternDatasource({
);
},
- getPublicAPI({
- state,
- setState,
- layerId,
- dateRange,
- }: PublicAPIProps) {
+ renderDimensionTrigger: (
+ domElement: Element,
+ props: DatasourceDimensionTriggerProps
+ ) => {
+ const columnLabelMap = uniqueLabels(props.state.layers);
+
+ render(
+
+
+
+
+ ,
+ domElement
+ );
+ },
+
+ renderDimensionEditor: (
+ domElement: Element,
+ props: DatasourceDimensionEditorProps
+ ) => {
+ const columnLabelMap = uniqueLabels(props.state.layers);
+
+ render(
+
+
+
+
+ ,
+ domElement
+ );
+ },
+
+ renderLayerPanel: (
+ domElement: Element,
+ props: DatasourceLayerPanelProps
+ ) => {
+ render(
+ {
+ changeLayerIndexPattern({
+ savedObjectsClient,
+ indexPatternId,
+ setState: props.setState,
+ state: props.state,
+ layerId: props.layerId,
+ onError: onIndexPatternLoadError,
+ replaceIfPossible: true,
+ });
+ }}
+ {...props}
+ />,
+ domElement
+ );
+ },
+
+ canHandleDrop,
+ onDrop,
+
+ getPublicAPI({ state, layerId }: PublicAPIProps) {
const columnLabelMap = uniqueLabels(state.layers);
return {
+ datasourceId: 'indexpattern',
+
getTableSpec: () => {
return state.layers[layerId].columnOrder.map(colId => ({ columnId: colId }));
},
@@ -218,58 +318,6 @@ export function getIndexPatternDatasource({
}
return null;
},
- renderDimensionPanel: (domElement: Element, props: DatasourceDimensionPanelProps) => {
- render(
-
-
-
-
- ,
- domElement
- );
- },
-
- renderLayerPanel: (domElement: Element, props: DatasourceLayerPanelProps) => {
- render(
- {
- changeLayerIndexPattern({
- savedObjectsClient,
- indexPatternId,
- setState,
- state,
- layerId: props.layerId,
- onError: onIndexPatternLoadError,
- replaceIfPossible: true,
- });
- }}
- {...props}
- />,
- domElement
- );
- },
};
},
getDatasourceSuggestionsForField(state, draggedField) {
diff --git a/x-pack/legacy/plugins/lens/public/indexpattern_datasource/layerpanel.test.tsx b/x-pack/legacy/plugins/lens/public/indexpattern_datasource/layerpanel.test.tsx
index af7afb9cf9342..219a6d935e436 100644
--- a/x-pack/legacy/plugins/lens/public/indexpattern_datasource/layerpanel.test.tsx
+++ b/x-pack/legacy/plugins/lens/public/indexpattern_datasource/layerpanel.test.tsx
@@ -178,6 +178,7 @@ describe('Layer Data Panel', () => {
defaultProps = {
layerId: 'first',
state: initialState,
+ setState: jest.fn(),
onChangeIndexPattern: jest.fn(async () => {}),
};
});
diff --git a/x-pack/legacy/plugins/lens/public/indexpattern_datasource/layerpanel.tsx b/x-pack/legacy/plugins/lens/public/indexpattern_datasource/layerpanel.tsx
index ae346ecc72cbc..eea00d52a77f9 100644
--- a/x-pack/legacy/plugins/lens/public/indexpattern_datasource/layerpanel.tsx
+++ b/x-pack/legacy/plugins/lens/public/indexpattern_datasource/layerpanel.tsx
@@ -11,7 +11,8 @@ import { DatasourceLayerPanelProps } from '../types';
import { IndexPatternPrivateState } from './types';
import { ChangeIndexPattern } from './change_indexpattern';
-export interface IndexPatternLayerPanelProps extends DatasourceLayerPanelProps {
+export interface IndexPatternLayerPanelProps
+ extends DatasourceLayerPanelProps {
state: IndexPatternPrivateState;
onChangeIndexPattern: (newId: string) => void;
}
diff --git a/x-pack/legacy/plugins/lens/public/metric_visualization/metric_config_panel.test.tsx b/x-pack/legacy/plugins/lens/public/metric_visualization/metric_config_panel.test.tsx
deleted file mode 100644
index eac35f82a50fa..0000000000000
--- a/x-pack/legacy/plugins/lens/public/metric_visualization/metric_config_panel.test.tsx
+++ /dev/null
@@ -1,69 +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 { ReactWrapper } from 'enzyme';
-import { mountWithIntl as mount } from 'test_utils/enzyme_helpers';
-import { MetricConfigPanel } from './metric_config_panel';
-import { DatasourceDimensionPanelProps, Operation, DatasourcePublicAPI } from '../types';
-import { State } from './types';
-import { NativeRendererProps } from '../native_renderer';
-import { createMockFramePublicAPI, createMockDatasource } from '../editor_frame_service/mocks';
-
-describe('MetricConfigPanel', () => {
- const dragDropContext = { dragging: undefined, setDragging: jest.fn() };
-
- function mockDatasource(): DatasourcePublicAPI {
- return createMockDatasource().publicAPIMock;
- }
-
- function testState(): State {
- return {
- accessor: 'foo',
- layerId: 'bar',
- };
- }
-
- function testSubj(component: ReactWrapper, subj: string) {
- return component
- .find(`[data-test-subj="${subj}"]`)
- .first()
- .props();
- }
-
- test('the value dimension panel only accepts singular numeric operations', () => {
- const state = testState();
- const component = mount(
-
- );
-
- const panel = testSubj(component, 'lns_metric_valueDimensionPanel');
- const nativeProps = (panel as NativeRendererProps).nativeProps;
- const { columnId, filterOperations } = nativeProps;
- const exampleOperation: Operation = {
- dataType: 'number',
- isBucketed: false,
- label: 'bar',
- };
- const ops: Operation[] = [
- { ...exampleOperation, dataType: 'number' },
- { ...exampleOperation, dataType: 'string' },
- { ...exampleOperation, dataType: 'boolean' },
- { ...exampleOperation, dataType: 'date' },
- ];
- expect(columnId).toEqual('shazm');
- expect(ops.filter(filterOperations)).toEqual([{ ...exampleOperation, dataType: 'number' }]);
- });
-});
diff --git a/x-pack/legacy/plugins/lens/public/metric_visualization/metric_config_panel.tsx b/x-pack/legacy/plugins/lens/public/metric_visualization/metric_config_panel.tsx
deleted file mode 100644
index 16e24f247fb68..0000000000000
--- a/x-pack/legacy/plugins/lens/public/metric_visualization/metric_config_panel.tsx
+++ /dev/null
@@ -1,39 +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 { i18n } from '@kbn/i18n';
-import { EuiFormRow } from '@elastic/eui';
-import { State } from './types';
-import { VisualizationLayerConfigProps, OperationMetadata } from '../types';
-import { NativeRenderer } from '../native_renderer';
-
-const isMetric = (op: OperationMetadata) => !op.isBucketed && op.dataType === 'number';
-
-export function MetricConfigPanel(props: VisualizationLayerConfigProps) {
- const { state, frame, layerId } = props;
- const datasource = frame.datasourceLayers[layerId];
-
- return (
-
-
-
- );
-}
diff --git a/x-pack/legacy/plugins/lens/public/metric_visualization/metric_expression.tsx b/x-pack/legacy/plugins/lens/public/metric_visualization/metric_expression.tsx
index 66ed963002f59..4d979a766cd2b 100644
--- a/x-pack/legacy/plugins/lens/public/metric_visualization/metric_expression.tsx
+++ b/x-pack/legacy/plugins/lens/public/metric_visualization/metric_expression.tsx
@@ -91,6 +91,11 @@ export function MetricChart({
const { title, accessor, mode } = args;
let value = '-';
const firstTable = Object.values(data.tables)[0];
+ if (!accessor) {
+ return (
+
+ );
+ }
if (firstTable) {
const column = firstTable.columns[0];
diff --git a/x-pack/legacy/plugins/lens/public/metric_visualization/metric_visualization.test.ts b/x-pack/legacy/plugins/lens/public/metric_visualization/metric_visualization.test.ts
index 88964b95c2ac7..276f24433c670 100644
--- a/x-pack/legacy/plugins/lens/public/metric_visualization/metric_visualization.test.ts
+++ b/x-pack/legacy/plugins/lens/public/metric_visualization/metric_visualization.test.ts
@@ -24,8 +24,8 @@ function mockFrame(): FramePublicAPI {
...createMockFramePublicAPI(),
addNewLayer: () => 'l42',
datasourceLayers: {
- l1: createMockDatasource().publicAPIMock,
- l42: createMockDatasource().publicAPIMock,
+ l1: createMockDatasource('l1').publicAPIMock,
+ l42: createMockDatasource('l42').publicAPIMock,
},
};
}
@@ -36,10 +36,10 @@ describe('metric_visualization', () => {
(generateId as jest.Mock).mockReturnValueOnce('test-id1');
const initialState = metricVisualization.initialize(mockFrame());
- expect(initialState.accessor).toBeDefined();
+ expect(initialState.accessor).not.toBeDefined();
expect(initialState).toMatchInlineSnapshot(`
Object {
- "accessor": "test-id1",
+ "accessor": undefined,
"layerId": "l42",
}
`);
@@ -60,7 +60,7 @@ describe('metric_visualization', () => {
it('returns a clean layer', () => {
(generateId as jest.Mock).mockReturnValueOnce('test-id1');
expect(metricVisualization.clearLayer(exampleState(), 'l1')).toEqual({
- accessor: 'test-id1',
+ accessor: undefined,
layerId: 'l1',
});
});
@@ -72,10 +72,47 @@ describe('metric_visualization', () => {
});
});
+ describe('#setDimension', () => {
+ it('sets the accessor', () => {
+ expect(
+ metricVisualization.setDimension({
+ prevState: {
+ accessor: undefined,
+ layerId: 'l1',
+ },
+ layerId: 'l1',
+ groupId: '',
+ columnId: 'newDimension',
+ })
+ ).toEqual({
+ accessor: 'newDimension',
+ layerId: 'l1',
+ });
+ });
+ });
+
+ describe('#removeDimension', () => {
+ it('removes the accessor', () => {
+ expect(
+ metricVisualization.removeDimension({
+ prevState: {
+ accessor: 'a',
+ layerId: 'l1',
+ },
+ layerId: 'l1',
+ columnId: 'a',
+ })
+ ).toEqual({
+ accessor: undefined,
+ layerId: 'l1',
+ });
+ });
+ });
+
describe('#toExpression', () => {
it('should map to a valid AST', () => {
const datasource: DatasourcePublicAPI = {
- ...createMockDatasource().publicAPIMock,
+ ...createMockDatasource('l1').publicAPIMock,
getOperationForColumnId(_: string) {
return {
id: 'a',
diff --git a/x-pack/legacy/plugins/lens/public/metric_visualization/metric_visualization.tsx b/x-pack/legacy/plugins/lens/public/metric_visualization/metric_visualization.tsx
index 6714c05787837..44256df5aed6d 100644
--- a/x-pack/legacy/plugins/lens/public/metric_visualization/metric_visualization.tsx
+++ b/x-pack/legacy/plugins/lens/public/metric_visualization/metric_visualization.tsx
@@ -4,23 +4,22 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import React from 'react';
-import { render } from 'react-dom';
-import { I18nProvider } from '@kbn/i18n/react';
import { i18n } from '@kbn/i18n';
import { Ast } from '@kbn/interpreter/target/common';
import { getSuggestions } from './metric_suggestions';
-import { MetricConfigPanel } from './metric_config_panel';
-import { Visualization, FramePublicAPI } from '../types';
+import { Visualization, FramePublicAPI, OperationMetadata } from '../types';
import { State, PersistableState } from './types';
-import { generateId } from '../id_generator';
import chartMetricSVG from '../assets/chart_metric.svg';
const toExpression = (
state: State,
frame: FramePublicAPI,
mode: 'reduced' | 'full' = 'full'
-): Ast => {
+): Ast | null => {
+ if (!state.accessor) {
+ return null;
+ }
+
const [datasource] = Object.values(frame.datasourceLayers);
const operation = datasource && datasource.getOperationForColumnId(state.accessor);
@@ -57,7 +56,7 @@ export const metricVisualization: Visualization = {
clearLayer(state) {
return {
...state,
- accessor: generateId(),
+ accessor: undefined,
};
},
@@ -80,22 +79,37 @@ export const metricVisualization: Visualization = {
return (
state || {
layerId: frame.addNewLayer(),
- accessor: generateId(),
+ accessor: undefined,
}
);
},
getPersistableState: state => state,
- renderLayerConfigPanel: (domElement, props) =>
- render(
-
-
- ,
- domElement
- ),
+ getConfiguration(props) {
+ return {
+ groups: [
+ {
+ groupId: 'metric',
+ groupLabel: i18n.translate('xpack.lens.metric.label', { defaultMessage: 'Metric' }),
+ layerId: props.state.layerId,
+ accessors: props.state.accessor ? [props.state.accessor] : [],
+ supportsMoreColumns: false,
+ filterOperations: (op: OperationMetadata) => !op.isBucketed && op.dataType === 'number',
+ },
+ ],
+ };
+ },
toExpression,
toPreviewExpression: (state: State, frame: FramePublicAPI) =>
toExpression(state, frame, 'reduced'),
+
+ setDimension({ prevState, columnId }) {
+ return { ...prevState, accessor: columnId };
+ },
+
+ removeDimension({ prevState }) {
+ return { ...prevState, accessor: undefined };
+ },
};
diff --git a/x-pack/legacy/plugins/lens/public/metric_visualization/types.ts b/x-pack/legacy/plugins/lens/public/metric_visualization/types.ts
index 6348d80b15e2f..53fc103934255 100644
--- a/x-pack/legacy/plugins/lens/public/metric_visualization/types.ts
+++ b/x-pack/legacy/plugins/lens/public/metric_visualization/types.ts
@@ -6,7 +6,7 @@
export interface State {
layerId: string;
- accessor: string;
+ accessor?: string;
}
export interface MetricConfig extends State {
diff --git a/x-pack/legacy/plugins/lens/public/multi_column_editor/multi_column_editor.test.tsx b/x-pack/legacy/plugins/lens/public/multi_column_editor/multi_column_editor.test.tsx
deleted file mode 100644
index 38f48c9cdaf72..0000000000000
--- a/x-pack/legacy/plugins/lens/public/multi_column_editor/multi_column_editor.test.tsx
+++ /dev/null
@@ -1,71 +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 { createMockDatasource } from '../editor_frame_service/mocks';
-import { MultiColumnEditor } from './multi_column_editor';
-import { mount } from 'enzyme';
-
-jest.useFakeTimers();
-
-describe('MultiColumnEditor', () => {
- it('should add a trailing accessor if the accessor list is empty', () => {
- const onAdd = jest.fn();
- mount(
- true}
- layerId="foo"
- onAdd={onAdd}
- onRemove={jest.fn()}
- testSubj="bar"
- />
- );
-
- expect(onAdd).toHaveBeenCalledTimes(0);
-
- jest.runAllTimers();
-
- expect(onAdd).toHaveBeenCalledTimes(1);
- });
-
- it('should add a trailing accessor if the last accessor is configured', () => {
- const onAdd = jest.fn();
- mount(
- true}
- layerId="foo"
- onAdd={onAdd}
- onRemove={jest.fn()}
- testSubj="bar"
- />
- );
-
- expect(onAdd).toHaveBeenCalledTimes(0);
-
- jest.runAllTimers();
-
- expect(onAdd).toHaveBeenCalledTimes(1);
- });
-});
diff --git a/x-pack/legacy/plugins/lens/public/multi_column_editor/multi_column_editor.tsx b/x-pack/legacy/plugins/lens/public/multi_column_editor/multi_column_editor.tsx
deleted file mode 100644
index 422f1dcf60f3c..0000000000000
--- a/x-pack/legacy/plugins/lens/public/multi_column_editor/multi_column_editor.tsx
+++ /dev/null
@@ -1,63 +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, { useEffect } from 'react';
-import { NativeRenderer } from '../native_renderer';
-import { DatasourcePublicAPI, OperationMetadata } from '../types';
-import { DragContextState } from '../drag_drop';
-
-interface Props {
- accessors: string[];
- datasource: DatasourcePublicAPI;
- dragDropContext: DragContextState;
- onRemove: (accessor: string) => void;
- onAdd: () => void;
- filterOperations: (op: OperationMetadata) => boolean;
- suggestedPriority?: 0 | 1 | 2 | undefined;
- testSubj: string;
- layerId: string;
-}
-
-export function MultiColumnEditor({
- accessors,
- datasource,
- dragDropContext,
- onRemove,
- onAdd,
- filterOperations,
- suggestedPriority,
- testSubj,
- layerId,
-}: Props) {
- const lastOperation = datasource.getOperationForColumnId(accessors[accessors.length - 1]);
-
- useEffect(() => {
- if (accessors.length === 0 || lastOperation !== null) {
- setTimeout(onAdd);
- }
- }, [lastOperation]);
-
- return (
- <>
- {accessors.map(accessor => (
-
-
-
- ))}
- >
- );
-}
diff --git a/x-pack/legacy/plugins/lens/public/plugin.tsx b/x-pack/legacy/plugins/lens/public/plugin.tsx
index cc029fee49d1d..c74653c70703c 100644
--- a/x-pack/legacy/plugins/lens/public/plugin.tsx
+++ b/x-pack/legacy/plugins/lens/public/plugin.tsx
@@ -114,7 +114,7 @@ export class LensPlugin {
const savedObjectsClient = coreStart.savedObjects.client;
addHelpMenuToAppChrome(coreStart.chrome);
- const instance = await this.createEditorFrame!({});
+ const instance = await this.createEditorFrame!();
setReportManager(
new LensReportManager({
diff --git a/x-pack/legacy/plugins/lens/public/types.ts b/x-pack/legacy/plugins/lens/public/types.ts
index b7983eeb8dbb8..c897979b06cfb 100644
--- a/x-pack/legacy/plugins/lens/public/types.ts
+++ b/x-pack/legacy/plugins/lens/public/types.ts
@@ -13,14 +13,10 @@ import { Document } from './persistence';
import { DateRange } from '../../../../plugins/lens/common';
import { Query, Filter, SavedQuery } from '../../../../../src/plugins/data/public';
-// eslint-disable-next-line
-export interface EditorFrameOptions {}
-
export type ErrorCallback = (e: { message: string }) => void;
export interface PublicAPIProps {
state: T;
- setState: StateSetter;
layerId: string;
dateRange: DateRange;
}
@@ -34,6 +30,7 @@ export interface EditorFrameProps {
savedQuery?: SavedQuery;
// Frame loader (app or embeddable) is expected to call this when it loads and updates
+ // This should be replaced with a top-down state
onChange: (newState: {
filterableIndexPatterns: DatasourceMetaData['filterableIndexPatterns'];
doc: Document;
@@ -53,7 +50,7 @@ export interface EditorFrameSetup {
}
export interface EditorFrameStart {
- createInstance: (options: EditorFrameOptions) => Promise;
+ createInstance: () => Promise;
}
// Hints the default nesting to the data source. 0 is the highest priority
@@ -138,8 +135,14 @@ export interface Datasource {
removeLayer: (state: T, layerId: string) => T;
clearLayer: (state: T, layerId: string) => T;
getLayers: (state: T) => string[];
+ removeColumn: (props: { prevState: T; layerId: string; columnId: string }) => T;
renderDataPanel: (domElement: Element, props: DatasourceDataPanelProps) => void;
+ renderDimensionTrigger: (domElement: Element, props: DatasourceDimensionTriggerProps) => void;
+ renderDimensionEditor: (domElement: Element, props: DatasourceDimensionEditorProps) => void;
+ renderLayerPanel: (domElement: Element, props: DatasourceLayerPanelProps) => void;
+ canHandleDrop: (props: DatasourceDimensionDropProps) => boolean;
+ onDrop: (props: DatasourceDimensionDropHandlerProps) => boolean;
toExpression: (state: T, layerId: string) => Ast | string | null;
@@ -155,22 +158,11 @@ export interface Datasource {
* This is an API provided to visualizations by the frame, which calls the publicAPI on the datasource
*/
export interface DatasourcePublicAPI {
- getTableSpec: () => TableSpec;
+ datasourceId: string;
+ getTableSpec: () => Array<{ columnId: string }>;
getOperationForColumnId: (columnId: string) => Operation | null;
-
- // Render can be called many times
- renderDimensionPanel: (domElement: Element, props: DatasourceDimensionPanelProps) => void;
- renderLayerPanel: (domElement: Element, props: DatasourceLayerPanelProps) => void;
}
-export interface TableSpecColumn {
- // Column IDs are the keys for internal state in data sources and visualizations
- columnId: string;
-}
-
-// TableSpec is managed by visualizations
-export type TableSpec = TableSpecColumn[];
-
export interface DatasourceDataPanelProps {
state: T;
dragDropContext: DragContextState;
@@ -181,31 +173,61 @@ export interface DatasourceDataPanelProps {
filters: Filter[];
}
-// The only way a visualization has to restrict the query building
-export interface DatasourceDimensionPanelProps {
- layerId: string;
- columnId: string;
-
- dragDropContext: DragContextState;
-
- // Visualizations can restrict operations based on their own rules
+interface SharedDimensionProps {
+ /** Visualizations can restrict operations based on their own rules.
+ * For example, limiting to only bucketed or only numeric operations.
+ */
filterOperations: (operation: OperationMetadata) => boolean;
- // Visualizations can hint at the role this dimension would play, which
- // affects the default ordering of the query
+ /** Visualizations can hint at the role this dimension would play, which
+ * affects the default ordering of the query
+ */
suggestedPriority?: DimensionPriority;
- onRemove?: (accessor: string) => void;
- // Some dimension editors will allow users to change the operation grouping
- // from the panel, and this lets the visualization hint that it doesn't want
- // users to have that level of control
+ /** Some dimension editors will allow users to change the operation grouping
+ * from the panel, and this lets the visualization hint that it doesn't want
+ * users to have that level of control
+ */
hideGrouping?: boolean;
}
-export interface DatasourceLayerPanelProps {
+export type DatasourceDimensionProps = SharedDimensionProps & {
layerId: string;
+ columnId: string;
+ onRemove?: (accessor: string) => void;
+ state: T;
+};
+
+// The only way a visualization has to restrict the query building
+export type DatasourceDimensionEditorProps = DatasourceDimensionProps & {
+ setState: StateSetter;
+ core: Pick;
+ dateRange: DateRange;
+};
+
+export type DatasourceDimensionTriggerProps = DatasourceDimensionProps & {
+ dragDropContext: DragContextState;
+ togglePopover: () => void;
+};
+
+export interface DatasourceLayerPanelProps {
+ layerId: string;
+ state: T;
+ setState: StateSetter;
}
+export type DatasourceDimensionDropProps = SharedDimensionProps & {
+ layerId: string;
+ columnId: string;
+ state: T;
+ setState: StateSetter;
+ dragDropContext: DragContextState;
+};
+
+export type DatasourceDimensionDropHandlerProps = DatasourceDimensionDropProps & {
+ droppedItem: unknown;
+};
+
export type DataType = 'document' | 'string' | 'number' | 'date' | 'boolean' | 'ip';
// An operation represents a column in a table, not any information
@@ -239,12 +261,32 @@ export interface LensMultiTable {
};
}
-export interface VisualizationLayerConfigProps {
+export interface VisualizationConfigProps {
layerId: string;
- dragDropContext: DragContextState;
frame: FramePublicAPI;
state: T;
+}
+
+export type VisualizationLayerWidgetProps = VisualizationConfigProps & {
setState: (newState: T) => void;
+};
+
+type VisualizationDimensionGroupConfig = SharedDimensionProps & {
+ groupLabel: string;
+
+ /** ID is passed back to visualization. For example, `x` */
+ groupId: string;
+ accessors: string[];
+ supportsMoreColumns: boolean;
+ /** If required, a warning will appear if accessors are empty */
+ required?: boolean;
+ dataTestSubj?: string;
+};
+
+interface VisualizationDimensionChangeProps {
+ layerId: string;
+ columnId: string;
+ prevState: T;
}
/**
@@ -329,16 +371,18 @@ export interface Visualization {
visualizationTypes: VisualizationType[];
getLayerIds: (state: T) => string[];
-
clearLayer: (state: T, layerId: string) => T;
-
removeLayer?: (state: T, layerId: string) => T;
-
appendLayer?: (state: T, layerId: string) => T;
+ // Layer context menu is used by visualizations for styling the entire layer
+ // For example, the XY visualization uses this to have multiple chart types
getLayerContextMenuIcon?: (opts: { state: T; layerId: string }) => IconType | undefined;
+ renderLayerContextMenu?: (domElement: Element, props: VisualizationLayerWidgetProps) => void;
- renderLayerContextMenu?: (domElement: Element, props: VisualizationLayerConfigProps) => void;
+ getConfiguration: (
+ props: VisualizationConfigProps
+ ) => { groups: VisualizationDimensionGroupConfig[] };
getDescription: (
state: T
@@ -354,7 +398,13 @@ export interface Visualization {
getPersistableState: (state: T) => P;
- renderLayerConfigPanel: (domElement: Element, props: VisualizationLayerConfigProps) => void;
+ // Actions triggered by the frame which tell the datasource that a dimension is being changed
+ setDimension: (
+ props: VisualizationDimensionChangeProps & {
+ groupId: string;
+ }
+ ) => T;
+ removeDimension: (props: VisualizationDimensionChangeProps) => T;
toExpression: (state: T, frame: FramePublicAPI) => Ast | string | null;
diff --git a/x-pack/legacy/plugins/lens/public/xy_visualization/__snapshots__/xy_visualization.test.ts.snap b/x-pack/legacy/plugins/lens/public/xy_visualization/__snapshots__/to_expression.test.ts.snap
similarity index 96%
rename from x-pack/legacy/plugins/lens/public/xy_visualization/__snapshots__/xy_visualization.test.ts.snap
rename to x-pack/legacy/plugins/lens/public/xy_visualization/__snapshots__/to_expression.test.ts.snap
index 76af8328673ad..6b68679bfd4ec 100644
--- a/x-pack/legacy/plugins/lens/public/xy_visualization/__snapshots__/xy_visualization.test.ts.snap
+++ b/x-pack/legacy/plugins/lens/public/xy_visualization/__snapshots__/to_expression.test.ts.snap
@@ -1,6 +1,6 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`xy_visualization #toExpression should map to a valid AST 1`] = `
+exports[`#toExpression should map to a valid AST 1`] = `
Object {
"chain": Array [
Object {
diff --git a/x-pack/legacy/plugins/lens/public/xy_visualization/to_expression.test.ts b/x-pack/legacy/plugins/lens/public/xy_visualization/to_expression.test.ts
new file mode 100644
index 0000000000000..6bc379ea33bca
--- /dev/null
+++ b/x-pack/legacy/plugins/lens/public/xy_visualization/to_expression.test.ts
@@ -0,0 +1,133 @@
+/*
+ * 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 { Ast } from '@kbn/interpreter/target/common';
+import { Position } from '@elastic/charts';
+import { xyVisualization } from './xy_visualization';
+import { Operation } from '../types';
+import { createMockDatasource, createMockFramePublicAPI } from '../editor_frame_service/mocks';
+
+describe('#toExpression', () => {
+ let mockDatasource: ReturnType;
+ let frame: ReturnType;
+
+ beforeEach(() => {
+ frame = createMockFramePublicAPI();
+ mockDatasource = createMockDatasource('testDatasource');
+
+ mockDatasource.publicAPIMock.getTableSpec.mockReturnValue([
+ { columnId: 'd' },
+ { columnId: 'a' },
+ { columnId: 'b' },
+ { columnId: 'c' },
+ ]);
+
+ mockDatasource.publicAPIMock.getOperationForColumnId.mockImplementation(col => {
+ return { label: `col_${col}`, dataType: 'number' } as Operation;
+ });
+
+ frame.datasourceLayers = {
+ first: mockDatasource.publicAPIMock,
+ };
+ });
+
+ it('should map to a valid AST', () => {
+ expect(
+ xyVisualization.toExpression(
+ {
+ legend: { position: Position.Bottom, isVisible: true },
+ preferredSeriesType: 'bar',
+ layers: [
+ {
+ layerId: 'first',
+ seriesType: 'area',
+ splitAccessor: 'd',
+ xAccessor: 'a',
+ accessors: ['b', 'c'],
+ },
+ ],
+ },
+ frame
+ )
+ ).toMatchSnapshot();
+ });
+
+ it('should not generate an expression when missing x', () => {
+ expect(
+ xyVisualization.toExpression(
+ {
+ legend: { position: Position.Bottom, isVisible: true },
+ preferredSeriesType: 'bar',
+ layers: [
+ {
+ layerId: 'first',
+ seriesType: 'area',
+ splitAccessor: undefined,
+ xAccessor: undefined,
+ accessors: ['a'],
+ },
+ ],
+ },
+ frame
+ )
+ ).toBeNull();
+ });
+
+ it('should not generate an expression when missing y', () => {
+ expect(
+ xyVisualization.toExpression(
+ {
+ legend: { position: Position.Bottom, isVisible: true },
+ preferredSeriesType: 'bar',
+ layers: [
+ {
+ layerId: 'first',
+ seriesType: 'area',
+ splitAccessor: undefined,
+ xAccessor: 'a',
+ accessors: [],
+ },
+ ],
+ },
+ frame
+ )
+ ).toBeNull();
+ });
+
+ it('should default to labeling all columns with their column label', () => {
+ const expression = xyVisualization.toExpression(
+ {
+ legend: { position: Position.Bottom, isVisible: true },
+ preferredSeriesType: 'bar',
+ layers: [
+ {
+ layerId: 'first',
+ seriesType: 'area',
+ splitAccessor: 'd',
+ xAccessor: 'a',
+ accessors: ['b', 'c'],
+ },
+ ],
+ },
+ frame
+ )! as Ast;
+
+ expect(mockDatasource.publicAPIMock.getOperationForColumnId).toHaveBeenCalledWith('b');
+ expect(mockDatasource.publicAPIMock.getOperationForColumnId).toHaveBeenCalledWith('c');
+ expect(mockDatasource.publicAPIMock.getOperationForColumnId).toHaveBeenCalledWith('d');
+ expect(expression.chain[0].arguments.xTitle).toEqual(['col_a']);
+ expect(expression.chain[0].arguments.yTitle).toEqual(['col_b']);
+ expect(
+ (expression.chain[0].arguments.layers[0] as Ast).chain[0].arguments.columnToLabel
+ ).toEqual([
+ JSON.stringify({
+ b: 'col_b',
+ c: 'col_c',
+ d: 'col_d',
+ }),
+ ]);
+ });
+});
diff --git a/x-pack/legacy/plugins/lens/public/xy_visualization/to_expression.ts b/x-pack/legacy/plugins/lens/public/xy_visualization/to_expression.ts
index f0e932d14f281..9b068b0ca5ef0 100644
--- a/x-pack/legacy/plugins/lens/public/xy_visualization/to_expression.ts
+++ b/x-pack/legacy/plugins/lens/public/xy_visualization/to_expression.ts
@@ -9,6 +9,10 @@ import { ScaleType } from '@elastic/charts';
import { State, LayerConfig } from './types';
import { FramePublicAPI, OperationMetadata } from '../types';
+interface ValidLayer extends LayerConfig {
+ xAccessor: NonNullable;
+}
+
function xyTitles(layer: LayerConfig, frame: FramePublicAPI) {
const defaults = {
xTitle: 'x',
@@ -22,8 +26,8 @@ function xyTitles(layer: LayerConfig, frame: FramePublicAPI) {
if (!datasource) {
return defaults;
}
- const x = datasource.getOperationForColumnId(layer.xAccessor);
- const y = datasource.getOperationForColumnId(layer.accessors[0]);
+ const x = layer.xAccessor ? datasource.getOperationForColumnId(layer.xAccessor) : null;
+ const y = layer.accessors[0] ? datasource.getOperationForColumnId(layer.accessors[0]) : null;
return {
xTitle: x ? x.label : defaults.xTitle,
@@ -36,26 +40,6 @@ export const toExpression = (state: State, frame: FramePublicAPI): Ast | null =>
return null;
}
- const stateWithValidAccessors = {
- ...state,
- layers: state.layers.map(layer => {
- const datasource = frame.datasourceLayers[layer.layerId];
-
- const newLayer = { ...layer };
-
- if (!datasource.getOperationForColumnId(layer.splitAccessor)) {
- delete newLayer.splitAccessor;
- }
-
- return {
- ...newLayer,
- accessors: layer.accessors.filter(accessor =>
- Boolean(datasource.getOperationForColumnId(accessor))
- ),
- };
- }),
- };
-
const metadata: Record> = {};
state.layers.forEach(layer => {
metadata[layer.layerId] = {};
@@ -68,12 +52,7 @@ export const toExpression = (state: State, frame: FramePublicAPI): Ast | null =>
});
});
- return buildExpression(
- stateWithValidAccessors,
- metadata,
- frame,
- xyTitles(state.layers[0], frame)
- );
+ return buildExpression(state, metadata, frame, xyTitles(state.layers[0], frame));
};
export function toPreviewExpression(state: State, frame: FramePublicAPI) {
@@ -122,82 +101,94 @@ export const buildExpression = (
metadata: Record>,
frame?: FramePublicAPI,
{ xTitle, yTitle }: { xTitle: string; yTitle: string } = { xTitle: '', yTitle: '' }
-): Ast => ({
- type: 'expression',
- chain: [
- {
- type: 'function',
- function: 'lens_xy_chart',
- arguments: {
- xTitle: [xTitle],
- yTitle: [yTitle],
- legend: [
- {
- type: 'expression',
- chain: [
- {
- type: 'function',
- function: 'lens_xy_legendConfig',
- arguments: {
- isVisible: [state.legend.isVisible],
- position: [state.legend.position],
+): Ast | null => {
+ const validLayers = state.layers.filter((layer): layer is ValidLayer =>
+ Boolean(layer.xAccessor && layer.accessors.length)
+ );
+ if (!validLayers.length) {
+ return null;
+ }
+
+ return {
+ type: 'expression',
+ chain: [
+ {
+ type: 'function',
+ function: 'lens_xy_chart',
+ arguments: {
+ xTitle: [xTitle],
+ yTitle: [yTitle],
+ legend: [
+ {
+ type: 'expression',
+ chain: [
+ {
+ type: 'function',
+ function: 'lens_xy_legendConfig',
+ arguments: {
+ isVisible: [state.legend.isVisible],
+ position: [state.legend.position],
+ },
},
- },
- ],
- },
- ],
- layers: state.layers.map(layer => {
- const columnToLabel: Record = {};
-
- if (frame) {
- const datasource = frame.datasourceLayers[layer.layerId];
- layer.accessors.concat([layer.splitAccessor]).forEach(accessor => {
- const operation = datasource.getOperationForColumnId(accessor);
- if (operation && operation.label) {
- columnToLabel[accessor] = operation.label;
- }
- });
- }
-
- const xAxisOperation =
- frame && frame.datasourceLayers[layer.layerId].getOperationForColumnId(layer.xAccessor);
-
- const isHistogramDimension = Boolean(
- xAxisOperation &&
- xAxisOperation.isBucketed &&
- xAxisOperation.scale &&
- xAxisOperation.scale !== 'ordinal'
- );
-
- return {
- type: 'expression',
- chain: [
- {
- type: 'function',
- function: 'lens_xy_layer',
- arguments: {
- layerId: [layer.layerId],
-
- hide: [Boolean(layer.hide)],
-
- xAccessor: [layer.xAccessor],
- yScaleType: [
- getScaleType(metadata[layer.layerId][layer.accessors[0]], ScaleType.Ordinal),
- ],
- xScaleType: [
- getScaleType(metadata[layer.layerId][layer.xAccessor], ScaleType.Linear),
- ],
- isHistogram: [isHistogramDimension],
- splitAccessor: [layer.splitAccessor],
- seriesType: [layer.seriesType],
- accessors: layer.accessors,
- columnToLabel: [JSON.stringify(columnToLabel)],
+ ],
+ },
+ ],
+ layers: validLayers.map(layer => {
+ const columnToLabel: Record = {};
+
+ if (frame) {
+ const datasource = frame.datasourceLayers[layer.layerId];
+ layer.accessors
+ .concat(layer.splitAccessor ? [layer.splitAccessor] : [])
+ .forEach(accessor => {
+ const operation = datasource.getOperationForColumnId(accessor);
+ if (operation && operation.label) {
+ columnToLabel[accessor] = operation.label;
+ }
+ });
+ }
+
+ const xAxisOperation =
+ frame &&
+ frame.datasourceLayers[layer.layerId].getOperationForColumnId(layer.xAccessor);
+
+ const isHistogramDimension = Boolean(
+ xAxisOperation &&
+ xAxisOperation.isBucketed &&
+ xAxisOperation.scale &&
+ xAxisOperation.scale !== 'ordinal'
+ );
+
+ return {
+ type: 'expression',
+ chain: [
+ {
+ type: 'function',
+ function: 'lens_xy_layer',
+ arguments: {
+ layerId: [layer.layerId],
+
+ hide: [Boolean(layer.hide)],
+
+ xAccessor: [layer.xAccessor],
+ yScaleType: [
+ getScaleType(metadata[layer.layerId][layer.accessors[0]], ScaleType.Ordinal),
+ ],
+ xScaleType: [
+ getScaleType(metadata[layer.layerId][layer.xAccessor], ScaleType.Linear),
+ ],
+ isHistogram: [isHistogramDimension],
+ splitAccessor: layer.splitAccessor ? [layer.splitAccessor] : [],
+ seriesType: [layer.seriesType],
+ accessors: layer.accessors,
+ columnToLabel: [JSON.stringify(columnToLabel)],
+ },
},
- },
- ],
- };
- }),
+ ],
+ };
+ }),
+ },
},
- },
- ],
-});
+ ],
+ };
+};
diff --git a/x-pack/legacy/plugins/lens/public/xy_visualization/types.ts b/x-pack/legacy/plugins/lens/public/xy_visualization/types.ts
index b49e6fa6b4b6f..f7b4afc76ec4b 100644
--- a/x-pack/legacy/plugins/lens/public/xy_visualization/types.ts
+++ b/x-pack/legacy/plugins/lens/public/xy_visualization/types.ts
@@ -191,10 +191,10 @@ export type SeriesType =
export interface LayerConfig {
hide?: boolean;
layerId: string;
- xAccessor: string;
+ xAccessor?: string;
accessors: string[];
seriesType: SeriesType;
- splitAccessor: string;
+ splitAccessor?: string;
}
export type LayerArgs = LayerConfig & {
diff --git a/x-pack/legacy/plugins/lens/public/xy_visualization/xy_config_panel.test.tsx b/x-pack/legacy/plugins/lens/public/xy_visualization/xy_config_panel.test.tsx
index 301c4a58a0ffd..7544ed0f87b7d 100644
--- a/x-pack/legacy/plugins/lens/public/xy_visualization/xy_config_panel.test.tsx
+++ b/x-pack/legacy/plugins/lens/public/xy_visualization/xy_config_panel.test.tsx
@@ -5,22 +5,15 @@
*/
import React from 'react';
-import { ReactWrapper } from 'enzyme';
import { mountWithIntl as mount } from 'test_utils/enzyme_helpers';
import { EuiButtonGroupProps } from '@elastic/eui';
-import { XYConfigPanel, LayerContextMenu } from './xy_config_panel';
-import { DatasourceDimensionPanelProps, Operation, FramePublicAPI } from '../types';
+import { LayerContextMenu } from './xy_config_panel';
+import { FramePublicAPI } from '../types';
import { State } from './types';
import { Position } from '@elastic/charts';
-import { NativeRendererProps } from '../native_renderer';
-import { generateId } from '../id_generator';
import { createMockFramePublicAPI, createMockDatasource } from '../editor_frame_service/mocks';
-jest.mock('../id_generator');
-
-describe('XYConfigPanel', () => {
- const dragDropContext = { dragging: undefined, setDragging: jest.fn() };
-
+describe('LayerContextMenu', () => {
let frame: FramePublicAPI;
function testState(): State {
@@ -39,17 +32,10 @@ describe('XYConfigPanel', () => {
};
}
- function testSubj(component: ReactWrapper, subj: string) {
- return component
- .find(`[data-test-subj="${subj}"]`)
- .first()
- .props();
- }
-
beforeEach(() => {
frame = createMockFramePublicAPI();
frame.datasourceLayers = {
- first: createMockDatasource().publicAPIMock,
+ first: createMockDatasource('test').publicAPIMock,
};
});
@@ -64,7 +50,6 @@ describe('XYConfigPanel', () => {
const component = mount(
{
const component = mount(
{
expect(options!.filter(({ isDisabled }) => isDisabled).map(({ id }) => id)).toEqual([]);
});
});
-
- test('the x dimension panel accepts only bucketed operations', () => {
- // TODO: this should eventually also accept raw operation
- const state = testState();
- const component = mount(
-
- );
-
- const panel = testSubj(component, 'lnsXY_xDimensionPanel');
- const nativeProps = (panel as NativeRendererProps).nativeProps;
- const { columnId, filterOperations } = nativeProps;
- const exampleOperation: Operation = {
- dataType: 'number',
- isBucketed: false,
- label: 'bar',
- };
- const bucketedOps: Operation[] = [
- { ...exampleOperation, isBucketed: true, dataType: 'number' },
- { ...exampleOperation, isBucketed: true, dataType: 'string' },
- { ...exampleOperation, isBucketed: true, dataType: 'boolean' },
- { ...exampleOperation, isBucketed: true, dataType: 'date' },
- ];
- const ops: Operation[] = [
- ...bucketedOps,
- { ...exampleOperation, dataType: 'number' },
- { ...exampleOperation, dataType: 'string' },
- { ...exampleOperation, dataType: 'boolean' },
- { ...exampleOperation, dataType: 'date' },
- ];
- expect(columnId).toEqual('shazm');
- expect(ops.filter(filterOperations)).toEqual(bucketedOps);
- });
-
- test('the y dimension panel accepts numeric operations', () => {
- const state = testState();
- const component = mount(
-
- );
-
- const filterOperations = component
- .find('[data-test-subj="lensXY_yDimensionPanel"]')
- .first()
- .prop('filterOperations') as (op: Operation) => boolean;
-
- const exampleOperation: Operation = {
- dataType: 'number',
- isBucketed: false,
- label: 'bar',
- };
- const ops: Operation[] = [
- { ...exampleOperation, dataType: 'number' },
- { ...exampleOperation, dataType: 'string' },
- { ...exampleOperation, dataType: 'boolean' },
- { ...exampleOperation, dataType: 'date' },
- ];
- expect(ops.filter(filterOperations).map(x => x.dataType)).toEqual(['number']);
- });
-
- test('allows removal of y dimensions', () => {
- const setState = jest.fn();
- const state = testState();
- const component = mount(
-
- );
-
- const onRemove = component
- .find('[data-test-subj="lensXY_yDimensionPanel"]')
- .first()
- .prop('onRemove') as (accessor: string) => {};
-
- onRemove('b');
-
- expect(setState).toHaveBeenCalledTimes(1);
- expect(setState.mock.calls[0][0]).toMatchObject({
- layers: [
- {
- ...state.layers[0],
- accessors: ['a', 'c'],
- },
- ],
- });
- });
-
- test('allows adding a y axis dimension', () => {
- (generateId as jest.Mock).mockReturnValueOnce('zed');
- const setState = jest.fn();
- const state = testState();
- const component = mount(
-
- );
-
- const onAdd = component
- .find('[data-test-subj="lensXY_yDimensionPanel"]')
- .first()
- .prop('onAdd') as () => {};
-
- onAdd();
-
- expect(setState).toHaveBeenCalledTimes(1);
- expect(setState.mock.calls[0][0]).toMatchObject({
- layers: [
- {
- ...state.layers[0],
- accessors: ['a', 'b', 'c', 'zed'],
- },
- ],
- });
- });
});
diff --git a/x-pack/legacy/plugins/lens/public/xy_visualization/xy_config_panel.tsx b/x-pack/legacy/plugins/lens/public/xy_visualization/xy_config_panel.tsx
index dbcfa24395001..5e85680cc2b2c 100644
--- a/x-pack/legacy/plugins/lens/public/xy_visualization/xy_config_panel.tsx
+++ b/x-pack/legacy/plugins/lens/public/xy_visualization/xy_config_panel.tsx
@@ -9,16 +9,10 @@ import React from 'react';
import { i18n } from '@kbn/i18n';
import { EuiButtonGroup, EuiFormRow } from '@elastic/eui';
import { State, SeriesType, visualizationTypes } from './types';
-import { VisualizationLayerConfigProps, OperationMetadata } from '../types';
-import { NativeRenderer } from '../native_renderer';
-import { MultiColumnEditor } from '../multi_column_editor';
-import { generateId } from '../id_generator';
+import { VisualizationLayerWidgetProps } from '../types';
import { isHorizontalChart, isHorizontalSeries } from './state_helpers';
import { trackUiEvent } from '../lens_ui_telemetry';
-const isNumericMetric = (op: OperationMetadata) => !op.isBucketed && op.dataType === 'number';
-const isBucketed = (op: OperationMetadata) => op.isBucketed;
-
type UnwrapArray = T extends Array ? P : T;
function updateLayer(state: State, layer: UnwrapArray, index: number): State {
@@ -31,7 +25,7 @@ function updateLayer(state: State, layer: UnwrapArray, index: n
};
}
-export function LayerContextMenu(props: VisualizationLayerConfigProps) {
+export function LayerContextMenu(props: VisualizationLayerWidgetProps) {
const { state, layerId } = props;
const horizontalOnly = isHorizontalChart(state.layers);
const index = state.layers.findIndex(l => l.layerId === layerId);
@@ -74,97 +68,3 @@ export function LayerContextMenu(props: VisualizationLayerConfigProps) {
);
}
-
-export function XYConfigPanel(props: VisualizationLayerConfigProps) {
- const { state, setState, frame, layerId } = props;
- const index = props.state.layers.findIndex(l => l.layerId === layerId);
-
- if (index < 0) {
- return null;
- }
-
- const layer = props.state.layers[index];
-
- return (
- <>
-
-
-
-
-
- setState(
- updateLayer(
- state,
- {
- ...layer,
- accessors: [...layer.accessors, generateId()],
- },
- index
- )
- )
- }
- onRemove={accessor =>
- setState(
- updateLayer(
- state,
- {
- ...layer,
- accessors: layer.accessors.filter(col => col !== accessor),
- },
- index
- )
- )
- }
- filterOperations={isNumericMetric}
- data-test-subj="lensXY_yDimensionPanel"
- testSubj="lensXY_yDimensionPanel"
- layerId={layer.layerId}
- />
-
-
-
-
- >
- );
-}
diff --git a/x-pack/legacy/plugins/lens/public/xy_visualization/xy_expression.tsx b/x-pack/legacy/plugins/lens/public/xy_visualization/xy_expression.tsx
index 27fd6e7064042..15aaf289eebf9 100644
--- a/x-pack/legacy/plugins/lens/public/xy_visualization/xy_expression.tsx
+++ b/x-pack/legacy/plugins/lens/public/xy_visualization/xy_expression.tsx
@@ -238,6 +238,8 @@ export function XYChart({ data, args, formatFactory, timeZone, chartTheme }: XYC
index
) => {
if (
+ !xAccessor ||
+ !accessors.length ||
!data.tables[layerId] ||
data.tables[layerId].rows.length === 0 ||
data.tables[layerId].rows.every(row => typeof row[xAccessor] === 'undefined')
@@ -246,7 +248,7 @@ export function XYChart({ data, args, formatFactory, timeZone, chartTheme }: XYC
}
const columnToLabelMap = columnToLabel ? JSON.parse(columnToLabel) : {};
- const splitAccessorLabel = columnToLabelMap[splitAccessor];
+ const splitAccessorLabel = splitAccessor ? columnToLabelMap[splitAccessor] : '';
const yAccessors = accessors.map(accessor => columnToLabelMap[accessor] || accessor);
const idForLegend = splitAccessorLabel || yAccessors;
const sanitized = sanitizeRows({
diff --git a/x-pack/legacy/plugins/lens/public/xy_visualization/xy_suggestions.test.ts b/x-pack/legacy/plugins/lens/public/xy_visualization/xy_suggestions.test.ts
index 04ff720309d62..ddbd9d11b5fad 100644
--- a/x-pack/legacy/plugins/lens/public/xy_visualization/xy_suggestions.test.ts
+++ b/x-pack/legacy/plugins/lens/public/xy_visualization/xy_suggestions.test.ts
@@ -123,7 +123,7 @@ describe('xy_suggestions', () => {
Array [
Object {
"seriesType": "bar_stacked",
- "splitAccessor": "aaa",
+ "splitAccessor": undefined,
"x": "date",
"y": Array [
"bytes",
@@ -240,7 +240,6 @@ describe('xy_suggestions', () => {
});
test('only makes a seriesType suggestion for unchanged table without split', () => {
- (generateId as jest.Mock).mockReturnValueOnce('dummyCol');
const currentState: XYState = {
legend: { isVisible: true, position: 'bottom' },
preferredSeriesType: 'bar',
@@ -249,7 +248,7 @@ describe('xy_suggestions', () => {
accessors: ['price'],
layerId: 'first',
seriesType: 'bar',
- splitAccessor: 'dummyCol',
+ splitAccessor: undefined,
xAccessor: 'date',
},
],
@@ -472,17 +471,17 @@ describe('xy_suggestions', () => {
});
expect(suggestionSubset(suggestion)).toMatchInlineSnapshot(`
- Array [
- Object {
- "seriesType": "bar_stacked",
- "splitAccessor": "ddd",
- "x": "quantity",
- "y": Array [
- "price",
- ],
- },
- ]
- `);
+ Array [
+ Object {
+ "seriesType": "bar_stacked",
+ "splitAccessor": undefined,
+ "x": "quantity",
+ "y": Array [
+ "price",
+ ],
+ },
+ ]
+ `);
});
test('handles ip', () => {
@@ -509,17 +508,17 @@ describe('xy_suggestions', () => {
});
expect(suggestionSubset(suggestion)).toMatchInlineSnapshot(`
- Array [
- Object {
- "seriesType": "bar_stacked",
- "splitAccessor": "ddd",
- "x": "myip",
- "y": Array [
- "quantity",
- ],
- },
- ]
- `);
+ Array [
+ Object {
+ "seriesType": "bar_stacked",
+ "splitAccessor": undefined,
+ "x": "myip",
+ "y": Array [
+ "quantity",
+ ],
+ },
+ ]
+ `);
});
test('handles unbucketed suggestions', () => {
@@ -545,16 +544,16 @@ describe('xy_suggestions', () => {
});
expect(suggestionSubset(suggestion)).toMatchInlineSnapshot(`
- Array [
- Object {
- "seriesType": "bar_stacked",
- "splitAccessor": "eee",
- "x": "mybool",
- "y": Array [
- "num votes",
- ],
- },
- ]
- `);
+ Array [
+ Object {
+ "seriesType": "bar_stacked",
+ "splitAccessor": undefined,
+ "x": "mybool",
+ "y": Array [
+ "num votes",
+ ],
+ },
+ ]
+ `);
});
});
diff --git a/x-pack/legacy/plugins/lens/public/xy_visualization/xy_suggestions.ts b/x-pack/legacy/plugins/lens/public/xy_visualization/xy_suggestions.ts
index 33181b7f3a467..5e9311bb1e928 100644
--- a/x-pack/legacy/plugins/lens/public/xy_visualization/xy_suggestions.ts
+++ b/x-pack/legacy/plugins/lens/public/xy_visualization/xy_suggestions.ts
@@ -15,7 +15,6 @@ import {
TableChangeType,
} from '../types';
import { State, SeriesType, XYState } from './types';
-import { generateId } from '../id_generator';
import { getIconForSeries } from './state_helpers';
const columnSortOrder = {
@@ -356,7 +355,7 @@ function buildSuggestion({
layerId,
seriesType,
xAccessor: xValue.columnId,
- splitAccessor: splitBy ? splitBy.columnId : generateId(),
+ splitAccessor: splitBy?.columnId,
accessors: yValues.map(col => col.columnId),
};
diff --git a/x-pack/legacy/plugins/lens/public/xy_visualization/xy_visualization.test.ts b/x-pack/legacy/plugins/lens/public/xy_visualization/xy_visualization.test.ts
index a27a8e7754b86..beccf0dc46eb4 100644
--- a/x-pack/legacy/plugins/lens/public/xy_visualization/xy_visualization.test.ts
+++ b/x-pack/legacy/plugins/lens/public/xy_visualization/xy_visualization.test.ts
@@ -9,10 +9,6 @@ import { Position } from '@elastic/charts';
import { Operation } from '../types';
import { State, SeriesType } from './types';
import { createMockDatasource, createMockFramePublicAPI } from '../editor_frame_service/mocks';
-import { generateId } from '../id_generator';
-import { Ast } from '@kbn/interpreter/target/common';
-
-jest.mock('../id_generator');
function exampleState(): State {
return {
@@ -87,31 +83,22 @@ describe('xy_visualization', () => {
describe('#initialize', () => {
it('loads default state', () => {
- (generateId as jest.Mock)
- .mockReturnValueOnce('test-id1')
- .mockReturnValueOnce('test-id2')
- .mockReturnValue('test-id3');
const mockFrame = createMockFramePublicAPI();
const initialState = xyVisualization.initialize(mockFrame);
expect(initialState.layers).toHaveLength(1);
- expect(initialState.layers[0].xAccessor).toBeDefined();
- expect(initialState.layers[0].accessors[0]).toBeDefined();
- expect(initialState.layers[0].xAccessor).not.toEqual(initialState.layers[0].accessors[0]);
+ expect(initialState.layers[0].xAccessor).not.toBeDefined();
+ expect(initialState.layers[0].accessors).toHaveLength(0);
expect(initialState).toMatchInlineSnapshot(`
Object {
"layers": Array [
Object {
- "accessors": Array [
- "test-id1",
- ],
+ "accessors": Array [],
"layerId": "",
"position": "top",
"seriesType": "bar_stacked",
"showGridlines": false,
- "splitAccessor": "test-id2",
- "xAccessor": "test-id3",
},
],
"legend": Object {
@@ -167,14 +154,11 @@ describe('xy_visualization', () => {
describe('#clearLayer', () => {
it('clears the specified layer', () => {
- (generateId as jest.Mock).mockReturnValue('test_empty_id');
const layer = xyVisualization.clearLayer(exampleState(), 'first').layers[0];
expect(layer).toMatchObject({
- accessors: ['test_empty_id'],
+ accessors: [],
layerId: 'first',
seriesType: 'bar',
- splitAccessor: 'test_empty_id',
- xAccessor: 'test_empty_id',
});
});
});
@@ -185,13 +169,94 @@ describe('xy_visualization', () => {
});
});
- describe('#toExpression', () => {
+ describe('#setDimension', () => {
+ it('sets the x axis', () => {
+ expect(
+ xyVisualization.setDimension({
+ prevState: {
+ ...exampleState(),
+ layers: [
+ {
+ layerId: 'first',
+ seriesType: 'area',
+ xAccessor: undefined,
+ accessors: [],
+ },
+ ],
+ },
+ layerId: 'first',
+ groupId: 'x',
+ columnId: 'newCol',
+ }).layers[0]
+ ).toEqual({
+ layerId: 'first',
+ seriesType: 'area',
+ xAccessor: 'newCol',
+ accessors: [],
+ });
+ });
+
+ it('replaces the x axis', () => {
+ expect(
+ xyVisualization.setDimension({
+ prevState: {
+ ...exampleState(),
+ layers: [
+ {
+ layerId: 'first',
+ seriesType: 'area',
+ xAccessor: 'a',
+ accessors: [],
+ },
+ ],
+ },
+ layerId: 'first',
+ groupId: 'x',
+ columnId: 'newCol',
+ }).layers[0]
+ ).toEqual({
+ layerId: 'first',
+ seriesType: 'area',
+ xAccessor: 'newCol',
+ accessors: [],
+ });
+ });
+ });
+
+ describe('#removeDimension', () => {
+ it('removes the x axis', () => {
+ expect(
+ xyVisualization.removeDimension({
+ prevState: {
+ ...exampleState(),
+ layers: [
+ {
+ layerId: 'first',
+ seriesType: 'area',
+ xAccessor: 'a',
+ accessors: [],
+ },
+ ],
+ },
+ layerId: 'first',
+ columnId: 'a',
+ }).layers[0]
+ ).toEqual({
+ layerId: 'first',
+ seriesType: 'area',
+ xAccessor: undefined,
+ accessors: [],
+ });
+ });
+ });
+
+ describe('#getConfiguration', () => {
let mockDatasource: ReturnType;
let frame: ReturnType;
beforeEach(() => {
frame = createMockFramePublicAPI();
- mockDatasource = createMockDatasource();
+ mockDatasource = createMockDatasource('testDatasource');
mockDatasource.publicAPIMock.getTableSpec.mockReturnValue([
{ columnId: 'd' },
@@ -200,36 +265,78 @@ describe('xy_visualization', () => {
{ columnId: 'c' },
]);
- mockDatasource.publicAPIMock.getOperationForColumnId.mockImplementation(col => {
- return { label: `col_${col}`, dataType: 'number' } as Operation;
- });
-
frame.datasourceLayers = {
first: mockDatasource.publicAPIMock,
};
});
- it('should map to a valid AST', () => {
- expect(xyVisualization.toExpression(exampleState(), frame)).toMatchSnapshot();
+ it('should return options for 3 dimensions', () => {
+ const options = xyVisualization.getConfiguration({
+ state: exampleState(),
+ frame,
+ layerId: 'first',
+ }).groups;
+ expect(options).toHaveLength(3);
+ expect(options.map(o => o.groupId)).toEqual(['x', 'y', 'breakdown']);
});
- it('should default to labeling all columns with their column label', () => {
- const expression = xyVisualization.toExpression(exampleState(), frame)! as Ast;
+ it('should only accept bucketed operations for x', () => {
+ const options = xyVisualization.getConfiguration({
+ state: exampleState(),
+ frame,
+ layerId: 'first',
+ }).groups;
+ const filterOperations = options.find(o => o.groupId === 'x')!.filterOperations;
- expect(mockDatasource.publicAPIMock.getOperationForColumnId).toHaveBeenCalledWith('b');
- expect(mockDatasource.publicAPIMock.getOperationForColumnId).toHaveBeenCalledWith('c');
- expect(mockDatasource.publicAPIMock.getOperationForColumnId).toHaveBeenCalledWith('d');
- expect(expression.chain[0].arguments.xTitle).toEqual(['col_a']);
- expect(expression.chain[0].arguments.yTitle).toEqual(['col_b']);
- expect(
- (expression.chain[0].arguments.layers[0] as Ast).chain[0].arguments.columnToLabel
- ).toEqual([
- JSON.stringify({
- b: 'col_b',
- c: 'col_c',
- d: 'col_d',
- }),
- ]);
+ const exampleOperation: Operation = {
+ dataType: 'number',
+ isBucketed: false,
+ label: 'bar',
+ };
+ const bucketedOps: Operation[] = [
+ { ...exampleOperation, isBucketed: true, dataType: 'number' },
+ { ...exampleOperation, isBucketed: true, dataType: 'string' },
+ { ...exampleOperation, isBucketed: true, dataType: 'boolean' },
+ { ...exampleOperation, isBucketed: true, dataType: 'date' },
+ ];
+ const ops: Operation[] = [
+ ...bucketedOps,
+ { ...exampleOperation, dataType: 'number' },
+ { ...exampleOperation, dataType: 'string' },
+ { ...exampleOperation, dataType: 'boolean' },
+ { ...exampleOperation, dataType: 'date' },
+ ];
+ expect(ops.filter(filterOperations)).toEqual(bucketedOps);
+ });
+
+ it('should not allow anything to be added to x', () => {
+ const options = xyVisualization.getConfiguration({
+ state: exampleState(),
+ frame,
+ layerId: 'first',
+ }).groups;
+ expect(options.find(o => o.groupId === 'x')?.supportsMoreColumns).toBe(false);
+ });
+
+ it('should allow number operations on y', () => {
+ const options = xyVisualization.getConfiguration({
+ state: exampleState(),
+ frame,
+ layerId: 'first',
+ }).groups;
+ const filterOperations = options.find(o => o.groupId === 'y')!.filterOperations;
+ const exampleOperation: Operation = {
+ dataType: 'number',
+ isBucketed: false,
+ label: 'bar',
+ };
+ const ops: Operation[] = [
+ { ...exampleOperation, dataType: 'number' },
+ { ...exampleOperation, dataType: 'string' },
+ { ...exampleOperation, dataType: 'boolean' },
+ { ...exampleOperation, dataType: 'date' },
+ ];
+ expect(ops.filter(filterOperations).map(x => x.dataType)).toEqual(['number']);
});
});
});
diff --git a/x-pack/legacy/plugins/lens/public/xy_visualization/xy_visualization.tsx b/x-pack/legacy/plugins/lens/public/xy_visualization/xy_visualization.tsx
index 75d6fcc7d160b..c72fa0fec24d7 100644
--- a/x-pack/legacy/plugins/lens/public/xy_visualization/xy_visualization.tsx
+++ b/x-pack/legacy/plugins/lens/public/xy_visualization/xy_visualization.tsx
@@ -11,17 +11,18 @@ import { Position } from '@elastic/charts';
import { I18nProvider } from '@kbn/i18n/react';
import { i18n } from '@kbn/i18n';
import { getSuggestions } from './xy_suggestions';
-import { XYConfigPanel, LayerContextMenu } from './xy_config_panel';
-import { Visualization } from '../types';
+import { LayerContextMenu } from './xy_config_panel';
+import { Visualization, OperationMetadata } from '../types';
import { State, PersistableState, SeriesType, visualizationTypes, LayerConfig } from './types';
import { toExpression, toPreviewExpression } from './to_expression';
-import { generateId } from '../id_generator';
import chartBarStackedSVG from '../assets/chart_bar_stacked.svg';
import chartMixedSVG from '../assets/chart_mixed_xy.svg';
import { isHorizontalChart } from './state_helpers';
const defaultIcon = chartBarStackedSVG;
const defaultSeriesType = 'bar_stacked';
+const isNumericMetric = (op: OperationMetadata) => !op.isBucketed && op.dataType === 'number';
+const isBucketed = (op: OperationMetadata) => op.isBucketed;
function getDescription(state?: State) {
if (!state) {
@@ -133,12 +134,10 @@ export const xyVisualization: Visualization = {
layers: [
{
layerId: frame.addNewLayer(),
- accessors: [generateId()],
+ accessors: [],
position: Position.Top,
seriesType: defaultSeriesType,
showGridlines: false,
- splitAccessor: generateId(),
- xAccessor: generateId(),
},
],
}
@@ -147,13 +146,89 @@ export const xyVisualization: Visualization = {
getPersistableState: state => state,
- renderLayerConfigPanel: (domElement, props) =>
- render(
-
-
- ,
- domElement
- ),
+ getConfiguration(props) {
+ const layer = props.state.layers.find(l => l.layerId === props.layerId)!;
+ return {
+ groups: [
+ {
+ groupId: 'x',
+ groupLabel: i18n.translate('xpack.lens.xyChart.xAxisLabel', {
+ defaultMessage: 'X-axis',
+ }),
+ accessors: layer.xAccessor ? [layer.xAccessor] : [],
+ filterOperations: isBucketed,
+ suggestedPriority: 1,
+ supportsMoreColumns: !layer.xAccessor,
+ required: true,
+ dataTestSubj: 'lnsXY_xDimensionPanel',
+ },
+ {
+ groupId: 'y',
+ groupLabel: i18n.translate('xpack.lens.xyChart.yAxisLabel', {
+ defaultMessage: 'Y-axis',
+ }),
+ accessors: layer.accessors,
+ filterOperations: isNumericMetric,
+ supportsMoreColumns: true,
+ required: true,
+ dataTestSubj: 'lnsXY_yDimensionPanel',
+ },
+ {
+ groupId: 'breakdown',
+ groupLabel: i18n.translate('xpack.lens.xyChart.splitSeries', {
+ defaultMessage: 'Break down by',
+ }),
+ accessors: layer.splitAccessor ? [layer.splitAccessor] : [],
+ filterOperations: isBucketed,
+ suggestedPriority: 0,
+ supportsMoreColumns: !layer.splitAccessor,
+ dataTestSubj: 'lnsXY_splitDimensionPanel',
+ },
+ ],
+ };
+ },
+
+ setDimension({ prevState, layerId, columnId, groupId }) {
+ const newLayer = prevState.layers.find(l => l.layerId === layerId);
+ if (!newLayer) {
+ return prevState;
+ }
+
+ if (groupId === 'x') {
+ newLayer.xAccessor = columnId;
+ }
+ if (groupId === 'y') {
+ newLayer.accessors = [...newLayer.accessors.filter(a => a !== columnId), columnId];
+ }
+ if (groupId === 'breakdown') {
+ newLayer.splitAccessor = columnId;
+ }
+
+ return {
+ ...prevState,
+ layers: prevState.layers.map(l => (l.layerId === layerId ? newLayer : l)),
+ };
+ },
+
+ removeDimension({ prevState, layerId, columnId }) {
+ const newLayer = prevState.layers.find(l => l.layerId === layerId);
+ if (!newLayer) {
+ return prevState;
+ }
+
+ if (newLayer.xAccessor === columnId) {
+ delete newLayer.xAccessor;
+ } else if (newLayer.splitAccessor === columnId) {
+ delete newLayer.splitAccessor;
+ } else if (newLayer.accessors.includes(columnId)) {
+ newLayer.accessors = newLayer.accessors.filter(a => a !== columnId);
+ }
+
+ return {
+ ...prevState,
+ layers: prevState.layers.map(l => (l.layerId === layerId ? newLayer : l)),
+ };
+ },
getLayerContextMenuIcon({ state, layerId }) {
const layer = state.layers.find(l => l.layerId === layerId);
@@ -177,8 +252,6 @@ function newLayerState(seriesType: SeriesType, layerId: string): LayerConfig {
return {
layerId,
seriesType,
- xAccessor: generateId(),
- accessors: [generateId()],
- splitAccessor: generateId(),
+ accessors: [],
};
}
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/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/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/monitoring/public/np_imports/angular/modules.ts b/x-pack/legacy/plugins/monitoring/public/np_imports/angular/modules.ts
index c14b64a32fb5c..b506784bf15ee 100644
--- a/x-pack/legacy/plugins/monitoring/public/np_imports/angular/modules.ts
+++ b/x-pack/legacy/plugins/monitoring/public/np_imports/angular/modules.ts
@@ -19,7 +19,6 @@ import {
StateManagementConfigProvider,
AppStateProvider,
KbnUrlProvider,
- RedirectWhenMissingProvider,
npStart,
} from '../legacy_imports';
@@ -79,8 +78,7 @@ function createLocalStateModule() {
function createLocalKbnUrlModule() {
angular
.module('monitoring/KbnUrl', ['monitoring/Private', 'ngRoute'])
- .service('kbnUrl', (Private: IPrivate) => Private(KbnUrlProvider))
- .service('redirectWhenMissing', (Private: IPrivate) => Private(RedirectWhenMissingProvider));
+ .service('kbnUrl', (Private: IPrivate) => Private(KbnUrlProvider));
}
function createLocalConfigModule(core: AppMountContext['core']) {
diff --git a/x-pack/legacy/plugins/monitoring/public/np_imports/legacy_imports.ts b/x-pack/legacy/plugins/monitoring/public/np_imports/legacy_imports.ts
index a2ebe8231456f..208b7e2acdb0f 100644
--- a/x-pack/legacy/plugins/monitoring/public/np_imports/legacy_imports.ts
+++ b/x-pack/legacy/plugins/monitoring/public/np_imports/legacy_imports.ts
@@ -18,5 +18,5 @@ export { AppStateProvider } from 'ui/state_management/app_state';
// @ts-ignore
export { EventsProvider } from 'ui/events';
// @ts-ignore
-export { KbnUrlProvider, RedirectWhenMissingProvider } from 'ui/url';
+export { KbnUrlProvider } from 'ui/url';
export { registerTimefilterWithGlobalStateFactory } from 'ui/timefilter/setup_router';
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/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/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/integration/timeline_data_providers.spec.ts b/x-pack/legacy/plugins/siem/cypress/integration/timeline_data_providers.spec.ts
index 4889d40ae7d39..aca988e195161 100644
--- a/x-pack/legacy/plugins/siem/cypress/integration/timeline_data_providers.spec.ts
+++ b/x-pack/legacy/plugins/siem/cypress/integration/timeline_data_providers.spec.ts
@@ -49,7 +49,7 @@ describe('timeline data providers', () => {
.first()
.invoke('text')
.should(hostname => {
- expect(dataProviderText).to.eq(`host.name: "${hostname}"`);
+ expect(dataProviderText).to.eq(hostname);
});
});
});
diff --git a/x-pack/legacy/plugins/siem/cypress/integration/timeline_flyout_button.spec.ts b/x-pack/legacy/plugins/siem/cypress/integration/timeline_flyout_button.spec.ts
index 1a94a4abbe5bf..02da7cbc28462 100644
--- a/x-pack/legacy/plugins/siem/cypress/integration/timeline_flyout_button.spec.ts
+++ b/x-pack/legacy/plugins/siem/cypress/integration/timeline_flyout_button.spec.ts
@@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { TIMELINE_FLYOUT_BODY, TIMELINE_NOT_READY_TO_DROP_BUTTON } from '../screens/timeline';
+import { TIMELINE_FLYOUT_HEADER, TIMELINE_NOT_READY_TO_DROP_BUTTON } from '../screens/timeline';
import { dragFirstHostToTimeline, waitForAllHostsToBeLoaded } from '../tasks/hosts/all_hosts';
import { loginAndWaitForPage } from '../tasks/login';
@@ -26,10 +26,11 @@ describe('timeline flyout button', () => {
it('toggles open the timeline', () => {
openTimeline();
- cy.get(TIMELINE_FLYOUT_BODY).should('have.css', 'visibility', 'visible');
+ cy.get(TIMELINE_FLYOUT_HEADER).should('have.css', 'visibility', 'visible');
});
- it('sets the flyout button background to euiColorSuccess with a 10% alpha channel when the user starts dragging a host, but is not hovering over the flyout button', () => {
+ // FLAKY: https://github.com/elastic/kibana/issues/60369
+ it.skip('sets the flyout button background to euiColorSuccess with a 10% alpha channel when the user starts dragging a host, but is not hovering over the flyout button', () => {
dragFirstHostToTimeline();
cy.get(TIMELINE_NOT_READY_TO_DROP_BUTTON).should(
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/screens/timeline.ts b/x-pack/legacy/plugins/siem/cypress/screens/timeline.ts
index 5638b8d23e83a..fbce585a70f86 100644
--- a/x-pack/legacy/plugins/siem/cypress/screens/timeline.ts
+++ b/x-pack/legacy/plugins/siem/cypress/screens/timeline.ts
@@ -31,6 +31,8 @@ export const TIMELINE_DROPPED_DATA_PROVIDERS = '[data-test-subj="providerContain
export const TIMELINE_FIELDS_BUTTON =
'[data-test-subj="timeline"] [data-test-subj="show-field-browser"]';
+export const TIMELINE_FLYOUT_HEADER = '[data-test-subj="eui-flyout-header"]';
+
export const TIMELINE_FLYOUT_BODY = '[data-test-subj="eui-flyout-body"]';
export const TIMELINE_INSPECT_BUTTON = '[data-test-subj="inspect-empty-button"]';
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/package.json b/x-pack/legacy/plugins/siem/package.json
index ad4a6e86ffc88..472a473842f02 100644
--- a/x-pack/legacy/plugins/siem/package.json
+++ b/x-pack/legacy/plugins/siem/package.json
@@ -14,7 +14,7 @@
"devDependencies": {
"@types/lodash": "^4.14.110",
"@types/js-yaml": "^3.12.1",
- "@types/react-beautiful-dnd": "^11.0.4"
+ "@types/react-beautiful-dnd": "^12.1.1"
},
"dependencies": {
"lodash": "^4.17.15",
diff --git a/x-pack/legacy/plugins/siem/public/components/charts/areachart.tsx b/x-pack/legacy/plugins/siem/public/components/charts/areachart.tsx
index f3b2b736ed87d..5c15f2d3c8d4f 100644
--- a/x-pack/legacy/plugins/siem/public/components/charts/areachart.tsx
+++ b/x-pack/legacy/plugins/siem/public/components/charts/areachart.tsx
@@ -16,8 +16,8 @@ import {
RecursivePartial,
} from '@elastic/charts';
import { getOr, get, isNull, isNumber } from 'lodash/fp';
-import useResizeObserver from 'use-resize-observer/polyfilled';
+import { useThrottledResizeObserver } from '../utils';
import { ChartPlaceHolder } from './chart_place_holder';
import { useTimeZone } from '../../lib/kibana';
import {
@@ -131,7 +131,7 @@ interface AreaChartComponentProps {
}
export const AreaChartComponent: React.FC = ({ areaChart, configs }) => {
- const { ref: measureRef, width, height } = useResizeObserver({});
+ const { ref: measureRef, width, height } = useThrottledResizeObserver();
const customHeight = get('customHeight', configs);
const customWidth = get('customWidth', configs);
const chartHeight = getChartHeight(customHeight, height);
diff --git a/x-pack/legacy/plugins/siem/public/components/charts/barchart.tsx b/x-pack/legacy/plugins/siem/public/components/charts/barchart.tsx
index da0f3d1d0047f..f53a1555fa1f4 100644
--- a/x-pack/legacy/plugins/siem/public/components/charts/barchart.tsx
+++ b/x-pack/legacy/plugins/siem/public/components/charts/barchart.tsx
@@ -8,8 +8,8 @@ import React from 'react';
import { Chart, BarSeries, Axis, Position, ScaleType, Settings } from '@elastic/charts';
import { getOr, get, isNumber } from 'lodash/fp';
import deepmerge from 'deepmerge';
-import useResizeObserver from 'use-resize-observer/polyfilled';
+import { useThrottledResizeObserver } from '../utils';
import { useTimeZone } from '../../lib/kibana';
import { ChartPlaceHolder } from './chart_place_holder';
import {
@@ -105,7 +105,7 @@ interface BarChartComponentProps {
}
export const BarChartComponent: React.FC = ({ barChart, configs }) => {
- const { ref: measureRef, width, height } = useResizeObserver({});
+ const { ref: measureRef, width, height } = useThrottledResizeObserver();
const customHeight = get('customHeight', configs);
const customWidth = get('customWidth', configs);
const chartHeight = getChartHeight(customHeight, height);
diff --git a/x-pack/legacy/plugins/siem/public/components/drag_and_drop/drag_drop_context_wrapper.tsx b/x-pack/legacy/plugins/siem/public/components/drag_and_drop/drag_drop_context_wrapper.tsx
index 72f5a62d0af97..11db33fff6d72 100644
--- a/x-pack/legacy/plugins/siem/public/components/drag_and_drop/drag_drop_context_wrapper.tsx
+++ b/x-pack/legacy/plugins/siem/public/components/drag_and_drop/drag_drop_context_wrapper.tsx
@@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { defaultTo, noop } from 'lodash/fp';
+import { noop } from 'lodash/fp';
import React, { useCallback } from 'react';
import { DropResult, DragDropContext } from 'react-beautiful-dnd';
import { connect, ConnectedProps } from 'react-redux';
@@ -103,10 +103,7 @@ DragDropContextWrapperComponent.displayName = 'DragDropContextWrapperComponent';
const emptyDataProviders: dragAndDropModel.IdToDataProvider = {}; // stable reference
const mapStateToProps = (state: State) => {
- const dataProviders = defaultTo(
- emptyDataProviders,
- dragAndDropSelectors.dataProvidersSelector(state)
- );
+ const dataProviders = dragAndDropSelectors.dataProvidersSelector(state) ?? emptyDataProviders;
return { dataProviders };
};
diff --git a/x-pack/legacy/plugins/siem/public/components/drag_and_drop/draggable_wrapper.test.tsx b/x-pack/legacy/plugins/siem/public/components/drag_and_drop/draggable_wrapper.test.tsx
index 9dcc335d4ff16..11891afabbf3d 100644
--- a/x-pack/legacy/plugins/siem/public/components/drag_and_drop/draggable_wrapper.test.tsx
+++ b/x-pack/legacy/plugins/siem/public/components/drag_and_drop/draggable_wrapper.test.tsx
@@ -88,21 +88,9 @@ describe('DraggableWrapper', () => {
describe('ConditionalPortal', () => {
const mount = useMountAppended();
const props = {
- usePortal: false,
registerProvider: jest.fn(),
- isDragging: true,
};
- it(`doesn't call registerProvider is NOT isDragging`, () => {
- mount(
-
-
-
- );
-
- expect(props.registerProvider.mock.calls.length).toEqual(0);
- });
-
it('calls registerProvider when isDragging', () => {
mount(
diff --git a/x-pack/legacy/plugins/siem/public/components/drag_and_drop/draggable_wrapper.tsx b/x-pack/legacy/plugins/siem/public/components/drag_and_drop/draggable_wrapper.tsx
index b7d368639ed92..3a6a4de7984db 100644
--- a/x-pack/legacy/plugins/siem/public/components/drag_and_drop/draggable_wrapper.tsx
+++ b/x-pack/legacy/plugins/siem/public/components/drag_and_drop/draggable_wrapper.tsx
@@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import React, { createContext, useCallback, useContext, useEffect, useState } from 'react';
+import React, { useCallback, useEffect, useState } from 'react';
import {
Draggable,
DraggableProvided,
@@ -15,7 +15,6 @@ import { useDispatch } from 'react-redux';
import styled from 'styled-components';
import deepEqual from 'fast-deep-equal';
-import { EuiPortal } from '@elastic/eui';
import { dragAndDropActions } from '../../store/drag_and_drop';
import { DataProvider } from '../timeline/data_providers/data_provider';
import { TruncatableText } from '../truncatable_text';
@@ -27,9 +26,6 @@ export const DragEffects = styled.div``;
DragEffects.displayName = 'DragEffects';
-export const DraggablePortalContext = createContext(false);
-export const useDraggablePortalContext = () => useContext(DraggablePortalContext);
-
/**
* Wraps the `react-beautiful-dnd` error boundary. See also:
* https://github.com/atlassian/react-beautiful-dnd/blob/v12.0.0/docs/guides/setup-problem-detection-and-error-recovery.md
@@ -89,7 +85,6 @@ export const DraggableWrapper = React.memo(
({ dataProvider, render, truncate }) => {
const [providerRegistered, setProviderRegistered] = useState(false);
const dispatch = useDispatch();
- const usePortal = useDraggablePortalContext();
const registerProvider = useCallback(() => {
if (!providerRegistered) {
@@ -113,7 +108,26 @@ export const DraggableWrapper = React.memo(
return (
-
+ (
+
+
+
+ {render(dataProvider, provided, snapshot)}
+
+
+
+ )}
+ >
{droppableProvided => (
(
key={getDraggableId(dataProvider.id)}
>
{(provided, snapshot) => (
-
-
- {truncate && !snapshot.isDragging ? (
-
- {render(dataProvider, provided, snapshot)}
-
- ) : (
-
- {render(dataProvider, provided, snapshot)}
-
- )}
-
-
+ {truncate && !snapshot.isDragging ? (
+
+ {render(dataProvider, provided, snapshot)}
+
+ ) : (
+
+ {render(dataProvider, provided, snapshot)}
+
+ )}
+
)}
{droppableProvided.placeholder}
@@ -178,20 +183,16 @@ DraggableWrapper.displayName = 'DraggableWrapper';
interface ConditionalPortalProps {
children: React.ReactNode;
- usePortal: boolean;
- isDragging: boolean;
registerProvider: () => void;
}
export const ConditionalPortal = React.memo
(
- ({ children, usePortal, registerProvider, isDragging }) => {
+ ({ children, registerProvider }) => {
useEffect(() => {
- if (isDragging) {
- registerProvider();
- }
- }, [isDragging, registerProvider]);
+ registerProvider();
+ }, [registerProvider]);
- return usePortal ? {children} : <>{children}>;
+ return <>{children}>;
}
);
diff --git a/x-pack/legacy/plugins/siem/public/components/drag_and_drop/droppable_wrapper.tsx b/x-pack/legacy/plugins/siem/public/components/drag_and_drop/droppable_wrapper.tsx
index 821ef9be10e8d..a81954f57564e 100644
--- a/x-pack/legacy/plugins/siem/public/components/drag_and_drop/droppable_wrapper.tsx
+++ b/x-pack/legacy/plugins/siem/public/components/drag_and_drop/droppable_wrapper.tsx
@@ -6,7 +6,7 @@
import { rgba } from 'polished';
import React from 'react';
-import { Droppable } from 'react-beautiful-dnd';
+import { Droppable, DraggableChildrenFn } from 'react-beautiful-dnd';
import styled from 'styled-components';
interface Props {
@@ -16,6 +16,7 @@ interface Props {
isDropDisabled?: boolean;
type?: string;
render?: ({ isDraggingOver }: { isDraggingOver: boolean }) => React.ReactNode;
+ renderClone?: DraggableChildrenFn;
}
const ReactDndDropTarget = styled.div<{ isDraggingOver: boolean; height: string }>`
@@ -94,12 +95,14 @@ export const DroppableWrapper = React.memo(
isDropDisabled = false,
type,
render = null,
+ renderClone,
}) => (
{(provided, snapshot) => (
(({ width }) => {
+ if (width) {
+ return {
+ style: {
+ width: `${width}px`,
+ },
+ };
+ }
+})`
background-color: ${({ theme }) => theme.eui.euiColorEmptyShade};
border: ${({ theme }) => theme.eui.euiBorderThin};
box-shadow: 0 2px 2px -1px ${({ theme }) => rgba(theme.eui.euiColorMediumShade, 0.3)},
@@ -24,12 +36,9 @@ Field.displayName = 'Field';
* Renders a field (e.g. `event.action`) as a draggable badge
*/
-// Passing the styles directly to the component because the width is
-// being calculated and is recommended by Styled Components for performance
-// https://github.com/styled-components/styled-components/issues/134#issuecomment-312415291
-export const DraggableFieldBadge = React.memo<{ fieldId: string; fieldWidth?: string }>(
+export const DraggableFieldBadge = React.memo<{ fieldId: string; fieldWidth?: number }>(
({ fieldId, fieldWidth }) => (
-
+
{fieldId}
)
diff --git a/x-pack/legacy/plugins/siem/public/components/draggables/index.tsx b/x-pack/legacy/plugins/siem/public/components/draggables/index.tsx
index 57f047416ec1c..1fe6c936d2823 100644
--- a/x-pack/legacy/plugins/siem/public/components/draggables/index.tsx
+++ b/x-pack/legacy/plugins/siem/public/components/draggables/index.tsx
@@ -4,8 +4,9 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { EuiBadge, EuiBadgeProps, EuiToolTip, IconType } from '@elastic/eui';
+import { EuiBadge, EuiToolTip, IconType } from '@elastic/eui';
import React from 'react';
+import styled from 'styled-components';
import { Omit } from '../../../common/utility_types';
import { DragEffects, DraggableWrapper } from '../drag_and_drop/draggable_wrapper';
@@ -116,13 +117,9 @@ export const DefaultDraggable = React.memo(
DefaultDraggable.displayName = 'DefaultDraggable';
-// Ref: https://github.com/elastic/eui/issues/1655
-// const Badge = styled(EuiBadge)`
-// vertical-align: top;
-// `;
-export const Badge = (props: EuiBadgeProps) => (
-