diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2903f23f55c9e..64a1dd0526d58 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -325,7 +325,7 @@ Note that for VSCode, to enable "live" linting of TypeScript (and other) file ty "eslint.autoFixOnSave": true, ``` -It is **not** recommended to use `prettier` plugin on Kibana project. Because settings are in `eslintrc.js` file and it is applied to too many files that shouldn't be prettier-ized. +:warning: It is **not** recommended to use the [`Prettier` extension/IDE plugin](https://prettier.io/) while maintaining the Kibana project. Formatting and styling roles are set in the multiple `.eslintrc.js` files across the project and some of them use the [NPM version of Prettier](https://www.npmjs.com/package/prettier). Using the IDE extension might cause conflicts, applying the formatting to too many files that shouldn't be prettier-ized and/or highlighting errors that are actually OK. ### Internationalization diff --git a/docs/canvas/canvas-share-workpad.asciidoc b/docs/canvas/canvas-share-workpad.asciidoc index 119ede16fe1e7..412019efc7f35 100644 --- a/docs/canvas/canvas-share-workpad.asciidoc +++ b/docs/canvas/canvas-share-workpad.asciidoc @@ -55,7 +55,7 @@ image::images/canvas-create-URL.gif[Create POST URL] [[add-workpad-website]] === Share the workpad on a website -beta[] Download the workpad and share it on any website, then customize the workpad behavior to autoplay the pages or hide the toolbar. +beta[] Canvas allows you to create _shareables_, which are workpads that you download and securely share on any website. To customize the behavior of the workpad on your website, you can choose to autoplay the pages or hide the workpad toolbar. . If you are using a Gold or Platinum license, enable reporting in your `config/kibana.yml` file. @@ -74,7 +74,7 @@ NOTE: Shareable workpads encode the current state of the workpad in a JSON file. [float] [[change-the-workpad-settings]] -=== Change the shareable workpad settings +=== Change the settings After you've added the workpad to your website, you can change the autoplay and toolbar settings. diff --git a/docs/development/core/server/kibana-plugin-server.httpservicesetup.createrouter.md b/docs/development/core/server/kibana-plugin-server.httpservicesetup.createrouter.md index 6431589c55bd1..71a7fd8fb6a22 100644 --- a/docs/development/core/server/kibana-plugin-server.httpservicesetup.createrouter.md +++ b/docs/development/core/server/kibana-plugin-server.httpservicesetup.createrouter.md @@ -21,7 +21,7 @@ Each route can have only one handler function, which is executed when the route ```ts const router = createRouter(); -// handler is called when '${my-plugin-id}/path' resource is requested with `GET` method +// handler is called when '/path' resource is requested with `GET` method router.get({ path: '/path', validate: false }, (context, req, res) => res.ok({ content: 'ok' })); ``` diff --git a/docs/development/core/server/kibana-plugin-server.httpservicesetup.md b/docs/development/core/server/kibana-plugin-server.httpservicesetup.md index d943ad53af843..dba0ad8c8560c 100644 --- a/docs/development/core/server/kibana-plugin-server.httpservicesetup.md +++ b/docs/development/core/server/kibana-plugin-server.httpservicesetup.md @@ -27,7 +27,7 @@ export interface HttpServiceSetup ## Example -To handle an incoming request in your plugin you should: - Create a `Router` instance. Router is already configured to use `plugin-id` to prefix path segment for your routes. +To handle an incoming request in your plugin you should: - Create a `Router` instance. ```ts const router = httpSetup.createRouter(); @@ -61,7 +61,7 @@ const handler = async (context: RequestHandlerContext, request: KibanaRequest, r } ``` -- Register route handler for GET request to 'my-app/path/{id}' path +- Register route handler for GET request to 'path/{id}' path ```ts import { schema, TypeOf } from '@kbn/config-schema'; diff --git a/docs/management/managing-beats.asciidoc b/docs/management/managing-beats.asciidoc index fb46d66611dfa..13e8f52f29b87 100644 --- a/docs/management/managing-beats.asciidoc +++ b/docs/management/managing-beats.asciidoc @@ -2,7 +2,7 @@ [role="xpack"] == Managing {beats} -beta[] +include::{asciidoc-dir}/../../shared/discontinued.asciidoc[tag=cm-discontinued] Use the Central Management UI under *Management > {beats}* to define and manage configurations in a central location in {kib} and quickly deploy diff --git a/docs/maps/search.asciidoc b/docs/maps/search.asciidoc index de72c32f153d1..97b10e389963e 100644 --- a/docs/maps/search.asciidoc +++ b/docs/maps/search.asciidoc @@ -14,7 +14,7 @@ You can create a layer that requests data from {es} from the following: ** Grid aggregation source -** <>. The search context is applied to both the terms join and the vector source when the vector source is provided by Elasticsearch documents. +** <> * <> with Grid aggregation source @@ -87,8 +87,11 @@ The most common cause for empty layers are searches for a field that exists in o [[maps-disable-search-for-layer]] ==== Disable search for layer -To prevent the global search bar from applying search context to a layer, clear the *Apply global filter to layer* checkbox in Layer settings. -Disabling the search context applies to the layer source and all <> configured for the layer. +You can prevent the search bar from applying search context to a layer by configuring the following: + +* In *Source settings*, clear the *Apply global filter to source* checkbox to turn off the global search context for the layer source. + +* In *Term joins*, clear the *Apply global filter to join* checkbox to turn off the global search context for the <>. [float] [[maps-add-index-search]] diff --git a/packages/kbn-test/src/functional_test_runner/lib/config/config.ts b/packages/kbn-test/src/functional_test_runner/lib/config/config.ts index 03eb048a125bb..ad9247523797a 100644 --- a/packages/kbn-test/src/functional_test_runner/lib/config/config.ts +++ b/packages/kbn-test/src/functional_test_runner/lib/config/config.ts @@ -58,7 +58,7 @@ export class Config { this[$values] = value; } - public has(key: string) { + public has(key: string | string[]) { function recursiveHasCheck( remainingPath: string[], values: Record, @@ -109,7 +109,7 @@ export class Config { return recursiveHasCheck(path, this[$values], schema); } - public get(key: string, defaultValue?: any) { + public get(key: string | string[], defaultValue?: any) { if (!this.has(key)) { throw new Error(`Unknown config key "${key}"`); } diff --git a/src/core/server/elasticsearch/__snapshots__/elasticsearch_config.test.ts.snap b/src/core/server/elasticsearch/__snapshots__/elasticsearch_config.test.ts.snap new file mode 100644 index 0000000000000..e81336c8863f5 --- /dev/null +++ b/src/core/server/elasticsearch/__snapshots__/elasticsearch_config.test.ts.snap @@ -0,0 +1,3 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`#username throws if equal to "elastic", only while running from source 1`] = `"[username]: value of \\"elastic\\" is forbidden. This is a superuser account that can obfuscate privilege-related issues. You should use the \\"kibana\\" user instead."`; diff --git a/src/core/server/elasticsearch/elasticsearch_config.test.ts b/src/core/server/elasticsearch/elasticsearch_config.test.ts index 383ba77f17779..5a52e1ea51ccc 100644 --- a/src/core/server/elasticsearch/elasticsearch_config.test.ts +++ b/src/core/server/elasticsearch/elasticsearch_config.test.ts @@ -107,3 +107,11 @@ test('#ssl.certificateAuthorities accepts both string and array of strings', () ); expect(configValue.ssl.certificateAuthorities).toEqual(['some-path', 'another-path']); }); + +test('#username throws if equal to "elastic", only while running from source', () => { + const obj = { + username: 'elastic', + }; + expect(() => config.schema.validate(obj, { dist: false })).toThrowErrorMatchingSnapshot(); + expect(() => config.schema.validate(obj, { dist: true })).not.toThrow(); +}); diff --git a/src/core/server/elasticsearch/elasticsearch_config.ts b/src/core/server/elasticsearch/elasticsearch_config.ts index 947a0d27546b1..23a1c69d055bc 100644 --- a/src/core/server/elasticsearch/elasticsearch_config.ts +++ b/src/core/server/elasticsearch/elasticsearch_config.ts @@ -19,6 +19,7 @@ import { schema, TypeOf } from '@kbn/config-schema'; import { Duration } from 'moment'; +import { Logger } from '../logging'; const hostURISchema = schema.uri({ scheme: ['http', 'https'] }); @@ -39,7 +40,23 @@ export const config = { defaultValue: 'http://localhost:9200', }), preserveHost: schema.boolean({ defaultValue: true }), - username: schema.maybe(schema.string()), + username: schema.maybe( + schema.conditional( + schema.contextRef('dist'), + false, + schema.string({ + validate: rawConfig => { + if (rawConfig === 'elastic') { + return ( + 'value of "elastic" is forbidden. This is a superuser account that can obfuscate ' + + 'privilege-related issues. You should use the "kibana" user instead.' + ); + } + }, + }), + schema.string() + ) + ), password: schema.maybe(schema.string()), requestHeadersWhitelist: schema.oneOf([schema.string(), schema.arrayOf(schema.string())], { defaultValue: ['authorization'], @@ -166,7 +183,7 @@ export class ElasticsearchConfig { */ public readonly customHeaders: ElasticsearchConfigType['customHeaders']; - constructor(rawConfig: ElasticsearchConfigType) { + constructor(rawConfig: ElasticsearchConfigType, log?: Logger) { this.ignoreVersionMismatch = rawConfig.ignoreVersionMismatch; this.apiVersion = rawConfig.apiVersion; this.logQueries = rawConfig.logQueries; @@ -195,5 +212,14 @@ export class ElasticsearchConfig { ...rawConfig.ssl, certificateAuthorities, }; + + if (this.username === 'elastic' && log !== undefined) { + // logger is optional / not used during tests + // TODO: logger can be removed when issue #40255 is resolved to support deprecations in NP config service + log.warn( + `Setting the elasticsearch username to "elastic" is deprecated. You should use the "kibana" user instead.`, + { tags: ['deprecation'] } + ); + } } } diff --git a/src/core/server/elasticsearch/elasticsearch_service.ts b/src/core/server/elasticsearch/elasticsearch_service.ts index 1f062412edaf2..be0a817c54146 100644 --- a/src/core/server/elasticsearch/elasticsearch_service.ts +++ b/src/core/server/elasticsearch/elasticsearch_service.ts @@ -51,7 +51,7 @@ export class ElasticsearchService implements CoreService('elasticsearch') - .pipe(map(rawConfig => new ElasticsearchConfig(rawConfig))); + .pipe(map(rawConfig => new ElasticsearchConfig(rawConfig, coreContext.logger.get('config')))); } public async setup(deps: SetupDeps): Promise { diff --git a/src/core/server/http/types.ts b/src/core/server/http/types.ts index 6f5cb02fd8cba..2c3dfedd1d181 100644 --- a/src/core/server/http/types.ts +++ b/src/core/server/http/types.ts @@ -52,7 +52,7 @@ export type RequestHandlerContextProvider< * * @example * To handle an incoming request in your plugin you should: - * - Create a `Router` instance. Router is already configured to use `plugin-id` to prefix path segment for your routes. + * - Create a `Router` instance. * ```ts * const router = httpSetup.createRouter(); * ``` @@ -87,7 +87,7 @@ export type RequestHandlerContextProvider< * } * ``` * - * - Register route handler for GET request to 'my-app/path/{id}' path + * - Register route handler for GET request to 'path/{id}' path * ```ts * import { schema, TypeOf } from '@kbn/config-schema'; * const router = httpSetup.createRouter(); @@ -184,7 +184,7 @@ export interface HttpServiceSetup { * @example * ```ts * const router = createRouter(); - * // handler is called when '${my-plugin-id}/path' resource is requested with `GET` method + * // handler is called when '/path' resource is requested with `GET` method * router.get({ path: '/path', validate: false }, (context, req, res) => res.ok({ content: 'ok' })); * ``` * @public diff --git a/src/legacy/core_plugins/kibana/public/home/components/__snapshots__/welcome.test.tsx.snap b/src/legacy/core_plugins/kibana/public/home/components/__snapshots__/welcome.test.tsx.snap index 5a6c6eba5c8db..2007a3bb773cf 100644 --- a/src/legacy/core_plugins/kibana/public/home/components/__snapshots__/welcome.test.tsx.snap +++ b/src/legacy/core_plugins/kibana/public/home/components/__snapshots__/welcome.test.tsx.snap @@ -157,13 +157,13 @@ exports[`should render a Welcome screen with the telemetry disclaimer 1`] = ` target="_blank" > @@ -171,7 +171,7 @@ exports[`should render a Welcome screen with the telemetry disclaimer 1`] = ` href="#/management/kibana/settings" > diff --git a/src/legacy/core_plugins/kibana/public/home/components/home.js b/src/legacy/core_plugins/kibana/public/home/components/home.js index 3266bbb79c625..fdda87e02fcf1 100644 --- a/src/legacy/core_plugins/kibana/public/home/components/home.js +++ b/src/legacy/core_plugins/kibana/public/home/components/home.js @@ -51,7 +51,7 @@ export class Home extends Component { getServices().getInjected('disableWelcomeScreen') || props.localStorage.getItem(KEY_ENABLE_WELCOME) === 'false' ); - const showTelemetryDisclaimer = getServices().getInjected('allowChangingOptInStatus'); + const showTelemetryDisclaimer = getServices().getInjected('telemetryNotifyUserAboutOptInDefault'); this.state = { // If welcome is enabled, we wait for loading to complete @@ -231,6 +231,7 @@ export class Home extends Component { onSkip={this.skipWelcome} urlBasePath={this.props.urlBasePath} showTelemetryDisclaimer={this.state.showTelemetryDisclaimer} + onOptInSeen={this.props.onOptInSeen} /> ); } @@ -269,4 +270,5 @@ Home.propTypes = { localStorage: PropTypes.object.isRequired, urlBasePath: PropTypes.string.isRequired, mlEnabled: PropTypes.bool.isRequired, + onOptInSeen: PropTypes.func.isRequired, }; diff --git a/src/legacy/core_plugins/kibana/public/home/components/home_app.js b/src/legacy/core_plugins/kibana/public/home/components/home_app.js index f8476a0c09670..f69bb654e65df 100644 --- a/src/legacy/core_plugins/kibana/public/home/components/home_app.js +++ b/src/legacy/core_plugins/kibana/public/home/components/home_app.js @@ -35,6 +35,9 @@ export function HomeApp({ directories }) { savedObjectsClient, getBasePath, addBasePath, + telemetryOptInProvider: { + setOptInNoticeSeen, + }, } = getServices(); const isCloudEnabled = getInjected('isCloudEnabled', false); @@ -83,6 +86,7 @@ export function HomeApp({ directories }) { find={savedObjectsClient.find} localStorage={localStorage} urlBasePath={getBasePath()} + onOptInSeen={setOptInNoticeSeen} /> diff --git a/src/legacy/core_plugins/kibana/public/home/components/welcome.test.tsx b/src/legacy/core_plugins/kibana/public/home/components/welcome.test.tsx index 195a527707af6..21dcfd9ef15de 100644 --- a/src/legacy/core_plugins/kibana/public/home/components/welcome.test.tsx +++ b/src/legacy/core_plugins/kibana/public/home/components/welcome.test.tsx @@ -35,7 +35,7 @@ jest.mock('../kibana_services', () => ({ test('should render a Welcome screen with the telemetry disclaimer', () => { const component = shallow( // @ts-ignore - {}} showTelemetryDisclaimer={true} /> + {}} showTelemetryDisclaimer={true} onOptInSeen={() => {}} /> ); expect(component).toMatchSnapshot(); @@ -45,8 +45,19 @@ test('should render a Welcome screen with no telemetry disclaimer', () => { // @ts-ignore const component = shallow( // @ts-ignore - {}} showTelemetryDisclaimer={false} /> + {}} showTelemetryDisclaimer={false} onOptInSeen={() => {}} /> ); expect(component).toMatchSnapshot(); }); + +test('fires opt-in seen when mounted', () => { + const seen = jest.fn(); + + shallow( + // @ts-ignore + {}} showTelemetryDisclaimer={true} onOptInSeen={seen} /> + ); + + expect(seen).toHaveBeenCalled(); +}); diff --git a/src/legacy/core_plugins/kibana/public/home/components/welcome.tsx b/src/legacy/core_plugins/kibana/public/home/components/welcome.tsx index d919a4ecf239c..c8de0bf7bb936 100644 --- a/src/legacy/core_plugins/kibana/public/home/components/welcome.tsx +++ b/src/legacy/core_plugins/kibana/public/home/components/welcome.tsx @@ -43,6 +43,7 @@ import { SampleDataCard } from './sample_data'; interface Props { urlBasePath: string; onSkip: () => void; + onOptInSeen: () => any; showTelemetryDisclaimer: boolean; } @@ -75,6 +76,7 @@ export class Welcome extends React.Component { componentDidMount() { this.services.trackUiMetric(this.services.METRIC_TYPE.LOADED, 'welcomeScreenMount'); + this.props.onOptInSeen(); document.addEventListener('keydown', this.hideOnEsc); } @@ -132,17 +134,17 @@ export class Welcome extends React.Component { > diff --git a/src/legacy/core_plugins/kibana/public/home/load_tutorials.js b/src/legacy/core_plugins/kibana/public/home/load_tutorials.js index a6f19bc166dc7..f597bd732c221 100644 --- a/src/legacy/core_plugins/kibana/public/home/load_tutorials.js +++ b/src/legacy/core_plugins/kibana/public/home/load_tutorials.js @@ -21,6 +21,7 @@ import _ from 'lodash'; import { getServices } from './kibana_services'; import { i18n } from '@kbn/i18n'; +const baseUrlLP = getServices().addBasePath('/api/kibana/home/tutorials_LP'); const baseUrl = getServices().addBasePath('/api/kibana/home/tutorials'); const headers = new Headers(); headers.append('Accept', 'application/json'); @@ -28,22 +29,36 @@ headers.append('Content-Type', 'application/json'); headers.append('kbn-xsrf', 'kibana'); let tutorials = []; +let tutorialsLegacyPlatform = []; +let tutorialsNewPlatform = []; let tutorialsLoaded = false; async function loadTutorials() { try { - const response = await fetch(baseUrl, { + const responseLegacyPlatform = await fetch(baseUrlLP, { method: 'get', credentials: 'include', headers: headers, }); - if (response.status >= 300) { + if (responseLegacyPlatform.status >= 300) { throw new Error(i18n.translate('kbn.home.loadTutorials.requestFailedErrorMessage', { - defaultMessage: 'Request failed with status code: {status}', values: { status: response.status } } + defaultMessage: 'Request failed with status code: {status}', values: { status: responseLegacyPlatform.status } } + )); + } + const responseNewPlatform = await fetch(baseUrl, { + method: 'get', + credentials: 'include', + headers: headers, + }); + if (responseNewPlatform.status >= 300) { + throw new Error(i18n.translate('kbn.home.loadTutorials.requestFailedErrorMessage', { + defaultMessage: 'Request failed with status code: {status}', values: { status: responseNewPlatform.status } } )); } - tutorials = await response.json(); + tutorialsLegacyPlatform = await responseLegacyPlatform.json(); + tutorialsNewPlatform = await responseNewPlatform.json(); + tutorials = tutorialsLegacyPlatform.concat(tutorialsNewPlatform); tutorialsLoaded = true; } catch(err) { getServices().toastNotifications.addDanger({ diff --git a/src/legacy/core_plugins/kibana/server/routes/api/home/register_tutorials.js b/src/legacy/core_plugins/kibana/server/routes/api/home/register_tutorials.js index 861ed1c244d13..fdf2e080c890c 100644 --- a/src/legacy/core_plugins/kibana/server/routes/api/home/register_tutorials.js +++ b/src/legacy/core_plugins/kibana/server/routes/api/home/register_tutorials.js @@ -20,7 +20,7 @@ export function registerTutorials(server) { server.route({ - path: '/api/kibana/home/tutorials', + path: '/api/kibana/home/tutorials_LP', method: ['GET'], handler: function (req) { return server.getTutorials(req); diff --git a/src/legacy/core_plugins/kibana/server/tutorials/aerospike_metrics/index.js b/src/legacy/core_plugins/kibana/server/tutorials/aerospike_metrics/index.js index 77f6df09b244b..28b1dbe6226dc 100644 --- a/src/legacy/core_plugins/kibana/server/tutorials/aerospike_metrics/index.js +++ b/src/legacy/core_plugins/kibana/server/tutorials/aerospike_metrics/index.js @@ -21,7 +21,7 @@ import { i18n } from '@kbn/i18n'; import { TUTORIAL_CATEGORY } from '../../../common/tutorials/tutorial_category'; import { onPremInstructions, cloudInstructions, onPremCloudInstructions } from '../../../common/tutorials/metricbeat_instructions'; -export function aerospikeMetricsSpecProvider(server, context) { +export function aerospikeMetricsSpecProvider(context) { const moduleName = 'aerospike'; return { id: 'aerospikeMetrics', diff --git a/src/legacy/core_plugins/kibana/server/tutorials/apache_logs/index.js b/src/legacy/core_plugins/kibana/server/tutorials/apache_logs/index.js index c73f4389aa2fe..221fc8f5263c1 100644 --- a/src/legacy/core_plugins/kibana/server/tutorials/apache_logs/index.js +++ b/src/legacy/core_plugins/kibana/server/tutorials/apache_logs/index.js @@ -21,7 +21,7 @@ import { i18n } from '@kbn/i18n'; import { TUTORIAL_CATEGORY } from '../../../common/tutorials/tutorial_category'; import { onPremInstructions, cloudInstructions, onPremCloudInstructions } from '../../../common/tutorials/filebeat_instructions'; -export function apacheLogsSpecProvider(server, context) { +export function apacheLogsSpecProvider(context) { const moduleName = 'apache'; const platforms = ['OSX', 'DEB', 'RPM', 'WINDOWS']; return { diff --git a/src/legacy/core_plugins/kibana/server/tutorials/apache_metrics/index.js b/src/legacy/core_plugins/kibana/server/tutorials/apache_metrics/index.js index c53c85f6a08e5..436af8b352590 100644 --- a/src/legacy/core_plugins/kibana/server/tutorials/apache_metrics/index.js +++ b/src/legacy/core_plugins/kibana/server/tutorials/apache_metrics/index.js @@ -21,7 +21,7 @@ import { i18n } from '@kbn/i18n'; import { TUTORIAL_CATEGORY } from '../../../common/tutorials/tutorial_category'; import { onPremInstructions, cloudInstructions, onPremCloudInstructions } from '../../../common/tutorials/metricbeat_instructions'; -export function apacheMetricsSpecProvider(server, context) { +export function apacheMetricsSpecProvider(context) { const moduleName = 'apache'; return { id: 'apacheMetrics', diff --git a/src/legacy/core_plugins/kibana/server/tutorials/auditbeat/index.js b/src/legacy/core_plugins/kibana/server/tutorials/auditbeat/index.js index 19994aefdb930..b67a872dcc0aa 100644 --- a/src/legacy/core_plugins/kibana/server/tutorials/auditbeat/index.js +++ b/src/legacy/core_plugins/kibana/server/tutorials/auditbeat/index.js @@ -25,7 +25,7 @@ import { onPremCloudInstructions, } from '../../../common/tutorials/auditbeat_instructions'; -export function auditbeatSpecProvider(server, context) { +export function auditbeatSpecProvider(context) { const platforms = ['OSX', 'DEB', 'RPM', 'WINDOWS']; return { id: 'auditbeat', diff --git a/src/legacy/core_plugins/kibana/server/tutorials/aws_metrics/index.js b/src/legacy/core_plugins/kibana/server/tutorials/aws_metrics/index.js index 56b6689f359f3..32ff79930a877 100644 --- a/src/legacy/core_plugins/kibana/server/tutorials/aws_metrics/index.js +++ b/src/legacy/core_plugins/kibana/server/tutorials/aws_metrics/index.js @@ -21,7 +21,7 @@ import { i18n } from '@kbn/i18n'; import { TUTORIAL_CATEGORY } from '../../../common/tutorials/tutorial_category'; import { onPremInstructions, cloudInstructions, onPremCloudInstructions } from '../../../common/tutorials/metricbeat_instructions'; -export function awsMetricsSpecProvider(server, context) { +export function awsMetricsSpecProvider(context) { const moduleName = 'aws'; return { id: 'awsMetrics', diff --git a/src/legacy/core_plugins/kibana/server/tutorials/ceph_metrics/index.js b/src/legacy/core_plugins/kibana/server/tutorials/ceph_metrics/index.js index f2b2749a79268..1f0001dbaaf94 100644 --- a/src/legacy/core_plugins/kibana/server/tutorials/ceph_metrics/index.js +++ b/src/legacy/core_plugins/kibana/server/tutorials/ceph_metrics/index.js @@ -21,7 +21,7 @@ import { i18n } from '@kbn/i18n'; import { TUTORIAL_CATEGORY } from '../../../common/tutorials/tutorial_category'; import { onPremInstructions, cloudInstructions, onPremCloudInstructions } from '../../../common/tutorials/metricbeat_instructions'; -export function cephMetricsSpecProvider(server, context) { +export function cephMetricsSpecProvider(context) { const moduleName = 'ceph'; return { id: 'cephMetrics', diff --git a/src/legacy/core_plugins/kibana/server/tutorials/cisco_logs/index.js b/src/legacy/core_plugins/kibana/server/tutorials/cisco_logs/index.js index 83123afde3882..90190bd0d6877 100644 --- a/src/legacy/core_plugins/kibana/server/tutorials/cisco_logs/index.js +++ b/src/legacy/core_plugins/kibana/server/tutorials/cisco_logs/index.js @@ -25,7 +25,7 @@ import { onPremCloudInstructions, } from '../../../common/tutorials/filebeat_instructions'; -export function ciscoLogsSpecProvider(server, context) { +export function ciscoLogsSpecProvider(context) { const moduleName = 'cisco'; const platforms = ['OSX', 'DEB', 'RPM', 'WINDOWS']; return { diff --git a/src/legacy/core_plugins/kibana/server/tutorials/cloudwatch_logs/index.js b/src/legacy/core_plugins/kibana/server/tutorials/cloudwatch_logs/index.js index b5b053e329d1a..7617f313b2436 100644 --- a/src/legacy/core_plugins/kibana/server/tutorials/cloudwatch_logs/index.js +++ b/src/legacy/core_plugins/kibana/server/tutorials/cloudwatch_logs/index.js @@ -21,7 +21,7 @@ import { i18n } from '@kbn/i18n'; import { TUTORIAL_CATEGORY } from '../../../common/tutorials/tutorial_category'; import { onPremInstructions, cloudInstructions, onPremCloudInstructions } from '../../../common/tutorials/functionbeat_instructions'; -export function cloudwatchLogsSpecProvider(server, context) { +export function cloudwatchLogsSpecProvider(context) { return { id: 'cloudwatchLogs', name: i18n.translate('kbn.server.tutorials.cloudwatchLogs.nameTitle', { diff --git a/src/legacy/core_plugins/kibana/server/tutorials/cockroachdb_metrics/index.js b/src/legacy/core_plugins/kibana/server/tutorials/cockroachdb_metrics/index.js index e05be3bda145f..865ddb47bbe5f 100644 --- a/src/legacy/core_plugins/kibana/server/tutorials/cockroachdb_metrics/index.js +++ b/src/legacy/core_plugins/kibana/server/tutorials/cockroachdb_metrics/index.js @@ -21,7 +21,7 @@ import { i18n } from '@kbn/i18n'; import { TUTORIAL_CATEGORY } from '../../../common/tutorials/tutorial_category'; import { onPremInstructions, cloudInstructions, onPremCloudInstructions } from '../../../common/tutorials/metricbeat_instructions'; -export function cockroachdbMetricsSpecProvider(server, context) { +export function cockroachdbMetricsSpecProvider(context) { const moduleName = 'cockroachdb'; return { id: 'cockroachdbMetrics', diff --git a/src/legacy/core_plugins/kibana/server/tutorials/consul_metrics/index.js b/src/legacy/core_plugins/kibana/server/tutorials/consul_metrics/index.js index 8823fe5ee5067..7d2668c60fe18 100644 --- a/src/legacy/core_plugins/kibana/server/tutorials/consul_metrics/index.js +++ b/src/legacy/core_plugins/kibana/server/tutorials/consul_metrics/index.js @@ -21,7 +21,7 @@ import { i18n } from '@kbn/i18n'; import { TUTORIAL_CATEGORY } from '../../../common/tutorials/tutorial_category'; import { onPremInstructions, cloudInstructions, onPremCloudInstructions } from '../../../common/tutorials/metricbeat_instructions'; -export function consulMetricsSpecProvider(server, context) { +export function consulMetricsSpecProvider(context) { const moduleName = 'consul'; return { id: 'consulMetrics', diff --git a/src/legacy/core_plugins/kibana/server/tutorials/coredns_metrics/index.js b/src/legacy/core_plugins/kibana/server/tutorials/coredns_metrics/index.js index 9536cab0886d5..a62613e9c2f13 100644 --- a/src/legacy/core_plugins/kibana/server/tutorials/coredns_metrics/index.js +++ b/src/legacy/core_plugins/kibana/server/tutorials/coredns_metrics/index.js @@ -21,7 +21,7 @@ import { i18n } from '@kbn/i18n'; import { TUTORIAL_CATEGORY } from '../../../common/tutorials/tutorial_category'; import { onPremInstructions, cloudInstructions, onPremCloudInstructions } from '../../../common/tutorials/metricbeat_instructions'; -export function corednsMetricsSpecProvider(server, context) { +export function corednsMetricsSpecProvider(context) { const moduleName = 'coredns'; return { id: 'corednsMetrics', diff --git a/src/legacy/core_plugins/kibana/server/tutorials/couchbase_metrics/index.js b/src/legacy/core_plugins/kibana/server/tutorials/couchbase_metrics/index.js index 9dc8a7337f434..8a6452703cca7 100644 --- a/src/legacy/core_plugins/kibana/server/tutorials/couchbase_metrics/index.js +++ b/src/legacy/core_plugins/kibana/server/tutorials/couchbase_metrics/index.js @@ -21,7 +21,7 @@ import { i18n } from '@kbn/i18n'; import { TUTORIAL_CATEGORY } from '../../../common/tutorials/tutorial_category'; import { onPremInstructions, cloudInstructions, onPremCloudInstructions } from '../../../common/tutorials/metricbeat_instructions'; -export function couchbaseMetricsSpecProvider(server, context) { +export function couchbaseMetricsSpecProvider(context) { const moduleName = 'couchbase'; return { id: 'couchbaseMetrics', diff --git a/src/legacy/core_plugins/kibana/server/tutorials/couchdb_metrics/index.js b/src/legacy/core_plugins/kibana/server/tutorials/couchdb_metrics/index.js index 437ed7132d617..24f29c1a263ab 100644 --- a/src/legacy/core_plugins/kibana/server/tutorials/couchdb_metrics/index.js +++ b/src/legacy/core_plugins/kibana/server/tutorials/couchdb_metrics/index.js @@ -21,7 +21,7 @@ import { i18n } from '@kbn/i18n'; import { TUTORIAL_CATEGORY } from '../../../common/tutorials/tutorial_category'; import { onPremInstructions, cloudInstructions, onPremCloudInstructions } from '../../../common/tutorials/metricbeat_instructions'; -export function couchdbMetricsSpecProvider(server, context) { +export function couchdbMetricsSpecProvider(context) { const moduleName = 'couchdb'; return { id: 'couchdbMetrics', diff --git a/src/legacy/core_plugins/kibana/server/tutorials/docker_metrics/index.js b/src/legacy/core_plugins/kibana/server/tutorials/docker_metrics/index.js index bc1cda7d52385..8268851d67697 100644 --- a/src/legacy/core_plugins/kibana/server/tutorials/docker_metrics/index.js +++ b/src/legacy/core_plugins/kibana/server/tutorials/docker_metrics/index.js @@ -21,7 +21,7 @@ import { i18n } from '@kbn/i18n'; import { TUTORIAL_CATEGORY } from '../../../common/tutorials/tutorial_category'; import { onPremInstructions, cloudInstructions, onPremCloudInstructions } from '../../../common/tutorials/metricbeat_instructions'; -export function dockerMetricsSpecProvider(server, context) { +export function dockerMetricsSpecProvider(context) { const moduleName = 'docker'; return { id: 'dockerMetrics', diff --git a/src/legacy/core_plugins/kibana/server/tutorials/dropwizard_metrics/index.js b/src/legacy/core_plugins/kibana/server/tutorials/dropwizard_metrics/index.js index c76743f84c0ac..9576518d7b095 100644 --- a/src/legacy/core_plugins/kibana/server/tutorials/dropwizard_metrics/index.js +++ b/src/legacy/core_plugins/kibana/server/tutorials/dropwizard_metrics/index.js @@ -21,7 +21,7 @@ import { i18n } from '@kbn/i18n'; import { TUTORIAL_CATEGORY } from '../../../common/tutorials/tutorial_category'; import { onPremInstructions, cloudInstructions, onPremCloudInstructions } from '../../../common/tutorials/metricbeat_instructions'; -export function dropwizardMetricsSpecProvider(server, context) { +export function dropwizardMetricsSpecProvider(context) { const moduleName = 'dropwizard'; return { id: 'dropwizardMetrics', diff --git a/src/legacy/core_plugins/kibana/server/tutorials/elasticsearch_logs/index.js b/src/legacy/core_plugins/kibana/server/tutorials/elasticsearch_logs/index.js index 9f88895917e5d..5778af07d8836 100644 --- a/src/legacy/core_plugins/kibana/server/tutorials/elasticsearch_logs/index.js +++ b/src/legacy/core_plugins/kibana/server/tutorials/elasticsearch_logs/index.js @@ -21,7 +21,7 @@ import { i18n } from '@kbn/i18n'; import { TUTORIAL_CATEGORY } from '../../../common/tutorials/tutorial_category'; import { onPremInstructions, cloudInstructions, onPremCloudInstructions } from '../../../common/tutorials/filebeat_instructions'; -export function elasticsearchLogsSpecProvider(server, context) { +export function elasticsearchLogsSpecProvider(context) { const moduleName = 'elasticsearch'; const platforms = ['OSX', 'DEB', 'RPM', 'WINDOWS']; return { diff --git a/src/legacy/core_plugins/kibana/server/tutorials/elasticsearch_metrics/index.js b/src/legacy/core_plugins/kibana/server/tutorials/elasticsearch_metrics/index.js index e31343a4ec48e..35ac8b74c9a1f 100644 --- a/src/legacy/core_plugins/kibana/server/tutorials/elasticsearch_metrics/index.js +++ b/src/legacy/core_plugins/kibana/server/tutorials/elasticsearch_metrics/index.js @@ -21,7 +21,7 @@ import { i18n } from '@kbn/i18n'; import { TUTORIAL_CATEGORY } from '../../../common/tutorials/tutorial_category'; import { onPremInstructions, cloudInstructions, onPremCloudInstructions } from '../../../common/tutorials/metricbeat_instructions'; -export function elasticsearchMetricsSpecProvider(server, context) { +export function elasticsearchMetricsSpecProvider(context) { const moduleName = 'elasticsearch'; return { id: 'elasticsearchMetrics', diff --git a/src/legacy/core_plugins/kibana/server/tutorials/envoyproxy_logs/index.js b/src/legacy/core_plugins/kibana/server/tutorials/envoyproxy_logs/index.js index 8e8d27b5ba43d..977decd413f08 100644 --- a/src/legacy/core_plugins/kibana/server/tutorials/envoyproxy_logs/index.js +++ b/src/legacy/core_plugins/kibana/server/tutorials/envoyproxy_logs/index.js @@ -25,7 +25,7 @@ import { onPremCloudInstructions, } from '../../../common/tutorials/filebeat_instructions'; -export function envoyproxyLogsSpecProvider(server, context) { +export function envoyproxyLogsSpecProvider(context) { const moduleName = 'envoyproxy'; const platforms = ['OSX', 'DEB', 'RPM', 'WINDOWS']; return { diff --git a/src/legacy/core_plugins/kibana/server/tutorials/etcd_metrics/index.js b/src/legacy/core_plugins/kibana/server/tutorials/etcd_metrics/index.js index 18463e8e91104..27c9259ad080b 100644 --- a/src/legacy/core_plugins/kibana/server/tutorials/etcd_metrics/index.js +++ b/src/legacy/core_plugins/kibana/server/tutorials/etcd_metrics/index.js @@ -21,7 +21,7 @@ import { i18n } from '@kbn/i18n'; import { TUTORIAL_CATEGORY } from '../../../common/tutorials/tutorial_category'; import { onPremInstructions, cloudInstructions, onPremCloudInstructions } from '../../../common/tutorials/metricbeat_instructions'; -export function etcdMetricsSpecProvider(server, context) { +export function etcdMetricsSpecProvider(context) { const moduleName = 'etcd'; return { id: 'etcdMetrics', diff --git a/src/legacy/core_plugins/kibana/server/tutorials/golang_metrics/index.js b/src/legacy/core_plugins/kibana/server/tutorials/golang_metrics/index.js index 594c0bf72edd8..e6823b6a51c64 100644 --- a/src/legacy/core_plugins/kibana/server/tutorials/golang_metrics/index.js +++ b/src/legacy/core_plugins/kibana/server/tutorials/golang_metrics/index.js @@ -21,7 +21,7 @@ import { i18n } from '@kbn/i18n'; import { TUTORIAL_CATEGORY } from '../../../common/tutorials/tutorial_category'; import { onPremInstructions, cloudInstructions, onPremCloudInstructions } from '../../../common/tutorials/metricbeat_instructions'; -export function golangMetricsSpecProvider(server, context) { +export function golangMetricsSpecProvider(context) { const moduleName = 'golang'; return { id: moduleName + 'Metrics', diff --git a/src/legacy/core_plugins/kibana/server/tutorials/haproxy_metrics/index.js b/src/legacy/core_plugins/kibana/server/tutorials/haproxy_metrics/index.js index 4eea8c1a3be59..ccb7e01e0481e 100644 --- a/src/legacy/core_plugins/kibana/server/tutorials/haproxy_metrics/index.js +++ b/src/legacy/core_plugins/kibana/server/tutorials/haproxy_metrics/index.js @@ -21,7 +21,7 @@ import { i18n } from '@kbn/i18n'; import { TUTORIAL_CATEGORY } from '../../../common/tutorials/tutorial_category'; import { onPremInstructions, cloudInstructions, onPremCloudInstructions } from '../../../common/tutorials/metricbeat_instructions'; -export function haproxyMetricsSpecProvider(server, context) { +export function haproxyMetricsSpecProvider(context) { const moduleName = 'haproxy'; return { id: 'haproxyMetrics', diff --git a/src/legacy/core_plugins/kibana/server/tutorials/iis_logs/index.js b/src/legacy/core_plugins/kibana/server/tutorials/iis_logs/index.js index 8a937dddfa509..14f96c1e851c6 100644 --- a/src/legacy/core_plugins/kibana/server/tutorials/iis_logs/index.js +++ b/src/legacy/core_plugins/kibana/server/tutorials/iis_logs/index.js @@ -21,7 +21,7 @@ import { i18n } from '@kbn/i18n'; import { TUTORIAL_CATEGORY } from '../../../common/tutorials/tutorial_category'; import { onPremInstructions, cloudInstructions, onPremCloudInstructions } from '../../../common/tutorials/filebeat_instructions'; -export function iisLogsSpecProvider(server, context) { +export function iisLogsSpecProvider(context) { const moduleName = 'iis'; const platforms = ['WINDOWS']; return { diff --git a/src/legacy/core_plugins/kibana/server/tutorials/iptables_logs/index.js b/src/legacy/core_plugins/kibana/server/tutorials/iptables_logs/index.js index b5522a825fc11..63246e44d2d0d 100644 --- a/src/legacy/core_plugins/kibana/server/tutorials/iptables_logs/index.js +++ b/src/legacy/core_plugins/kibana/server/tutorials/iptables_logs/index.js @@ -25,7 +25,7 @@ import { onPremCloudInstructions, } from '../../../common/tutorials/filebeat_instructions'; -export function iptablesLogsSpecProvider(server, context) { +export function iptablesLogsSpecProvider(context) { const moduleName = 'iptables'; const platforms = ['DEB', 'RPM']; return { diff --git a/src/legacy/core_plugins/kibana/server/tutorials/kafka_logs/index.js b/src/legacy/core_plugins/kibana/server/tutorials/kafka_logs/index.js index 4b9ba85157a49..ab1d9af6286cd 100644 --- a/src/legacy/core_plugins/kibana/server/tutorials/kafka_logs/index.js +++ b/src/legacy/core_plugins/kibana/server/tutorials/kafka_logs/index.js @@ -21,7 +21,7 @@ import { i18n } from '@kbn/i18n'; import { TUTORIAL_CATEGORY } from '../../../common/tutorials/tutorial_category'; import { onPremInstructions, cloudInstructions, onPremCloudInstructions } from '../../../common/tutorials/filebeat_instructions'; -export function kafkaLogsSpecProvider(server, context) { +export function kafkaLogsSpecProvider(context) { const moduleName = 'kafka'; const platforms = ['OSX', 'DEB', 'RPM', 'WINDOWS']; return { diff --git a/src/legacy/core_plugins/kibana/server/tutorials/kafka_metrics/index.js b/src/legacy/core_plugins/kibana/server/tutorials/kafka_metrics/index.js index 5dfc786fc2ecd..68651e6833804 100644 --- a/src/legacy/core_plugins/kibana/server/tutorials/kafka_metrics/index.js +++ b/src/legacy/core_plugins/kibana/server/tutorials/kafka_metrics/index.js @@ -21,7 +21,7 @@ import { i18n } from '@kbn/i18n'; import { TUTORIAL_CATEGORY } from '../../../common/tutorials/tutorial_category'; import { onPremInstructions, cloudInstructions, onPremCloudInstructions } from '../../../common/tutorials/metricbeat_instructions'; -export function kafkaMetricsSpecProvider(server, context) { +export function kafkaMetricsSpecProvider(context) { const moduleName = 'kafka'; return { id: 'kafkaMetrics', diff --git a/src/legacy/core_plugins/kibana/server/tutorials/kibana_metrics/index.js b/src/legacy/core_plugins/kibana/server/tutorials/kibana_metrics/index.js index bce5eb2169f1c..c85f1399c25f5 100644 --- a/src/legacy/core_plugins/kibana/server/tutorials/kibana_metrics/index.js +++ b/src/legacy/core_plugins/kibana/server/tutorials/kibana_metrics/index.js @@ -21,7 +21,7 @@ import { i18n } from '@kbn/i18n'; import { TUTORIAL_CATEGORY } from '../../../common/tutorials/tutorial_category'; import { onPremInstructions, cloudInstructions, onPremCloudInstructions } from '../../../common/tutorials/metricbeat_instructions'; -export function kibanaMetricsSpecProvider(server, context) { +export function kibanaMetricsSpecProvider(context) { const moduleName = 'kibana'; return { id: 'kibanaMetrics', diff --git a/src/legacy/core_plugins/kibana/server/tutorials/kubernetes_metrics/index.js b/src/legacy/core_plugins/kibana/server/tutorials/kubernetes_metrics/index.js index c89c5764b9108..2ff1460563928 100644 --- a/src/legacy/core_plugins/kibana/server/tutorials/kubernetes_metrics/index.js +++ b/src/legacy/core_plugins/kibana/server/tutorials/kubernetes_metrics/index.js @@ -21,7 +21,7 @@ import { i18n } from '@kbn/i18n'; import { TUTORIAL_CATEGORY } from '../../../common/tutorials/tutorial_category'; import { onPremInstructions, cloudInstructions, onPremCloudInstructions } from '../../../common/tutorials/metricbeat_instructions'; -export function kubernetesMetricsSpecProvider(server, context) { +export function kubernetesMetricsSpecProvider(context) { const moduleName = 'kubernetes'; return { id: 'kubernetesMetrics', diff --git a/src/legacy/core_plugins/kibana/server/tutorials/logstash_logs/index.js b/src/legacy/core_plugins/kibana/server/tutorials/logstash_logs/index.js index 463043a66b70f..47ae15dff4d3e 100644 --- a/src/legacy/core_plugins/kibana/server/tutorials/logstash_logs/index.js +++ b/src/legacy/core_plugins/kibana/server/tutorials/logstash_logs/index.js @@ -21,7 +21,7 @@ import { i18n } from '@kbn/i18n'; import { TUTORIAL_CATEGORY } from '../../../common/tutorials/tutorial_category'; import { onPremInstructions, cloudInstructions, onPremCloudInstructions } from '../../../common/tutorials/filebeat_instructions'; -export function logstashLogsSpecProvider(server, context) { +export function logstashLogsSpecProvider(context) { const moduleName = 'logstash'; const platforms = ['OSX', 'DEB', 'RPM', 'WINDOWS']; return { diff --git a/src/legacy/core_plugins/kibana/server/tutorials/logstash_metrics/index.js b/src/legacy/core_plugins/kibana/server/tutorials/logstash_metrics/index.js index 06b24cc0ee706..838316655db6c 100644 --- a/src/legacy/core_plugins/kibana/server/tutorials/logstash_metrics/index.js +++ b/src/legacy/core_plugins/kibana/server/tutorials/logstash_metrics/index.js @@ -21,7 +21,7 @@ import { i18n } from '@kbn/i18n'; import { TUTORIAL_CATEGORY } from '../../../common/tutorials/tutorial_category'; import { onPremInstructions, cloudInstructions, onPremCloudInstructions } from '../../../common/tutorials/metricbeat_instructions'; -export function logstashMetricsSpecProvider(server, context) { +export function logstashMetricsSpecProvider(context) { const moduleName = 'logstash'; return { id: moduleName + 'Metrics', diff --git a/src/legacy/core_plugins/kibana/server/tutorials/memcached_metrics/index.js b/src/legacy/core_plugins/kibana/server/tutorials/memcached_metrics/index.js index f1fbd9998c62b..ce31b4fba351f 100644 --- a/src/legacy/core_plugins/kibana/server/tutorials/memcached_metrics/index.js +++ b/src/legacy/core_plugins/kibana/server/tutorials/memcached_metrics/index.js @@ -21,7 +21,7 @@ import { i18n } from '@kbn/i18n'; import { TUTORIAL_CATEGORY } from '../../../common/tutorials/tutorial_category'; import { onPremInstructions, cloudInstructions, onPremCloudInstructions } from '../../../common/tutorials/metricbeat_instructions'; -export function memcachedMetricsSpecProvider(server, context) { +export function memcachedMetricsSpecProvider(context) { const moduleName = 'memcached'; return { id: 'memcachedMetrics', diff --git a/src/legacy/core_plugins/kibana/server/tutorials/mongodb_metrics/index.js b/src/legacy/core_plugins/kibana/server/tutorials/mongodb_metrics/index.js index fa54055c813a7..e9bf02585c766 100644 --- a/src/legacy/core_plugins/kibana/server/tutorials/mongodb_metrics/index.js +++ b/src/legacy/core_plugins/kibana/server/tutorials/mongodb_metrics/index.js @@ -21,7 +21,7 @@ import { i18n } from '@kbn/i18n'; import { TUTORIAL_CATEGORY } from '../../../common/tutorials/tutorial_category'; import { onPremInstructions, cloudInstructions, onPremCloudInstructions } from '../../../common/tutorials/metricbeat_instructions'; -export function mongodbMetricsSpecProvider(server, context) { +export function mongodbMetricsSpecProvider(context) { const moduleName = 'mongodb'; return { id: 'mongodbMetrics', diff --git a/src/legacy/core_plugins/kibana/server/tutorials/mssql_metrics/index.js b/src/legacy/core_plugins/kibana/server/tutorials/mssql_metrics/index.js index 58c5acca6f1b1..201f1de69daa6 100644 --- a/src/legacy/core_plugins/kibana/server/tutorials/mssql_metrics/index.js +++ b/src/legacy/core_plugins/kibana/server/tutorials/mssql_metrics/index.js @@ -21,7 +21,7 @@ import { i18n } from '@kbn/i18n'; import { TUTORIAL_CATEGORY } from '../../../common/tutorials/tutorial_category'; import { onPremInstructions, cloudInstructions, onPremCloudInstructions } from '../../../common/tutorials/metricbeat_instructions'; -export function mssqlMetricsSpecProvider(server, context) { +export function mssqlMetricsSpecProvider(context) { const moduleName = 'mssql'; return { id: 'mssqlMetrics', diff --git a/src/legacy/core_plugins/kibana/server/tutorials/munin_metrics/index.js b/src/legacy/core_plugins/kibana/server/tutorials/munin_metrics/index.js index e6e6489dc6fca..8bf1c2a171524 100644 --- a/src/legacy/core_plugins/kibana/server/tutorials/munin_metrics/index.js +++ b/src/legacy/core_plugins/kibana/server/tutorials/munin_metrics/index.js @@ -21,7 +21,7 @@ import { i18n } from '@kbn/i18n'; import { TUTORIAL_CATEGORY } from '../../../common/tutorials/tutorial_category'; import { onPremInstructions, cloudInstructions, onPremCloudInstructions } from '../../../common/tutorials/metricbeat_instructions'; -export function muninMetricsSpecProvider(server, context) { +export function muninMetricsSpecProvider(context) { const moduleName = 'munin'; return { id: 'muninMetrics', diff --git a/src/legacy/core_plugins/kibana/server/tutorials/mysql_logs/index.js b/src/legacy/core_plugins/kibana/server/tutorials/mysql_logs/index.js index e3425d4531b42..56607b421864d 100644 --- a/src/legacy/core_plugins/kibana/server/tutorials/mysql_logs/index.js +++ b/src/legacy/core_plugins/kibana/server/tutorials/mysql_logs/index.js @@ -21,7 +21,7 @@ import { i18n } from '@kbn/i18n'; import { TUTORIAL_CATEGORY } from '../../../common/tutorials/tutorial_category'; import { onPremInstructions, cloudInstructions, onPremCloudInstructions } from '../../../common/tutorials/filebeat_instructions'; -export function mysqlLogsSpecProvider(server, context) { +export function mysqlLogsSpecProvider(context) { const moduleName = 'mysql'; const platforms = ['OSX', 'DEB', 'RPM', 'WINDOWS']; return { diff --git a/src/legacy/core_plugins/kibana/server/tutorials/mysql_metrics/index.js b/src/legacy/core_plugins/kibana/server/tutorials/mysql_metrics/index.js index c7c60406106ea..c7cc4688efa02 100644 --- a/src/legacy/core_plugins/kibana/server/tutorials/mysql_metrics/index.js +++ b/src/legacy/core_plugins/kibana/server/tutorials/mysql_metrics/index.js @@ -21,7 +21,7 @@ import { i18n } from '@kbn/i18n'; import { TUTORIAL_CATEGORY } from '../../../common/tutorials/tutorial_category'; import { onPremInstructions, cloudInstructions, onPremCloudInstructions } from '../../../common/tutorials/metricbeat_instructions'; -export function mysqlMetricsSpecProvider(server, context) { +export function mysqlMetricsSpecProvider(context) { const moduleName = 'mysql'; return { id: 'mysqlMetrics', diff --git a/src/legacy/core_plugins/kibana/server/tutorials/nats_logs/index.js b/src/legacy/core_plugins/kibana/server/tutorials/nats_logs/index.js index badaa338bff43..9da1787d9742f 100644 --- a/src/legacy/core_plugins/kibana/server/tutorials/nats_logs/index.js +++ b/src/legacy/core_plugins/kibana/server/tutorials/nats_logs/index.js @@ -21,7 +21,7 @@ import { i18n } from '@kbn/i18n'; import { TUTORIAL_CATEGORY } from '../../../common/tutorials/tutorial_category'; import { onPremInstructions, cloudInstructions, onPremCloudInstructions } from '../../../common/tutorials/filebeat_instructions'; -export function natsLogsSpecProvider(server, context) { +export function natsLogsSpecProvider(context) { const moduleName = 'nats'; const geoipRequired = false; const uaRequired = false; diff --git a/src/legacy/core_plugins/kibana/server/tutorials/nats_metrics/index.js b/src/legacy/core_plugins/kibana/server/tutorials/nats_metrics/index.js index 53f7dd531cbbd..f3be55ccbc904 100644 --- a/src/legacy/core_plugins/kibana/server/tutorials/nats_metrics/index.js +++ b/src/legacy/core_plugins/kibana/server/tutorials/nats_metrics/index.js @@ -21,7 +21,7 @@ import { i18n } from '@kbn/i18n'; import { TUTORIAL_CATEGORY } from '../../../common/tutorials/tutorial_category'; import { onPremInstructions, cloudInstructions, onPremCloudInstructions } from '../../../common/tutorials/metricbeat_instructions'; -export function natsMetricsSpecProvider(server, context) { +export function natsMetricsSpecProvider(context) { const moduleName = 'nats'; return { id: 'natsMetrics', diff --git a/src/legacy/core_plugins/kibana/server/tutorials/nginx_logs/index.js b/src/legacy/core_plugins/kibana/server/tutorials/nginx_logs/index.js index b08fa2729c1af..18bd3f649313f 100644 --- a/src/legacy/core_plugins/kibana/server/tutorials/nginx_logs/index.js +++ b/src/legacy/core_plugins/kibana/server/tutorials/nginx_logs/index.js @@ -21,7 +21,7 @@ import { i18n } from '@kbn/i18n'; import { TUTORIAL_CATEGORY } from '../../../common/tutorials/tutorial_category'; import { onPremInstructions, cloudInstructions, onPremCloudInstructions } from '../../../common/tutorials/filebeat_instructions'; -export function nginxLogsSpecProvider(server, context) { +export function nginxLogsSpecProvider(context) { const moduleName = 'nginx'; const platforms = ['OSX', 'DEB', 'RPM', 'WINDOWS']; return { diff --git a/src/legacy/core_plugins/kibana/server/tutorials/nginx_metrics/index.js b/src/legacy/core_plugins/kibana/server/tutorials/nginx_metrics/index.js index 99bee7c3a5510..f0ebe92295119 100644 --- a/src/legacy/core_plugins/kibana/server/tutorials/nginx_metrics/index.js +++ b/src/legacy/core_plugins/kibana/server/tutorials/nginx_metrics/index.js @@ -21,7 +21,7 @@ import { i18n } from '@kbn/i18n'; import { TUTORIAL_CATEGORY } from '../../../common/tutorials/tutorial_category'; import { onPremInstructions, cloudInstructions, onPremCloudInstructions } from '../../../common/tutorials/metricbeat_instructions'; -export function nginxMetricsSpecProvider(server, context) { +export function nginxMetricsSpecProvider(context) { const moduleName = 'nginx'; return { id: 'nginxMetrics', diff --git a/src/legacy/core_plugins/kibana/server/tutorials/osquery_logs/index.js b/src/legacy/core_plugins/kibana/server/tutorials/osquery_logs/index.js index c435e95db2acb..eddb81a9762e3 100644 --- a/src/legacy/core_plugins/kibana/server/tutorials/osquery_logs/index.js +++ b/src/legacy/core_plugins/kibana/server/tutorials/osquery_logs/index.js @@ -25,7 +25,7 @@ import { onPremCloudInstructions, } from '../../../common/tutorials/filebeat_instructions'; -export function osqueryLogsSpecProvider(server, context) { +export function osqueryLogsSpecProvider(context) { const moduleName = 'osquery'; const platforms = ['OSX', 'DEB', 'RPM', 'WINDOWS']; return { diff --git a/src/legacy/core_plugins/kibana/server/tutorials/php_fpm_metrics/index.js b/src/legacy/core_plugins/kibana/server/tutorials/php_fpm_metrics/index.js index 077574d70615d..1e55be37e4c52 100644 --- a/src/legacy/core_plugins/kibana/server/tutorials/php_fpm_metrics/index.js +++ b/src/legacy/core_plugins/kibana/server/tutorials/php_fpm_metrics/index.js @@ -21,7 +21,7 @@ import { i18n } from '@kbn/i18n'; import { TUTORIAL_CATEGORY } from '../../../common/tutorials/tutorial_category'; import { onPremInstructions, cloudInstructions, onPremCloudInstructions } from '../../../common/tutorials/metricbeat_instructions'; -export function phpfpmMetricsSpecProvider(server, context) { +export function phpfpmMetricsSpecProvider(context) { const moduleName = 'php_fpm'; return { id: 'phpfpmMetrics', diff --git a/src/legacy/core_plugins/kibana/server/tutorials/postgresql_logs/index.js b/src/legacy/core_plugins/kibana/server/tutorials/postgresql_logs/index.js index 2f7ea4558476c..a79394fa75fe7 100644 --- a/src/legacy/core_plugins/kibana/server/tutorials/postgresql_logs/index.js +++ b/src/legacy/core_plugins/kibana/server/tutorials/postgresql_logs/index.js @@ -21,7 +21,7 @@ import { i18n } from '@kbn/i18n'; import { TUTORIAL_CATEGORY } from '../../../common/tutorials/tutorial_category'; import { onPremInstructions, cloudInstructions, onPremCloudInstructions } from '../../../common/tutorials/filebeat_instructions'; -export function postgresqlLogsSpecProvider(server, context) { +export function postgresqlLogsSpecProvider(context) { const moduleName = 'postgresql'; const platforms = ['OSX', 'DEB', 'RPM', 'WINDOWS']; return { diff --git a/src/legacy/core_plugins/kibana/server/tutorials/postgresql_metrics/index.js b/src/legacy/core_plugins/kibana/server/tutorials/postgresql_metrics/index.js index 6690979d55cc7..74bf88da864b6 100644 --- a/src/legacy/core_plugins/kibana/server/tutorials/postgresql_metrics/index.js +++ b/src/legacy/core_plugins/kibana/server/tutorials/postgresql_metrics/index.js @@ -21,7 +21,7 @@ import { i18n } from '@kbn/i18n'; import { TUTORIAL_CATEGORY } from '../../../common/tutorials/tutorial_category'; import { onPremInstructions, cloudInstructions, onPremCloudInstructions } from '../../../common/tutorials/metricbeat_instructions'; -export function postgresqlMetricsSpecProvider(server, context) { +export function postgresqlMetricsSpecProvider(context) { const moduleName = 'postgresql'; return { id: 'postgresqlMetrics', diff --git a/src/legacy/core_plugins/kibana/server/tutorials/prometheus_metrics/index.js b/src/legacy/core_plugins/kibana/server/tutorials/prometheus_metrics/index.js index ccede68549f31..8e21833afb5a5 100644 --- a/src/legacy/core_plugins/kibana/server/tutorials/prometheus_metrics/index.js +++ b/src/legacy/core_plugins/kibana/server/tutorials/prometheus_metrics/index.js @@ -21,7 +21,7 @@ import { i18n } from '@kbn/i18n'; import { TUTORIAL_CATEGORY } from '../../../common/tutorials/tutorial_category'; import { onPremInstructions, cloudInstructions, onPremCloudInstructions } from '../../../common/tutorials/metricbeat_instructions'; -export function prometheusMetricsSpecProvider(server, context) { +export function prometheusMetricsSpecProvider(context) { const moduleName = 'prometheus'; return { id: moduleName + 'Metrics', diff --git a/src/legacy/core_plugins/kibana/server/tutorials/rabbitmq_metrics/index.js b/src/legacy/core_plugins/kibana/server/tutorials/rabbitmq_metrics/index.js index f40fe41124382..9a8a040ce8b86 100644 --- a/src/legacy/core_plugins/kibana/server/tutorials/rabbitmq_metrics/index.js +++ b/src/legacy/core_plugins/kibana/server/tutorials/rabbitmq_metrics/index.js @@ -21,7 +21,7 @@ import { i18n } from '@kbn/i18n'; import { TUTORIAL_CATEGORY } from '../../../common/tutorials/tutorial_category'; import { onPremInstructions, cloudInstructions, onPremCloudInstructions } from '../../../common/tutorials/metricbeat_instructions'; -export function rabbitmqMetricsSpecProvider(server, context) { +export function rabbitmqMetricsSpecProvider(context) { const moduleName = 'rabbitmq'; return { id: 'rabbitmqMetrics', diff --git a/src/legacy/core_plugins/kibana/server/tutorials/redis_logs/index.js b/src/legacy/core_plugins/kibana/server/tutorials/redis_logs/index.js index d37e6d66bdd3a..dc31203ff928c 100644 --- a/src/legacy/core_plugins/kibana/server/tutorials/redis_logs/index.js +++ b/src/legacy/core_plugins/kibana/server/tutorials/redis_logs/index.js @@ -21,7 +21,7 @@ import { i18n } from '@kbn/i18n'; import { TUTORIAL_CATEGORY } from '../../../common/tutorials/tutorial_category'; import { onPremInstructions, cloudInstructions, onPremCloudInstructions } from '../../../common/tutorials/filebeat_instructions'; -export function redisLogsSpecProvider(server, context) { +export function redisLogsSpecProvider(context) { const moduleName = 'redis'; const platforms = ['OSX', 'DEB', 'RPM', 'WINDOWS']; return { diff --git a/src/legacy/core_plugins/kibana/server/tutorials/redis_metrics/index.js b/src/legacy/core_plugins/kibana/server/tutorials/redis_metrics/index.js index e92dd15bfc962..a6177b0c551a0 100644 --- a/src/legacy/core_plugins/kibana/server/tutorials/redis_metrics/index.js +++ b/src/legacy/core_plugins/kibana/server/tutorials/redis_metrics/index.js @@ -21,7 +21,7 @@ import { i18n } from '@kbn/i18n'; import { TUTORIAL_CATEGORY } from '../../../common/tutorials/tutorial_category'; import { onPremInstructions, cloudInstructions, onPremCloudInstructions } from '../../../common/tutorials/metricbeat_instructions'; -export function redisMetricsSpecProvider(server, context) { +export function redisMetricsSpecProvider(context) { const moduleName = 'redis'; return { id: 'redisMetrics', diff --git a/src/legacy/core_plugins/kibana/server/tutorials/register.js b/src/legacy/core_plugins/kibana/server/tutorials/register.js index a95baad4ccb65..f1f65acf131ce 100644 --- a/src/legacy/core_plugins/kibana/server/tutorials/register.js +++ b/src/legacy/core_plugins/kibana/server/tutorials/register.js @@ -16,7 +16,6 @@ * specific language governing permissions and limitations * under the License. */ - import { systemLogsSpecProvider } from './system_logs'; import { systemMetricsSpecProvider } from './system_metrics'; import { apacheLogsSpecProvider } from './apache_logs'; @@ -81,66 +80,66 @@ import { consulMetricsSpecProvider } from './consul_metrics'; import { cockroachdbMetricsSpecProvider } from './cockroachdb_metrics'; export function registerTutorials(server) { - server.registerTutorial(systemLogsSpecProvider); - server.registerTutorial(systemMetricsSpecProvider); - server.registerTutorial(apacheLogsSpecProvider); - server.registerTutorial(apacheMetricsSpecProvider); - server.registerTutorial(elasticsearchLogsSpecProvider); - server.registerTutorial(iisLogsSpecProvider); - server.registerTutorial(kafkaLogsSpecProvider); - server.registerTutorial(logstashLogsSpecProvider); - server.registerTutorial(nginxLogsSpecProvider); - server.registerTutorial(nginxMetricsSpecProvider); - server.registerTutorial(mysqlLogsSpecProvider); - server.registerTutorial(mysqlMetricsSpecProvider); - server.registerTutorial(mongodbMetricsSpecProvider); - server.registerTutorial(osqueryLogsSpecProvider); - server.registerTutorial(phpfpmMetricsSpecProvider); - server.registerTutorial(postgresqlMetricsSpecProvider); - server.registerTutorial(postgresqlLogsSpecProvider); - server.registerTutorial(rabbitmqMetricsSpecProvider); - server.registerTutorial(redisLogsSpecProvider); - server.registerTutorial(redisMetricsSpecProvider); - server.registerTutorial(suricataLogsSpecProvider); - server.registerTutorial(dockerMetricsSpecProvider); - server.registerTutorial(kubernetesMetricsSpecProvider); - server.registerTutorial(uwsgiMetricsSpecProvider); - server.registerTutorial(netflowSpecProvider); - server.registerTutorial(traefikLogsSpecProvider); + server.newPlatform.setup.plugins.home.tutorials.registerTutorial(systemLogsSpecProvider); + server.newPlatform.setup.plugins.home.tutorials.registerTutorial(systemMetricsSpecProvider); + server.newPlatform.setup.plugins.home.tutorials.registerTutorial(apacheLogsSpecProvider); + server.newPlatform.setup.plugins.home.tutorials.registerTutorial(apacheMetricsSpecProvider); + server.newPlatform.setup.plugins.home.tutorials.registerTutorial(elasticsearchLogsSpecProvider); + server.newPlatform.setup.plugins.home.tutorials.registerTutorial(iisLogsSpecProvider); + server.newPlatform.setup.plugins.home.tutorials.registerTutorial(kafkaLogsSpecProvider); + server.newPlatform.setup.plugins.home.tutorials.registerTutorial(logstashLogsSpecProvider); + server.newPlatform.setup.plugins.home.tutorials.registerTutorial(nginxLogsSpecProvider); + server.newPlatform.setup.plugins.home.tutorials.registerTutorial(nginxMetricsSpecProvider); + server.newPlatform.setup.plugins.home.tutorials.registerTutorial(mysqlLogsSpecProvider); + server.newPlatform.setup.plugins.home.tutorials.registerTutorial(mysqlMetricsSpecProvider); + server.newPlatform.setup.plugins.home.tutorials.registerTutorial(mongodbMetricsSpecProvider); + server.newPlatform.setup.plugins.home.tutorials.registerTutorial(osqueryLogsSpecProvider); + server.newPlatform.setup.plugins.home.tutorials.registerTutorial(phpfpmMetricsSpecProvider); + server.newPlatform.setup.plugins.home.tutorials.registerTutorial(postgresqlMetricsSpecProvider); + server.newPlatform.setup.plugins.home.tutorials.registerTutorial(postgresqlLogsSpecProvider); + server.newPlatform.setup.plugins.home.tutorials.registerTutorial(rabbitmqMetricsSpecProvider); + server.newPlatform.setup.plugins.home.tutorials.registerTutorial(redisLogsSpecProvider); + server.newPlatform.setup.plugins.home.tutorials.registerTutorial(redisMetricsSpecProvider); + server.newPlatform.setup.plugins.home.tutorials.registerTutorial(suricataLogsSpecProvider); + server.newPlatform.setup.plugins.home.tutorials.registerTutorial(dockerMetricsSpecProvider); + server.newPlatform.setup.plugins.home.tutorials.registerTutorial(kubernetesMetricsSpecProvider); + server.newPlatform.setup.plugins.home.tutorials.registerTutorial(uwsgiMetricsSpecProvider); + server.newPlatform.setup.plugins.home.tutorials.registerTutorial(netflowSpecProvider); + server.newPlatform.setup.plugins.home.tutorials.registerTutorial(traefikLogsSpecProvider); server.registerTutorial(apmSpecProvider); - server.registerTutorial(cephMetricsSpecProvider); - server.registerTutorial(aerospikeMetricsSpecProvider); - server.registerTutorial(couchbaseMetricsSpecProvider); - server.registerTutorial(dropwizardMetricsSpecProvider); - server.registerTutorial(elasticsearchMetricsSpecProvider); - server.registerTutorial(etcdMetricsSpecProvider); - server.registerTutorial(haproxyMetricsSpecProvider); - server.registerTutorial(kafkaMetricsSpecProvider); - server.registerTutorial(kibanaMetricsSpecProvider); - server.registerTutorial(memcachedMetricsSpecProvider); - server.registerTutorial(muninMetricsSpecProvider); - server.registerTutorial(vSphereMetricsSpecProvider); - server.registerTutorial(windowsMetricsSpecProvider); - server.registerTutorial(windowsEventLogsSpecProvider); - server.registerTutorial(golangMetricsSpecProvider); - server.registerTutorial(logstashMetricsSpecProvider); - server.registerTutorial(prometheusMetricsSpecProvider); - server.registerTutorial(zookeeperMetricsSpecProvider); - server.registerTutorial(uptimeMonitorsSpecProvider); - server.registerTutorial(cloudwatchLogsSpecProvider); - server.registerTutorial(awsMetricsSpecProvider); - server.registerTutorial(mssqlMetricsSpecProvider); - server.registerTutorial(natsMetricsSpecProvider); - server.registerTutorial(natsLogsSpecProvider); - server.registerTutorial(zeekLogsSpecProvider); - server.registerTutorial(corednsMetricsSpecProvider); - server.registerTutorial(corednsLogsSpecProvider); - server.registerTutorial(auditbeatSpecProvider); - server.registerTutorial(iptablesLogsSpecProvider); - server.registerTutorial(ciscoLogsSpecProvider); - server.registerTutorial(envoyproxyLogsSpecProvider); - server.registerTutorial(couchdbMetricsSpecProvider); + server.newPlatform.setup.plugins.home.tutorials.registerTutorial(cephMetricsSpecProvider); + server.newPlatform.setup.plugins.home.tutorials.registerTutorial(aerospikeMetricsSpecProvider); + server.newPlatform.setup.plugins.home.tutorials.registerTutorial(couchbaseMetricsSpecProvider); + server.newPlatform.setup.plugins.home.tutorials.registerTutorial(dropwizardMetricsSpecProvider); + server.newPlatform.setup.plugins.home.tutorials.registerTutorial(elasticsearchMetricsSpecProvider); + server.newPlatform.setup.plugins.home.tutorials.registerTutorial(etcdMetricsSpecProvider); + server.newPlatform.setup.plugins.home.tutorials.registerTutorial(haproxyMetricsSpecProvider); + server.newPlatform.setup.plugins.home.tutorials.registerTutorial(kafkaMetricsSpecProvider); + server.newPlatform.setup.plugins.home.tutorials.registerTutorial(kibanaMetricsSpecProvider); + server.newPlatform.setup.plugins.home.tutorials.registerTutorial(memcachedMetricsSpecProvider); + server.newPlatform.setup.plugins.home.tutorials.registerTutorial(muninMetricsSpecProvider); + server.newPlatform.setup.plugins.home.tutorials.registerTutorial(vSphereMetricsSpecProvider); + server.newPlatform.setup.plugins.home.tutorials.registerTutorial(windowsMetricsSpecProvider); + server.newPlatform.setup.plugins.home.tutorials.registerTutorial(windowsEventLogsSpecProvider); + server.newPlatform.setup.plugins.home.tutorials.registerTutorial(golangMetricsSpecProvider); + server.newPlatform.setup.plugins.home.tutorials.registerTutorial(logstashMetricsSpecProvider); + server.newPlatform.setup.plugins.home.tutorials.registerTutorial(prometheusMetricsSpecProvider); + server.newPlatform.setup.plugins.home.tutorials.registerTutorial(zookeeperMetricsSpecProvider); + server.newPlatform.setup.plugins.home.tutorials.registerTutorial(uptimeMonitorsSpecProvider); + server.newPlatform.setup.plugins.home.tutorials.registerTutorial(cloudwatchLogsSpecProvider); + server.newPlatform.setup.plugins.home.tutorials.registerTutorial(awsMetricsSpecProvider); + server.newPlatform.setup.plugins.home.tutorials.registerTutorial(mssqlMetricsSpecProvider); + server.newPlatform.setup.plugins.home.tutorials.registerTutorial(natsMetricsSpecProvider); + server.newPlatform.setup.plugins.home.tutorials.registerTutorial(natsLogsSpecProvider); + server.newPlatform.setup.plugins.home.tutorials.registerTutorial(zeekLogsSpecProvider); + server.newPlatform.setup.plugins.home.tutorials.registerTutorial(corednsMetricsSpecProvider); + server.newPlatform.setup.plugins.home.tutorials.registerTutorial(corednsLogsSpecProvider); + server.newPlatform.setup.plugins.home.tutorials.registerTutorial(auditbeatSpecProvider); + server.newPlatform.setup.plugins.home.tutorials.registerTutorial(iptablesLogsSpecProvider); + server.newPlatform.setup.plugins.home.tutorials.registerTutorial(ciscoLogsSpecProvider); + server.newPlatform.setup.plugins.home.tutorials.registerTutorial(envoyproxyLogsSpecProvider); + server.newPlatform.setup.plugins.home.tutorials.registerTutorial(couchdbMetricsSpecProvider); server.registerTutorial(emsBoundariesSpecProvider); - server.registerTutorial(consulMetricsSpecProvider); - server.registerTutorial(cockroachdbMetricsSpecProvider); + server.newPlatform.setup.plugins.home.tutorials.registerTutorial(consulMetricsSpecProvider); + server.newPlatform.setup.plugins.home.tutorials.registerTutorial(cockroachdbMetricsSpecProvider); } diff --git a/src/legacy/core_plugins/kibana/server/tutorials/suricata_logs/index.js b/src/legacy/core_plugins/kibana/server/tutorials/suricata_logs/index.js index e4e9d5b7e0fd8..3f2ecfa78d3b2 100644 --- a/src/legacy/core_plugins/kibana/server/tutorials/suricata_logs/index.js +++ b/src/legacy/core_plugins/kibana/server/tutorials/suricata_logs/index.js @@ -25,7 +25,7 @@ import { onPremCloudInstructions, } from '../../../common/tutorials/filebeat_instructions'; -export function suricataLogsSpecProvider(server, context) { +export function suricataLogsSpecProvider(context) { const moduleName = 'suricata'; const platforms = ['OSX', 'DEB', 'RPM', 'WINDOWS']; return { diff --git a/src/legacy/core_plugins/kibana/server/tutorials/system_logs/index.js b/src/legacy/core_plugins/kibana/server/tutorials/system_logs/index.js index a9b8018762c85..efba0c00cbbc3 100644 --- a/src/legacy/core_plugins/kibana/server/tutorials/system_logs/index.js +++ b/src/legacy/core_plugins/kibana/server/tutorials/system_logs/index.js @@ -21,7 +21,7 @@ import { i18n } from '@kbn/i18n'; import { TUTORIAL_CATEGORY } from '../../../common/tutorials/tutorial_category'; import { onPremInstructions, cloudInstructions, onPremCloudInstructions } from '../../../common/tutorials/filebeat_instructions'; -export function systemLogsSpecProvider(server, context) { +export function systemLogsSpecProvider(context) { const moduleName = 'system'; const platforms = ['OSX', 'DEB', 'RPM']; return { diff --git a/src/legacy/core_plugins/kibana/server/tutorials/system_metrics/index.js b/src/legacy/core_plugins/kibana/server/tutorials/system_metrics/index.js index 563c065a41a8f..4c6fd20aa56c4 100644 --- a/src/legacy/core_plugins/kibana/server/tutorials/system_metrics/index.js +++ b/src/legacy/core_plugins/kibana/server/tutorials/system_metrics/index.js @@ -21,7 +21,7 @@ import { i18n } from '@kbn/i18n'; import { TUTORIAL_CATEGORY } from '../../../common/tutorials/tutorial_category'; import { onPremInstructions, cloudInstructions, onPremCloudInstructions } from '../../../common/tutorials/metricbeat_instructions'; -export function systemMetricsSpecProvider(server, context) { +export function systemMetricsSpecProvider(context) { const moduleName = 'system'; return { id: 'systemMetrics', diff --git a/src/legacy/core_plugins/kibana/server/tutorials/traefik_logs/index.js b/src/legacy/core_plugins/kibana/server/tutorials/traefik_logs/index.js index 2b05b2669737e..b9b2d4d7e3e5b 100644 --- a/src/legacy/core_plugins/kibana/server/tutorials/traefik_logs/index.js +++ b/src/legacy/core_plugins/kibana/server/tutorials/traefik_logs/index.js @@ -21,7 +21,7 @@ import { i18n } from '@kbn/i18n'; import { TUTORIAL_CATEGORY } from '../../../common/tutorials/tutorial_category'; import { onPremInstructions, cloudInstructions, onPremCloudInstructions } from '../../../common/tutorials/filebeat_instructions'; -export function traefikLogsSpecProvider(server, context) { +export function traefikLogsSpecProvider(context) { const moduleName = 'traefik'; const platforms = ['OSX', 'DEB', 'RPM', 'WINDOWS']; return { diff --git a/src/legacy/core_plugins/kibana/server/tutorials/uptime_monitors/index.js b/src/legacy/core_plugins/kibana/server/tutorials/uptime_monitors/index.js index 8ba0ba1ecc910..7cc90c740eb69 100644 --- a/src/legacy/core_plugins/kibana/server/tutorials/uptime_monitors/index.js +++ b/src/legacy/core_plugins/kibana/server/tutorials/uptime_monitors/index.js @@ -25,7 +25,7 @@ import { onPremCloudInstructions, } from '../../../common/tutorials/heartbeat_instructions'; -export function uptimeMonitorsSpecProvider(server, context) { +export function uptimeMonitorsSpecProvider(context) { return { id: 'uptimeMonitors', name: i18n.translate('kbn.server.tutorials.uptimeMonitors.nameTitle', { diff --git a/src/legacy/core_plugins/kibana/server/tutorials/uwsgi_metrics/index.js b/src/legacy/core_plugins/kibana/server/tutorials/uwsgi_metrics/index.js index a0dd93524f43f..7c5f8e88b50dc 100644 --- a/src/legacy/core_plugins/kibana/server/tutorials/uwsgi_metrics/index.js +++ b/src/legacy/core_plugins/kibana/server/tutorials/uwsgi_metrics/index.js @@ -21,7 +21,7 @@ import { i18n } from '@kbn/i18n'; import { TUTORIAL_CATEGORY } from '../../../common/tutorials/tutorial_category'; import { onPremInstructions, cloudInstructions, onPremCloudInstructions } from '../../../common/tutorials/metricbeat_instructions'; -export function uwsgiMetricsSpecProvider(server, context) { +export function uwsgiMetricsSpecProvider(context) { const moduleName = 'uwsgi'; return { id: 'uwsgiMetrics', diff --git a/src/legacy/core_plugins/kibana/server/tutorials/vsphere_metrics/index.js b/src/legacy/core_plugins/kibana/server/tutorials/vsphere_metrics/index.js index 0ba6430c5cfd6..7de8fd8fc445b 100644 --- a/src/legacy/core_plugins/kibana/server/tutorials/vsphere_metrics/index.js +++ b/src/legacy/core_plugins/kibana/server/tutorials/vsphere_metrics/index.js @@ -21,7 +21,7 @@ import { i18n } from '@kbn/i18n'; import { TUTORIAL_CATEGORY } from '../../../common/tutorials/tutorial_category'; import { onPremInstructions, cloudInstructions, onPremCloudInstructions } from '../../../common/tutorials/metricbeat_instructions'; -export function vSphereMetricsSpecProvider(server, context) { +export function vSphereMetricsSpecProvider(context) { const moduleName = 'vsphere'; return { id: 'vsphereMetrics', diff --git a/src/legacy/core_plugins/kibana/server/tutorials/windows_event_logs/index.js b/src/legacy/core_plugins/kibana/server/tutorials/windows_event_logs/index.js index cd2ee09c09f74..272535ad3e4e1 100644 --- a/src/legacy/core_plugins/kibana/server/tutorials/windows_event_logs/index.js +++ b/src/legacy/core_plugins/kibana/server/tutorials/windows_event_logs/index.js @@ -25,7 +25,7 @@ import { onPremCloudInstructions, } from '../../../common/tutorials/winlogbeat_instructions'; -export function windowsEventLogsSpecProvider(server, context) { +export function windowsEventLogsSpecProvider(context) { return { id: 'windowsEventLogs', name: i18n.translate('kbn.server.tutorials.windowsEventLogs.nameTitle', { diff --git a/src/legacy/core_plugins/kibana/server/tutorials/windows_metrics/index.js b/src/legacy/core_plugins/kibana/server/tutorials/windows_metrics/index.js index 8f9e04103cc0a..eb2f2aeec7e5e 100644 --- a/src/legacy/core_plugins/kibana/server/tutorials/windows_metrics/index.js +++ b/src/legacy/core_plugins/kibana/server/tutorials/windows_metrics/index.js @@ -21,7 +21,7 @@ import { i18n } from '@kbn/i18n'; import { TUTORIAL_CATEGORY } from '../../../common/tutorials/tutorial_category'; import { onPremInstructions, cloudInstructions, onPremCloudInstructions } from '../../../common/tutorials/metricbeat_instructions'; -export function windowsMetricsSpecProvider(server, context) { +export function windowsMetricsSpecProvider(context) { const moduleName = 'windows'; return { id: 'windowsMetrics', diff --git a/src/legacy/core_plugins/kibana/server/tutorials/zeek_logs/index.js b/src/legacy/core_plugins/kibana/server/tutorials/zeek_logs/index.js index 839a9c81f948e..07d46c9c6ae84 100644 --- a/src/legacy/core_plugins/kibana/server/tutorials/zeek_logs/index.js +++ b/src/legacy/core_plugins/kibana/server/tutorials/zeek_logs/index.js @@ -25,7 +25,7 @@ import { onPremCloudInstructions, } from '../../../common/tutorials/filebeat_instructions'; -export function zeekLogsSpecProvider(server, context) { +export function zeekLogsSpecProvider(context) { const moduleName = 'zeek'; const platforms = ['OSX', 'DEB', 'RPM']; return { diff --git a/src/legacy/core_plugins/kibana/server/tutorials/zookeeper_metrics/index.js b/src/legacy/core_plugins/kibana/server/tutorials/zookeeper_metrics/index.js index 22527073b1680..9be44a257a8b4 100644 --- a/src/legacy/core_plugins/kibana/server/tutorials/zookeeper_metrics/index.js +++ b/src/legacy/core_plugins/kibana/server/tutorials/zookeeper_metrics/index.js @@ -21,7 +21,7 @@ import { i18n } from '@kbn/i18n'; import { TUTORIAL_CATEGORY } from '../../../common/tutorials/tutorial_category'; import { onPremInstructions, cloudInstructions, onPremCloudInstructions } from '../../../common/tutorials/metricbeat_instructions'; -export function zookeeperMetricsSpecProvider(server, context) { +export function zookeeperMetricsSpecProvider(context) { const moduleName = 'zookeeper'; return { id: moduleName + 'Metrics', diff --git a/src/legacy/core_plugins/telemetry/index.ts b/src/legacy/core_plugins/telemetry/index.ts index 9993f2dbf0b86..5ae0d5f127eed 100644 --- a/src/legacy/core_plugins/telemetry/index.ts +++ b/src/legacy/core_plugins/telemetry/index.ts @@ -112,6 +112,7 @@ const telemetry = (kibana: any) => { telemetryOptInStatusUrl: config.get('telemetry.optInStatusUrl'), allowChangingOptInStatus: config.get('telemetry.allowChangingOptInStatus'), telemetrySendUsageFrom: config.get('telemetry.sendUsageFrom'), + telemetryNotifyUserAboutOptInDefault: false, }; }, hacks: ['plugins/telemetry/hacks/telemetry_init', 'plugins/telemetry/hacks/telemetry_opt_in'], diff --git a/src/legacy/core_plugins/telemetry/mappings.json b/src/legacy/core_plugins/telemetry/mappings.json index 95c6ebfc7dc79..a88372a5578e8 100644 --- a/src/legacy/core_plugins/telemetry/mappings.json +++ b/src/legacy/core_plugins/telemetry/mappings.json @@ -14,6 +14,9 @@ "lastVersionChecked": { "ignore_above": 256, "type": "keyword" + }, + "userHasSeenNotice": { + "type": "boolean" } } } diff --git a/src/legacy/core_plugins/telemetry/public/components/__snapshots__/opted_in_notice_banner.test.tsx.snap b/src/legacy/core_plugins/telemetry/public/components/__snapshots__/opted_in_notice_banner.test.tsx.snap new file mode 100644 index 0000000000000..9c26909dc68f1 --- /dev/null +++ b/src/legacy/core_plugins/telemetry/public/components/__snapshots__/opted_in_notice_banner.test.tsx.snap @@ -0,0 +1,51 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`OptInDetailsComponent renders as expected 1`] = ` + + + + , + "privacyStatementLink": + + , + } + } + /> + + + + + +`; diff --git a/src/legacy/core_plugins/telemetry/public/components/opted_in_notice_banner.test.tsx b/src/legacy/core_plugins/telemetry/public/components/opted_in_notice_banner.test.tsx new file mode 100644 index 0000000000000..008603526be38 --- /dev/null +++ b/src/legacy/core_plugins/telemetry/public/components/opted_in_notice_banner.test.tsx @@ -0,0 +1,43 @@ +/* + * 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 { EuiButton } from '@elastic/eui'; +import { shallowWithIntl } from 'test_utils/enzyme_helpers'; +import { OptedInBanner } from './opted_in_notice_banner'; + +describe('OptInDetailsComponent', () => { + it('renders as expected', () => { + expect(shallowWithIntl( {}} />)).toMatchSnapshot(); + }); + + it('fires the "onSeenBanner" prop when a link is clicked', () => { + const onLinkClick = jest.fn(); + const component = shallowWithIntl(); + + const button = component.findWhere(n => n.type() === EuiButton); + + if (!button) { + throw new Error(`Couldn't find any buttons in opt-in notice`); + } + + button.simulate('click'); + + expect(onLinkClick).toHaveBeenCalled(); + }); +}); diff --git a/src/legacy/core_plugins/telemetry/public/components/opted_in_notice_banner.tsx b/src/legacy/core_plugins/telemetry/public/components/opted_in_notice_banner.tsx new file mode 100644 index 0000000000000..a535835f7cb83 --- /dev/null +++ b/src/legacy/core_plugins/telemetry/public/components/opted_in_notice_banner.tsx @@ -0,0 +1,79 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/* eslint @elastic/eui/href-or-on-click:0 */ + +import * as React from 'react'; +import { EuiButton, EuiLink, EuiCallOut, EuiSpacer } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n/react'; + +interface Props { + onSeenBanner: () => any; +} + +/** + * React component for displaying the Telemetry opt-in notice. + */ +export class OptedInBanner extends React.PureComponent { + onLinkClick = () => { + this.props.onSeenBanner(); + return; + }; + + render() { + return ( + + + + + ), + disableLink: ( + + + + ), + }} + /> + + + + + + ); + } +} diff --git a/src/legacy/core_plugins/telemetry/public/hacks/welcome_banner/inject_banner.js b/src/legacy/core_plugins/telemetry/public/hacks/welcome_banner/inject_banner.js index 13417a137e6c3..c4c5c3e9e0aa2 100644 --- a/src/legacy/core_plugins/telemetry/public/hacks/welcome_banner/inject_banner.js +++ b/src/legacy/core_plugins/telemetry/public/hacks/welcome_banner/inject_banner.js @@ -21,7 +21,9 @@ import chrome from 'ui/chrome'; import { fetchTelemetry } from '../fetch_telemetry'; import { renderBanner } from './render_banner'; +import { renderOptedInBanner } from './render_notice_banner'; import { shouldShowBanner } from './should_show_banner'; +import { shouldShowOptInBanner } from './should_show_opt_in_banner'; import { TelemetryOptInProvider, isUnauthenticated } from '../../services'; import { npStart } from 'ui/new_platform'; @@ -48,12 +50,16 @@ async function asyncInjectBanner($injector) { return; } + const $http = $injector.get('$http'); + // determine if the banner should be displayed if (await shouldShowBanner(telemetryOptInProvider, config)) { - const $http = $injector.get('$http'); - renderBanner(telemetryOptInProvider, () => fetchTelemetry($http, { unencrypted: true })); } + + if (await shouldShowOptInBanner(telemetryOptInProvider, config)) { + renderOptedInBanner(telemetryOptInProvider, () => fetchTelemetry($http, { unencrypted: true })); + } } /** diff --git a/src/legacy/core_plugins/telemetry/public/hacks/welcome_banner/render_notice_banner.js b/src/legacy/core_plugins/telemetry/public/hacks/welcome_banner/render_notice_banner.js new file mode 100644 index 0000000000000..9323e4ec34e80 --- /dev/null +++ b/src/legacy/core_plugins/telemetry/public/hacks/welcome_banner/render_notice_banner.js @@ -0,0 +1,42 @@ +/* + * 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 { banners } from 'ui/notify'; +import { OptedInBanner } from '../../components/opted_in_notice_banner'; + +/** + * Render the Telemetry Opt-in notice banner. + * + * @param {Object} telemetryOptInProvider The telemetry opt-in provider. + * @param {Object} _banners Banners singleton, which can be overridden for tests. + */ +export function renderOptedInBanner(telemetryOptInProvider, { _banners = banners } = {}) { + const bannerId = _banners.add({ + component: ( + + ), + priority: 10000 + }); + + telemetryOptInProvider.setOptInBannerNoticeId(bannerId); +} diff --git a/src/legacy/core_plugins/telemetry/public/hacks/welcome_banner/render_notice_banner.test.js b/src/legacy/core_plugins/telemetry/public/hacks/welcome_banner/render_notice_banner.test.js new file mode 100644 index 0000000000000..f9571e3c793eb --- /dev/null +++ b/src/legacy/core_plugins/telemetry/public/hacks/welcome_banner/render_notice_banner.test.js @@ -0,0 +1,42 @@ +/* + * 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 '../../services/telemetry_opt_in.test.mocks'; +import { renderOptedInBanner } from './render_notice_banner'; + +describe('render_notice_banner', () => { + + it('adds a banner to banners with priority of 10000', () => { + const bannerID = 'brucer-wayne'; + + const telemetryOptInProvider = { setOptInBannerNoticeId: jest.fn() }; + const banners = { add: jest.fn().mockReturnValue(bannerID) }; + + renderOptedInBanner(telemetryOptInProvider, { _banners: banners }); + + expect(banners.add).toBeCalledTimes(1); + expect(telemetryOptInProvider.setOptInBannerNoticeId).toBeCalledWith(bannerID); + + const bannerConfig = banners.add.mock.calls[0][0]; + + expect(bannerConfig.component).not.toBe(undefined); + expect(bannerConfig.priority).toBe(10000); + }); + +}); diff --git a/src/legacy/core_plugins/telemetry/public/hacks/welcome_banner/should_show_opt_in_banner.js b/src/legacy/core_plugins/telemetry/public/hacks/welcome_banner/should_show_opt_in_banner.js new file mode 100644 index 0000000000000..45539c4eea46c --- /dev/null +++ b/src/legacy/core_plugins/telemetry/public/hacks/welcome_banner/should_show_opt_in_banner.js @@ -0,0 +1,30 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + * Determine if the notice banner should be displayed. + * + * This method can have side-effects related to deprecated config settings. + * + * @param {Object} telemetryOptInProvider The Telemetry opt-in provider singleton. + * @return {Boolean} {@code true} if the banner should be displayed. {@code false} otherwise. + */ +export async function shouldShowOptInBanner(telemetryOptInProvider) { + return telemetryOptInProvider.notifyUserAboutOptInDefault(); +} diff --git a/src/legacy/core_plugins/telemetry/public/services/telemetry_opt_in.test.js b/src/legacy/core_plugins/telemetry/public/services/telemetry_opt_in.test.js index b0ebb9e7382f6..a3103664b7be8 100644 --- a/src/legacy/core_plugins/telemetry/public/services/telemetry_opt_in.test.js +++ b/src/legacy/core_plugins/telemetry/public/services/telemetry_opt_in.test.js @@ -21,12 +21,17 @@ import { mockInjectedMetadata } from './telemetry_opt_in.test.mocks'; import { TelemetryOptInProvider } from './telemetry_opt_in'; describe('TelemetryOptInProvider', () => { - const setup = ({ optedIn, simulatePostError }) => { + const setup = ({ optedIn, simulatePostError, simulatePutError }) => { const mockHttp = { post: jest.fn(async () => { if (simulatePostError) { return Promise.reject('Something happened'); } + }), + put: jest.fn(async () => { + if (simulatePutError) { + return Promise.reject('Something happened'); + } }) }; @@ -34,7 +39,7 @@ describe('TelemetryOptInProvider', () => { addBasePath: (url) => url }; - mockInjectedMetadata({ telemetryOptedIn: optedIn, allowChangingOptInStatus: true }); + mockInjectedMetadata({ telemetryOptedIn: optedIn, allowChangingOptInStatus: true, telemetryNotifyUserAboutOptInDefault: true }); const mockInjector = { get: (key) => { @@ -98,4 +103,43 @@ describe('TelemetryOptInProvider', () => { provider.setBannerId(bannerId); expect(provider.getBannerId()).toEqual(bannerId); }); + + describe('Notice Banner', () => { + it('should return the current bannerId', () => { + const { provider } = setup({}); + const bannerId = 'bruce-wayne'; + provider.setOptInBannerNoticeId(bannerId); + + expect(provider.getOptInBannerNoticeId()).toEqual(bannerId); + expect(provider.getBannerId()).not.toEqual(bannerId); + }); + + it('should persist that a user has seen the notice', async () => { + const { provider, mockHttp } = setup({}); + await provider.setOptInNoticeSeen(); + + expect(mockHttp.put).toHaveBeenCalledWith(`/api/telemetry/v2/userHasSeenNotice`); + + expect(provider.notifyUserAboutOptInDefault()).toEqual(false); + }); + + it('should only call the API once', async () => { + const { provider, mockHttp } = setup({}); + await provider.setOptInNoticeSeen(); + await provider.setOptInNoticeSeen(); + + expect(mockHttp.put).toHaveBeenCalledTimes(1); + + expect(provider.notifyUserAboutOptInDefault()).toEqual(false); + }); + + it('should gracefully handle errors', async () => { + const { provider } = setup({ simulatePutError: true }); + + await provider.setOptInNoticeSeen(); + + // opt-in change should not be reflected + expect(provider.notifyUserAboutOptInDefault()).toEqual(true); + }); + }); }); diff --git a/src/legacy/core_plugins/telemetry/public/services/telemetry_opt_in.test.mocks.js b/src/legacy/core_plugins/telemetry/public/services/telemetry_opt_in.test.mocks.js index 012f8de640042..574aaefd4f1f7 100644 --- a/src/legacy/core_plugins/telemetry/public/services/telemetry_opt_in.test.mocks.js +++ b/src/legacy/core_plugins/telemetry/public/services/telemetry_opt_in.test.mocks.js @@ -24,11 +24,12 @@ import { } from '../../../../../core/public/mocks'; const injectedMetadataMock = injectedMetadataServiceMock.createStartContract(); -export function mockInjectedMetadata({ telemetryOptedIn, allowChangingOptInStatus }) { +export function mockInjectedMetadata({ telemetryOptedIn, allowChangingOptInStatus, telemetryNotifyUserAboutOptInDefault }) { const mockGetInjectedVar = jest.fn().mockImplementation((key) => { switch (key) { case 'telemetryOptedIn': return telemetryOptedIn; case 'allowChangingOptInStatus': return allowChangingOptInStatus; + case 'telemetryNotifyUserAboutOptInDefault': return telemetryNotifyUserAboutOptInDefault; default: throw new Error(`unexpected injectedVar ${key}`); } }); diff --git a/src/legacy/core_plugins/telemetry/public/services/telemetry_opt_in.ts b/src/legacy/core_plugins/telemetry/public/services/telemetry_opt_in.ts index 9b32f88df1218..ea7fe2ee5d9f2 100644 --- a/src/legacy/core_plugins/telemetry/public/services/telemetry_opt_in.ts +++ b/src/legacy/core_plugins/telemetry/public/services/telemetry_opt_in.ts @@ -19,12 +19,15 @@ import moment from 'moment'; import { setCanTrackUiMetrics } from 'ui/ui_metric'; -import { toastNotifications } from 'ui/notify'; +// @ts-ignore +import { banners, toastNotifications } from 'ui/notify'; import { npStart } from 'ui/new_platform'; import { i18n } from '@kbn/i18n'; let bannerId: string | null = null; +let optInBannerNoticeId: string | null = null; let currentOptInStatus = false; +let telemetryNotifyUserAboutOptInDefault = true; async function sendOptInStatus($injector: any, chrome: any, enabled: boolean) { const telemetryOptInStatusUrl = npStart.core.injectedMetadata.getInjectedVar( @@ -57,18 +60,58 @@ async function sendOptInStatus($injector: any, chrome: any, enabled: boolean) { } export function TelemetryOptInProvider($injector: any, chrome: any, sendOptInStatusChange = true) { currentOptInStatus = npStart.core.injectedMetadata.getInjectedVar('telemetryOptedIn') as boolean; + const allowChangingOptInStatus = npStart.core.injectedMetadata.getInjectedVar( 'allowChangingOptInStatus' ) as boolean; + telemetryNotifyUserAboutOptInDefault = npStart.core.injectedMetadata.getInjectedVar( + 'telemetryNotifyUserAboutOptInDefault' + ) as boolean; + setCanTrackUiMetrics(currentOptInStatus); + const provider = { getBannerId: () => bannerId, + getOptInBannerNoticeId: () => optInBannerNoticeId, getOptIn: () => currentOptInStatus, canChangeOptInStatus: () => allowChangingOptInStatus, + notifyUserAboutOptInDefault: () => telemetryNotifyUserAboutOptInDefault, setBannerId(id: string) { bannerId = id; }, + setOptInBannerNoticeId(id: string) { + optInBannerNoticeId = id; + }, + setOptInNoticeSeen: async () => { + const $http = $injector.get('$http'); + + // If they've seen the notice don't spam the API + if (!telemetryNotifyUserAboutOptInDefault) { + return telemetryNotifyUserAboutOptInDefault; + } + + if (optInBannerNoticeId) { + banners.remove(optInBannerNoticeId); + } + + try { + await $http.put(chrome.addBasePath('/api/telemetry/v2/userHasSeenNotice')); + telemetryNotifyUserAboutOptInDefault = false; + } catch (error) { + toastNotifications.addError(error, { + title: i18n.translate('telemetry.optInNoticeSeenErrorTitle', { + defaultMessage: 'Error', + }), + toastMessage: i18n.translate('telemetry.optInNoticeSeenErrorToastText', { + defaultMessage: 'An error occurred dismissing the notice', + }), + }); + telemetryNotifyUserAboutOptInDefault = true; + } + + return telemetryNotifyUserAboutOptInDefault; + }, setOptIn: async (enabled: boolean) => { if (!allowChangingOptInStatus) { return; @@ -88,7 +131,8 @@ export function TelemetryOptInProvider($injector: any, chrome: any, sendOptInSta defaultMessage: 'Error', }), toastMessage: i18n.translate('telemetry.optInErrorToastText', { - defaultMessage: 'An error occured while trying to set the usage statistics preference.', + defaultMessage: + 'An error occurred while trying to set the usage statistics preference.', }), }); return false; diff --git a/src/legacy/core_plugins/telemetry/server/routes/index.ts b/src/legacy/core_plugins/telemetry/server/routes/index.ts index 66a7b2c97f3ae..30c018ca7796d 100644 --- a/src/legacy/core_plugins/telemetry/server/routes/index.ts +++ b/src/legacy/core_plugins/telemetry/server/routes/index.ts @@ -21,6 +21,7 @@ import { CoreSetup } from 'src/core/server'; import { registerTelemetryOptInRoutes } from './telemetry_opt_in'; import { registerTelemetryUsageStatsRoutes } from './telemetry_usage_stats'; import { registerTelemetryOptInStatsRoutes } from './telemetry_opt_in_stats'; +import { registerTelemetryUserHasSeenNotice } from './telemetry_user_has_seen_notice'; interface RegisterRoutesParams { core: CoreSetup; @@ -31,4 +32,5 @@ export function registerRoutes({ core, currentKibanaVersion }: RegisterRoutesPar registerTelemetryOptInRoutes({ core, currentKibanaVersion }); registerTelemetryUsageStatsRoutes(core); registerTelemetryOptInStatsRoutes(core); + registerTelemetryUserHasSeenNotice(core); } diff --git a/src/legacy/core_plugins/telemetry/server/routes/telemetry_user_has_seen_notice.ts b/src/legacy/core_plugins/telemetry/server/routes/telemetry_user_has_seen_notice.ts new file mode 100644 index 0000000000000..93416058c3277 --- /dev/null +++ b/src/legacy/core_plugins/telemetry/server/routes/telemetry_user_has_seen_notice.ts @@ -0,0 +1,59 @@ +/* + * 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 { Legacy } from 'kibana'; +import { Request } from 'hapi'; +import { CoreSetup } from 'src/core/server'; +import { + TelemetrySavedObject, + TelemetrySavedObjectAttributes, + getTelemetrySavedObject, + updateTelemetrySavedObject, +} from '../telemetry_repository'; + +const getInternalRepository = (server: Legacy.Server) => { + const { getSavedObjectsRepository } = server.savedObjects; + const { callWithInternalUser } = server.plugins.elasticsearch.getCluster('admin'); + const internalRepository = getSavedObjectsRepository(callWithInternalUser); + return internalRepository; +}; + +export function registerTelemetryUserHasSeenNotice(core: CoreSetup) { + const { server }: { server: Legacy.Server } = core.http as any; + + server.route({ + method: 'PUT', + path: '/api/telemetry/v2/userHasSeenNotice', + handler: async (req: Request): Promise => { + const internalRepository = getInternalRepository(server); + const telemetrySavedObject: TelemetrySavedObject = await getTelemetrySavedObject( + internalRepository + ); + + // update the object with a flag stating that the opt-in notice has been seen + const updatedAttributes: TelemetrySavedObjectAttributes = { + ...telemetrySavedObject, + userHasSeenNotice: true, + }; + await updateTelemetrySavedObject(internalRepository, updatedAttributes); + + return updatedAttributes; + }, + }); +} diff --git a/src/legacy/core_plugins/telemetry/server/telemetry_config/get_telemetry_notify_user_about_optin_default.test.ts b/src/legacy/core_plugins/telemetry/server/telemetry_config/get_telemetry_notify_user_about_optin_default.test.ts new file mode 100644 index 0000000000000..af142973a535d --- /dev/null +++ b/src/legacy/core_plugins/telemetry/server/telemetry_config/get_telemetry_notify_user_about_optin_default.test.ts @@ -0,0 +1,104 @@ +/* + * 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 { getNotifyUserAboutOptInDefault } from './get_telemetry_notify_user_about_optin_default'; + +describe('getNotifyUserAboutOptInDefault: get a flag that describes if the user must be notified about optin default', () => { + it('should return true when kibana has fresh defaults', () => { + expect( + getNotifyUserAboutOptInDefault({ + allowChangingOptInStatus: true, + telemetrySavedObject: { userHasSeenNotice: false }, + telemetryOptedIn: true, + configTelemetryOptIn: true, + }) + ).toBe(true); + }); + + it('should return false if allowChangingOptInStatus = false', () => { + expect( + getNotifyUserAboutOptInDefault({ + allowChangingOptInStatus: false, + telemetrySavedObject: null, + telemetryOptedIn: false, + configTelemetryOptIn: false, + }) + ).toBe(false); + + expect( + getNotifyUserAboutOptInDefault({ + allowChangingOptInStatus: false, + telemetrySavedObject: null, + telemetryOptedIn: true, + configTelemetryOptIn: true, + }) + ).toBe(false); + }); + + it('should return false if user has seen notice', () => { + expect( + getNotifyUserAboutOptInDefault({ + allowChangingOptInStatus: true, + telemetrySavedObject: { userHasSeenNotice: true }, + telemetryOptedIn: false, + configTelemetryOptIn: false, + }) + ).toBe(false); + + expect( + getNotifyUserAboutOptInDefault({ + allowChangingOptInStatus: true, + telemetrySavedObject: { userHasSeenNotice: true }, + telemetryOptedIn: true, + configTelemetryOptIn: true, + }) + ).toBe(false); + }); + + it('should return false if user is opted out', () => { + expect( + getNotifyUserAboutOptInDefault({ + allowChangingOptInStatus: true, + telemetrySavedObject: { userHasSeenNotice: false }, + telemetryOptedIn: false, + configTelemetryOptIn: true, + }) + ).toBe(false); + + expect( + getNotifyUserAboutOptInDefault({ + allowChangingOptInStatus: true, + telemetrySavedObject: { userHasSeenNotice: false }, + telemetryOptedIn: false, + configTelemetryOptIn: false, + }) + ).toBe(false); + }); + + it('should return false if kibana is opted out via config', () => { + expect( + getNotifyUserAboutOptInDefault({ + allowChangingOptInStatus: true, + telemetrySavedObject: { userHasSeenNotice: false }, + telemetryOptedIn: true, + configTelemetryOptIn: false, + }) + ).toBe(false); + }); +}); diff --git a/src/legacy/core_plugins/telemetry/server/telemetry_config/get_telemetry_notify_user_about_optin_default.ts b/src/legacy/core_plugins/telemetry/server/telemetry_config/get_telemetry_notify_user_about_optin_default.ts new file mode 100644 index 0000000000000..8ef3bd8388ecb --- /dev/null +++ b/src/legacy/core_plugins/telemetry/server/telemetry_config/get_telemetry_notify_user_about_optin_default.ts @@ -0,0 +1,45 @@ +/* + * 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 { TelemetrySavedObject } from '../telemetry_repository/get_telemetry_saved_object'; + +interface NotifyOpts { + allowChangingOptInStatus: boolean; + telemetrySavedObject: TelemetrySavedObject; + telemetryOptedIn: boolean | null; + configTelemetryOptIn: boolean; +} + +export function getNotifyUserAboutOptInDefault({ + allowChangingOptInStatus, + telemetrySavedObject, + telemetryOptedIn, + configTelemetryOptIn, +}: NotifyOpts) { + if (allowChangingOptInStatus === false) { + return false; + } + + // determine if notice has been seen before + if (telemetrySavedObject && telemetrySavedObject.userHasSeenNotice === true) { + return false; + } + + return telemetryOptedIn === true && configTelemetryOptIn === true; +} diff --git a/src/legacy/core_plugins/telemetry/server/telemetry_config/replace_injected_vars.ts b/src/legacy/core_plugins/telemetry/server/telemetry_config/replace_injected_vars.ts index 90d1f9cfdac65..02f9150a095d9 100644 --- a/src/legacy/core_plugins/telemetry/server/telemetry_config/replace_injected_vars.ts +++ b/src/legacy/core_plugins/telemetry/server/telemetry_config/replace_injected_vars.ts @@ -21,6 +21,7 @@ import { getTelemetrySavedObject } from '../telemetry_repository'; import { getTelemetryOptIn } from './get_telemetry_opt_in'; import { getTelemetrySendUsageFrom } from './get_telemetry_send_usage_from'; import { getTelemetryAllowChangingOptInStatus } from './get_telemetry_allow_changing_opt_in_status'; +import { getNotifyUserAboutOptInDefault } from './get_telemetry_notify_user_about_optin_default'; export async function replaceTelemetryInjectedVars(request: any) { const config = request.server.config(); @@ -56,8 +57,16 @@ export async function replaceTelemetryInjectedVars(request: any) { telemetrySavedObject, }); + const telemetryNotifyUserAboutOptInDefault = getNotifyUserAboutOptInDefault({ + telemetrySavedObject, + allowChangingOptInStatus, + configTelemetryOptIn, + telemetryOptedIn, + }); + return { telemetryOptedIn, telemetrySendUsageFrom, + telemetryNotifyUserAboutOptInDefault, }; } diff --git a/src/legacy/core_plugins/telemetry/server/telemetry_repository/index.ts b/src/legacy/core_plugins/telemetry/server/telemetry_repository/index.ts index f3629abc1620c..b9ba2ce5573c3 100644 --- a/src/legacy/core_plugins/telemetry/server/telemetry_repository/index.ts +++ b/src/legacy/core_plugins/telemetry/server/telemetry_repository/index.ts @@ -26,4 +26,5 @@ export interface TelemetrySavedObjectAttributes { sendUsageFrom?: 'browser' | 'server'; lastReported?: number; telemetryAllowChangingOptInStatus?: boolean; + userHasSeenNotice?: boolean; } diff --git a/src/legacy/ui/public/url/index.js b/src/legacy/ui/public/url/index.js index a8f7b5fed350c..f3beb05e577c1 100644 --- a/src/legacy/ui/public/url/index.js +++ b/src/legacy/ui/public/url/index.js @@ -19,4 +19,4 @@ export { KbnUrlProvider } from './url'; export { RedirectWhenMissingProvider } from './redirect_when_missing'; -export { modifyUrl } from '../../../../core/public/utils'; +export { modifyUrl } from '../../../../core/utils'; diff --git a/src/legacy/ui/tutorials_mixin.js b/src/legacy/ui/tutorials_mixin.js index af3663a83b812..5238e82e8f14f 100644 --- a/src/legacy/ui/tutorials_mixin.js +++ b/src/legacy/ui/tutorials_mixin.js @@ -36,6 +36,7 @@ export function tutorialsMixin(kbnServer, server) { }); server.decorate('server', 'registerTutorial', (specProvider) => { + // registration during setup const emptyContext = {}; const { error } = Joi.validate(specProvider(server, emptyContext), tutorialSchema); @@ -47,6 +48,7 @@ export function tutorialsMixin(kbnServer, server) { }); server.decorate('server', 'addScopedTutorialContextFactory', (scopedTutorialContextFactory) => { + // returned by the setup method of the new plugin, they will do the same thing as now if (typeof scopedTutorialContextFactory !== 'function') { throw new Error(`Unable to add scoped(request) context factory because you did not provide a function`); } diff --git a/src/optimize/base_optimizer.js b/src/optimize/base_optimizer.js index 0e7d03498c0aa..28eb448d12d82 100644 --- a/src/optimize/base_optimizer.js +++ b/src/optimize/base_optimizer.js @@ -543,7 +543,8 @@ export default class BaseOptimizer { `Optimizations failure.\n${details.split('\n').join('\n ')}\n`, stats.toJson(defaults({ warningsFilter: STATS_WARNINGS_FILTER, - ...Stats.presetToOptions('detailed') + ...Stats.presetToOptions('detailed'), + maxModules: 1000, })) ); } diff --git a/src/plugins/home/kibana.json b/src/plugins/home/kibana.json new file mode 100644 index 0000000000000..8d2d79560f854 --- /dev/null +++ b/src/plugins/home/kibana.json @@ -0,0 +1,6 @@ +{ + "id": "home", + "version": "kibana", + "server": true, + "ui": false +} diff --git a/src/plugins/home/server/index.ts b/src/plugins/home/server/index.ts new file mode 100644 index 0000000000000..178a77dc85ca9 --- /dev/null +++ b/src/plugins/home/server/index.ts @@ -0,0 +1,24 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export { HomePluginSetup, HomePluginStart } from './plugin'; +export { TutorialProvider } from './services'; +import { HomePlugin } from './plugin'; + +export const plugin = () => new HomePlugin(); diff --git a/src/plugins/home/server/lib/tutorial_schema.ts b/src/plugins/home/server/lib/tutorial_schema.ts new file mode 100644 index 0000000000000..eb001ac96cceb --- /dev/null +++ b/src/plugins/home/server/lib/tutorial_schema.ts @@ -0,0 +1,149 @@ +/* + * 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 Joi from 'joi'; + +const PARAM_TYPES = { + NUMBER: 'number', + STRING: 'string', +}; + +const TUTORIAL_CATEGORY = { + LOGGING: 'logging', + SIEM: 'siem', + METRICS: 'metrics', + OTHER: 'other', +}; + +const dashboardSchema = Joi.object({ + id: Joi.string().required(), // Dashboard saved object id + linkLabel: Joi.string().when('isOverview', { + is: true, + then: Joi.required(), + }), + // Is this an Overview / Entry Point dashboard? + isOverview: Joi.boolean().required(), +}); + +const artifactsSchema = Joi.object({ + // Fields present in Elasticsearch documents created by this product. + exportedFields: Joi.object({ + documentationUrl: Joi.string().required(), + }), + // Kibana dashboards created by this product. + dashboards: Joi.array() + .items(dashboardSchema) + .required(), + application: Joi.object({ + path: Joi.string().required(), + label: Joi.string().required(), + }), +}); + +const statusCheckSchema = Joi.object({ + title: Joi.string(), + text: Joi.string(), + btnLabel: Joi.string(), + success: Joi.string(), + error: Joi.string(), + esHitsCheck: Joi.object({ + index: Joi.alternatives() + .try(Joi.string(), Joi.array().items(Joi.string())) + .required(), + query: Joi.object().required(), + }).required(), +}); + +const instructionSchema = Joi.object({ + title: Joi.string(), + textPre: Joi.string(), + commands: Joi.array().items(Joi.string().allow('')), + textPost: Joi.string(), +}); + +const instructionVariantSchema = Joi.object({ + id: Joi.string().required(), + instructions: Joi.array() + .items(instructionSchema) + .required(), +}); + +const instructionSetSchema = Joi.object({ + title: Joi.string(), + callOut: Joi.object({ + title: Joi.string().required(), + message: Joi.string(), + iconType: Joi.string(), + }), + // Variants (OSes, languages, etc.) for which tutorial instructions are specified. + instructionVariants: Joi.array() + .items(instructionVariantSchema) + .required(), + statusCheck: statusCheckSchema, +}); + +const paramSchema = Joi.object({ + defaultValue: Joi.required(), + id: Joi.string() + .regex(/^[a-zA-Z_]+$/) + .required(), + label: Joi.string().required(), + type: Joi.string() + .valid(Object.values(PARAM_TYPES)) + .required(), +}); + +const instructionsSchema = Joi.object({ + instructionSets: Joi.array() + .items(instructionSetSchema) + .required(), + params: Joi.array().items(paramSchema), +}); + +export const tutorialSchema = { + id: Joi.string() + .regex(/^[a-zA-Z0-9-]+$/) + .required(), + category: Joi.string() + .valid(Object.values(TUTORIAL_CATEGORY)) + .required(), + name: Joi.string().required(), + isBeta: Joi.boolean().default(false), + shortDescription: Joi.string().required(), + euiIconType: Joi.string(), // EUI icon type string, one of https://elastic.github.io/eui/#/icons + longDescription: Joi.string().required(), + completionTimeMinutes: Joi.number().integer(), + previewImagePath: Joi.string(), + + // kibana and elastic cluster running on prem + onPrem: instructionsSchema.required(), + + // kibana and elastic cluster running in elastic's cloud + elasticCloud: instructionsSchema, + + // kibana running on prem and elastic cluster running in elastic's cloud + onPremElasticCloud: instructionsSchema, + + // Elastic stack artifacts produced by product when it is setup and run. + artifacts: artifactsSchema, + + // saved objects used by data module. + savedObjects: Joi.array().items(), + savedObjectsInstallMsg: Joi.string(), +}; diff --git a/src/plugins/home/server/lib/tutorials_registry_types.ts b/src/plugins/home/server/lib/tutorials_registry_types.ts new file mode 100644 index 0000000000000..d081639e5c7e2 --- /dev/null +++ b/src/plugins/home/server/lib/tutorials_registry_types.ts @@ -0,0 +1,110 @@ +/* + * 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 { IconType } from '@elastic/eui'; +import { KibanaRequest } from 'src/core/server'; + +/** @public */ +export enum TutorialsCategory { + LOGGING = 'logging', + SIEM = 'siem', + METRICS = 'metrics', + OTHER = 'other', +} +export interface ParamTypes { + NUMBER: string; + STRING: string; +} +export interface InstructionSetSchema { + readonly title: string; + readonly callOut: { + title: string; + message: string; + iconType: IconType; + }; +} +export interface ParamsSchema { + defaultValue: any; + id: string; + label: string; + type: ParamTypes; +} +export interface InstructionsSchema { + readonly instructionSets: InstructionSetSchema[]; + readonly params: ParamsSchema[]; +} +export interface DashboardSchema { + id: string; + linkLabel?: { + is: boolean; + then: any; + }; + isOverview: boolean; +} +export interface ArtifactsSchema { + readonly exportedFields: { + documentationUrl: string; + }; + readonly dashboards: DashboardSchema[]; + readonly application: { + path: string; + label: string; + }; +} +export interface TutorialSchema { + id: string; + category: TutorialsCategory; + name: string; + isBeta: boolean; + shortDescription: string; + euiIconType: IconType; // EUI icon type string, one of https://elastic.github.io/eui/#/icon; + longDescription: string; + completionTimeMinutes: number; + previewImagePath: string; + + // kibana and elastic cluster running on prem + onPrem: InstructionsSchema; + + // kibana and elastic cluster running in elastic's cloud + elasticCloud: InstructionsSchema; + + // kibana running on prem and elastic cluster running in elastic's cloud + onPremElasticCloud: InstructionsSchema; + + // Elastic stack artifacts produced by product when it is setup and run. + artifacts: ArtifactsSchema; + + // saved objects used by data module. + savedObjects: any[]; + savedObjectsInstallMsg: string; +} +export type TutorialProvider = (context: { [key: string]: unknown }) => TutorialSchema; +export type TutorialContextFactory = ( + req: KibanaRequest< + Readonly<{ + [x: string]: any; + }>, + Readonly<{ + [x: string]: any; + }>, + Readonly<{ + [x: string]: any; + }> + > +) => { [key: string]: unknown }; +export type ScopedTutorialContextFactory = (...args: any[]) => any; diff --git a/src/plugins/home/server/plugin.test.mocks.ts b/src/plugins/home/server/plugin.test.mocks.ts new file mode 100644 index 0000000000000..df63b467d8656 --- /dev/null +++ b/src/plugins/home/server/plugin.test.mocks.ts @@ -0,0 +1,24 @@ +/* + * 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 { tutorialsRegistryMock } from './services/tutorials_registry.mock'; + +export const registryMock = tutorialsRegistryMock.create(); +jest.doMock('./services', () => ({ + TutorialsRegistry: jest.fn(() => registryMock), +})); diff --git a/src/plugins/home/server/plugin.test.ts b/src/plugins/home/server/plugin.test.ts new file mode 100644 index 0000000000000..e86a2d807109f --- /dev/null +++ b/src/plugins/home/server/plugin.test.ts @@ -0,0 +1,51 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { registryMock } from './plugin.test.mocks'; +import { HomePlugin } from './plugin'; +import { coreMock } from '../../../core/server/mocks'; +import { CoreSetup } from '../../../core/server'; + +type MockedKeys = { [P in keyof T]: jest.Mocked }; + +describe('HomePlugin', () => { + beforeEach(() => { + registryMock.setup.mockClear(); + registryMock.start.mockClear(); + }); + + describe('setup', () => { + const mockCoreSetup: MockedKeys = coreMock.createSetup(); + + test('wires up and returns registerTutorial and addScopedTutorialContextFactory', () => { + const setup = new HomePlugin().setup(mockCoreSetup); + expect(setup).toHaveProperty('tutorials'); + expect(setup.tutorials).toHaveProperty('registerTutorial'); + expect(setup.tutorials).toHaveProperty('addScopedTutorialContextFactory'); + }); + }); + + describe('start', () => { + test('is defined', () => { + const start = new HomePlugin().start(); + expect(start).toBeDefined(); + expect(start).toHaveProperty('tutorials'); + }); + }); +}); diff --git a/src/plugins/home/server/plugin.ts b/src/plugins/home/server/plugin.ts new file mode 100644 index 0000000000000..d5a3f235f8490 --- /dev/null +++ b/src/plugins/home/server/plugin.ts @@ -0,0 +1,46 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { CoreSetup, Plugin } from 'src/core/server'; +import { TutorialsRegistry, TutorialsRegistrySetup, TutorialsRegistryStart } from './services'; + +export class HomePlugin implements Plugin { + private readonly tutorialsRegistry = new TutorialsRegistry(); + + public setup(core: CoreSetup) { + return { + tutorials: { ...this.tutorialsRegistry.setup(core) }, + }; + } + + public start() { + return { + tutorials: { ...this.tutorialsRegistry.start() }, + }; + } +} + +/** @public */ +export interface HomePluginSetup { + tutorials: TutorialsRegistrySetup; +} + +/** @public */ +export interface HomePluginStart { + tutorials: TutorialsRegistryStart; +} diff --git a/src/plugins/home/server/services/index.ts b/src/plugins/home/server/services/index.ts new file mode 100644 index 0000000000000..5fe5cb0ba4760 --- /dev/null +++ b/src/plugins/home/server/services/index.ts @@ -0,0 +1,27 @@ +/* + * 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. + */ +// provided to other plugins as APIs +// should model the plugin lifecycle + +export { + TutorialsRegistry, + TutorialsRegistrySetup, + TutorialsRegistryStart, +} from './tutorials_registry'; +export * from '../lib/tutorials_registry_types'; diff --git a/src/plugins/home/server/services/tutorials_registry.mock.ts b/src/plugins/home/server/services/tutorials_registry.mock.ts new file mode 100644 index 0000000000000..b54b0be4ea2b7 --- /dev/null +++ b/src/plugins/home/server/services/tutorials_registry.mock.ts @@ -0,0 +1,53 @@ +/* + * 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 { + TutorialsRegistrySetup, + TutorialsRegistryStart, + TutorialsRegistry, +} from './tutorials_registry'; + +const createSetupMock = (): jest.Mocked => { + const setup = { + registerTutorial: jest.fn(), + addScopedTutorialContextFactory: jest.fn(), + }; + return setup; +}; + +const createStartMock = (): jest.Mocked => { + const start = {}; + return start; +}; + +const createMock = (): jest.Mocked> => { + const service = { + setup: jest.fn(), + start: jest.fn(), + }; + service.setup.mockImplementation(createSetupMock); + service.start.mockImplementation(createStartMock); + return service; +}; + +export const tutorialsRegistryMock = { + createSetup: createSetupMock, + createStart: createStartMock, + create: createMock, +}; diff --git a/src/plugins/home/server/services/tutorials_registry.test.ts b/src/plugins/home/server/services/tutorials_registry.test.ts new file mode 100644 index 0000000000000..04c26bab1f065 --- /dev/null +++ b/src/plugins/home/server/services/tutorials_registry.test.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 { TutorialsRegistry } from './tutorials_registry'; +import { coreMock } from '../../../../core/server/mocks'; +import { CoreSetup } from '../../../../core/server'; +import { httpServerMock } from '../../../../../src/core/server/mocks'; + +import { + TutorialProvider, + TutorialSchema, + TutorialsCategory, + ScopedTutorialContextFactory, +} from '../lib/tutorials_registry_types'; + +const INVALID_TUTORIAL: TutorialSchema = { + id: 'test', + category: 'logging' as TutorialsCategory, + name: '', + isBeta: false, + shortDescription: 'short description', + euiIconType: 'alert', + longDescription: 'long description with lots of text', + completionTimeMinutes: 10, + previewImagePath: 'path', + onPrem: { instructionSets: [], params: [] }, + elasticCloud: { instructionSets: [], params: [] }, + onPremElasticCloud: { instructionSets: [], params: [] }, + artifacts: { + exportedFields: { documentationUrl: 'url' }, + dashboards: [], + application: { path: 'path', label: 'path' }, + }, + savedObjects: [], + savedObjectsInstallMsg: 'testMsg', +}; +const VALID_TUTORIAL: TutorialSchema = { + id: 'test', + category: 'logging' as TutorialsCategory, + name: 'new tutorial provider', + isBeta: false, + shortDescription: 'short description', + euiIconType: 'alert', + longDescription: 'long description with lots of text', + completionTimeMinutes: 10, + previewImagePath: 'path', + onPrem: { instructionSets: [], params: [] }, + elasticCloud: { instructionSets: [], params: [] }, + onPremElasticCloud: { instructionSets: [], params: [] }, + artifacts: { + exportedFields: { documentationUrl: 'url' }, + dashboards: [], + application: { path: 'path', label: 'path' }, + }, + savedObjects: [], + savedObjectsInstallMsg: 'testMsg', +}; +const invalidTutorialProvider = INVALID_TUTORIAL; +const validTutorialProvider = VALID_TUTORIAL; + +describe('TutorialsRegistry', () => { + let mockCoreSetup: MockedKeys; + let testProvider: TutorialProvider; + let testScopedTutorialContextFactory: ScopedTutorialContextFactory; + + describe('GET /api/kibana/home/tutorials', () => { + beforeEach(() => { + mockCoreSetup = coreMock.createSetup(); + }); + + test('has a router that retrieves registered tutorials', () => { + const mockResponse = httpServerMock.createResponseFactory(); + expect(mockResponse.ok.mock.calls).toMatchInlineSnapshot(`Array []`); + }); + }); + + describe('setup', () => { + test('exposes proper contract', () => { + const setup = new TutorialsRegistry().setup(mockCoreSetup); + expect(setup).toHaveProperty('registerTutorial'); + expect(setup).toHaveProperty('addScopedTutorialContextFactory'); + }); + + test('registerTutorial throws when registering a tutorial with an invalid schema', () => { + const setup = new TutorialsRegistry().setup(mockCoreSetup); + testProvider = ({}) => invalidTutorialProvider; + expect(() => setup.registerTutorial(testProvider)).toThrowErrorMatchingInlineSnapshot( + `"Unable to register tutorial spec because its invalid. ValidationError: child \\"name\\" fails because [\\"name\\" is not allowed to be empty]"` + ); + }); + + test('registerTutorial registers a tutorial with a valid schema', () => { + const setup = new TutorialsRegistry().setup(mockCoreSetup); + testProvider = ({}) => validTutorialProvider; + expect(() => setup.registerTutorial(testProvider)).not.toThrowError(); + }); + + test('addScopedTutorialContextFactory throws when given a scopedTutorialContextFactory that is not a function', () => { + const setup = new TutorialsRegistry().setup(mockCoreSetup); + const testItem = {} as TutorialProvider; + expect(() => + setup.addScopedTutorialContextFactory(testItem) + ).toThrowErrorMatchingInlineSnapshot( + `"Unable to add scoped(request) context factory because you did not provide a function"` + ); + }); + + test('addScopedTutorialContextFactory adds a scopedTutorialContextFactory when given a function', () => { + const setup = new TutorialsRegistry().setup(mockCoreSetup); + testScopedTutorialContextFactory = ({}) => 'string'; + expect(() => + setup.addScopedTutorialContextFactory(testScopedTutorialContextFactory) + ).not.toThrowError(); + }); + }); + + describe('start', () => { + test('exposes proper contract', () => { + const start = new TutorialsRegistry().start(); + expect(start).toBeDefined(); + }); + }); +}); diff --git a/src/plugins/home/server/services/tutorials_registry.ts b/src/plugins/home/server/services/tutorials_registry.ts new file mode 100644 index 0000000000000..40692d8558656 --- /dev/null +++ b/src/plugins/home/server/services/tutorials_registry.ts @@ -0,0 +1,88 @@ +/* + * 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 Joi from 'joi'; +import { CoreSetup } from 'src/core/server'; +import { + TutorialProvider, + TutorialContextFactory, + ScopedTutorialContextFactory, +} from '../lib/tutorials_registry_types'; +import { tutorialSchema } from '../lib/tutorial_schema'; + +export class TutorialsRegistry { + private readonly tutorialProviders: TutorialProvider[] = []; // pre-register all the tutorials we know we want in here + private readonly scopedTutorialContextFactories: TutorialContextFactory[] = []; + + public setup(core: CoreSetup) { + const router = core.http.createRouter(); + router.get( + { path: '/api/kibana/home/tutorials', validate: false }, + async (context, req, res) => { + const initialContext = {}; + const scopedContext = this.scopedTutorialContextFactories.reduce( + (accumulatedContext, contextFactory) => { + return { ...accumulatedContext, ...contextFactory(req) }; + }, + initialContext + ); + + return res.ok({ + body: this.tutorialProviders.map(tutorialProvider => { + return tutorialProvider(scopedContext); // All the tutorialProviders need to be refactored so that they don't need the server. + }), + }); + } + ); + return { + registerTutorial: (specProvider: TutorialProvider) => { + const emptyContext = {}; + const { error } = Joi.validate(specProvider(emptyContext), tutorialSchema); + + if (error) { + throw new Error(`Unable to register tutorial spec because its invalid. ${error}`); + } + + this.tutorialProviders.push(specProvider); + }, + + addScopedTutorialContextFactory: ( + scopedTutorialContextFactory: ScopedTutorialContextFactory + ) => { + if (typeof scopedTutorialContextFactory !== 'function') { + throw new Error( + `Unable to add scoped(request) context factory because you did not provide a function` + ); + } + + this.scopedTutorialContextFactories.push(scopedTutorialContextFactory); + }, + }; + } + + public start() { + return {}; + } +} + +/** @public */ +export type TutorialsRegistrySetup = ReturnType; + +/** @public */ +export type TutorialsRegistryStart = ReturnType; diff --git a/src/test_utils/kbn_server.ts b/src/test_utils/kbn_server.ts index 1494c01166e20..0fc4c1f0d352e 100644 --- a/src/test_utils/kbn_server.ts +++ b/src/test_utils/kbn_server.ts @@ -270,8 +270,8 @@ export function createTestServers({ // Override provided configs, we know what the elastic user is now kbnSettings.elasticsearch = { hosts: [esTestConfig.getUrl()], - username: esTestConfig.getUrlParts().username, - password: esTestConfig.getUrlParts().password, + username: kibanaServerTestUser.username, + password: kibanaServerTestUser.password, }; } @@ -279,8 +279,8 @@ export function createTestServers({ stop: async () => await es.cleanup(), es, hosts: [esTestConfig.getUrl()], - username: esTestConfig.getUrlParts().username, - password: esTestConfig.getUrlParts().password, + username: kibanaServerTestUser.username, + password: kibanaServerTestUser.password, }; }, startKibana: async () => { diff --git a/test/common/config.js b/test/common/config.js index 58161e545bd06..03a9a34a975e5 100644 --- a/test/common/config.js +++ b/test/common/config.js @@ -19,7 +19,7 @@ import path from 'path'; import { format as formatUrl } from 'url'; -import { OPTIMIZE_BUNDLE_DIR, esTestConfig, kbnTestConfig } from '@kbn/test'; +import { OPTIMIZE_BUNDLE_DIR, esTestConfig, kbnTestConfig, kibanaServerTestUser } from '@kbn/test'; import { services } from './services'; export default function () { @@ -53,8 +53,8 @@ export default function () { '--status.allowAnonymous=true', '--optimize.enabled=true', `--elasticsearch.hosts=${formatUrl(servers.elasticsearch)}`, - `--elasticsearch.username=${servers.elasticsearch.username}`, - `--elasticsearch.password=${servers.elasticsearch.password}`, + `--elasticsearch.username=${kibanaServerTestUser.username}`, + `--elasticsearch.password=${kibanaServerTestUser.password}`, `--kibana.disableWelcomeScreen=true`, '--telemetry.banner=false', `--server.maxPayloadBytes=1679958`, diff --git a/test/functional/page_objects/common_page.js b/test/functional/page_objects/common_page.ts similarity index 53% rename from test/functional/page_objects/common_page.js rename to test/functional/page_objects/common_page.ts index 5320ba978cbe9..19a7bd25db9c6 100644 --- a/test/functional/page_objects/common_page.js +++ b/test/functional/page_objects/common_page.ts @@ -19,10 +19,13 @@ import { delay } from 'bluebird'; import expect from '@kbn/expect'; +// @ts-ignore import fetch from 'node-fetch'; +import { FtrProviderContext } from '../ftr_provider_context'; +// @ts-ignore not TS yet import getUrl from '../../../src/test_utils/get_url'; -export function CommonPageProvider({ getService, getPageObjects }) { +export function CommonPageProvider({ getService, getPageObjects }: FtrProviderContext) { const log = getService('log'); const config = getService('config'); const browser = getService('browser'); @@ -30,19 +33,22 @@ export function CommonPageProvider({ getService, getPageObjects }) { const find = getService('find'); const globalNav = getService('globalNav'); const testSubjects = getService('testSubjects'); - const kibanaServer = getService('kibanaServer'); const PageObjects = getPageObjects(['shield']); const defaultTryTimeout = config.get('timeouts.try'); const defaultFindTimeout = config.get('timeouts.find'); class CommonPage { - - static async navigateToUrlAndHandleAlert(url, shouldAcceptAlert) { + /** + * Navigates the browser window to provided URL + * @param url URL + * @param shouldAcceptAlert pass 'true' if browser alert should be accepted + */ + private static async navigateToUrlAndHandleAlert(url: string, shouldAcceptAlert: boolean) { log.debug('Navigate to: ' + url); try { await browser.get(url); - } catch(navigationError) { + } catch (navigationError) { log.debug('Error navigating to url'); const alert = await browser.getAlert(); if (alert && alert.accept) { @@ -50,7 +56,7 @@ export function CommonPageProvider({ getService, getPageObjects }) { log.debug('Should accept alert'); try { await alert.accept(); - } catch(alertException) { + } catch (alertException) { log.debug('Error accepting alert'); throw alertException; } @@ -64,63 +70,85 @@ export function CommonPageProvider({ getService, getPageObjects }) { } } - getHostPort() { + /** + * Returns Kibana host URL + */ + public getHostPort() { return getUrl.baseUrl(config.get('servers.kibana')); } - getEsHostPort() { + /** + * Returns ES host URL + */ + public getEsHostPort() { return getUrl.baseUrl(config.get('servers.elasticsearch')); } /** - * @param {string} appName As defined in the apps config - * @param {string} subUrl The route after the hash (#) + * Logins to Kibana as default user and navigates to provided app + * @param appUrl Kibana URL */ - async navigateToUrl(appName, subUrl, { - basePath = '', - ensureCurrentUrl = true, - shouldLoginIfPrompted = true, - shouldAcceptAlert = true - } = {}) { - // we onlt use the pathname from the appConfig and use the subUrl as the hash - const appConfig = { - pathname: `${basePath}${config.get(['apps', appName]).pathname}`, - hash: `/${appName}/${subUrl}`, - }; - - const appUrl = getUrl.noAuth(config.get('servers.kibana'), appConfig); - - await retry.try(async () => { - await CommonPage.navigateToUrlAndHandleAlert(appUrl, shouldAcceptAlert); - const currentUrl = shouldLoginIfPrompted ? await this.loginIfPrompted(appUrl) : await browser.getCurrentUrl(); + private async loginIfPrompted(appUrl: string) { + let currentUrl = await browser.getCurrentUrl(); + log.debug(`currentUrl = ${currentUrl}\n appUrl = ${appUrl}`); + await find.byCssSelector('[data-test-subj="kibanaChrome"]', 6 * defaultFindTimeout); // 60 sec waiting + const loginPage = currentUrl.includes('/login'); + const wantedLoginPage = appUrl.includes('/login') || appUrl.includes('/logout'); - if (ensureCurrentUrl && !currentUrl.includes(appUrl)) { - throw new Error(`expected ${currentUrl}.includes(${appUrl})`); - } - }); + 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') + ); + await find.byCssSelector( + '[data-test-subj="kibanaChrome"] nav:not(.ng-hide)', + 2 * defaultFindTimeout + ); + await browser.get(appUrl); + currentUrl = await browser.getCurrentUrl(); + log.debug(`Finished login process currentUrl = ${currentUrl}`); + } + return currentUrl; } /** - * @param {string} appName As defined in the apps config - * @param {string} hash The route after the hash (#) + * Navigates browser using the pathname from the appConfig and subUrl as the hash + * @param appName As defined in the apps config, e.g. 'home' + * @param subUrl The route after the hash (#), e.g. 'tutorial_directory/sampleData' + * @param args additional arguments */ - async navigateToActualUrl(appName, hash, { - basePath = '', - ensureCurrentUrl = true, - shouldLoginIfPrompted = true - } = {}) { - // we only use the apps config to get the application path + public async navigateToUrl( + appName: string, + subUrl?: string, + { + basePath = '', + ensureCurrentUrl = true, + shouldLoginIfPrompted = true, + shouldAcceptAlert = true, + useActualUrl = false, + } = {} + ) { const appConfig = { pathname: `${basePath}${config.get(['apps', appName]).pathname}`, - hash, + hash: useActualUrl ? subUrl : `/${appName}/${subUrl}`, }; const appUrl = getUrl.noAuth(config.get('servers.kibana'), appConfig); + await retry.try(async () => { - log.debug(`navigateToActualUrl ${appUrl}`); - await browser.get(appUrl); + if (useActualUrl) { + log.debug(`navigateToActualUrl ${appUrl}`); + await browser.get(appUrl); + } else { + await CommonPage.navigateToUrlAndHandleAlert(appUrl, shouldAcceptAlert); + } - const currentUrl = shouldLoginIfPrompted ? await this.loginIfPrompted(appUrl) : await browser.getCurrentUrl(); + const currentUrl = shouldLoginIfPrompted + ? await this.loginIfPrompted(appUrl) + : await browser.getCurrentUrl(); if (ensureCurrentUrl && !currentUrl.includes(appUrl)) { throw new Error(`expected ${currentUrl}.includes(${appUrl})`); @@ -128,32 +156,42 @@ export function CommonPageProvider({ getService, getPageObjects }) { }); } - - async loginIfPrompted(appUrl) { - let currentUrl = await browser.getCurrentUrl(); - log.debug(`currentUrl = ${currentUrl}\n appUrl = ${appUrl}`); - await find.byCssSelector('[data-test-subj="kibanaChrome"]', defaultTryTimeout * 2); - const loginPage = currentUrl.includes('/login'); - 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') - ); - await find.byCssSelector('[data-test-subj="kibanaChrome"] nav:not(.ng-hide)', 20000); - await browser.get(appUrl); - currentUrl = await browser.getCurrentUrl(); - log.debug(`Finished login process currentUrl = ${currentUrl}`); - } - return currentUrl; + /** + * Navigates browser using only the pathname from the appConfig + * @param appName As defined in the apps config, e.g. 'kibana' + * @param hash The route after the hash (#), e.g. 'management/kibana/settings' + * @param args additional arguments + */ + async navigateToActualUrl( + appName: string, + hash?: string, + { + basePath = '', + ensureCurrentUrl = true, + shouldLoginIfPrompted = true, + shouldAcceptAlert = true, + } = {} + ) { + await this.navigateToUrl(appName, hash, { + basePath, + ensureCurrentUrl, + shouldLoginIfPrompted, + shouldAcceptAlert, + useActualUrl: true, + }); } - navigateToApp(appName, { basePath = '', shouldLoginIfPrompted = true, shouldAcceptAlert = true, hash = '' } = {}) { - const self = this; + async sleep(sleepMilliseconds: number) { + log.debug(`... sleep(${sleepMilliseconds}) start`); + await delay(sleepMilliseconds); + log.debug(`... sleep(${sleepMilliseconds}) end`); + } - let appUrl; + async navigateToApp( + appName: string, + { basePath = '', shouldLoginIfPrompted = true, shouldAcceptAlert = true, hash = '' } = {} + ) { + let appUrl: string; if (config.has(['apps', appName])) { // Legacy applications const appConfig = config.get(['apps', appName]); @@ -164,116 +202,73 @@ export function CommonPageProvider({ getService, getPageObjects }) { } else { appUrl = getUrl.noAuth(config.get('servers.kibana'), { pathname: `${basePath}/app/${appName}`, - hash + hash, }); } log.debug('navigating to ' + appName + ' url: ' + appUrl); - function navigateTo(url) { - return retry.try(function () { + await retry.tryForTime(defaultTryTimeout * 2, async () => { + let lastUrl = await retry.try(async () => { // since we're using hash URLs, always reload first to force re-render - return kibanaServer.uiSettings.getDefaultIndex() - .then(async function () { - return await CommonPage.navigateToUrlAndHandleAlert(url, shouldAcceptAlert); - }) - .then(function () { - return self.sleep(700); - }) - .then(function () { - log.debug('returned from get, calling refresh'); - return browser.refresh(); - }) - .then(async function () { - const currentUrl = shouldLoginIfPrompted ? await self.loginIfPrompted(appUrl) : browser.getCurrentUrl(); - - if (currentUrl.includes('app/kibana')) { - await testSubjects.find('kibanaChrome'); - } - }) - .then(async function () { - - const currentUrl = (await browser.getCurrentUrl()).replace(/\/\/\w+:\w+@/, '//'); - const maxAdditionalLengthOnNavUrl = 230; - // On several test failures at the end of the TileMap test we try to navigate back to - // Visualize so we can create the next Vertical Bar Chart, but we can see from the - // logging and the screenshot that it's still on the TileMap page. Why didn't the "get" - // with a new timestamped URL go? I thought that sleep(700) between the get and the - // refresh would solve the problem but didn't seem to always work. - // So this hack fails the navSuccessful check if the currentUrl doesn't match the - // appUrl plus up to 230 other chars. - // Navigating to Settings when there is a default index pattern has a URL length of 196 - // (from debug output). Some other tabs may also be long. But a rather simple configured - // visualization is about 1000 chars long. So at least we catch that case. - - // Browsers don't show the ':port' if it's 80 or 443 so we have to - // remove that part so we can get a match in the tests. - const navSuccessful = new RegExp(appUrl.replace(':80/', '/').replace(':443/', '/') - + '.{0,' + maxAdditionalLengthOnNavUrl + '}$') - .test(currentUrl); - - if (!navSuccessful) { - const msg = 'App failed to load: ' + appName + - ' in ' + defaultFindTimeout + 'ms' + - ' appUrl = ' + appUrl + - ' currentUrl = ' + currentUrl; - log.debug(msg); - throw new Error(msg); - } - - return currentUrl; - }); + await CommonPage.navigateToUrlAndHandleAlert(appUrl, shouldAcceptAlert); + await this.sleep(700); + log.debug('returned from get, calling refresh'); + await browser.refresh(); + let currentUrl = shouldLoginIfPrompted + ? await this.loginIfPrompted(appUrl) + : await browser.getCurrentUrl(); + + if (currentUrl.includes('app/kibana')) { + await testSubjects.find('kibanaChrome'); + } + + currentUrl = (await browser.getCurrentUrl()).replace(/\/\/\w+:\w+@/, '//'); + const maxAdditionalLengthOnNavUrl = 230; + + // On several test failures at the end of the TileMap test we try to navigate back to + // Visualize so we can create the next Vertical Bar Chart, but we can see from the + // logging and the screenshot that it's still on the TileMap page. Why didn't the "get" + // with a new timestamped URL go? I thought that sleep(700) between the get and the + // refresh would solve the problem but didn't seem to always work. + // So this hack fails the navSuccessful check if the currentUrl doesn't match the + // appUrl plus up to 230 other chars. + // Navigating to Settings when there is a default index pattern has a URL length of 196 + // (from debug output). Some other tabs may also be long. But a rather simple configured + // visualization is about 1000 chars long. So at least we catch that case. + + // Browsers don't show the ':port' if it's 80 or 443 so we have to + // remove that part so we can get a match in the tests. + const navSuccessful = new RegExp( + appUrl.replace(':80/', '/').replace(':443/', '/') + + `.{0,${maxAdditionalLengthOnNavUrl}}$` + ).test(currentUrl); + + if (!navSuccessful) { + const msg = `App failed to load: ${appName} in ${defaultFindTimeout}ms appUrl=${appUrl} currentUrl=${currentUrl}`; + log.debug(msg); + throw new Error(msg); + } + return currentUrl; }); - } - return retry.tryForTime(defaultTryTimeout * 3, () => { - return navigateTo(appUrl) - .then(function (currentUrl) { - let lastUrl = currentUrl; - return retry.try(function () { - // give the app time to update the URL - return self.sleep(501) - .then(function () { - return browser.getCurrentUrl(); - }) - .then(function (currentUrl) { - log.debug('in navigateTo url = ' + currentUrl); - if (lastUrl !== currentUrl) { - lastUrl = currentUrl; - throw new Error('URL changed, waiting for it to settle'); - } - }); - }); - }) - .then(async () => { - if (appName === 'status_page') return; - if (await testSubjects.exists('statusPageContainer')) { - throw new Error('Navigation ended up at the status page.'); - } - }); + await retry.try(async () => { + await this.sleep(501); + const currentUrl = await browser.getCurrentUrl(); + log.debug('in navigateTo url = ' + currentUrl); + if (lastUrl !== currentUrl) { + lastUrl = currentUrl; + throw new Error('URL changed, waiting for it to settle'); + } + }); + if (appName === 'status_page') return; + if (await testSubjects.exists('statusPageContainer')) { + throw new Error('Navigation ended up at the status page.'); + } }); } - async sleep(sleepMilliseconds) { - log.debug('... sleep(' + sleepMilliseconds + ') start'); - await delay(sleepMilliseconds); - log.debug('... sleep(' + sleepMilliseconds + ') end'); - } - - createErrorHandler(testObj) { - const testName = (testObj.parent) ? [testObj.parent.name, testObj.name].join('_') : testObj.name; - return error => { - const now = Date.now(); - const fileName = `failure_${now}_${testName}`; - - return this.saveScreenshot(fileName, true) - .then(function () { - throw error; - }); - }; - } - - async waitUntilUrlIncludes(path) { + async waitUntilUrlIncludes(path: string) { await retry.try(async () => { const url = await browser.getCurrentUrl(); if (!url.includes(path)) { @@ -288,13 +283,10 @@ export function CommonPageProvider({ getService, getPageObjects }) { return { title: await element.getAttribute('data-title'), - description: await element.getAttribute('data-description') + description: await element.getAttribute('data-description'), }; } - /** - * Makes sure the modal overlay is not showing, tries a few times in case it is in the process of hiding. - */ async ensureModalOverlayHidden() { return retry.try(async () => { const shown = await testSubjects.exists('confirmModalTitleText'); @@ -316,9 +308,11 @@ export function CommonPageProvider({ getService, getPageObjects }) { await browser.pressKeys(browser.keys.ENTER); } - // pass in true if your test will show multiple modals - // in succession - async clickCancelOnModal(overlayWillStay = false) { + /** + * Clicks cancel button on modal + * @param overlayWillStay pass in true if your test will show multiple modals in succession + */ + async clickCancelOnModal(overlayWillStay = true) { log.debug('Clicking modal cancel'); await testSubjects.click('confirmModalCancelButton'); if (!overlayWillStay) { @@ -326,19 +320,17 @@ export function CommonPageProvider({ getService, getPageObjects }) { } } - async expectConfirmModalOpenState(state) { - if (typeof state !== 'boolean') { - throw new Error('pass true or false to expectConfirmModalOpenState()'); - } - + async expectConfirmModalOpenState(state: boolean) { log.debug(`expectConfirmModalOpenState(${state})`); - // we use retry here instead of a simple .exists() check because the modal // fades in/out, which takes time, and we really only care that at some point // the modal is either open or closed await retry.try(async () => { const actualState = await testSubjects.exists('confirmModalCancelButton'); - expect(actualState).to.be(state); + expect(actualState).to.equal( + state, + state ? 'Confirm modal should be present' : 'Confirm modal should be hidden' + ); }); } @@ -364,16 +356,10 @@ export function CommonPageProvider({ getService, getPageObjects }) { } async closeToast() { - let toast; - await retry.try(async () => { - toast = await find.byCssSelector('.euiToast'); - if (!toast) { - throw new Error('Toast is not visible yet'); - } - }); + const toast = await find.byCssSelector('.euiToast', 2 * defaultFindTimeout); await toast.moveMouseTo(); const title = await (await find.byCssSelector('.euiToastHeader__title')).getVisibleText(); - log.debug(title); + log.debug(`Toast title: ${title}`); await find.clickByCssSelector('.euiToast__closeButton'); return title; } @@ -392,7 +378,7 @@ export function CommonPageProvider({ getService, getPageObjects }) { } async getBodyText() { - if (await find.existsByCssSelector('a[id=rawdata-tab]', 10000)) { + if (await find.existsByCssSelector('a[id=rawdata-tab]', defaultFindTimeout)) { // Firefox has 3 tabs and requires navigation to see Raw output await find.clickByCssSelector('a[id=rawdata-tab]'); } @@ -418,7 +404,7 @@ export function CommonPageProvider({ getService, getPageObjects }) { method: 'get', headers: { 'Content-Type': 'application/json', - 'Authorization': 'Basic ' + Buffer.from(username + ':' + password).toString('base64') + Authorization: 'Basic ' + Buffer.from(username + ':' + password).toString('base64'), }, }); return response.status !== 200; diff --git a/test/functional/page_objects/index.ts b/test/functional/page_objects/index.ts index 84562990191d1..5a104c8d17bf2 100644 --- a/test/functional/page_objects/index.ts +++ b/test/functional/page_objects/index.ts @@ -17,7 +17,6 @@ * under the License. */ -// @ts-ignore not TS yet import { CommonPageProvider } from './common_page'; // @ts-ignore not TS yet import { ConsolePageProvider } from './console_page'; diff --git a/x-pack/legacy/plugins/alerting/server/lib/alert_instance.test.ts b/x-pack/legacy/plugins/alerting/server/lib/alert_instance.test.ts index d3f1100621246..6a80f4d2de4cb 100644 --- a/x-pack/legacy/plugins/alerting/server/lib/alert_instance.test.ts +++ b/x-pack/legacy/plugins/alerting/server/lib/alert_instance.test.ts @@ -18,9 +18,17 @@ afterAll(() => clock.restore()); describe('hasScheduledActions()', () => { test('defaults to false', () => { const alertInstance = new AlertInstance(); - expect(alertInstance.hasScheduledActions(null)).toEqual(false); + expect(alertInstance.hasScheduledActions()).toEqual(false); }); + test('returns true when scheduleActions is called', () => { + const alertInstance = new AlertInstance(); + alertInstance.scheduleActions('default'); + expect(alertInstance.hasScheduledActions()).toEqual(true); + }); +}); + +describe('isThrottled', () => { test(`should throttle when group didn't change and throttle period is still active`, () => { const alertInstance = new AlertInstance({ meta: { @@ -32,7 +40,7 @@ describe('hasScheduledActions()', () => { }); clock.tick(30000); alertInstance.scheduleActions('default'); - expect(alertInstance.hasScheduledActions('1m')).toEqual(false); + expect(alertInstance.isThrottled('1m')).toEqual(true); }); test(`shouldn't throttle when group didn't change and throttle period expired`, () => { @@ -46,7 +54,7 @@ describe('hasScheduledActions()', () => { }); clock.tick(30000); alertInstance.scheduleActions('default'); - expect(alertInstance.hasScheduledActions('15s')).toEqual(true); + expect(alertInstance.isThrottled('15s')).toEqual(false); }); test(`shouldn't throttle when group changes`, () => { @@ -60,7 +68,7 @@ describe('hasScheduledActions()', () => { }); clock.tick(5000); alertInstance.scheduleActions('other-group'); - expect(alertInstance.hasScheduledActions('1m')).toEqual(true); + expect(alertInstance.isThrottled('1m')).toEqual(false); }); }); @@ -75,9 +83,9 @@ describe('unscheduleActions()', () => { test('makes hasScheduledActions() return false', () => { const alertInstance = new AlertInstance(); alertInstance.scheduleActions('default'); - expect(alertInstance.hasScheduledActions(null)).toEqual(true); + expect(alertInstance.hasScheduledActions()).toEqual(true); alertInstance.unscheduleActions(); - expect(alertInstance.hasScheduledActions(null)).toEqual(false); + expect(alertInstance.hasScheduledActions()).toEqual(false); }); test('makes getScheduledActionOptions() return undefined', () => { @@ -113,10 +121,10 @@ describe('scheduleActions()', () => { }, }); alertInstance.replaceState({ otherField: true }).scheduleActions('default', { field: true }); - expect(alertInstance.hasScheduledActions(null)).toEqual(true); + expect(alertInstance.hasScheduledActions()).toEqual(true); }); - test('makes hasScheduledActions() return false when throttled', () => { + test('makes isThrottled() return true when throttled', () => { const alertInstance = new AlertInstance({ state: { foo: true }, meta: { @@ -127,10 +135,10 @@ describe('scheduleActions()', () => { }, }); alertInstance.replaceState({ otherField: true }).scheduleActions('default', { field: true }); - expect(alertInstance.hasScheduledActions('1m')).toEqual(false); + expect(alertInstance.isThrottled('1m')).toEqual(true); }); - test('make hasScheduledActions() return true when throttled expired', () => { + test('make isThrottled() return false when throttled expired', () => { const alertInstance = new AlertInstance({ state: { foo: true }, meta: { @@ -142,7 +150,7 @@ describe('scheduleActions()', () => { }); clock.tick(120000); alertInstance.replaceState({ otherField: true }).scheduleActions('default', { field: true }); - expect(alertInstance.hasScheduledActions('1m')).toEqual(true); + expect(alertInstance.isThrottled('1m')).toEqual(false); }); test('makes getScheduledActionOptions() return given options', () => { diff --git a/x-pack/legacy/plugins/alerting/server/lib/alert_instance.ts b/x-pack/legacy/plugins/alerting/server/lib/alert_instance.ts index ec2dc1dfa4691..1e2cc26f364ad 100644 --- a/x-pack/legacy/plugins/alerting/server/lib/alert_instance.ts +++ b/x-pack/legacy/plugins/alerting/server/lib/alert_instance.ts @@ -35,13 +35,14 @@ export class AlertInstance { this.meta = meta; } - hasScheduledActions(throttle: string | null) { - // scheduleActions function wasn't called + hasScheduledActions() { + return this.scheduledExecutionOptions !== undefined; + } + + isThrottled(throttle: string | null) { if (this.scheduledExecutionOptions === undefined) { return false; } - // Shouldn't schedule actions if still within throttling window - // Reset if actionGroup changes const throttleMills = throttle ? parseDuration(throttle) : 0; const actionGroup = this.scheduledExecutionOptions.actionGroup; if ( @@ -49,9 +50,9 @@ export class AlertInstance { this.meta.lastScheduledActions.group === actionGroup && new Date(this.meta.lastScheduledActions.date).getTime() + throttleMills > Date.now() ) { - return false; + return true; } - return true; + return false; } getScheduledActionOptions() { @@ -68,7 +69,7 @@ export class AlertInstance { } scheduleActions(actionGroup: string, context: Context = {}) { - if (this.hasScheduledActions(null)) { + if (this.hasScheduledActions()) { throw new Error('Alert instance execution has already been scheduled, cannot schedule twice'); } this.scheduledExecutionOptions = { actionGroup, context, state: this.state }; diff --git a/x-pack/legacy/plugins/alerting/server/lib/task_runner_factory.ts b/x-pack/legacy/plugins/alerting/server/lib/task_runner_factory.ts index 0c6bd1b4a777a..66d445f57fe73 100644 --- a/x-pack/legacy/plugins/alerting/server/lib/task_runner_factory.ts +++ b/x-pack/legacy/plugins/alerting/server/lib/task_runner_factory.ts @@ -148,8 +148,12 @@ export class TaskRunnerFactory { await Promise.all( Object.keys(alertInstances).map(alertInstanceId => { const alertInstance = alertInstances[alertInstanceId]; - if (alertInstance.hasScheduledActions(throttle)) { - if (muteAll || mutedInstanceIds.includes(alertInstanceId)) { + if (alertInstance.hasScheduledActions()) { + if ( + alertInstance.isThrottled(throttle) || + muteAll || + mutedInstanceIds.includes(alertInstanceId) + ) { return; } const { actionGroup, context, state } = alertInstance.getScheduledActionOptions()!; diff --git a/x-pack/legacy/plugins/maps/common/constants.js b/x-pack/legacy/plugins/maps/common/constants.js index 942d0a21123c2..ade645d76cad9 100644 --- a/x-pack/legacy/plugins/maps/common/constants.js +++ b/x-pack/legacy/plugins/maps/common/constants.js @@ -59,6 +59,9 @@ export const SOURCE_DATA_ID_ORIGIN = 'source'; export const GEOJSON_FILE = 'GEOJSON_FILE'; +export const MIN_ZOOM = 0; +export const MAX_ZOOM = 24; + export const DECIMAL_DEGREES_PRECISION = 5; // meters precision export const ZOOM_PRECISION = 2; export const ES_SIZE_LIMIT = 10000; diff --git a/x-pack/legacy/plugins/maps/common/migrations/move_apply_global_query.js b/x-pack/legacy/plugins/maps/common/migrations/move_apply_global_query.js new file mode 100644 index 0000000000000..89619893d757c --- /dev/null +++ b/x-pack/legacy/plugins/maps/common/migrations/move_apply_global_query.js @@ -0,0 +1,51 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import _ from 'lodash'; +import { + ES_GEO_GRID, + ES_PEW_PEW, + ES_SEARCH, +} from '../constants'; + +function isEsSource(layerDescriptor) { + const sourceType = _.get(layerDescriptor, 'sourceDescriptor.type'); + return [ES_GEO_GRID, ES_PEW_PEW, ES_SEARCH].includes(sourceType); +} + +// Migration to move applyGlobalQuery from layer to sources. +// Moving to source to provide user the granularity needed to apply global filter per source. +export function moveApplyGlobalQueryToSources({ attributes }) { + if (!attributes.layerListJSON) { + return attributes; + } + + const layerList = JSON.parse(attributes.layerListJSON); + layerList.forEach((layerDescriptor) => { + + const applyGlobalQuery = _.get(layerDescriptor, 'applyGlobalQuery', true); + delete layerDescriptor.applyGlobalQuery; + + if (isEsSource(layerDescriptor)) { + layerDescriptor.sourceDescriptor.applyGlobalQuery = applyGlobalQuery; + } + + if (_.has(layerDescriptor, 'joins')) { + layerDescriptor.joins.forEach(joinDescriptor => { + if (_.has(joinDescriptor, 'right')) { + // joinDescriptor.right is ES_TERM_SOURCE source descriptor + joinDescriptor.right.applyGlobalQuery = applyGlobalQuery; + } + }); + } + + }); + + return { + ...attributes, + layerListJSON: JSON.stringify(layerList), + }; +} diff --git a/x-pack/legacy/plugins/maps/common/migrations/move_apply_global_query.test.js b/x-pack/legacy/plugins/maps/common/migrations/move_apply_global_query.test.js new file mode 100644 index 0000000000000..5a66012cc625d --- /dev/null +++ b/x-pack/legacy/plugins/maps/common/migrations/move_apply_global_query.test.js @@ -0,0 +1,109 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +/* eslint max-len: 0 */ + +import { moveApplyGlobalQueryToSources } from './move_apply_global_query'; + +describe('moveApplyGlobalQueryToSources', () => { + + test('Should handle missing layerListJSON attribute', () => { + const attributes = { + title: 'my map', + }; + expect(moveApplyGlobalQueryToSources({ attributes })).toEqual({ + title: 'my map', + }); + }); + + test('Should ignore layers without ES sources', () => { + const layerListJSON = JSON.stringify([ + { + type: 'TILE', + sourceDescriptor: { + type: 'EMS_TMS' + } + } + ]); + const attributes = { + title: 'my map', + layerListJSON + }; + expect(moveApplyGlobalQueryToSources({ attributes })).toEqual({ + title: 'my map', + layerListJSON, + }); + }); + + test('Should move applyGlobalQuery from layer to source', () => { + const layerListJSON = JSON.stringify([ + { + type: 'HEATMAP', + applyGlobalQuery: false, + sourceDescriptor: { + type: 'ES_GEO_GRID' + } + } + ]); + const attributes = { + title: 'my map', + layerListJSON + }; + expect(moveApplyGlobalQueryToSources({ attributes })).toEqual({ + title: 'my map', + layerListJSON: '[{\"type\":\"HEATMAP\",\"sourceDescriptor\":{\"type\":\"ES_GEO_GRID\",\"applyGlobalQuery\":false}}]', + }); + }); + + test('Should move applyGlobalQuery from layer to join', () => { + const layerListJSON = JSON.stringify([ + { + type: 'VECTOR', + applyGlobalQuery: false, + sourceDescriptor: { + type: 'EMS_FILE' + }, + joins: [ + { + right: {} + } + ] + } + ]); + const attributes = { + title: 'my map', + layerListJSON + }; + expect(moveApplyGlobalQueryToSources({ attributes })).toEqual({ + title: 'my map', + layerListJSON: '[{\"type\":\"VECTOR\",\"sourceDescriptor\":{\"type\":\"EMS_FILE\"},\"joins\":[{\"right\":{\"applyGlobalQuery\":false}}]}]', + }); + }); + + test('Should set applyGlobalQuery to true sources when no value is provided in layer', () => { + const layerListJSON = JSON.stringify([ + { + type: 'VECTOR', + sourceDescriptor: { + type: 'ES_GEO_GRID' + }, + joins: [ + { + right: {} + } + ] + } + ]); + const attributes = { + title: 'my map', + layerListJSON + }; + expect(moveApplyGlobalQueryToSources({ attributes })).toEqual({ + title: 'my map', + layerListJSON: '[{\"type\":\"VECTOR\",\"sourceDescriptor\":{\"type\":\"ES_GEO_GRID\",\"applyGlobalQuery\":true},\"joins\":[{\"right\":{\"applyGlobalQuery\":true}}]}]', + }); + }); +}); diff --git a/x-pack/legacy/plugins/maps/migrations.js b/x-pack/legacy/plugins/maps/migrations.js index cdec1f25ce247..39dc58f259961 100644 --- a/x-pack/legacy/plugins/maps/migrations.js +++ b/x-pack/legacy/plugins/maps/migrations.js @@ -7,6 +7,7 @@ import { extractReferences } from './common/migrations/references'; import { emsRasterTileToEmsVectorTile } from './common/migrations/ems_raster_tile_to_ems_vector_tile'; import { topHitsTimeToSort } from './common/migrations/top_hits_time_to_sort'; +import { moveApplyGlobalQueryToSources } from './common/migrations/move_apply_global_query'; export const migrations = { 'map': { @@ -30,6 +31,14 @@ export const migrations = { '7.5.0': (doc) => { const attributes = topHitsTimeToSort(doc); + return { + ...doc, + attributes, + }; + }, + '7.6.0': (doc) => { + const attributes = moveApplyGlobalQueryToSources(doc); + return { ...doc, attributes, diff --git a/x-pack/legacy/plugins/maps/public/actions/map_actions.js b/x-pack/legacy/plugins/maps/public/actions/map_actions.js index 33771a355ddd5..0dbbbf18426a5 100644 --- a/x-pack/legacy/plugins/maps/public/actions/map_actions.js +++ b/x-pack/legacy/plugins/maps/public/actions/map_actions.js @@ -634,19 +634,6 @@ export function setLayerQuery(id, query) { }; } -export function setLayerApplyGlobalQuery(id, applyGlobalQuery) { - return (dispatch) => { - dispatch({ - type: UPDATE_LAYER_PROP, - id, - propName: 'applyGlobalQuery', - newValue: applyGlobalQuery, - }); - - dispatch(syncDataForLayer(id)); - }; -} - export function removeSelectedLayer() { return (dispatch, getState) => { const state = getState(); diff --git a/x-pack/legacy/plugins/maps/public/angular/get_initial_layers.test.js b/x-pack/legacy/plugins/maps/public/angular/get_initial_layers.test.js index 5dc08751347e4..d362fac7570ce 100644 --- a/x-pack/legacy/plugins/maps/public/angular/get_initial_layers.test.js +++ b/x-pack/legacy/plugins/maps/public/angular/get_initial_layers.test.js @@ -45,7 +45,6 @@ describe('kibana.yml configured with map.tilemap.url', () => { alpha: 1, __dataRequests: [], id: layers[0].id, - applyGlobalQuery: true, label: null, maxZoom: 24, minZoom: 0, @@ -87,7 +86,6 @@ describe('EMS is enabled', () => { alpha: 1, __dataRequests: [], id: layers[0].id, - applyGlobalQuery: true, label: null, maxZoom: 24, minZoom: 0, diff --git a/x-pack/legacy/plugins/maps/public/components/__snapshots__/geometry_filter_form.test.js.snap b/x-pack/legacy/plugins/maps/public/components/__snapshots__/geometry_filter_form.test.js.snap index 0205519674be3..98e6fa0517f58 100644 --- a/x-pack/legacy/plugins/maps/public/components/__snapshots__/geometry_filter_form.test.js.snap +++ b/x-pack/legacy/plugins/maps/public/components/__snapshots__/geometry_filter_form.test.js.snap @@ -188,6 +188,88 @@ exports[`should not show "within" relation when filter geometry is not closed 1` `; +exports[`should render error message 1`] = ` + + + + + + + + + My index + + +
+ my geo field + , + "value": "My index/my geo field", + }, + ] + } + valueOfSelected="My index/my geo field" + /> +
+ + + Simulated error + + + + Create filter + + +
+`; + exports[`should render relation select when geo field is geo_shape 1`] = ` {this.props.errorMsg}; + } return ( + {error} + { + const component = shallow( + + ); + + expect(component).toMatchSnapshot(); +}); diff --git a/x-pack/legacy/plugins/maps/public/components/global_filter_checkbox.js b/x-pack/legacy/plugins/maps/public/components/global_filter_checkbox.js new file mode 100644 index 0000000000000..e841fa573c9a5 --- /dev/null +++ b/x-pack/legacy/plugins/maps/public/components/global_filter_checkbox.js @@ -0,0 +1,33 @@ +/* + * 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 { EuiFormRow, EuiSwitch } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; + +const label = i18n.translate('xpack.maps.layerPanel.applyGlobalQueryCheckboxLabel', { + defaultMessage: `Apply global filter to source`, +}); + +export function GlobalFilterCheckbox({ applyGlobalQuery, customLabel, setApplyGlobalQuery }) { + const onApplyGlobalQueryChange = event => { + setApplyGlobalQuery(event.target.checked); + }; + + return ( + + + + ); +} diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/filter_editor/filter_editor.js b/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/filter_editor/filter_editor.js index f736f87dc46e1..20520ad3ff8f1 100644 --- a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/filter_editor/filter_editor.js +++ b/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/filter_editor/filter_editor.js @@ -43,7 +43,8 @@ export class FilterEditor extends Component { } _loadIndexPatterns = async () => { - const indexPatternIds = this.props.layer.getIndexPatternIds(); + // Filter only effects source so only load source indices. + const indexPatternIds = this.props.layer.getSource().getIndexPatternIds(); const indexPatterns = []; const getIndexPatternPromises = indexPatternIds.map(async indexPatternId => { try { diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/join_editor/resources/join.js b/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/join_editor/resources/join.js index 44987e0d241e3..2b7c614f182fd 100644 --- a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/join_editor/resources/join.js +++ b/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/join_editor/resources/join.js @@ -15,6 +15,7 @@ import { i18n } from '@kbn/i18n'; import { JoinExpression } from './join_expression'; import { MetricsExpression } from './metrics_expression'; import { WhereExpression } from './where_expression'; +import { GlobalFilterCheckbox } from '../../../../components/global_filter_checkbox'; import { indexPatternService, @@ -168,6 +169,16 @@ export class Join extends Component { }); } + _onApplyGlobalQueryChange = applyGlobalQuery => { + this.props.onChange({ + leftField: this.props.join.leftField, + right: { + ...this.props.join.right, + applyGlobalQuery, + }, + }); + } + render() { const { join, @@ -184,6 +195,7 @@ export class Join extends Component { const isJoinConfigComplete = join.leftField && right.indexPatternId && right.term; let metricsExpression; + let globalFilterCheckbox; if (isJoinConfigComplete) { metricsExpression = ( @@ -194,6 +206,15 @@ export class Join extends Component { /> ); + globalFilterCheckbox = ( + + ); } let whereExpression; @@ -234,6 +255,8 @@ export class Join extends Component { {whereExpression} + {globalFilterCheckbox} + dispatch(updateLayerMinZoom(id, minZoom)), updateMaxZoom: (id, maxZoom) => dispatch(updateLayerMaxZoom(id, maxZoom)), updateAlpha: (id, alpha) => dispatch(updateLayerAlpha(id, alpha)), - setLayerApplyGlobalQuery: (layerId, applyGlobalQuery) => { - dispatch(setLayerApplyGlobalQuery(layerId, applyGlobalQuery)); - } }; } diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/layer_settings/layer_settings.js b/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/layer_settings/layer_settings.js index 5be842f949871..7b89bba29352a 100644 --- a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/layer_settings/layer_settings.js +++ b/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/layer_settings/layer_settings.js @@ -12,17 +12,13 @@ import { EuiFormRow, EuiFieldText, EuiSpacer, - EuiSwitch, - EuiToolTip, } from '@elastic/eui'; import { ValidatedRange } from '../../../components/validated_range'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import { ValidatedDualRange } from 'ui/validated_range'; - -const MIN_ZOOM = 0; -const MAX_ZOOM = 24; +import { MAX_ZOOM, MIN_ZOOM } from '../../../../common/constants'; export function LayerSettings(props) { const onLabelChange = event => { @@ -37,14 +33,9 @@ export function LayerSettings(props) { const onAlphaChange = alpha => { const alphaDecimal = alpha / 100; - props.updateAlpha(props.layerId, alphaDecimal); }; - const onApplyGlobalQueryChange = event => { - props.setLayerApplyGlobalQuery(props.layerId, event.target.checked); - }; - const renderZoomSliders = () => { return ( { - const layerSupportsGlobalQuery = props.layer.getIndexPatternIds().length; - - const applyGlobalQueryCheckbox = ( - - - - ); - - if (layerSupportsGlobalQuery) { - return applyGlobalQueryCheckbox; - } - - return ( - - {applyGlobalQueryCheckbox} - - ); - }; - return ( @@ -164,7 +116,6 @@ export function LayerSettings(props) { {renderLabel()} {renderZoomSliders()} {renderAlphaSlider()} - {renderApplyGlobalQueryCheckbox()} diff --git a/x-pack/legacy/plugins/maps/public/connected_components/map/features_tooltip/feature_geometry_filter_form.js b/x-pack/legacy/plugins/maps/public/connected_components/map/features_tooltip/feature_geometry_filter_form.js index b5029407d4786..5552a0f4bd5ee 100644 --- a/x-pack/legacy/plugins/maps/public/connected_components/map/features_tooltip/feature_geometry_filter_form.js +++ b/x-pack/legacy/plugins/maps/public/connected_components/map/features_tooltip/feature_geometry_filter_form.js @@ -11,11 +11,16 @@ import { i18n } from '@kbn/i18n'; import { createSpatialFilterWithGeometry } from '../../../elasticsearch_geo_utils'; import { GEO_JSON_TYPE } from '../../../../common/constants'; import { GeometryFilterForm } from '../../../components/geometry_filter_form'; +import { UrlOverflowService } from 'ui/error_url_overflow'; +import rison from 'rison-node'; + +const urlOverflow = new UrlOverflowService(); export class FeatureGeometryFilterForm extends Component { state = { isLoading: false, + errorMsg: undefined, } componentDidMount() { @@ -46,6 +51,7 @@ export class FeatureGeometryFilterForm extends Component { } _createFilter = async ({ geometryLabel, indexPatternId, geoFieldName, geoFieldType, relation }) => { + this.setState({ errorMsg: undefined }); const preIndexedShape = await this._loadPreIndexedShape(); if (!this._isMounted) { // do not create filter if component is unmounted @@ -61,6 +67,18 @@ export class FeatureGeometryFilterForm extends Component { geoFieldType, relation, }); + + // Ensure filter will not overflow URL. Filters that contain geometry can be extremely large. + // No elasticsearch support for pre-indexed shapes and geo_point spatial queries. + if (window.location.href.length + rison.encode(filter).length > urlOverflow.failLength()) { + this.setState({ + errorMsg: i18n.translate('xpack.maps.tooltip.geometryFilterForm.filterTooLargeMessage', { + defaultMessage: 'Cannot create filter. Filters are added to the URL, and this shape has too many vertices to fit in the URL.' + }) + }); + return; + } + this.props.addFilters([filter]); this.props.onClose(); } @@ -102,6 +120,7 @@ export class FeatureGeometryFilterForm extends Component { isFilterGeometryClosed={this.props.geometry.type !== GEO_JSON_TYPE.LINE_STRING && this.props.geometry.type !== GEO_JSON_TYPE.MULTI_LINE_STRING} isLoading={this.state.isLoading} + errorMsg={this.state.errorMsg} /> ); } diff --git a/x-pack/legacy/plugins/maps/public/connected_components/map/mb/tooltip_control/__snapshots__/tool_control.test.js.snap b/x-pack/legacy/plugins/maps/public/connected_components/map/mb/tooltip_control/__snapshots__/tooltip_control.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/map/mb/tooltip_control/__snapshots__/tool_control.test.js.snap rename to x-pack/legacy/plugins/maps/public/connected_components/map/mb/tooltip_control/__snapshots__/tooltip_control.test.js.snap diff --git a/x-pack/legacy/plugins/maps/public/connected_components/map/mb/tooltip_control/tool_control.test.js b/x-pack/legacy/plugins/maps/public/connected_components/map/mb/tooltip_control/tooltip_control.test.js similarity index 98% rename from x-pack/legacy/plugins/maps/public/connected_components/map/mb/tooltip_control/tool_control.test.js rename to x-pack/legacy/plugins/maps/public/connected_components/map/mb/tooltip_control/tooltip_control.test.js index 2d3c6ef4bfb1a..ea5a5054e5633 100644 --- a/x-pack/legacy/plugins/maps/public/connected_components/map/mb/tooltip_control/tool_control.test.js +++ b/x-pack/legacy/plugins/maps/public/connected_components/map/mb/tooltip_control/tooltip_control.test.js @@ -4,6 +4,12 @@ * you may not use this file except in compliance with the Elastic License. */ +jest.mock('../../features_tooltip/features_tooltip', () => ({ + FeaturesTooltip: () => { + return (
mockFeaturesTooltip
); + } +})); + import sinon from 'sinon'; import React from 'react'; import { mount, shallow } from 'enzyme'; diff --git a/x-pack/legacy/plugins/maps/public/connected_components/map/mb/utils.js b/x-pack/legacy/plugins/maps/public/connected_components/map/mb/utils.js index dfe50a015eb24..d7ea18440dc8c 100644 --- a/x-pack/legacy/plugins/maps/public/connected_components/map/mb/utils.js +++ b/x-pack/legacy/plugins/maps/public/connected_components/map/mb/utils.js @@ -109,25 +109,38 @@ function getImageData(img) { return context.getImageData(0, 0, img.width, img.height); } -export async function addSpritesheetToMap(json, imgUrl, mbMap) { - - const image = new Image(); - image.crossOrigin = 'Anonymous'; - image.onload = (el) => { - const imgData = getImageData(el.currentTarget); - for (const imageId in json) { - if (!(json.hasOwnProperty(imageId) && !mbMap.hasImage(imageId))) { - continue; - } - const { width, height, x, y, sdf, pixelRatio } = json[imageId]; - if (typeof width !== 'number' || typeof height !== 'number') { - continue; - } +export async function loadSpriteSheetImageData(imgUrl) { + return new Promise((resolve, reject) => { + const image = new Image(); + image.crossOrigin = 'Anonymous'; + image.onload = (el) => { + const imgData = getImageData(el.currentTarget); + resolve(imgData); + }; + image.onerror = (e) =>{ + reject(e); + }; + image.src = imgUrl; + }); +} - const data = new RGBAImage({ width, height }); - RGBAImage.copy(imgData, data, { x, y }, { x: 0, y: 0 }, { width, height }); - mbMap.addImage(imageId, data, { pixelRatio, sdf }); +export function addSpriteSheetToMapFromImageData(json, imgData, mbMap) { + for (const imageId in json) { + if (!(json.hasOwnProperty(imageId) && !mbMap.hasImage(imageId))) { + continue; } - }; - image.src = imgUrl; + const { width, height, x, y, sdf, pixelRatio } = json[imageId]; + if (typeof width !== 'number' || typeof height !== 'number') { + continue; + } + + const data = new RGBAImage({ width, height }); + RGBAImage.copy(imgData, data, { x, y }, { x: 0, y: 0 }, { width, height }); + mbMap.addImage(imageId, data, { pixelRatio, sdf }); + } +} + +export async function addSpritesheetToMap(json, imgUrl, mbMap) { + const imgData = await loadSpriteSheetImageData(imgUrl); + addSpriteSheetToMapFromImageData(json, imgData, mbMap); } diff --git a/x-pack/legacy/plugins/maps/public/connected_components/toolbar_overlay/set_view_control/set_view_control.js b/x-pack/legacy/plugins/maps/public/connected_components/toolbar_overlay/set_view_control/set_view_control.js index 05ec23d10795a..9c983447bfbf6 100644 --- a/x-pack/legacy/plugins/maps/public/connected_components/toolbar_overlay/set_view_control/set_view_control.js +++ b/x-pack/legacy/plugins/maps/public/connected_components/toolbar_overlay/set_view_control/set_view_control.js @@ -18,6 +18,7 @@ import { } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; +import { MAX_ZOOM, MIN_ZOOM } from '../../../../common/constants'; function getViewString(lat, lon, zoom) { return `${lat},${lon},${zoom}`; @@ -117,8 +118,8 @@ export class SetViewControl extends Component { const { isInvalid: isZoomInvalid, component: zoomFormRow } = this._renderNumberFormRow({ value: this.state.zoom, - min: 0, - max: 24, + min: MIN_ZOOM, + max: MAX_ZOOM, onChange: this._onZoomChange, label: i18n.translate('xpack.maps.setViewControl.zoomLabel', { defaultMessage: 'Zoom', diff --git a/x-pack/legacy/plugins/maps/public/layers/joins/inner_join.js b/x-pack/legacy/plugins/maps/public/layers/joins/inner_join.js index 9c9aa912f3a39..c1ca1a90c15e6 100644 --- a/x-pack/legacy/plugins/maps/public/layers/joins/inner_join.js +++ b/x-pack/legacy/plugins/maps/public/layers/joins/inner_join.js @@ -90,6 +90,10 @@ export class InnerJoin { return this._rightSource.getIndexPatternIds(); } + getQueryableIndexPatternIds() { + return this._rightSource.getQueryableIndexPatternIds(); + } + getWhereQuery() { return this._rightSource.getWhereQuery(); } diff --git a/x-pack/legacy/plugins/maps/public/layers/layer.js b/x-pack/legacy/plugins/maps/public/layers/layer.js index 6515ab608c2ea..3cde1b4bc0a41 100644 --- a/x-pack/legacy/plugins/maps/public/layers/layer.js +++ b/x-pack/legacy/plugins/maps/public/layers/layer.js @@ -10,8 +10,10 @@ import turf from 'turf'; import turfBooleanContains from '@turf/boolean-contains'; import { DataRequest } from './util/data_request'; import { + MAX_ZOOM, MB_SOURCE_ID_LAYER_ID_PREFIX_DELIMITER, - SOURCE_DATA_ID_ORIGIN + MIN_ZOOM, + SOURCE_DATA_ID_ORIGIN, } from '../../common/constants'; import uuid from 'uuid/v4'; import { copyPersistentState } from '../reducers/util'; @@ -44,11 +46,10 @@ export class AbstractLayer { layerDescriptor.__dataRequests = _.get(options, '__dataRequests', []); layerDescriptor.id = _.get(options, 'id', uuid()); layerDescriptor.label = options.label && options.label.length > 0 ? options.label : null; - layerDescriptor.minZoom = _.get(options, 'minZoom', 0); - layerDescriptor.maxZoom = _.get(options, 'maxZoom', 24); + layerDescriptor.minZoom = _.get(options, 'minZoom', MIN_ZOOM); + layerDescriptor.maxZoom = _.get(options, 'maxZoom', MAX_ZOOM); layerDescriptor.alpha = _.get(options, 'alpha', 0.75); layerDescriptor.visible = _.get(options, 'visible', true); - layerDescriptor.applyGlobalQuery = _.get(options, 'applyGlobalQuery', true); layerDescriptor.style = _.get(options, 'style', {}); return layerDescriptor; @@ -231,10 +232,6 @@ export class AbstractLayer { return this._descriptor.query; } - getApplyGlobalQuery() { - return this._descriptor.applyGlobalQuery; - } - getZoomConfig() { return { minZoom: this._descriptor.minZoom, @@ -383,14 +380,10 @@ export class AbstractLayer { } getIndexPatternIds() { - return []; + return []; } getQueryableIndexPatternIds() { - if (this.getApplyGlobalQuery()) { - return this.getIndexPatternIds(); - } - return []; } diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/client_file_source/constants.js b/x-pack/legacy/plugins/maps/public/layers/sources/client_file_source/constants.js deleted file mode 100644 index 779ac2861e9f4..0000000000000 --- a/x-pack/legacy/plugins/maps/public/layers/sources/client_file_source/constants.js +++ /dev/null @@ -1,7 +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 DEFAULT_APPLY_GLOBAL_QUERY = false; diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/client_file_source/geojson_file_source.js b/x-pack/legacy/plugins/maps/public/layers/sources/client_file_source/geojson_file_source.js index 59cfc7b486bdd..6c298352cc03a 100644 --- a/x-pack/legacy/plugins/maps/public/layers/sources/client_file_source/geojson_file_source.js +++ b/x-pack/legacy/plugins/maps/public/layers/sources/client_file_source/geojson_file_source.js @@ -15,9 +15,6 @@ import { ClientFileCreateSourceEditor } from './create_client_file_source_editor import { ESSearchSource } from '../es_search_source'; import uuid from 'uuid/v4'; import _ from 'lodash'; -import { - DEFAULT_APPLY_GLOBAL_QUERY -} from './constants'; import { i18n } from '@kbn/i18n'; export class GeojsonFileSource extends AbstractVectorSource { @@ -31,9 +28,6 @@ export class GeojsonFileSource extends AbstractVectorSource { }); static icon = 'importAction'; static isIndexingSource = true; - static layerDefaults = { - applyGlobalQuery: DEFAULT_APPLY_GLOBAL_QUERY - } static createDescriptor(geoJson, name) { // Wrap feature as feature collection if needed @@ -96,7 +90,7 @@ export class GeojsonFileSource extends AbstractVectorSource { geoField, filterByMapBounds }, inspectorAdapters); - addAndViewSource(source, this.layerDefaults); + addAndViewSource(source); importSuccessHandler(indexResponses); } }; diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/es_geo_grid_source/es_geo_grid_source.js b/x-pack/legacy/plugins/maps/public/layers/sources/es_geo_grid_source/es_geo_grid_source.js index a8b52e586da28..53a77dc0c00a8 100644 --- a/x-pack/legacy/plugins/maps/public/layers/sources/es_geo_grid_source/es_geo_grid_source.js +++ b/x-pack/legacy/plugins/maps/public/layers/sources/es_geo_grid_source/es_geo_grid_source.js @@ -85,6 +85,7 @@ export class ESGeoGridSource extends AbstractESAggSource { metrics={this._descriptor.metrics} renderAs={this._descriptor.requestType} resolution={this._descriptor.resolution} + applyGlobalQuery={this._descriptor.applyGlobalQuery} /> ); } diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/es_geo_grid_source/update_source_editor.js b/x-pack/legacy/plugins/maps/public/layers/sources/es_geo_grid_source/update_source_editor.js index 9ea5093724ed9..1b446e1f2159a 100644 --- a/x-pack/legacy/plugins/maps/public/layers/sources/es_geo_grid_source/update_source_editor.js +++ b/x-pack/legacy/plugins/maps/public/layers/sources/es_geo_grid_source/update_source_editor.js @@ -14,6 +14,7 @@ import { ResolutionEditor } from './resolution_editor'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import { EuiSpacer, EuiTitle } from '@elastic/eui'; +import { GlobalFilterCheckbox } from '../../../components/global_filter_checkbox'; export class UpdateSourceEditor extends Component { state = { @@ -62,6 +63,10 @@ export class UpdateSourceEditor extends Component { this.props.onChange({ propName: 'resolution', value: e }); }; + _onApplyGlobalQueryChange = applyGlobalQuery => { + this.props.onChange({ propName: 'applyGlobalQuery', value: applyGlobalQuery }); + }; + _renderMetricsEditor() { const metricsFilter = this.props.renderAs === RENDER_AS.HEATMAP @@ -95,7 +100,13 @@ export class UpdateSourceEditor extends Component { + {this._renderMetricsEditor()} + + ); } diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/es_pew_pew_source/es_pew_pew_source.js b/x-pack/legacy/plugins/maps/public/layers/sources/es_pew_pew_source/es_pew_pew_source.js index 6cc6ab196f7d8..0e224578c5754 100644 --- a/x-pack/legacy/plugins/maps/public/layers/sources/es_pew_pew_source/es_pew_pew_source.js +++ b/x-pack/legacy/plugins/maps/public/layers/sources/es_pew_pew_source/es_pew_pew_source.js @@ -68,6 +68,7 @@ export class ESPewPewSource extends AbstractESAggSource { indexPatternId={this._descriptor.indexPatternId} onChange={onChange} metrics={this._descriptor.metrics} + applyGlobalQuery={this._descriptor.applyGlobalQuery} /> ); } diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/es_pew_pew_source/update_source_editor.js b/x-pack/legacy/plugins/maps/public/layers/sources/es_pew_pew_source/update_source_editor.js index 5f73ae61a2864..2df7dfc3e0764 100644 --- a/x-pack/legacy/plugins/maps/public/layers/sources/es_pew_pew_source/update_source_editor.js +++ b/x-pack/legacy/plugins/maps/public/layers/sources/es_pew_pew_source/update_source_editor.js @@ -11,6 +11,7 @@ import { indexPatternService } from '../../../kibana_services'; import { i18n } from '@kbn/i18n'; import { EuiTitle, EuiSpacer } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; +import { GlobalFilterCheckbox } from '../../../components/global_filter_checkbox'; export class UpdateSourceEditor extends Component { state = { @@ -55,6 +56,10 @@ export class UpdateSourceEditor extends Component { this.props.onChange({ propName: 'metrics', value: metrics }); }; + _onApplyGlobalQueryChange = applyGlobalQuery => { + this.props.onChange({ propName: 'applyGlobalQuery', value: applyGlobalQuery }); + }; + render() { return ( <> @@ -70,6 +75,10 @@ export class UpdateSourceEditor extends Component { metrics={this.props.metrics} onChange={this._onMetricsChange} /> + ); } diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/__snapshots__/update_source_editor.test.js.snap b/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/__snapshots__/update_source_editor.test.js.snap index c0e443758ada6..eb9bba76e4405 100644 --- a/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/__snapshots__/update_source_editor.test.js.snap +++ b/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/__snapshots__/update_source_editor.test.js.snap @@ -96,6 +96,9 @@ exports[`should enable sort order select when sort field provided 1`] = ` onChange={[Function]} />
+ `; @@ -234,6 +237,9 @@ exports[`should render top hits form when useTopHits is true 1`] = ` onChange={[Function]} />
+ `; @@ -332,5 +338,8 @@ exports[`should render update source editor 1`] = ` onChange={[Function]} /> + `; diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/es_search_source.js b/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/es_search_source.js index d9c48424bb77d..d3f6f3aeaf30f 100644 --- a/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/es_search_source.js +++ b/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/es_search_source.js @@ -55,6 +55,7 @@ export class ESSearchSource extends AbstractESSource { constructor(descriptor, inspectorAdapters) { super({ + ...descriptor, id: descriptor.id, type: ESSearchSource.type, indexPatternId: descriptor.indexPatternId, @@ -81,6 +82,7 @@ export class ESSearchSource extends AbstractESSource { useTopHits={this._descriptor.useTopHits} topHitsSplitField={this._descriptor.topHitsSplitField} topHitsSize={this._descriptor.topHitsSize} + applyGlobalQuery={this._descriptor.applyGlobalQuery} /> ); } diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/update_source_editor.js b/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/update_source_editor.js index 3678af4d54940..760e087f2e6f6 100644 --- a/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/update_source_editor.js +++ b/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/update_source_editor.js @@ -15,6 +15,7 @@ import { } from '@elastic/eui'; import { SingleFieldSelect } from '../../../components/single_field_select'; import { TooltipSelector } from '../../../components/tooltip_selector'; +import { GlobalFilterCheckbox } from '../../../components/global_filter_checkbox'; import { indexPatternService } from '../../../kibana_services'; import { i18n } from '@kbn/i18n'; @@ -106,6 +107,10 @@ export class UpdateSourceEditor extends Component { this.props.onChange({ propName: 'topHitsSize', value: size }); }; + _onApplyGlobalQueryChange = applyGlobalQuery => { + this.props.onChange({ propName: 'applyGlobalQuery', value: applyGlobalQuery }); + }; + renderTopHitsForm() { if (!this.props.useTopHits) { return null; @@ -236,6 +241,11 @@ export class UpdateSourceEditor extends Component { /> + + ); } diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/es_source.js b/x-pack/legacy/plugins/maps/public/layers/sources/es_source.js index cc53ee27af471..010b9360d6501 100644 --- a/x-pack/legacy/plugins/maps/public/layers/sources/es_source.js +++ b/x-pack/legacy/plugins/maps/public/layers/sources/es_source.js @@ -24,6 +24,13 @@ export class AbstractESSource extends AbstractVectorSource { static icon = 'logoElasticsearch'; + constructor(descriptor, inspectorAdapters) { + super({ + ...descriptor, + applyGlobalQuery: _.get(descriptor, 'applyGlobalQuery', true), + }, inspectorAdapters); + } + isFieldAware() { return true; } @@ -40,6 +47,13 @@ export class AbstractESSource extends AbstractVectorSource { return [this._descriptor.indexPatternId]; } + getQueryableIndexPatternIds() { + if (this.getApplyGlobalQuery()) { + return [this._descriptor.indexPatternId]; + } + return []; + } + supportsElasticsearchFilters() { return true; } @@ -55,7 +69,6 @@ export class AbstractESSource extends AbstractVectorSource { return clonedDescriptor; } - async _runEsQuery(requestName, searchSource, registerCancelCallback, requestDescription) { const abortController = new AbortController(); registerCancelCallback(() => abortController.abort()); diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/source.js b/x-pack/legacy/plugins/maps/public/layers/sources/source.js index 3bee49cff6d18..78e57f79bbe56 100644 --- a/x-pack/legacy/plugins/maps/public/layers/sources/source.js +++ b/x-pack/legacy/plugins/maps/public/layers/sources/source.js @@ -95,8 +95,16 @@ export class AbstractSource { return null; } + getApplyGlobalQuery() { + return !!this._descriptor.applyGlobalQuery; + } + getIndexPatternIds() { - return []; + return []; + } + + getQueryableIndexPatternIds() { + return []; } getGeoGridPrecision() { diff --git a/x-pack/legacy/plugins/maps/public/layers/vector_layer.js b/x-pack/legacy/plugins/maps/public/layers/vector_layer.js index b2f45cb6206c6..925ff963e05d4 100644 --- a/x-pack/legacy/plugins/maps/public/layers/vector_layer.js +++ b/x-pack/legacy/plugins/maps/public/layers/vector_layer.js @@ -292,6 +292,14 @@ export class VectorLayer extends AbstractLayer { return indexPatternIds; } + getQueryableIndexPatternIds() { + const indexPatternIds = this._source.getQueryableIndexPatternIds(); + this.getValidJoins().forEach(join => { + indexPatternIds.push(...join.getQueryableIndexPatternIds()); + }); + return indexPatternIds; + } + _findDataRequestForSource(sourceDataId) { return this._dataRequests.find(dataRequest => dataRequest.getDataId() === sourceDataId); } @@ -389,7 +397,7 @@ export class VectorLayer extends AbstractLayer { ...dataFilters, fieldNames: joinSource.getFieldNames(), sourceQuery: joinSource.getWhereQuery(), - applyGlobalQuery: this.getApplyGlobalQuery(), + applyGlobalQuery: joinSource.getApplyGlobalQuery(), }; const canSkip = await this._canSkipSourceUpdate(joinSource, sourceDataId, searchFilters); if (canSkip) { @@ -452,7 +460,7 @@ export class VectorLayer extends AbstractLayer { fieldNames: _.uniq(fieldNames).sort(), geogridPrecision: this._source.getGeoGridPrecision(dataFilters.zoom), sourceQuery: this.getQuery(), - applyGlobalQuery: this.getApplyGlobalQuery(), + applyGlobalQuery: this._source.getApplyGlobalQuery(), sourceMeta: this._source.getSyncMeta(), }; } diff --git a/x-pack/legacy/plugins/maps/public/layers/vector_tile_layer.js b/x-pack/legacy/plugins/maps/public/layers/vector_tile_layer.js index a7f0346b09ef5..d714ac3b092f6 100644 --- a/x-pack/legacy/plugins/maps/public/layers/vector_tile_layer.js +++ b/x-pack/legacy/plugins/maps/public/layers/vector_tile_layer.js @@ -8,7 +8,10 @@ import { TileLayer } from './tile_layer'; import _ from 'lodash'; import { SOURCE_DATA_ID_ORIGIN, LAYER_TYPE } from '../../common/constants'; import { isRetina } from '../meta'; -import { addSpritesheetToMap } from '../connected_components/map/mb/utils';//todo move this implementation +import { + addSpriteSheetToMapFromImageData, + loadSpriteSheetImageData +} from '../connected_components/map/mb/utils';//todo move this implementation const MB_STYLE_TYPE_TO_OPACITY = { 'fill': ['fill-opacity'], @@ -45,7 +48,12 @@ export class VectorTileLayer extends TileLayer { startLoading(SOURCE_DATA_ID_ORIGIN, requestToken, dataFilters); try { const styleAndSprites = await this._source.getVectorStyleSheetAndSpriteMeta(isRetina()); - stopLoading(SOURCE_DATA_ID_ORIGIN, requestToken, styleAndSprites, {}); + const spriteSheetImageData = await loadSpriteSheetImageData(styleAndSprites.spriteMeta.png); + const data = { + ...styleAndSprites, + spriteSheetImageData + }; + stopLoading(SOURCE_DATA_ID_ORIGIN, requestToken, data, {}); } catch(error) { onLoadError(SOURCE_DATA_ID_ORIGIN, requestToken, error.message); } @@ -76,6 +84,15 @@ export class VectorTileLayer extends TileLayer { return vectorStyleAndSprites.spriteMeta; } + _getSpriteImageData() { + const sourceDataRequest = this.getSourceDataRequest(); + if (!sourceDataRequest) { + return null; + } + const vectorStyleAndSprites = sourceDataRequest.getData(); + return vectorStyleAndSprites.spriteSheetImageData; + } + getMbLayerIds() { const vectorStyle = this._getVectorStyle(); if (!vectorStyle) { @@ -118,8 +135,6 @@ export class VectorTileLayer extends TileLayer { } let initialBootstrapCompleted = false; - - //sync sources const sourceIds = Object.keys(vectorStyle.sources); sourceIds.forEach(sourceId => { if (initialBootstrapCompleted) { @@ -149,7 +164,12 @@ export class VectorTileLayer extends TileLayer { newJson[namespacedImageId] = spriteMeta.json[imageId]; } } - addSpritesheetToMap(newJson, spriteMeta.png, mbMap); + + const imageData = this._getSpriteImageData(); + if (!imageData) { + return; + } + addSpriteSheetToMapFromImageData(newJson, imageData, mbMap); //sync layers vectorStyle.layers.forEach(layer => { diff --git a/x-pack/legacy/plugins/ml/common/types/modules.ts b/x-pack/legacy/plugins/ml/common/types/modules.ts index 9eb77d2140323..8fdc0d13a78a9 100644 --- a/x-pack/legacy/plugins/ml/common/types/modules.ts +++ b/x-pack/legacy/plugins/ml/common/types/modules.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ import { SavedObjectAttributes } from 'src/core/server/types'; -import { Datafeed, Job } from '../../public/jobs/new_job_new/common/job_creator/configs'; +import { Datafeed, Job } from '../../public/jobs/new_job/common/job_creator/configs'; export interface ModuleJob { id: string; diff --git a/x-pack/legacy/plugins/ml/common/util/__tests__/parse_interval.js b/x-pack/legacy/plugins/ml/common/util/__tests__/parse_interval.js deleted file mode 100644 index d06e1412b5090..0000000000000 --- a/x-pack/legacy/plugins/ml/common/util/__tests__/parse_interval.js +++ /dev/null @@ -1,70 +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 { parseInterval } from '../parse_interval'; -import expect from '@kbn/expect'; - -describe('ML parse interval util', function () { - it('correctly parses an interval containing unit and value', function () { - let duration = parseInterval('1d'); - expect(duration.as('d')).to.be(1); - - duration = parseInterval('2y'); - expect(duration.as('y')).to.be(2); - - duration = parseInterval('5M'); - expect(duration.as('M')).to.be(5); - - duration = parseInterval('5m'); - expect(duration.as('m')).to.be(5); - - duration = parseInterval('250ms'); - expect(duration.as('ms')).to.be(250); - - duration = parseInterval('100s'); - expect(duration.as('s')).to.be(100); - - duration = parseInterval('23d'); - expect(duration.as('d')).to.be(23); - - duration = parseInterval('52w'); - expect(duration.as('w')).to.be(52); - - duration = parseInterval('0s'); - expect(duration.as('s')).to.be(0); - - duration = parseInterval('0h'); - expect(duration.as('h')).to.be(0); - - }); - - it('correctly handles zero value intervals', function () { - let duration = parseInterval('0h'); - expect(duration.as('h')).to.be(0); - - duration = parseInterval('0d'); - expect(duration).to.not.be.ok(); - }); - - it('returns null for an invalid interval', function () { - let duration = parseInterval(''); - expect(duration).to.not.be.ok(); - - duration = parseInterval(null); - expect(duration).to.not.be.ok(); - - duration = parseInterval('234asdf'); - expect(duration).to.not.be.ok(); - - duration = parseInterval('m'); - expect(duration).to.not.be.ok(); - - duration = parseInterval('1.5h'); - expect(duration).to.not.be.ok(); - }); -}); diff --git a/x-pack/legacy/plugins/ml/common/util/group_color_utils.d.ts b/x-pack/legacy/plugins/ml/common/util/group_color_utils.d.ts deleted file mode 100644 index 4a1a6ebb8fdf3..0000000000000 --- a/x-pack/legacy/plugins/ml/common/util/group_color_utils.d.ts +++ /dev/null @@ -1,6 +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 function tabColor(name: string): string; diff --git a/x-pack/legacy/plugins/ml/common/util/group_color_utils.js b/x-pack/legacy/plugins/ml/common/util/group_color_utils.ts similarity index 56% rename from x-pack/legacy/plugins/ml/common/util/group_color_utils.js rename to x-pack/legacy/plugins/ml/common/util/group_color_utils.ts index 51afa2aff4d95..92f5c6b2c1347 100644 --- a/x-pack/legacy/plugins/ml/common/util/group_color_utils.js +++ b/x-pack/legacy/plugins/ml/common/util/group_color_utils.ts @@ -4,9 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import * as euiVars from '@elastic/eui/dist/eui_theme_dark.json'; -import { stringHash } from './string_utils'; - +import euiVars from '@elastic/eui/dist/eui_theme_dark.json'; const COLORS = [ euiVars.euiColorVis0, @@ -20,18 +18,32 @@ const COLORS = [ euiVars.euiColorVis8, euiVars.euiColorVis9, euiVars.euiColorDarkShade, - euiVars.euiColorPrimary + euiVars.euiColorPrimary, ]; -const colorMap = {}; +const colorMap: Record = {}; -export function tabColor(name) { +export function tabColor(name: string): string { if (colorMap[name] === undefined) { const n = stringHash(name); - const color = COLORS[(n % COLORS.length)]; + const color = COLORS[n % COLORS.length]; colorMap[name] = color; return color; } else { return colorMap[name]; } } + +function stringHash(str: string): number { + let hash = 0; + let chr = 0; + if (str.length === 0) { + return hash; + } + for (let i = 0; i < str.length; i++) { + chr = str.charCodeAt(i); + hash = (hash << 5) - hash + chr; // eslint-disable-line no-bitwise + hash |= 0; // eslint-disable-line no-bitwise + } + return hash < 0 ? hash * -2 : hash; +} diff --git a/x-pack/legacy/plugins/ml/common/util/job_utils.d.ts b/x-pack/legacy/plugins/ml/common/util/job_utils.d.ts index 3e4db7f34bde2..23152afe0af2f 100644 --- a/x-pack/legacy/plugins/ml/common/util/job_utils.d.ts +++ b/x-pack/legacy/plugins/ml/common/util/job_utils.d.ts @@ -32,4 +32,10 @@ export const ML_DATA_PREVIEW_COUNT: number; export function isJobIdValid(jobId: string): boolean; +export function validateModelMemoryLimitUnits( + modelMemoryLimit: string +): { valid: boolean; messages: any[]; contains: () => boolean; find: () => void }; + export function processCreatedBy(customSettings: { created_by?: string }): void; + +export function mlFunctionToESAggregation(functionName: string): string | null; diff --git a/x-pack/legacy/plugins/ml/common/util/job_utils.js b/x-pack/legacy/plugins/ml/common/util/job_utils.js index 7b7a698cafb9c..90a00d40d17b1 100644 --- a/x-pack/legacy/plugins/ml/common/util/job_utils.js +++ b/x-pack/legacy/plugins/ml/common/util/job_utils.js @@ -12,7 +12,7 @@ import numeral from '@elastic/numeral'; import { ALLOWED_DATA_UNITS, JOB_ID_MAX_LENGTH } from '../constants/validation'; import { parseInterval } from './parse_interval'; import { maxLengthValidator } from './validators'; -import { CREATED_BY_LABEL } from '../../public/jobs/new_job_new/common/job_creator/util/constants'; +import { CREATED_BY_LABEL } from '../../public/jobs/new_job/common/job_creator/util/constants'; // work out the default frequency based on the bucket_span in seconds export function calculateDatafeedFrequencyDefaultSeconds(bucketSpanSeconds) { @@ -405,10 +405,11 @@ export function basicJobValidation(job, fields, limits, skipMmlChecks = false) { if (skipMmlChecks === false) { // model memory limit + const mml = job.analysis_limits && job.analysis_limits.model_memory_limit; const { messages: mmlUnitMessages, valid: mmlUnitValid, - } = validateModelMemoryLimitUnits(job); + } = validateModelMemoryLimitUnits(mml); messages.push(...mmlUnitMessages); valid = (valid && mmlUnitValid); @@ -494,12 +495,12 @@ export function validateModelMemoryLimit(job, limits) { }; } -export function validateModelMemoryLimitUnits(job) { +export function validateModelMemoryLimitUnits(modelMemoryLimit) { const messages = []; let valid = true; - if (typeof job.analysis_limits !== 'undefined' && typeof job.analysis_limits.model_memory_limit !== 'undefined') { - const mml = job.analysis_limits.model_memory_limit.toUpperCase(); + if (modelMemoryLimit !== undefined) { + const mml = modelMemoryLimit.toUpperCase(); const mmlSplit = mml.match(/\d+(\w+)$/); const unit = (mmlSplit && mmlSplit.length === 2) ? mmlSplit[1] : null; diff --git a/x-pack/legacy/plugins/ml/common/util/parse_interval.test.ts b/x-pack/legacy/plugins/ml/common/util/parse_interval.test.ts new file mode 100644 index 0000000000000..1717b2f0dd80b --- /dev/null +++ b/x-pack/legacy/plugins/ml/common/util/parse_interval.test.ts @@ -0,0 +1,34 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { parseInterval } from './parse_interval'; + +describe('ML parse interval util', () => { + test('correctly parses an interval containing unit and value', () => { + expect(parseInterval('1d')!.as('d')).toBe(1); + expect(parseInterval('2y')!.as('y')).toBe(2); + expect(parseInterval('5M')!.as('M')).toBe(5); + expect(parseInterval('5m')!.as('m')).toBe(5); + expect(parseInterval('250ms')!.as('ms')).toBe(250); + expect(parseInterval('100s')!.as('s')).toBe(100); + expect(parseInterval('23d')!.as('d')).toBe(23); + expect(parseInterval('52w')!.as('w')).toBe(52); + expect(parseInterval('0s')!.as('s')).toBe(0); + expect(parseInterval('0s')!.as('h')).toBe(0); + }); + + test('correctly handles zero value intervals', () => { + expect(parseInterval('0h')!.as('h')).toBe(0); + expect(parseInterval('0d')).toBe(null); + }); + + test('returns null for an invalid interval', () => { + expect(parseInterval('')).toBe(null); + expect(parseInterval('234asdf')).toBe(null); + expect(parseInterval('m')).toBe(null); + expect(parseInterval('1.5h')).toBe(null); + }); +}); diff --git a/x-pack/legacy/plugins/ml/common/util/parse_interval.js b/x-pack/legacy/plugins/ml/common/util/parse_interval.ts similarity index 73% rename from x-pack/legacy/plugins/ml/common/util/parse_interval.js rename to x-pack/legacy/plugins/ml/common/util/parse_interval.ts index bff1d3ca05e70..98a41be96941b 100644 --- a/x-pack/legacy/plugins/ml/common/util/parse_interval.js +++ b/x-pack/legacy/plugins/ml/common/util/parse_interval.ts @@ -4,17 +4,17 @@ * you may not use this file except in compliance with the Elastic License. */ - - -import moment from 'moment'; +import { duration, Duration, unitOfTime } from 'moment'; import dateMath from '@elastic/datemath'; +type SupportedUnits = unitOfTime.Base; + // Assume interval is in the form (value)(unit), such as "1h" const INTERVAL_STRING_RE = new RegExp('^([0-9]*)\\s*(' + dateMath.units.join('|') + ')$'); // moment.js is only designed to allow fractional values between 0 and 1 // for units of hour or less. -const SUPPORT_ZERO_DURATION_UNITS = ['ms', 's', 'm', 'h']; +const SUPPORT_ZERO_DURATION_UNITS: SupportedUnits[] = ['ms', 's', 'm', 'h']; // Parses an interval String, such as 7d, 1h or 30m to a moment duration. // Differs from the Kibana ui/utils/parse_interval in the following ways: @@ -25,22 +25,25 @@ const SUPPORT_ZERO_DURATION_UNITS = ['ms', 's', 'm', 'h']; // to work with units less than 'day'. // 3. Fractional intervals e.g. 1.5h or 4.5d are not allowed, in line with the behaviour // of the Elasticsearch date histogram aggregation. -export function parseInterval(interval) { - const matches = String(interval).trim().match(INTERVAL_STRING_RE); - if (!Array.isArray(matches)) return null; - if (matches.length < 3) return null; +export function parseInterval(interval: string): Duration | null { + const matches = String(interval) + .trim() + .match(INTERVAL_STRING_RE); + if (!Array.isArray(matches) || matches.length < 3) { + return null; + } try { - const value = parseInt(matches[1]); - const unit = matches[2]; + const value = parseInt(matches[1], 10); + const unit = matches[2] as SupportedUnits; // In line with moment.js, only allow zero value intervals when the unit is less than 'day'. // And check for isNaN as e.g. valueless 'm' will pass the regex test. - if (isNaN(value) || (value < 1 && SUPPORT_ZERO_DURATION_UNITS.indexOf(unit) === -1)) { + if (isNaN(value) || (value < 1 && SUPPORT_ZERO_DURATION_UNITS.indexOf(unit) === -1)) { return null; } - return moment.duration(value, unit); + return duration(value, unit); } catch (e) { return null; } diff --git a/x-pack/legacy/plugins/ml/common/util/string_utils.d.ts b/x-pack/legacy/plugins/ml/common/util/string_utils.d.ts deleted file mode 100644 index f8dbc00643d07..0000000000000 --- a/x-pack/legacy/plugins/ml/common/util/string_utils.d.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 function renderTemplate(str: string, data: string): string; -export function stringHash(str: string): string; diff --git a/x-pack/legacy/plugins/ml/common/util/__tests__/string_utils.js b/x-pack/legacy/plugins/ml/common/util/string_utils.test.ts similarity index 63% rename from x-pack/legacy/plugins/ml/common/util/__tests__/string_utils.js rename to x-pack/legacy/plugins/ml/common/util/string_utils.test.ts index e2a791c74bd7b..aba2dbd230ada 100644 --- a/x-pack/legacy/plugins/ml/common/util/__tests__/string_utils.js +++ b/x-pack/legacy/plugins/ml/common/util/string_utils.test.ts @@ -4,29 +4,24 @@ * you may not use this file except in compliance with the Elastic License. */ - - -import expect from '@kbn/expect'; -import { renderTemplate } from '../string_utils'; +import { renderTemplate } from './string_utils'; describe('ML - string utils', () => { describe('renderTemplate', () => { - - it('returns plain string', () => { + test('returns plain string', () => { const templateString = 'plain string'; const result = renderTemplate(templateString); - expect(result).to.be(result); + expect(result).toBe(result); }); - it('returns rendered template with one replacement', () => { + test('returns rendered template with one replacement', () => { const templateString = 'string with {{one}} replacement'; const result = renderTemplate(templateString, { one: '1' }); - expect(result).to.be('string with 1 replacement'); + expect(result).toBe('string with 1 replacement'); }); - it('returns rendered template with two replacements', () => { + test('returns rendered template with two replacements', () => { const templateString = 'string with {{one}} replacement, and a {{two}} one.'; const result = renderTemplate(templateString, { one: '1', two: '2nd' }); - expect(result).to.be('string with 1 replacement, and a 2nd one.'); + expect(result).toBe('string with 1 replacement, and a 2nd one.'); }); - }); }); diff --git a/x-pack/legacy/plugins/ml/common/util/string_utils.js b/x-pack/legacy/plugins/ml/common/util/string_utils.ts similarity index 59% rename from x-pack/legacy/plugins/ml/common/util/string_utils.js rename to x-pack/legacy/plugins/ml/common/util/string_utils.ts index 383c77f151b72..432baabe773cc 100644 --- a/x-pack/legacy/plugins/ml/common/util/string_utils.js +++ b/x-pack/legacy/plugins/ml/common/util/string_utils.ts @@ -4,15 +4,12 @@ * you may not use this file except in compliance with the Elastic License. */ - - - // A simple template renderer, it replaces mustache/angular style {{...}} tags with // the values provided via the data object -export function renderTemplate(str, data) { +export function renderTemplate(str: string, data?: Record): string { const matches = str.match(/{{(.*?)}}/g); - if (Array.isArray(matches)) { + if (Array.isArray(matches) && data !== undefined) { matches.forEach(v => { str = str.replace(v, data[v.replace(/{{|}}/g, '')]); }); @@ -20,17 +17,3 @@ export function renderTemplate(str, data) { return str; } - -export function stringHash(str) { - let hash = 0; - let chr = ''; - if (str.length === 0) { - return hash; - } - for (let i = 0; i < str.length; i++) { - chr = str.charCodeAt(i); - hash = ((hash << 5) - hash) + chr; - hash |= 0; - } - return hash < 0 ? hash * -2 : hash; -} diff --git a/x-pack/legacy/plugins/ml/common/util/validation_utils.d.ts b/x-pack/legacy/plugins/ml/common/util/validation_utils.d.ts deleted file mode 100644 index 073b111dbb498..0000000000000 --- a/x-pack/legacy/plugins/ml/common/util/validation_utils.d.ts +++ /dev/null @@ -1,7 +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 function isValidJson(json: string): boolean; diff --git a/x-pack/legacy/plugins/ml/common/util/validation_utils.js b/x-pack/legacy/plugins/ml/common/util/validation_utils.js deleted file mode 100644 index 140a8bca45ca2..0000000000000 --- a/x-pack/legacy/plugins/ml/common/util/validation_utils.js +++ /dev/null @@ -1,54 +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 { VALIDATION_STATUS } from '../constants/validation'; - -// get the most severe status level from a list of messages -const contains = (arr, str) => arr.findIndex(v => v === str) >= 0; -export function getMostSevereMessageStatus(messages) { - const statuses = messages.map(m => m.status); - return [ - VALIDATION_STATUS.INFO, - VALIDATION_STATUS.WARNING, - VALIDATION_STATUS.ERROR - ].reduce((previous, current) => { - return contains(statuses, current) ? current : previous; - }, VALIDATION_STATUS.SUCCESS); -} - -// extends an angular directive's scope with the necessary methods -// needed to embed the job validation button -export function addJobValidationMethods($scope, service) { - $scope.getDuration = () => ({ - start: $scope.formConfig.start, - end: $scope.formConfig.end - }); - - // isCurrentJobConfig is used to track if the form configuration - // changed since the last job validation was done - $scope.isCurrentJobConfig = false; - // need to pass true as third argument here to track granular changes - $scope.$watch('formConfig', () => { $scope.isCurrentJobConfig = false; }, true); - $scope.getJobConfig = () => { - $scope.isCurrentJobConfig = true; - return service.getJobFromConfig($scope.formConfig); - }; -} - -export function isValidJson(json) { - if(json === null) { - return false; - } - - try { - JSON.parse(json); - return true; - } catch (error) { - return false; - } -} diff --git a/x-pack/legacy/plugins/ml/common/util/validation_utils.ts b/x-pack/legacy/plugins/ml/common/util/validation_utils.ts new file mode 100644 index 0000000000000..1ae5a899a4b4d --- /dev/null +++ b/x-pack/legacy/plugins/ml/common/util/validation_utils.ts @@ -0,0 +1,33 @@ +/* + * 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 { VALIDATION_STATUS } from '../constants/validation'; + +// get the most severe status level from a list of messages +const contains = (arr: string[], str: string) => arr.indexOf(str) >= 0; + +export function getMostSevereMessageStatus(messages: Array<{ status: string }>): VALIDATION_STATUS { + const statuses = messages.map(m => m.status); + return [VALIDATION_STATUS.INFO, VALIDATION_STATUS.WARNING, VALIDATION_STATUS.ERROR].reduce( + (previous, current) => { + return contains(statuses, current) ? current : previous; + }, + VALIDATION_STATUS.SUCCESS + ); +} + +export function isValidJson(json: string) { + if (json === null) { + return false; + } + + try { + JSON.parse(json); + return true; + } catch (error) { + return false; + } +} diff --git a/x-pack/legacy/plugins/ml/index.ts b/x-pack/legacy/plugins/ml/index.ts old mode 100644 new mode 100755 diff --git a/x-pack/legacy/plugins/ml/public/components/anomalies_table/anomalies_table_columns.js b/x-pack/legacy/plugins/ml/public/components/anomalies_table/anomalies_table_columns.js index d448021d0e84f..be2a3e1f4223b 100644 --- a/x-pack/legacy/plugins/ml/public/components/anomalies_table/anomalies_table_columns.js +++ b/x-pack/legacy/plugins/ml/public/components/anomalies_table/anomalies_table_columns.js @@ -48,10 +48,10 @@ function renderTime(date, aggregationInterval) { } } -function showLinksMenuForItem(item) { - const canConfigureRules = (isRuleSupported(item) && checkPermission('canUpdateJob')); +function showLinksMenuForItem(item, showViewSeriesLink) { + const canConfigureRules = (isRuleSupported(item.source) && checkPermission('canUpdateJob')); return (canConfigureRules || - item.isTimeSeriesViewRecord || + (showViewSeriesLink && item.isTimeSeriesViewRecord) || item.entityName === 'mlcategory' || item.customUrls !== undefined); } @@ -248,7 +248,7 @@ export function getColumns( }); } - const showLinks = (showViewSeriesLink === true) || items.some(item => showLinksMenuForItem(item)); + const showLinks = items.some(item => showLinksMenuForItem(item, showViewSeriesLink)); if (showLinks === true) { columns.push({ diff --git a/x-pack/legacy/plugins/ml/public/components/anomalies_table/description_cell.js b/x-pack/legacy/plugins/ml/public/components/anomalies_table/description_cell.js index 9dc990e0c376d..9c1191ec26626 100644 --- a/x-pack/legacy/plugins/ml/public/components/anomalies_table/description_cell.js +++ b/x-pack/legacy/plugins/ml/public/components/anomalies_table/description_cell.js @@ -29,7 +29,7 @@ export function DescriptionCell({ actual, typical }) { } = getMetricChangeDescription(actual, typical); return ( - + {iconType !== undefined && { context.currentIndexPattern === undefined || context.currentSavedSearch === undefined || context.indexPatterns === undefined || - context.kbnBaseUrl === undefined || context.kibanaConfig === undefined ) { throw new Error('required attribute is undefined'); diff --git a/x-pack/legacy/plugins/ml/public/data_frame_analytics/pages/analytics_exploration/directive.tsx b/x-pack/legacy/plugins/ml/public/data_frame_analytics/pages/analytics_exploration/directive.tsx index 4a28e0b0b881e..76df839b9346b 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame_analytics/pages/analytics_exploration/directive.tsx +++ b/x-pack/legacy/plugins/ml/public/data_frame_analytics/pages/analytics_exploration/directive.tsx @@ -13,10 +13,9 @@ const module = uiModules.get('apps/ml', ['react']); import { IndexPatterns } from 'ui/index_patterns'; import { I18nContext } from 'ui/i18n'; -import { IPrivate } from 'ui/private'; import { InjectorService } from '../../../../common/types/angular'; -import { SearchItemsProvider } from '../../../jobs/new_job_new/utils/new_job_utils'; +import { createSearchItems } from '../../../jobs/new_job/utils/new_job_utils'; import { KibanaConfigTypeFix, KibanaContext } from '../../../contexts/kibana'; @@ -31,19 +30,20 @@ module.directive('mlDataFrameAnalyticsExploration', ($injector: InjectorService) globalState.fetch(); const indexPatterns = $injector.get('indexPatterns'); - const kbnBaseUrl = $injector.get('kbnBaseUrl'); const kibanaConfig = $injector.get('config'); - const Private = $injector.get('Private'); + const $route = $injector.get('$route'); - const createSearchItems = Private(SearchItemsProvider); - const { indexPattern, savedSearch, combinedQuery } = createSearchItems(); + const { indexPattern, savedSearch, combinedQuery } = createSearchItems( + kibanaConfig, + $route.current.locals.indexPattern, + $route.current.locals.savedSearch + ); const kibanaContext = { combinedQuery, currentIndexPattern: indexPattern, currentSavedSearch: savedSearch, indexPatterns, - kbnBaseUrl, kibanaConfig, }; diff --git a/x-pack/legacy/plugins/ml/public/data_frame_analytics/pages/analytics_management/components/create_analytics_form/create_analytics_form.test.tsx b/x-pack/legacy/plugins/ml/public/data_frame_analytics/pages/analytics_management/components/create_analytics_form/create_analytics_form.test.tsx index 1371eacef799b..846397aa93929 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame_analytics/pages/analytics_management/components/create_analytics_form/create_analytics_form.test.tsx +++ b/x-pack/legacy/plugins/ml/public/data_frame_analytics/pages/analytics_management/components/create_analytics_form/create_analytics_form.test.tsx @@ -45,7 +45,7 @@ describe('Data Frame Analytics: ', () => { ); const euiFormRows = wrapper.find('EuiFormRow'); - expect(euiFormRows.length).toBe(6); + expect(euiFormRows.length).toBe(7); const row1 = euiFormRows.at(0); expect(row1.find('label').text()).toBe('Job type'); diff --git a/x-pack/legacy/plugins/ml/public/data_frame_analytics/pages/analytics_management/components/create_analytics_form/create_analytics_form.tsx b/x-pack/legacy/plugins/ml/public/data_frame_analytics/pages/analytics_management/components/create_analytics_form/create_analytics_form.tsx index ab8cc5a5982bb..598f88387f410 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame_analytics/pages/analytics_management/components/create_analytics_form/create_analytics_form.tsx +++ b/x-pack/legacy/plugins/ml/public/data_frame_analytics/pages/analytics_management/components/create_analytics_form/create_analytics_form.tsx @@ -21,15 +21,21 @@ import { FormattedMessage } from '@kbn/i18n/react'; import { metadata } from 'ui/metadata'; import { IndexPattern, INDEX_PATTERN_ILLEGAL_CHARACTERS } from 'ui/index_patterns'; +import { ml } from '../../../../../services/ml_api_service'; import { Field, EVENT_RATE_FIELD_ID } from '../../../../../../common/types/fields'; import { newJobCapsService } from '../../../../../services/new_job_capabilities_service'; import { useKibanaContext } from '../../../../../contexts/kibana'; import { CreateAnalyticsFormProps } from '../../hooks/use_create_analytics_form'; -import { JOB_TYPES } from '../../hooks/use_create_analytics_form/state'; +import { + JOB_TYPES, + DEFAULT_MODEL_MEMORY_LIMIT, + getJobConfigFromFormState, +} from '../../hooks/use_create_analytics_form/state'; import { JOB_ID_MAX_LENGTH } from '../../../../../../common/constants/validation'; import { Messages } from './messages'; import { JobType } from './job_type'; +import { mmlUnitInvalidErrorMessage } from '../../hooks/use_create_analytics_form/reducer'; // based on code used by `ui/index_patterns` internally // remove the space character from the list of illegal characters @@ -73,6 +79,8 @@ export const CreateAnalyticsForm: FC = ({ actions, sta jobIdInvalidMaxLength, jobType, loadingDepFieldOptions, + modelMemoryLimit, + modelMemoryLimitUnitValid, sourceIndex, sourceIndexNameEmpty, sourceIndexNameValid, @@ -103,6 +111,25 @@ export const CreateAnalyticsForm: FC = ({ actions, sta } }; + const loadModelMemoryLimitEstimate = async () => { + try { + const jobConfig = getJobConfigFromFormState(form); + delete jobConfig.dest; + delete jobConfig.model_memory_limit; + const resp = await ml.dataFrameAnalytics.estimateDataFrameAnalyticsMemoryUsage(jobConfig); + setFormState({ + modelMemoryLimit: resp.expected_memory_without_disk, + }); + } catch (e) { + setFormState({ + modelMemoryLimit: + jobType !== undefined + ? DEFAULT_MODEL_MEMORY_LIMIT[jobType] + : DEFAULT_MODEL_MEMORY_LIMIT.outlier_detection, + }); + } + }; + const loadDependentFieldOptions = async () => { setFormState({ loadingDepFieldOptions: true, @@ -175,6 +202,21 @@ export const CreateAnalyticsForm: FC = ({ actions, sta } }, [sourceIndex, jobType, sourceIndexNameEmpty]); + useEffect(() => { + const hasBasicRequiredFields = + jobType !== undefined && sourceIndex !== '' && sourceIndexNameValid === true; + + const hasRequiredAnalysisFields = + (jobType === JOB_TYPES.REGRESSION && + dependentVariable !== '' && + trainingPercent !== undefined) || + jobType === JOB_TYPES.OUTLIER_DETECTION; + + if (hasBasicRequiredFields && hasRequiredAnalysisFields) { + loadModelMemoryLimitEstimate(); + } + }, [jobType, sourceIndex, dependentVariable, trainingPercent]); + return ( @@ -277,7 +319,7 @@ export const CreateAnalyticsForm: FC = ({ actions, sta placeholder={i18n.translate( 'xpack.ml.dataframe.analytics.create.sourceIndexPlaceholder', { - defaultMessage: 'Choose a source index pattern or saved search.', + defaultMessage: 'Choose a source index pattern.', } )} singleSelection={{ asPlainText: true }} @@ -437,6 +479,24 @@ export const CreateAnalyticsForm: FC = ({ actions, sta )} + + setFormState({ modelMemoryLimit: e.target.value })} + isInvalid={modelMemoryLimit === ''} + /> + { const indexPatterns = $injector.get('indexPatterns'); - const kbnBaseUrl = $injector.get('kbnBaseUrl'); const kibanaConfig = $injector.get('config'); - const Private = $injector.get('Private'); + const $route = $injector.get('$route'); - const createSearchItems = Private(SearchItemsProvider); - const { indexPattern, savedSearch, combinedQuery } = createSearchItems(); + const { indexPattern, savedSearch, combinedQuery } = createSearchItems( + kibanaConfig, + $route.current.locals.indexPattern, + $route.current.locals.savedSearch + ); const kibanaContext = { combinedQuery, currentIndexPattern: indexPattern, currentSavedSearch: savedSearch, indexPatterns, - kbnBaseUrl, kibanaConfig, }; diff --git a/x-pack/legacy/plugins/ml/public/data_frame_analytics/pages/analytics_management/hooks/use_create_analytics_form/reducer.test.ts b/x-pack/legacy/plugins/ml/public/data_frame_analytics/pages/analytics_management/hooks/use_create_analytics_form/reducer.test.ts index da5a27f0e12e0..cabf0946ce871 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame_analytics/pages/analytics_management/hooks/use_create_analytics_form/reducer.test.ts +++ b/x-pack/legacy/plugins/ml/public/data_frame_analytics/pages/analytics_management/hooks/use_create_analytics_form/reducer.test.ts @@ -18,7 +18,13 @@ jest.mock('ui/index_patterns', () => ({ type SourceIndex = DataFrameAnalyticsConfig['source']['index']; -const getMockState = (index: SourceIndex) => +const getMockState = ({ + index, + modelMemoryLimit, +}: { + index: SourceIndex; + modelMemoryLimit?: string; +}) => merge(getInitialState(), { form: { jobIdEmpty: false, @@ -30,6 +36,7 @@ const getMockState = (index: SourceIndex) => source: { index }, dest: { index: 'the-destination-index' }, analysis: {}, + model_memory_limit: modelMemoryLimit, }, }); @@ -89,27 +96,50 @@ describe('useCreateAnalyticsForm', () => { test('validateAdvancedEditor(): check index pattern variations', () => { // valid single index pattern - expect(validateAdvancedEditor(getMockState('the-source-index')).isValid).toBe(true); + expect(validateAdvancedEditor(getMockState({ index: 'the-source-index' })).isValid).toBe(true); // valid array with one ES index pattern - expect(validateAdvancedEditor(getMockState(['the-source-index'])).isValid).toBe(true); + expect(validateAdvancedEditor(getMockState({ index: ['the-source-index'] })).isValid).toBe( + true + ); // valid array with two ES index patterns expect( - validateAdvancedEditor(getMockState(['the-source-index-1', 'the-source-index-2'])).isValid + validateAdvancedEditor(getMockState({ index: ['the-source-index-1', 'the-source-index-2'] })) + .isValid ).toBe(true); // invalid comma-separated index pattern, this is only allowed in the simple form // but not the advanced editor. expect( - validateAdvancedEditor(getMockState('the-source-index-1,the-source-index-2')).isValid + validateAdvancedEditor(getMockState({ index: 'the-source-index-1,the-source-index-2' })) + .isValid ).toBe(false); expect( validateAdvancedEditor( - getMockState(['the-source-index-1,the-source-index-2', 'the-source-index-3']) + getMockState({ index: ['the-source-index-1,the-source-index-2', 'the-source-index-3'] }) ).isValid ).toBe(false); // invalid formats ("fake" TS casting to get valid TS and be able to run the tests) - expect(validateAdvancedEditor(getMockState({} as SourceIndex)).isValid).toBe(false); + expect(validateAdvancedEditor(getMockState({ index: {} as SourceIndex })).isValid).toBe(false); expect( - validateAdvancedEditor(getMockState((undefined as unknown) as SourceIndex)).isValid + validateAdvancedEditor(getMockState({ index: (undefined as unknown) as SourceIndex })).isValid + ).toBe(false); + }); + + test('validateAdvancedEditor(): check model memory limit validation', () => { + // valid model_memory_limit units + expect( + validateAdvancedEditor(getMockState({ index: 'the-source-index', modelMemoryLimit: '100mb' })) + .isValid + ).toBe(true); + // invalid model_memory_limit units + expect( + validateAdvancedEditor( + getMockState({ index: 'the-source-index', modelMemoryLimit: '100bob' }) + ).isValid + ).toBe(false); + // invalid model_memory_limit if empty + expect( + validateAdvancedEditor(getMockState({ index: 'the-source-index', modelMemoryLimit: '' })) + .isValid ).toBe(false); }); }); diff --git a/x-pack/legacy/plugins/ml/public/data_frame_analytics/pages/analytics_management/hooks/use_create_analytics_form/reducer.ts b/x-pack/legacy/plugins/ml/public/data_frame_analytics/pages/analytics_management/hooks/use_create_analytics_form/reducer.ts index 037ec95ec17cc..f0fa2ad3b66db 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame_analytics/pages/analytics_management/hooks/use_create_analytics_form/reducer.ts +++ b/x-pack/legacy/plugins/ml/public/data_frame_analytics/pages/analytics_management/hooks/use_create_analytics_form/reducer.ts @@ -13,11 +13,29 @@ import { isValidIndexName } from '../../../../../../common/util/es_utils'; import { Action, ACTION } from './actions'; import { getInitialState, getJobConfigFromFormState, State, JOB_TYPES } from './state'; -import { isJobIdValid } from '../../../../../../common/util/job_utils'; +import { + isJobIdValid, + validateModelMemoryLimitUnits, +} from '../../../../../../common/util/job_utils'; import { maxLengthValidator } from '../../../../../../common/util/validators'; -import { JOB_ID_MAX_LENGTH } from '../../../../../../common/constants/validation'; +import { + JOB_ID_MAX_LENGTH, + ALLOWED_DATA_UNITS, +} from '../../../../../../common/constants/validation'; import { getDependentVar, isRegressionAnalysis } from '../../../../common/analytics'; +const mmlAllowedUnitsStr = `${ALLOWED_DATA_UNITS.slice(0, ALLOWED_DATA_UNITS.length - 1).join( + ', ' +)} or ${[...ALLOWED_DATA_UNITS].pop()}`; + +export const mmlUnitInvalidErrorMessage = i18n.translate( + 'xpack.ml.dataframe.analytics.create.modelMemoryUnitsInvalidError', + { + defaultMessage: 'Model memory limit data unit unrecognized. It must be {str}', + values: { str: mmlAllowedUnitsStr }, + } +); + const getSourceIndexString = (state: State) => { const { jobConfig } = state; @@ -63,6 +81,12 @@ export const validateAdvancedEditor = (state: State): State => { const destinationIndexNameValid = isValidIndexName(destinationIndexName); const destinationIndexPatternTitleExists = state.indexPatternsMap[destinationIndexName] !== undefined; + const mml = jobConfig.model_memory_limit; + const modelMemoryLimitEmpty = mml === ''; + if (!modelMemoryLimitEmpty && mml !== undefined) { + const { valid } = validateModelMemoryLimitUnits(mml); + state.form.modelMemoryLimitUnitValid = valid; + } let dependentVariableEmpty = false; if (isRegressionAnalysis(jobConfig.analysis)) { @@ -126,7 +150,27 @@ export const validateAdvancedEditor = (state: State): State => { }); } + if (modelMemoryLimitEmpty) { + state.advancedEditorMessages.push({ + error: i18n.translate( + 'xpack.ml.dataframe.analytics.create.advancedEditorMessage.modelMemoryLimitEmpty', + { + defaultMessage: 'The model memory limit field must not be empty.', + } + ), + message: '', + }); + } + + if (!state.form.modelMemoryLimitUnitValid) { + state.advancedEditorMessages.push({ + error: mmlUnitInvalidErrorMessage, + message: '', + }); + } + state.isValid = + state.form.modelMemoryLimitUnitValid && !jobIdEmpty && jobIdValid && !jobIdExists && @@ -135,6 +179,7 @@ export const validateAdvancedEditor = (state: State): State => { !destinationIndexNameEmpty && destinationIndexNameValid && !dependentVariableEmpty && + !modelMemoryLimitEmpty && (!destinationIndexPatternTitleExists || !createIndexPattern); return state; @@ -153,11 +198,19 @@ const validateForm = (state: State): State => { destinationIndexPatternTitleExists, createIndexPattern, dependentVariable, + modelMemoryLimit, } = state.form; const dependentVariableEmpty = jobType === JOB_TYPES.REGRESSION && dependentVariable === ''; + const modelMemoryLimitEmpty = modelMemoryLimit === ''; + + if (!modelMemoryLimitEmpty && modelMemoryLimit !== undefined) { + const { valid } = validateModelMemoryLimitUnits(modelMemoryLimit); + state.form.modelMemoryLimitUnitValid = valid; + } state.isValid = + state.form.modelMemoryLimitUnitValid && !jobIdEmpty && jobIdValid && !jobIdExists && @@ -166,6 +219,7 @@ const validateForm = (state: State): State => { !destinationIndexNameEmpty && destinationIndexNameValid && !dependentVariableEmpty && + !modelMemoryLimitEmpty && (!destinationIndexPatternTitleExists || !createIndexPattern); return state; diff --git a/x-pack/legacy/plugins/ml/public/data_frame_analytics/pages/analytics_management/hooks/use_create_analytics_form/state.ts b/x-pack/legacy/plugins/ml/public/data_frame_analytics/pages/analytics_management/hooks/use_create_analytics_form/state.ts index fb97f562ea680..b90317015c8c9 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame_analytics/pages/analytics_management/hooks/use_create_analytics_form/state.ts +++ b/x-pack/legacy/plugins/ml/public/data_frame_analytics/pages/analytics_management/hooks/use_create_analytics_form/state.ts @@ -10,8 +10,11 @@ import { mlNodesAvailable } from '../../../../../ml_nodes_check/check_ml_nodes'; import { DataFrameAnalyticsId, DataFrameAnalyticsConfig } from '../../../../common'; -const OUTLIER_DETECTION_DEFAULT_MODEL_MEMORY_LIMIT = '50mb'; -const REGRESSION_DEFAULT_MODEL_MEMORY_LIMIT = '100mb'; +export enum DEFAULT_MODEL_MEMORY_LIMIT { + regression = '100mb', + // eslint-disable-next-line @typescript-eslint/camelcase + outlier_detection = '50mb', +} export type EsIndexName = string; export type DependentVariable = string; @@ -53,6 +56,8 @@ export interface State { jobIdValid: boolean; jobType: AnalyticsJobType; loadingDepFieldOptions: boolean; + modelMemoryLimit: string | undefined; + modelMemoryLimitUnitValid: boolean; sourceIndex: EsIndexName; sourceIndexNameEmpty: boolean; sourceIndexNameValid: boolean; @@ -94,6 +99,8 @@ export const getInitialState = (): State => ({ jobIdValid: false, jobType: undefined, loadingDepFieldOptions: false, + modelMemoryLimit: undefined, + modelMemoryLimitUnitValid: true, sourceIndex: '', sourceIndexNameEmpty: true, sourceIndexNameValid: false, @@ -121,11 +128,6 @@ export const getInitialState = (): State => ({ export const getJobConfigFromFormState = ( formState: State['form'] ): DeepPartial => { - const modelMemoryLimit = - formState.jobType === JOB_TYPES.REGRESSION - ? REGRESSION_DEFAULT_MODEL_MEMORY_LIMIT - : OUTLIER_DETECTION_DEFAULT_MODEL_MEMORY_LIMIT; - const jobConfig: DeepPartial = { source: { // If a Kibana index patterns includes commas, we need to split @@ -144,7 +146,7 @@ export const getJobConfigFromFormState = ( analysis: { outlier_detection: {}, }, - model_memory_limit: modelMemoryLimit, + model_memory_limit: formState.modelMemoryLimit, }; if (formState.jobType === JOB_TYPES.REGRESSION) { diff --git a/x-pack/legacy/plugins/ml/public/datavisualizer/directive.js b/x-pack/legacy/plugins/ml/public/datavisualizer/directive.tsx similarity index 50% rename from x-pack/legacy/plugins/ml/public/datavisualizer/directive.js rename to x-pack/legacy/plugins/ml/public/datavisualizer/directive.tsx index 022f4ea536b44..130042b6dd730 100644 --- a/x-pack/legacy/plugins/ml/public/datavisualizer/directive.js +++ b/x-pack/legacy/plugins/ml/public/datavisualizer/directive.tsx @@ -4,38 +4,52 @@ * you may not use this file except in compliance with the Elastic License. */ -import 'ngreact'; +import React from 'react'; +import ReactDOM from 'react-dom'; +import { I18nContext } from 'ui/i18n'; -import { wrapInI18nContext } from 'ui/i18n'; +// @ts-ignore import { uiModules } from 'ui/modules'; const module = uiModules.get('apps/ml', ['react']); +import uiRoutes from 'ui/routes'; import { getDataVisualizerBreadcrumbs } from './breadcrumbs'; import { checkBasicLicense } from '../license/check_license'; import { checkFindFileStructurePrivilege } from '../privilege/check_privilege'; -import uiRoutes from 'ui/routes'; - const template = `
`; -uiRoutes - .when('/datavisualizer', { - template, - k7Breadcrumbs: getDataVisualizerBreadcrumbs, - resolve: { - CheckLicense: checkBasicLicense, - privileges: checkFindFileStructurePrivilege, - } - }); - +uiRoutes.when('/datavisualizer', { + template, + k7Breadcrumbs: getDataVisualizerBreadcrumbs, + resolve: { + CheckLicense: checkBasicLicense, + privileges: checkFindFileStructurePrivilege, + }, +}); +// @ts-ignore import { DatavisualizerSelector } from './datavisualizer_selector'; -module.directive('datavisualizerSelector', function ($injector) { - const reactDirective = $injector.get('reactDirective'); - - return reactDirective(wrapInI18nContext(DatavisualizerSelector), undefined, { restrict: 'E' }, { }); +module.directive('datavisualizerSelector', function() { + return { + scope: {}, + restrict: 'E', + link: (scope: ng.IScope, element: ng.IAugmentedJQuery) => { + ReactDOM.render( + + + , + element[0] + ); + + element.on('$destroy', () => { + ReactDOM.unmountComponentAtNode(element[0]); + scope.$destroy(); + }); + }, + }; }); diff --git a/x-pack/legacy/plugins/ml/public/datavisualizer/file_based/components/file_datavisualizer_view/file_datavisualizer_view.js b/x-pack/legacy/plugins/ml/public/datavisualizer/file_based/components/file_datavisualizer_view/file_datavisualizer_view.js index 94e9c2c2ac584..852f068ef419f 100644 --- a/x-pack/legacy/plugins/ml/public/datavisualizer/file_based/components/file_datavisualizer_view/file_datavisualizer_view.js +++ b/x-pack/legacy/plugins/ml/public/datavisualizer/file_based/components/file_datavisualizer_view/file_datavisualizer_view.js @@ -7,7 +7,7 @@ import { FormattedMessage } from '@kbn/i18n/react'; import React, { - Component, + Component } from 'react'; import { diff --git a/x-pack/legacy/plugins/ml/public/datavisualizer/file_based/components/import_view/import_view.js b/x-pack/legacy/plugins/ml/public/datavisualizer/file_based/components/import_view/import_view.js index c1ffcad948adb..c89f618aa835b 100644 --- a/x-pack/legacy/plugins/ml/public/datavisualizer/file_based/components/import_view/import_view.js +++ b/x-pack/legacy/plugins/ml/public/datavisualizer/file_based/components/import_view/import_view.js @@ -25,7 +25,7 @@ import { ImportErrors } from '../import_errors'; import { ImportSummary } from '../import_summary'; import { ImportSettings } from '../import_settings'; import { ExperimentalBadge } from '../experimental_badge'; -import { getIndexPatternNames, refreshIndexPatterns } from '../../../../util/index_utils'; +import { getIndexPatternNames, loadIndexPatterns } from '../../../../util/index_utils'; import { ml } from '../../../../services/ml_api_service'; import { hasImportPermission } from '../utils'; @@ -359,7 +359,7 @@ export class ImportView extends Component { } async loadIndexPatternNames() { - await refreshIndexPatterns(); + await loadIndexPatterns(); const indexPatternNames = getIndexPatternNames(); this.setState({ indexPatternNames }); } diff --git a/x-pack/legacy/plugins/ml/public/datavisualizer/file_based/file_datavisualizer_directive.js b/x-pack/legacy/plugins/ml/public/datavisualizer/file_based/file_datavisualizer_directive.js deleted file mode 100644 index 8b76e57029bd1..0000000000000 --- a/x-pack/legacy/plugins/ml/public/datavisualizer/file_based/file_datavisualizer_directive.js +++ /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 'ngreact'; - -import { wrapInI18nContext } from 'ui/i18n'; -import { uiModules } from 'ui/modules'; - -const module = uiModules.get('apps/ml', ['react']); - -import { getFileDataVisualizerBreadcrumbs } from './breadcrumbs'; -import { checkBasicLicense } from '../../license/check_license'; -import { checkFindFileStructurePrivilege } from '../../privilege/check_privilege'; -import { getMlNodeCount } from '../../ml_nodes_check/check_ml_nodes'; -import { loadMlServerInfo } from '../../services/ml_server_info'; -import { loadIndexPatterns } from '../../util/index_utils'; -import { FileDataVisualizerPage } from './file_datavisualizer'; - -import uiRoutes from 'ui/routes'; - -const template = ` -
- -`; - -uiRoutes - .when('/filedatavisualizer/?', { - template, - k7Breadcrumbs: getFileDataVisualizerBreadcrumbs, - resolve: { - CheckLicense: checkBasicLicense, - privileges: checkFindFileStructurePrivilege, - indexPatterns: loadIndexPatterns, - mlNodeCount: getMlNodeCount, - loadMlServerInfo, - } - }); - -module.directive('fileDatavisualizerPage', function ($injector) { - const reactDirective = $injector.get('reactDirective'); - const indexPatterns = $injector.get('indexPatterns'); - const kibanaConfig = $injector.get('config'); - - return reactDirective(wrapInI18nContext(FileDataVisualizerPage), undefined, { restrict: 'E' }, { indexPatterns, kibanaConfig }); -}); diff --git a/x-pack/legacy/plugins/ml/public/datavisualizer/file_based/file_datavisualizer_directive.tsx b/x-pack/legacy/plugins/ml/public/datavisualizer/file_based/file_datavisualizer_directive.tsx new file mode 100644 index 0000000000000..6b9c053b88d34 --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/datavisualizer/file_based/file_datavisualizer_directive.tsx @@ -0,0 +1,75 @@ +/* + * 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 ReactDOM from 'react-dom'; +import { I18nContext } from 'ui/i18n'; + +// @ts-ignore +import { uiModules } from 'ui/modules'; + +const module = uiModules.get('apps/ml', ['react']); + +import uiRoutes from 'ui/routes'; +import { IndexPatterns } from 'ui/index_patterns'; +import { KibanaConfigTypeFix } from '../../contexts/kibana'; +// @ts-ignore +import { getFileDataVisualizerBreadcrumbs } from './breadcrumbs'; +import { InjectorService } from '../../../common/types/angular'; +import { checkBasicLicense } from '../../license/check_license'; +import { checkFindFileStructurePrivilege } from '../../privilege/check_privilege'; +import { getMlNodeCount } from '../../ml_nodes_check/check_ml_nodes'; +import { loadMlServerInfo } from '../../services/ml_server_info'; +import { loadIndexPatterns } from '../../util/index_utils'; +// @ts-ignore +import { FileDataVisualizerPage } from './file_datavisualizer'; + +const template = ` +
+ +`; + +uiRoutes.when('/filedatavisualizer/?', { + template, + k7Breadcrumbs: getFileDataVisualizerBreadcrumbs, + resolve: { + CheckLicense: checkBasicLicense, + privileges: checkFindFileStructurePrivilege, + indexPatterns: loadIndexPatterns, + mlNodeCount: getMlNodeCount, + loadMlServerInfo, + }, +}); + +interface Props { + indexPatterns: IndexPatterns; + kibanaConfig: KibanaConfigTypeFix; +} + +module.directive('fileDatavisualizerPage', function($injector: InjectorService) { + return { + scope: {}, + restrict: 'E', + link: (scope: ng.IScope, element: ng.IAugmentedJQuery) => { + const indexPatterns = $injector.get('indexPatterns'); + const kibanaConfig = $injector.get('config'); + + const props: Props = { + indexPatterns, + kibanaConfig, + }; + ReactDOM.render( + {React.createElement(FileDataVisualizerPage, props)}, + element[0] + ); + + element.on('$destroy', () => { + ReactDOM.unmountComponentAtNode(element[0]); + scope.$destroy(); + }); + }, + }; +}); diff --git a/x-pack/legacy/plugins/ml/public/datavisualizer/file_based/index.js b/x-pack/legacy/plugins/ml/public/datavisualizer/file_based/index.ts similarity index 99% rename from x-pack/legacy/plugins/ml/public/datavisualizer/file_based/index.js rename to x-pack/legacy/plugins/ml/public/datavisualizer/file_based/index.ts index cd7a23430202a..15796ea9ff0bd 100644 --- a/x-pack/legacy/plugins/ml/public/datavisualizer/file_based/index.js +++ b/x-pack/legacy/plugins/ml/public/datavisualizer/file_based/index.ts @@ -4,5 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ - import './file_datavisualizer_directive'; diff --git a/x-pack/legacy/plugins/ml/public/datavisualizer/index_based/directive.tsx b/x-pack/legacy/plugins/ml/public/datavisualizer/index_based/directive.tsx index e621bdd1d8b92..df152b80c315e 100644 --- a/x-pack/legacy/plugins/ml/public/datavisualizer/index_based/directive.tsx +++ b/x-pack/legacy/plugins/ml/public/datavisualizer/index_based/directive.tsx @@ -13,11 +13,10 @@ const module = uiModules.get('apps/ml', ['react']); import { I18nContext } from 'ui/i18n'; import { IndexPatterns } from 'ui/index_patterns'; -import { IPrivate } from 'ui/private'; import { InjectorService } from '../../../common/types/angular'; import { KibanaConfigTypeFix, KibanaContext } from '../../contexts/kibana/kibana_context'; -import { SearchItemsProvider } from '../../jobs/new_job_new/utils/new_job_utils'; +import { createSearchItems } from '../../jobs/new_job/utils/new_job_utils'; import { Page } from './page'; @@ -27,19 +26,20 @@ module.directive('mlDataVisualizer', ($injector: InjectorService) => { restrict: 'E', link: (scope: ng.IScope, element: ng.IAugmentedJQuery) => { const indexPatterns = $injector.get('indexPatterns'); - const kbnBaseUrl = $injector.get('kbnBaseUrl'); const kibanaConfig = $injector.get('config'); - const Private = $injector.get('Private'); + const $route = $injector.get('$route'); - const createSearchItems = Private(SearchItemsProvider); - const { indexPattern, savedSearch, combinedQuery } = createSearchItems(); + const { indexPattern, savedSearch, combinedQuery } = createSearchItems( + kibanaConfig, + $route.current.locals.indexPattern, + $route.current.locals.savedSearch + ); const kibanaContext = { combinedQuery, currentIndexPattern: indexPattern, currentSavedSearch: savedSearch, indexPatterns, - kbnBaseUrl, kibanaConfig, }; diff --git a/x-pack/legacy/plugins/ml/public/explorer/explorer_controller.js b/x-pack/legacy/plugins/ml/public/explorer/explorer_controller.js index 6315dd95ea8e4..3bedd90f05c37 100644 --- a/x-pack/legacy/plugins/ml/public/explorer/explorer_controller.js +++ b/x-pack/legacy/plugins/ml/public/explorer/explorer_controller.js @@ -23,7 +23,7 @@ import { import { getAnomalyExplorerBreadcrumbs } from './breadcrumbs'; import { checkFullLicense } from '../license/check_license'; import { checkGetJobsPrivilege } from '../privilege/check_privilege'; -import { getIndexPatterns, loadIndexPatterns } from '../util/index_utils'; +import { loadIndexPatterns } from '../util/index_utils'; import { TimeBuckets } from 'plugins/ml/util/time_buckets'; import { explorer$ } from './explorer_dashboard_service'; import { mlTimefilterRefresh$ } from '../services/timefilter_refresh_service'; @@ -114,7 +114,7 @@ module.controller('MlExplorerController', function ( } // Populate the map of jobs / detectors / field formatters for the selected IDs. - mlFieldFormatService.populateFormats(selectedJobIds, getIndexPatterns()) + mlFieldFormatService.populateFormats(selectedJobIds) .catch((err) => { console.log('Error populating field formats:', err); }) diff --git a/x-pack/legacy/plugins/ml/public/formatters/format_value.js b/x-pack/legacy/plugins/ml/public/formatters/format_value.js index 800eb9dc48af6..48988b5561e70 100644 --- a/x-pack/legacy/plugins/ml/public/formatters/format_value.js +++ b/x-pack/legacy/plugins/ml/public/formatters/format_value.js @@ -37,8 +37,10 @@ export function formatValue(value, mlFunction, fieldFormat, record) { if (value.length === 1) { return formatSingleValue(value[0], mlFunction, fieldFormat, record); } else { - // Return with array style formatting. - const values = value.map(val => formatSingleValue(val, mlFunction, fieldFormat, record)); + // Currently only multi-value response is for lat_long detectors. + // Return with array style formatting, with items formatted as numbers, rather than + // the default String format which is set for geo_point and geo_shape fields. + const values = value.map(val => formatSingleValue(val, mlFunction, undefined, record)); return `[${values}]`; } } else { diff --git a/x-pack/legacy/plugins/ml/public/jobs/components/custom_url_editor/list.test.tsx b/x-pack/legacy/plugins/ml/public/jobs/components/custom_url_editor/list.test.tsx index f9fb9c644583f..42ee18bafd870 100644 --- a/x-pack/legacy/plugins/ml/public/jobs/components/custom_url_editor/list.test.tsx +++ b/x-pack/legacy/plugins/ml/public/jobs/components/custom_url_editor/list.test.tsx @@ -6,7 +6,7 @@ import React from 'react'; import { shallow } from 'enzyme'; -import { Job } from '../../new_job_new/common/job_creator/configs'; +import { Job } from '../../new_job/common/job_creator/configs'; import { CustomUrlList, CustomUrlListProps } from './list'; diff --git a/x-pack/legacy/plugins/ml/public/jobs/components/custom_url_editor/list.tsx b/x-pack/legacy/plugins/ml/public/jobs/components/custom_url_editor/list.tsx index 5f93a36793873..c23fdef324da7 100644 --- a/x-pack/legacy/plugins/ml/public/jobs/components/custom_url_editor/list.tsx +++ b/x-pack/legacy/plugins/ml/public/jobs/components/custom_url_editor/list.tsx @@ -26,7 +26,7 @@ import { getTestUrl } from './utils'; import { parseInterval } from '../../../../common/util/parse_interval'; import { TIME_RANGE_TYPE } from './constants'; import { KibanaUrlConfig } from '../../../../common/types/custom_urls'; -import { Job } from '../../new_job_new/common/job_creator/configs'; +import { Job } from '../../new_job/common/job_creator/configs'; function isValidTimeRange(timeRange: KibanaUrlConfig['time_range']): boolean { // Allow empty timeRange string, which gives the 'auto' behaviour. diff --git a/x-pack/legacy/plugins/ml/public/jobs/components/custom_url_editor/utils.d.ts b/x-pack/legacy/plugins/ml/public/jobs/components/custom_url_editor/utils.d.ts index 1841a17c4e728..f8f618ae06762 100644 --- a/x-pack/legacy/plugins/ml/public/jobs/components/custom_url_editor/utils.d.ts +++ b/x-pack/legacy/plugins/ml/public/jobs/components/custom_url_editor/utils.d.ts @@ -5,6 +5,6 @@ */ import { KibanaUrlConfig } from '../../../../common/types/custom_urls'; -import { Job } from '../../new_job_new/common/job_creator/configs'; +import { Job } from '../../new_job/common/job_creator/configs'; export function getTestUrl(job: Job, customUrl: KibanaUrlConfig): Promise; diff --git a/x-pack/legacy/plugins/ml/public/jobs/index.js b/x-pack/legacy/plugins/ml/public/jobs/index.js index 4629f306f2ff7..1ade8752d6721 100644 --- a/x-pack/legacy/plugins/ml/public/jobs/index.js +++ b/x-pack/legacy/plugins/ml/public/jobs/index.js @@ -7,4 +7,4 @@ import './jobs_list'; -import './new_job_new'; +import './new_job'; diff --git a/x-pack/legacy/plugins/ml/public/jobs/jobs_list/components/validate_job.js b/x-pack/legacy/plugins/ml/public/jobs/jobs_list/components/validate_job.js index 71e16188db948..e55075b0eb850 100644 --- a/x-pack/legacy/plugins/ml/public/jobs/jobs_list/components/validate_job.js +++ b/x-pack/legacy/plugins/ml/public/jobs/jobs_list/components/validate_job.js @@ -6,7 +6,7 @@ import { getNewJobLimits } from '../../../services/ml_server_info'; -import { populateValidationMessages } from '../../new_job_new/common/job_validator/util'; +import { populateValidationMessages } from '../../new_job/common/job_validator/util'; import { validateModelMemoryLimit as validateModelMemoryLimitUtils, @@ -23,7 +23,7 @@ export function validateModelMemoryLimit(mml) { } }; - let validationResults = validateModelMemoryLimitUnitsUtils(tempJob); + let validationResults = validateModelMemoryLimitUnitsUtils(mml); let { valid } = validationResults; if(valid) { diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/common/chart_loader/chart_loader.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/common/chart_loader/chart_loader.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/common/chart_loader/chart_loader.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/common/chart_loader/chart_loader.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/common/chart_loader/index.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/common/chart_loader/index.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/common/chart_loader/index.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/common/chart_loader/index.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/common/chart_loader/searches.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/common/chart_loader/searches.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/common/chart_loader/searches.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/common/chart_loader/searches.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/common/components/index.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/common/components/index.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/common/components/index.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/common/components/index.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/common/components/job_groups_input.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/common/components/job_groups_input.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/common/components/job_groups_input.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/common/components/job_groups_input.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/common/components/time_range_picker.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/common/components/time_range_picker.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/common/components/time_range_picker.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/common/components/time_range_picker.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/common/index.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/common/index.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/common/index.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/common/index.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/common/index_pattern_context.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/common/index_pattern_context.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/common/index_pattern_context.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/common/index_pattern_context.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/common/job_creator/advanced_job_creator.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/common/job_creator/advanced_job_creator.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/common/job_creator/advanced_job_creator.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/common/job_creator/advanced_job_creator.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/common/job_creator/configs/combined_job.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/common/job_creator/configs/combined_job.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/common/job_creator/configs/combined_job.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/common/job_creator/configs/combined_job.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/common/job_creator/configs/datafeed.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/common/job_creator/configs/datafeed.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/common/job_creator/configs/datafeed.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/common/job_creator/configs/datafeed.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/common/job_creator/configs/index.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/common/job_creator/configs/index.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/common/job_creator/configs/index.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/common/job_creator/configs/index.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/common/job_creator/configs/job.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/common/job_creator/configs/job.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/common/job_creator/configs/job.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/common/job_creator/configs/job.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/common/job_creator/index.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/common/job_creator/index.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/common/job_creator/index.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/common/job_creator/index.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/common/job_creator/job_creator.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/common/job_creator/job_creator.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/common/job_creator/job_creator.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/common/job_creator/job_creator.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/common/job_creator/job_creator_factory.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/common/job_creator/job_creator_factory.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/common/job_creator/job_creator_factory.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/common/job_creator/job_creator_factory.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/common/job_creator/multi_metric_job_creator.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/common/job_creator/multi_metric_job_creator.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/common/job_creator/multi_metric_job_creator.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/common/job_creator/multi_metric_job_creator.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/common/job_creator/population_job_creator.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/common/job_creator/population_job_creator.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/common/job_creator/population_job_creator.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/common/job_creator/population_job_creator.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/common/job_creator/single_metric_job_creator.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/common/job_creator/single_metric_job_creator.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/common/job_creator/single_metric_job_creator.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/common/job_creator/single_metric_job_creator.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/common/job_creator/type_guards.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/common/job_creator/type_guards.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/common/job_creator/type_guards.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/common/job_creator/type_guards.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/common/job_creator/util/constants.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/common/job_creator/util/constants.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/common/job_creator/util/constants.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/common/job_creator/util/constants.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/common/job_creator/util/default_configs.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/common/job_creator/util/default_configs.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/common/job_creator/util/default_configs.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/common/job_creator/util/default_configs.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/common/job_creator/util/general.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/common/job_creator/util/general.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/common/job_creator/util/general.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/common/job_creator/util/general.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/common/job_runner/index.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/common/job_runner/index.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/common/job_runner/index.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/common/job_runner/index.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/common/job_runner/job_runner.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/common/job_runner/job_runner.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/common/job_runner/job_runner.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/common/job_runner/job_runner.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/common/job_validator/index.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/common/job_validator/index.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/common/job_validator/index.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/common/job_validator/index.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/common/job_validator/job_validator.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/common/job_validator/job_validator.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/common/job_validator/job_validator.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/common/job_validator/job_validator.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/common/job_validator/util.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/common/job_validator/util.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/common/job_validator/util.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/common/job_validator/util.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/common/results_loader/index.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/common/results_loader/index.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/common/results_loader/index.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/common/results_loader/index.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/common/results_loader/results_loader.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/common/results_loader/results_loader.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/common/results_loader/results_loader.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/common/results_loader/results_loader.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/common/results_loader/searches.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/common/results_loader/searches.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/common/results_loader/searches.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/common/results_loader/searches.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/index.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/index.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/index.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/index.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/charts/anomaly_chart/anomalies.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/charts/anomaly_chart/anomalies.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/charts/anomaly_chart/anomalies.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/charts/anomaly_chart/anomalies.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/charts/anomaly_chart/anomaly_chart.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/charts/anomaly_chart/anomaly_chart.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/charts/anomaly_chart/anomaly_chart.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/charts/anomaly_chart/anomaly_chart.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/charts/anomaly_chart/index.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/charts/anomaly_chart/index.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/charts/anomaly_chart/index.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/charts/anomaly_chart/index.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/charts/anomaly_chart/line.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/charts/anomaly_chart/line.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/charts/anomaly_chart/line.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/charts/anomaly_chart/line.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/charts/anomaly_chart/model_bounds.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/charts/anomaly_chart/model_bounds.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/charts/anomaly_chart/model_bounds.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/charts/anomaly_chart/model_bounds.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/charts/anomaly_chart/scatter.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/charts/anomaly_chart/scatter.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/charts/anomaly_chart/scatter.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/charts/anomaly_chart/scatter.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/charts/common/axes.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/charts/common/axes.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/charts/common/axes.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/charts/common/axes.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/charts/common/settings.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/charts/common/settings.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/charts/common/settings.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/charts/common/settings.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/charts/common/utils.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/charts/common/utils.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/charts/common/utils.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/charts/common/utils.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/charts/event_rate_chart/event_rate_chart.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/charts/event_rate_chart/event_rate_chart.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/charts/event_rate_chart/event_rate_chart.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/charts/event_rate_chart/event_rate_chart.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/charts/event_rate_chart/index.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/charts/event_rate_chart/index.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/charts/event_rate_chart/index.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/charts/event_rate_chart/index.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/charts/loading_wrapper/index.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/charts/loading_wrapper/index.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/charts/loading_wrapper/index.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/charts/loading_wrapper/index.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/charts/loading_wrapper/loading_wrapper.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/charts/loading_wrapper/loading_wrapper.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/charts/loading_wrapper/loading_wrapper.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/charts/loading_wrapper/loading_wrapper.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/common/datafeed_preview_flyout/datafeed_preview_flyout.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/common/datafeed_preview_flyout/datafeed_preview_flyout.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/common/datafeed_preview_flyout/datafeed_preview_flyout.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/common/datafeed_preview_flyout/datafeed_preview_flyout.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/common/datafeed_preview_flyout/index.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/common/datafeed_preview_flyout/index.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/common/datafeed_preview_flyout/index.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/common/datafeed_preview_flyout/index.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/common/json_editor_flyout/index.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/common/json_editor_flyout/index.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/common/json_editor_flyout/index.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/common/json_editor_flyout/index.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/common/json_editor_flyout/json_editor_flyout.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/common/json_editor_flyout/json_editor_flyout.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/common/json_editor_flyout/json_editor_flyout.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/common/json_editor_flyout/json_editor_flyout.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/common/model_memory_limit/description.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/common/model_memory_limit/description.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/common/model_memory_limit/description.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/common/model_memory_limit/description.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/common/model_memory_limit/index.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/common/model_memory_limit/index.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/common/model_memory_limit/index.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/common/model_memory_limit/index.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/common/model_memory_limit/model_memory_limit_input.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/common/model_memory_limit/model_memory_limit_input.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/common/model_memory_limit/model_memory_limit_input.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/common/model_memory_limit/model_memory_limit_input.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/datafeed_step/components/frequency/description.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/datafeed_step/components/frequency/description.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/datafeed_step/components/frequency/description.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/datafeed_step/components/frequency/description.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/datafeed_step/components/frequency/frequency_input.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/datafeed_step/components/frequency/frequency_input.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/datafeed_step/components/frequency/frequency_input.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/datafeed_step/components/frequency/frequency_input.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/datafeed_step/components/frequency/index.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/datafeed_step/components/frequency/index.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/datafeed_step/components/frequency/index.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/datafeed_step/components/frequency/index.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/datafeed_step/components/hooks.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/datafeed_step/components/hooks.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/datafeed_step/components/hooks.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/datafeed_step/components/hooks.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/datafeed_step/components/query/description.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/datafeed_step/components/query/description.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/datafeed_step/components/query/description.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/datafeed_step/components/query/description.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/datafeed_step/components/query/index.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/datafeed_step/components/query/index.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/datafeed_step/components/query/index.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/datafeed_step/components/query/index.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/datafeed_step/components/query/query_input.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/datafeed_step/components/query/query_input.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/datafeed_step/components/query/query_input.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/datafeed_step/components/query/query_input.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/datafeed_step/components/query_delay/description.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/datafeed_step/components/query_delay/description.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/datafeed_step/components/query_delay/description.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/datafeed_step/components/query_delay/description.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/datafeed_step/components/query_delay/index.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/datafeed_step/components/query_delay/index.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/datafeed_step/components/query_delay/index.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/datafeed_step/components/query_delay/index.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/datafeed_step/components/query_delay/query_delay_input.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/datafeed_step/components/query_delay/query_delay_input.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/datafeed_step/components/query_delay/query_delay_input.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/datafeed_step/components/query_delay/query_delay_input.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/datafeed_step/components/scroll_size/description.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/datafeed_step/components/scroll_size/description.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/datafeed_step/components/scroll_size/description.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/datafeed_step/components/scroll_size/description.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/datafeed_step/components/scroll_size/index.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/datafeed_step/components/scroll_size/index.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/datafeed_step/components/scroll_size/index.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/datafeed_step/components/scroll_size/index.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/datafeed_step/components/scroll_size/scroll_size_input.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/datafeed_step/components/scroll_size/scroll_size_input.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/datafeed_step/components/scroll_size/scroll_size_input.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/datafeed_step/components/scroll_size/scroll_size_input.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/datafeed_step/components/time_field/description.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/datafeed_step/components/time_field/description.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/datafeed_step/components/time_field/description.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/datafeed_step/components/time_field/description.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/datafeed_step/components/time_field/index.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/datafeed_step/components/time_field/index.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/datafeed_step/components/time_field/index.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/datafeed_step/components/time_field/index.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/datafeed_step/components/time_field/time_field.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/datafeed_step/components/time_field/time_field.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/datafeed_step/components/time_field/time_field.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/datafeed_step/components/time_field/time_field.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/datafeed_step/components/time_field/time_field_select.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/datafeed_step/components/time_field/time_field_select.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/datafeed_step/components/time_field/time_field_select.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/datafeed_step/components/time_field/time_field_select.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/datafeed_step/datafeed.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/datafeed_step/datafeed.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/datafeed_step/datafeed.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/datafeed_step/datafeed.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/datafeed_step/index.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/datafeed_step/index.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/datafeed_step/index.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/datafeed_step/index.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/job_creator_context.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/job_creator_context.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/job_creator_context.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/job_creator_context.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/job_details_step/components/additional_section/additional_section.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/job_details_step/components/additional_section/additional_section.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/job_details_step/components/additional_section/additional_section.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/job_details_step/components/additional_section/additional_section.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/job_details_step/components/additional_section/components/calendars/calendars_selection.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/job_details_step/components/additional_section/components/calendars/calendars_selection.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/job_details_step/components/additional_section/components/calendars/calendars_selection.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/job_details_step/components/additional_section/components/calendars/calendars_selection.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/job_details_step/components/additional_section/components/calendars/description.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/job_details_step/components/additional_section/components/calendars/description.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/job_details_step/components/additional_section/components/calendars/description.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/job_details_step/components/additional_section/components/calendars/description.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/job_details_step/components/additional_section/components/calendars/index.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/job_details_step/components/additional_section/components/calendars/index.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/job_details_step/components/additional_section/components/calendars/index.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/job_details_step/components/additional_section/components/calendars/index.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/job_details_step/components/additional_section/index.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/job_details_step/components/additional_section/index.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/job_details_step/components/additional_section/index.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/job_details_step/components/additional_section/index.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/job_details_step/components/advanced_section/advanced_section.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/job_details_step/components/advanced_section/advanced_section.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/job_details_step/components/advanced_section/advanced_section.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/job_details_step/components/advanced_section/advanced_section.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/job_details_step/components/advanced_section/components/dedicated_index/dedicated_index_switch.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/job_details_step/components/advanced_section/components/dedicated_index/dedicated_index_switch.tsx similarity index 98% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/job_details_step/components/advanced_section/components/dedicated_index/dedicated_index_switch.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/job_details_step/components/advanced_section/components/dedicated_index/dedicated_index_switch.tsx index 5c8f346d71baf..b50a8e0affa2d 100644 --- a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/job_details_step/components/advanced_section/components/dedicated_index/dedicated_index_switch.tsx +++ b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/job_details_step/components/advanced_section/components/dedicated_index/dedicated_index_switch.tsx @@ -30,7 +30,6 @@ export const DedicatedIndexSwitch: FC = () => { checked={useDedicatedIndex} onChange={toggleModelPlot} data-test-subj="mlJobWizardSwitchUseDedicatedIndex" - showLabel={false} label={i18n.translate( 'xpack.ml.newJob.wizard.jobDetailsStep.advancedSection.useDedicatedIndex.title', { diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/job_details_step/components/advanced_section/components/dedicated_index/description.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/job_details_step/components/advanced_section/components/dedicated_index/description.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/job_details_step/components/advanced_section/components/dedicated_index/description.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/job_details_step/components/advanced_section/components/dedicated_index/description.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/job_details_step/components/advanced_section/components/dedicated_index/index.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/job_details_step/components/advanced_section/components/dedicated_index/index.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/job_details_step/components/advanced_section/components/dedicated_index/index.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/job_details_step/components/advanced_section/components/dedicated_index/index.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/job_details_step/components/advanced_section/components/model_plot/description.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/job_details_step/components/advanced_section/components/model_plot/description.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/job_details_step/components/advanced_section/components/model_plot/description.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/job_details_step/components/advanced_section/components/model_plot/description.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/job_details_step/components/advanced_section/components/model_plot/index.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/job_details_step/components/advanced_section/components/model_plot/index.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/job_details_step/components/advanced_section/components/model_plot/index.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/job_details_step/components/advanced_section/components/model_plot/index.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/job_details_step/components/advanced_section/components/model_plot/model_plot_switch.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/job_details_step/components/advanced_section/components/model_plot/model_plot_switch.tsx similarity index 98% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/job_details_step/components/advanced_section/components/model_plot/model_plot_switch.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/job_details_step/components/advanced_section/components/model_plot/model_plot_switch.tsx index 41ac4311b71ce..226742bf3e97a 100644 --- a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/job_details_step/components/advanced_section/components/model_plot/model_plot_switch.tsx +++ b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/job_details_step/components/advanced_section/components/model_plot/model_plot_switch.tsx @@ -30,7 +30,6 @@ export const ModelPlotSwitch: FC = () => { checked={modelPlotEnabled} onChange={toggleModelPlot} data-test-subj="mlJobWizardSwitchModelPlot" - showLabel={false} label={i18n.translate( 'xpack.ml.newJob.wizard.jobDetailsStep.advancedSection.enableModelPlot.title', { diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/job_details_step/components/advanced_section/index.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/job_details_step/components/advanced_section/index.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/job_details_step/components/advanced_section/index.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/job_details_step/components/advanced_section/index.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/job_details_step/components/groups/description.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/job_details_step/components/groups/description.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/job_details_step/components/groups/description.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/job_details_step/components/groups/description.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/job_details_step/components/groups/groups_input.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/job_details_step/components/groups/groups_input.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/job_details_step/components/groups/groups_input.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/job_details_step/components/groups/groups_input.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/job_details_step/components/groups/index.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/job_details_step/components/groups/index.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/job_details_step/components/groups/index.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/job_details_step/components/groups/index.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/job_details_step/components/job_description/description.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/job_details_step/components/job_description/description.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/job_details_step/components/job_description/description.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/job_details_step/components/job_description/description.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/job_details_step/components/job_description/index.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/job_details_step/components/job_description/index.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/job_details_step/components/job_description/index.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/job_details_step/components/job_description/index.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/job_details_step/components/job_description/job_description_input.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/job_details_step/components/job_description/job_description_input.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/job_details_step/components/job_description/job_description_input.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/job_details_step/components/job_description/job_description_input.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/job_details_step/components/job_id/description.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/job_details_step/components/job_id/description.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/job_details_step/components/job_id/description.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/job_details_step/components/job_id/description.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/job_details_step/components/job_id/index.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/job_details_step/components/job_id/index.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/job_details_step/components/job_id/index.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/job_details_step/components/job_id/index.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/job_details_step/components/job_id/job_id_input.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/job_details_step/components/job_id/job_id_input.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/job_details_step/components/job_id/job_id_input.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/job_details_step/components/job_id/job_id_input.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/job_details_step/index.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/job_details_step/index.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/job_details_step/index.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/job_details_step/index.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/job_details_step/job_details.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/job_details_step/job_details.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/job_details_step/job_details.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/job_details_step/job_details.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/advanced_detector_modal/advanced_detector_modal.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/advanced_detector_modal/advanced_detector_modal.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/advanced_detector_modal/advanced_detector_modal.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/advanced_detector_modal/advanced_detector_modal.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/advanced_detector_modal/descriptions.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/advanced_detector_modal/descriptions.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/advanced_detector_modal/descriptions.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/advanced_detector_modal/descriptions.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/advanced_detector_modal/index.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/advanced_detector_modal/index.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/advanced_detector_modal/index.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/advanced_detector_modal/index.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/advanced_detector_modal/modal_wrapper.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/advanced_detector_modal/modal_wrapper.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/advanced_detector_modal/modal_wrapper.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/advanced_detector_modal/modal_wrapper.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/advanced_view/advanced_view.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/advanced_view/advanced_view.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/advanced_view/advanced_view.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/advanced_view/advanced_view.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/advanced_view/detector_list.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/advanced_view/detector_list.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/advanced_view/detector_list.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/advanced_view/detector_list.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/advanced_view/extra.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/advanced_view/extra.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/advanced_view/extra.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/advanced_view/extra.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/advanced_view/index.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/advanced_view/index.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/advanced_view/index.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/advanced_view/index.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/advanced_view/metric_selection.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/advanced_view/metric_selection.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/advanced_view/metric_selection.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/advanced_view/metric_selection.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/advanced_view/metric_selection_summary.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/advanced_view/metric_selection_summary.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/advanced_view/metric_selection_summary.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/advanced_view/metric_selection_summary.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/advanced_view/metric_selector.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/advanced_view/metric_selector.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/advanced_view/metric_selector.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/advanced_view/metric_selector.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/advanced_view/settings.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/advanced_view/settings.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/advanced_view/settings.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/advanced_view/settings.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/agg_select/agg_select.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/agg_select/agg_select.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/agg_select/agg_select.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/agg_select/agg_select.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/agg_select/index.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/agg_select/index.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/agg_select/index.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/agg_select/index.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/bucket_span/bucket_span.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/bucket_span/bucket_span.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/bucket_span/bucket_span.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/bucket_span/bucket_span.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/bucket_span/bucket_span_input.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/bucket_span/bucket_span_input.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/bucket_span/bucket_span_input.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/bucket_span/bucket_span_input.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/bucket_span/description.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/bucket_span/description.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/bucket_span/description.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/bucket_span/description.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/bucket_span/index.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/bucket_span/index.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/bucket_span/index.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/bucket_span/index.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/bucket_span_estimator/bucket_span_estimator.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/bucket_span_estimator/bucket_span_estimator.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/bucket_span_estimator/bucket_span_estimator.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/bucket_span_estimator/bucket_span_estimator.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/bucket_span_estimator/estimate_bucket_span.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/bucket_span_estimator/estimate_bucket_span.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/bucket_span_estimator/estimate_bucket_span.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/bucket_span_estimator/estimate_bucket_span.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/bucket_span_estimator/index.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/bucket_span_estimator/index.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/bucket_span_estimator/index.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/bucket_span_estimator/index.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/categorization_field/categorization_field.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/categorization_field/categorization_field.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/categorization_field/categorization_field.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/categorization_field/categorization_field.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/categorization_field/categorization_field_select.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/categorization_field/categorization_field_select.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/categorization_field/categorization_field_select.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/categorization_field/categorization_field_select.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/categorization_field/description.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/categorization_field/description.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/categorization_field/description.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/categorization_field/description.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/categorization_field/index.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/categorization_field/index.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/categorization_field/index.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/categorization_field/index.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/detector_title/detector_title.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/detector_title/detector_title.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/detector_title/detector_title.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/detector_title/detector_title.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/detector_title/index.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/detector_title/index.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/detector_title/index.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/detector_title/index.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/influencers/description.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/influencers/description.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/influencers/description.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/influencers/description.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/influencers/index.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/influencers/index.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/influencers/index.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/influencers/index.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/influencers/influencers.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/influencers/influencers.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/influencers/influencers.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/influencers/influencers.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/influencers/influencers_select.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/influencers/influencers_select.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/influencers/influencers_select.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/influencers/influencers_select.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/multi_metric_view/chart_grid.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/multi_metric_view/chart_grid.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/multi_metric_view/chart_grid.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/multi_metric_view/chart_grid.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/multi_metric_view/index.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/multi_metric_view/index.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/multi_metric_view/index.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/multi_metric_view/index.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/multi_metric_view/metric_selection.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/multi_metric_view/metric_selection.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/multi_metric_view/metric_selection.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/multi_metric_view/metric_selection.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/multi_metric_view/metric_selection_summary.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/multi_metric_view/metric_selection_summary.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/multi_metric_view/metric_selection_summary.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/multi_metric_view/metric_selection_summary.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/multi_metric_view/metric_selector.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/multi_metric_view/metric_selector.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/multi_metric_view/metric_selector.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/multi_metric_view/metric_selector.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/multi_metric_view/multi_metric_view.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/multi_metric_view/multi_metric_view.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/multi_metric_view/multi_metric_view.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/multi_metric_view/multi_metric_view.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/multi_metric_view/settings.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/multi_metric_view/settings.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/multi_metric_view/settings.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/multi_metric_view/settings.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/population_view/chart_grid.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/population_view/chart_grid.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/population_view/chart_grid.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/population_view/chart_grid.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/population_view/index.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/population_view/index.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/population_view/index.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/population_view/index.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/population_view/metric_selection.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/population_view/metric_selection.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/population_view/metric_selection.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/population_view/metric_selection.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/population_view/metric_selection_summary.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/population_view/metric_selection_summary.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/population_view/metric_selection_summary.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/population_view/metric_selection_summary.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/population_view/metric_selector.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/population_view/metric_selector.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/population_view/metric_selector.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/population_view/metric_selector.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/population_view/population_view.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/population_view/population_view.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/population_view/population_view.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/population_view/population_view.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/population_view/settings.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/population_view/settings.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/population_view/settings.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/population_view/settings.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/single_metric_view/index.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/single_metric_view/index.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/single_metric_view/index.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/single_metric_view/index.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/single_metric_view/metric_selection.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/single_metric_view/metric_selection.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/single_metric_view/metric_selection.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/single_metric_view/metric_selection.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/single_metric_view/metric_selection_summary.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/single_metric_view/metric_selection_summary.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/single_metric_view/metric_selection_summary.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/single_metric_view/metric_selection_summary.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/single_metric_view/settings.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/single_metric_view/settings.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/single_metric_view/settings.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/single_metric_view/settings.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/single_metric_view/single_metric_view.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/single_metric_view/single_metric_view.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/single_metric_view/single_metric_view.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/single_metric_view/single_metric_view.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/sparse_data/description.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/sparse_data/description.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/sparse_data/description.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/sparse_data/description.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/sparse_data/index.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/sparse_data/index.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/sparse_data/index.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/sparse_data/index.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/sparse_data/sparse_data_switch.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/sparse_data/sparse_data_switch.tsx similarity index 98% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/sparse_data/sparse_data_switch.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/sparse_data/sparse_data_switch.tsx index 3f2c45f0c62bd..76461e1306333 100644 --- a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/sparse_data/sparse_data_switch.tsx +++ b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/sparse_data/sparse_data_switch.tsx @@ -44,7 +44,6 @@ export const SparseDataSwitch: FC = () => { checked={sparseData} onChange={toggleSparseData} data-test-subj="mlJobWizardSwitchSparseData" - showLabel={false} label={i18n.translate('xpack.ml.newJob.wizard.pickFieldsStep.sparseData.title', { defaultMessage: 'Sparse data', })} diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/split_cards/animate_split_hook.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/split_cards/animate_split_hook.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/split_cards/animate_split_hook.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/split_cards/animate_split_hook.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/split_cards/index.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/split_cards/index.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/split_cards/index.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/split_cards/index.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/split_cards/split_cards.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/split_cards/split_cards.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/split_cards/split_cards.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/split_cards/split_cards.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/split_field/by_field.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/split_field/by_field.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/split_field/by_field.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/split_field/by_field.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/split_field/description.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/split_field/description.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/split_field/description.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/split_field/description.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/split_field/index.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/split_field/index.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/split_field/index.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/split_field/index.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/split_field/split_field.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/split_field/split_field.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/split_field/split_field.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/split_field/split_field.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/split_field/split_field_select.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/split_field/split_field_select.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/split_field/split_field_select.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/split_field/split_field_select.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/summary_count_field/description.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/summary_count_field/description.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/summary_count_field/description.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/summary_count_field/description.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/summary_count_field/index.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/summary_count_field/index.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/summary_count_field/index.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/summary_count_field/index.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/summary_count_field/summary_count_field.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/summary_count_field/summary_count_field.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/summary_count_field/summary_count_field.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/summary_count_field/summary_count_field.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/summary_count_field/summary_count_field_select.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/summary_count_field/summary_count_field_select.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/summary_count_field/summary_count_field_select.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/components/summary_count_field/summary_count_field_select.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/index.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/index.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/index.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/index.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/pick_fields.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/pick_fields.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/pick_fields.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/pick_fields_step/pick_fields.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/step_types.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/step_types.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/step_types.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/step_types.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/summary_step/components/common.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/summary_step/components/common.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/summary_step/components/common.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/summary_step/components/common.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/summary_step/components/datafeed_details/datafeed_details.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/summary_step/components/datafeed_details/datafeed_details.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/summary_step/components/datafeed_details/datafeed_details.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/summary_step/components/datafeed_details/datafeed_details.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/summary_step/components/datafeed_details/index.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/summary_step/components/datafeed_details/index.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/summary_step/components/datafeed_details/index.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/summary_step/components/datafeed_details/index.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/summary_step/components/detector_chart/detector_chart.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/summary_step/components/detector_chart/detector_chart.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/summary_step/components/detector_chart/detector_chart.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/summary_step/components/detector_chart/detector_chart.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/summary_step/components/detector_chart/index.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/summary_step/components/detector_chart/index.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/summary_step/components/detector_chart/index.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/summary_step/components/detector_chart/index.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/summary_step/components/job_details/index.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/summary_step/components/job_details/index.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/summary_step/components/job_details/index.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/summary_step/components/job_details/index.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/summary_step/components/job_details/job_details.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/summary_step/components/job_details/job_details.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/summary_step/components/job_details/job_details.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/summary_step/components/job_details/job_details.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/summary_step/components/job_progress/index.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/summary_step/components/job_progress/index.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/summary_step/components/job_progress/index.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/summary_step/components/job_progress/index.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/summary_step/components/job_progress/job_progress.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/summary_step/components/job_progress/job_progress.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/summary_step/components/job_progress/job_progress.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/summary_step/components/job_progress/job_progress.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/summary_step/components/post_save_options/index.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/summary_step/components/post_save_options/index.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/summary_step/components/post_save_options/index.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/summary_step/components/post_save_options/index.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/summary_step/components/post_save_options/post_save_options.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/summary_step/components/post_save_options/post_save_options.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/summary_step/components/post_save_options/post_save_options.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/summary_step/components/post_save_options/post_save_options.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/summary_step/index.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/summary_step/index.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/summary_step/index.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/summary_step/index.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/summary_step/summary.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/summary_step/summary.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/summary_step/summary.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/summary_step/summary.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/time_range_step/index.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/time_range_step/index.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/time_range_step/index.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/time_range_step/index.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/time_range_step/time_range.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/time_range_step/time_range.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/time_range_step/time_range.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/time_range_step/time_range.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/validation_step/index.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/validation_step/index.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/validation_step/index.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/validation_step/index.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/validation_step/validation.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/validation_step/validation.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/validation_step/validation.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/validation_step/validation.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/wizard_nav/index.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/wizard_nav/index.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/wizard_nav/index.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/wizard_nav/index.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/wizard_nav/wizard_nav.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/wizard_nav/wizard_nav.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/wizard_nav/wizard_nav.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/components/wizard_nav/wizard_nav.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/index_or_search/__test__/directive.js b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/index_or_search/__test__/directive.js similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/index_or_search/__test__/directive.js rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/index_or_search/__test__/directive.js diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/index_or_search/directive.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/index_or_search/directive.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/index_or_search/directive.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/index_or_search/directive.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/index_or_search/page.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/index_or_search/page.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/index_or_search/page.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/index_or_search/page.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/index_or_search/preconfigured_job_redirect.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/index_or_search/preconfigured_job_redirect.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/index_or_search/preconfigured_job_redirect.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/index_or_search/preconfigured_job_redirect.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/index_or_search/route.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/index_or_search/route.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/index_or_search/route.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/index_or_search/route.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/job_type/__test__/directive.js b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/job_type/__test__/directive.js similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/job_type/__test__/directive.js rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/job_type/__test__/directive.js diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/job_type/directive.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/job_type/directive.tsx similarity index 84% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/job_type/directive.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/job_type/directive.tsx index 592dce3ce5b17..59dff64c1cd78 100644 --- a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/job_type/directive.tsx +++ b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/job_type/directive.tsx @@ -14,10 +14,8 @@ import { timefilter } from 'ui/timefilter'; import { IndexPatterns } from 'ui/index_patterns'; import { I18nContext } from 'ui/i18n'; -import { IPrivate } from 'ui/private'; import { InjectorService } from '../../../../../common/types/angular'; - -import { SearchItemsProvider } from '../../../new_job_new/utils/new_job_utils'; +import { createSearchItems } from '../../../new_job/utils/new_job_utils'; import { Page } from './page'; import { KibanaContext, KibanaConfigTypeFix } from '../../../../contexts/kibana'; @@ -32,18 +30,19 @@ module.directive('mlJobTypePage', ($injector: InjectorService) => { timefilter.disableAutoRefreshSelector(); const indexPatterns = $injector.get('indexPatterns'); - const kbnBaseUrl = $injector.get('kbnBaseUrl'); const kibanaConfig = $injector.get('config'); - const Private = $injector.get('Private'); + const $route = $injector.get('$route'); - const createSearchItems = Private(SearchItemsProvider); - const { indexPattern, savedSearch, combinedQuery } = createSearchItems(); + const { indexPattern, savedSearch, combinedQuery } = createSearchItems( + kibanaConfig, + $route.current.locals.indexPattern, + $route.current.locals.savedSearch + ); const kibanaContext = { combinedQuery, currentIndexPattern: indexPattern, currentSavedSearch: savedSearch, indexPatterns, - kbnBaseUrl, kibanaConfig, }; diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/job_type/page.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/job_type/page.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/job_type/page.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/job_type/page.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/job_type/route.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/job_type/route.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/job_type/route.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/job_type/route.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/new_job/directive.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/new_job/directive.tsx similarity index 87% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/new_job/directive.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/new_job/directive.tsx index 815e0228882ce..1725211861c0c 100644 --- a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/new_job/directive.tsx +++ b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/new_job/directive.tsx @@ -14,10 +14,8 @@ import { timefilter } from 'ui/timefilter'; import { IndexPatterns } from 'ui/index_patterns'; import { I18nContext } from 'ui/i18n'; -import { IPrivate } from 'ui/private'; import { InjectorService } from '../../../../../common/types/angular'; - -import { SearchItemsProvider } from '../../utils/new_job_utils'; +import { createSearchItems } from '../../utils/new_job_utils'; import { Page, PageProps } from './page'; import { JOB_TYPE } from '../../common/job_creator/util/constants'; @@ -32,9 +30,7 @@ module.directive('mlNewJobPage', ($injector: InjectorService) => { timefilter.disableAutoRefreshSelector(); const indexPatterns = $injector.get('indexPatterns'); - const kbnBaseUrl = $injector.get('kbnBaseUrl'); const kibanaConfig = $injector.get('config'); - const Private = $injector.get('Private'); const $route = $injector.get('$route'); const existingJobsAndGroups = $route.current.locals.existingJobsAndGroups; @@ -43,15 +39,17 @@ module.directive('mlNewJobPage', ($injector: InjectorService) => { } const jobType: JOB_TYPE = $route.current.locals.jobType; - const createSearchItems = Private(SearchItemsProvider); - const { indexPattern, savedSearch, combinedQuery } = createSearchItems(); + const { indexPattern, savedSearch, combinedQuery } = createSearchItems( + kibanaConfig, + $route.current.locals.indexPattern, + $route.current.locals.savedSearch + ); const kibanaContext = { combinedQuery, currentIndexPattern: indexPattern, currentSavedSearch: savedSearch, indexPatterns, - kbnBaseUrl, kibanaConfig, }; diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/new_job/page.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/new_job/page.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/new_job/page.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/new_job/page.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/new_job/route.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/new_job/route.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/new_job/route.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/new_job/route.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/new_job/wizard.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/new_job/wizard.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/new_job/wizard.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/new_job/wizard.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/new_job/wizard_horizontal_steps.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/new_job/wizard_horizontal_steps.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/new_job/wizard_horizontal_steps.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/new_job/wizard_horizontal_steps.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/new_job/wizard_steps.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/pages/new_job/wizard_steps.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/new_job/wizard_steps.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/pages/new_job/wizard_steps.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/recognize/__test__/directive.js b/x-pack/legacy/plugins/ml/public/jobs/new_job/recognize/__test__/directive.js similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/recognize/__test__/directive.js rename to x-pack/legacy/plugins/ml/public/jobs/new_job/recognize/__test__/directive.js diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/recognize/components/create_result_callout.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/recognize/components/create_result_callout.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/recognize/components/create_result_callout.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/recognize/components/create_result_callout.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/recognize/components/edit_job.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/recognize/components/edit_job.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/recognize/components/edit_job.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/recognize/components/edit_job.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/recognize/components/job_item.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/recognize/components/job_item.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/recognize/components/job_item.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/recognize/components/job_item.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/recognize/components/job_settings_form.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/recognize/components/job_settings_form.tsx similarity index 99% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/recognize/components/job_settings_form.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/recognize/components/job_settings_form.tsx index 8dda1415a0ab8..bae16d620af5b 100644 --- a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/recognize/components/job_settings_form.tsx +++ b/x-pack/legacy/plugins/ml/public/jobs/new_job/recognize/components/job_settings_form.tsx @@ -247,7 +247,6 @@ export const JobSettingsForm: FC = ({ useDedicatedIndex: checked, }); }} - showLabel={false} label={i18n.translate('xpack.ml.newJob.recognize.useDedicatedIndexLabel', { defaultMessage: 'Use dedicated index', })} diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/recognize/components/kibana_objects.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/recognize/components/kibana_objects.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/recognize/components/kibana_objects.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/recognize/components/kibana_objects.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/recognize/components/module_jobs.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/recognize/components/module_jobs.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/recognize/components/module_jobs.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/recognize/components/module_jobs.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/recognize/directive.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/recognize/directive.tsx similarity index 86% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/recognize/directive.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/recognize/directive.tsx index cf80cad30b7ca..1882296f96418 100644 --- a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/recognize/directive.tsx +++ b/x-pack/legacy/plugins/ml/public/jobs/new_job/recognize/directive.tsx @@ -14,10 +14,9 @@ import { timefilter } from 'ui/timefilter'; import { IndexPatterns } from 'ui/index_patterns'; import { I18nContext } from 'ui/i18n'; -import { IPrivate } from 'ui/private'; import { InjectorService } from '../../../../common/types/angular'; -import { SearchItemsProvider } from '../../new_job_new/utils/new_job_utils'; +import { createSearchItems } from '../../new_job/utils/new_job_utils'; import { Page } from './page'; import { KibanaContext, KibanaConfigTypeFix } from '../../../contexts/kibana'; @@ -32,22 +31,22 @@ module.directive('mlRecognizePage', ($injector: InjectorService) => { timefilter.disableAutoRefreshSelector(); const indexPatterns = $injector.get('indexPatterns'); - const kbnBaseUrl = $injector.get('kbnBaseUrl'); const kibanaConfig = $injector.get('config'); - const Private = $injector.get('Private'); const $route = $injector.get('$route'); const moduleId = $route.current.params.id; const existingGroupIds: string[] = $route.current.locals.existingJobsAndGroups.groupIds; - const createSearchItems = Private(SearchItemsProvider); - const { indexPattern, savedSearch, combinedQuery } = createSearchItems(); + const { indexPattern, savedSearch, combinedQuery } = createSearchItems( + kibanaConfig, + $route.current.locals.indexPattern, + $route.current.locals.savedSearch + ); const kibanaContext = { combinedQuery, currentIndexPattern: indexPattern, currentSavedSearch: savedSearch, indexPatterns, - kbnBaseUrl, kibanaConfig, }; diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/recognize/page.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job/recognize/page.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/recognize/page.tsx rename to x-pack/legacy/plugins/ml/public/jobs/new_job/recognize/page.tsx diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/recognize/resolvers.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/recognize/resolvers.ts similarity index 94% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/recognize/resolvers.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/recognize/resolvers.ts index d92ec7152adf8..d2ca22972c201 100644 --- a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/recognize/resolvers.ts +++ b/x-pack/legacy/plugins/ml/public/jobs/new_job/recognize/resolvers.ts @@ -7,7 +7,6 @@ import chrome from 'ui/chrome'; import { i18n } from '@kbn/i18n'; import { toastNotifications } from 'ui/notify'; -import { IPrivate } from 'ui/private'; import { mlJobService } from '../../../services/job_service'; import { ml } from '../../../services/ml_api_service'; import { KibanaObjects } from './page'; @@ -17,12 +16,7 @@ import { KibanaObjects } from './page'; * Redirects to the Anomaly Explorer to view the jobs if they have been created, * or the recognizer job wizard for the module if not. */ -export function checkViewOrCreateJobs( - Private: IPrivate, - $route: any, - kbnBaseUrl: string, - kbnUrl: any -) { +export function checkViewOrCreateJobs($route: any) { return new Promise((resolve, reject) => { const moduleId = $route.current.params.id; const indexPatternId = $route.current.params.index; @@ -58,7 +52,7 @@ export function checkViewOrCreateJobs( }), }); - kbnUrl.redirect(`/jobs`); + window.location.href = '#/jobs'; reject(); }); }); diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/recognize/route.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/recognize/route.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/recognize/route.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/recognize/route.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/utils/new_job_utils.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job/utils/new_job_utils.ts similarity index 53% rename from x-pack/legacy/plugins/ml/public/jobs/new_job_new/utils/new_job_utils.ts rename to x-pack/legacy/plugins/ml/public/jobs/new_job/utils/new_job_utils.ts index 85beb32fffa3c..cb4e7a21997e6 100644 --- a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/utils/new_job_utils.ts +++ b/x-pack/legacy/plugins/ml/public/jobs/new_job/utils/new_job_utils.ts @@ -4,9 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ +import { IndexPattern } from 'ui/index_patterns'; import { SavedSearch } from 'src/legacy/core_plugins/kibana/public/discover/types'; import { KibanaConfigTypeFix } from '../../../contexts/kibana'; -import { InjectorService } from '../../../../common/types/angular'; import { esQuery, IIndexPattern } from '../../../../../../../../src/plugins/data/public'; export interface SearchItems { @@ -18,55 +18,50 @@ export interface SearchItems { // Provider for creating the items used for searching and job creation. // Uses the $route object to retrieve the indexPattern and savedSearch from the url -export function SearchItemsProvider($injector: InjectorService) { - const kibanaConfig = $injector.get('config'); - const $route = $injector.get('$route'); - function createSearchItems() { - let indexPattern = $route.current.locals.indexPattern; - - // query is only used by the data visualizer as it needs - // a lucene query_string. - // Using a blank query will cause match_all:{} to be used - // when passed through luceneStringToDsl - let query = { - query: '', - language: 'lucene', - }; - - let combinedQuery: any = { - bool: { - must: [ - { - match_all: {}, - }, - ], - }, - }; +export function createSearchItems( + kibanaConfig: KibanaConfigTypeFix, + indexPattern: IndexPattern, + savedSearch: SavedSearch +) { + // query is only used by the data visualizer as it needs + // a lucene query_string. + // Using a blank query will cause match_all:{} to be used + // when passed through luceneStringToDsl + let query = { + query: '', + language: 'lucene', + }; - const savedSearch = $route.current.locals.savedSearch; - if (indexPattern.id === undefined && savedSearch.id !== undefined) { - const searchSource = savedSearch.searchSource; - indexPattern = searchSource.getField('index'); + let combinedQuery: any = { + bool: { + must: [ + { + match_all: {}, + }, + ], + }, + }; - query = searchSource.getField('query'); - const fs = searchSource.getField('filter'); + if (indexPattern.id === undefined && savedSearch.id !== undefined) { + const searchSource = savedSearch.searchSource; + indexPattern = searchSource.getField('index'); - const filters = fs.length ? fs : []; + query = searchSource.getField('query'); + const fs = searchSource.getField('filter'); - const esQueryConfigs = esQuery.getEsQueryConfig(kibanaConfig); - combinedQuery = esQuery.buildEsQuery(indexPattern, [query], filters, esQueryConfigs); - } + const filters = fs.length ? fs : []; - return { - indexPattern, - savedSearch, - query, - combinedQuery, - }; + const esQueryConfigs = esQuery.getEsQueryConfig(kibanaConfig); + combinedQuery = esQuery.buildEsQuery(indexPattern, [query], filters, esQueryConfigs); } - return createSearchItems; + return { + indexPattern, + savedSearch, + query, + combinedQuery, + }; } // Only model plot cardinality relevant diff --git a/x-pack/legacy/plugins/ml/public/license/check_license.js b/x-pack/legacy/plugins/ml/public/license/check_license.tsx similarity index 67% rename from x-pack/legacy/plugins/ml/public/license/check_license.js rename to x-pack/legacy/plugins/ml/public/license/check_license.tsx index 9e86fa429b0da..8457e462567cc 100644 --- a/x-pack/legacy/plugins/ml/public/license/check_license.js +++ b/x-pack/legacy/plugins/ml/public/license/check_license.tsx @@ -4,51 +4,44 @@ * you may not use this file except in compliance with the Elastic License. */ - import React from 'react'; +// @ts-ignore No declaration file for module +import { banners } from 'ui/notify'; +import { EuiCallOut } from '@elastic/eui'; +// @ts-ignore No declaration file for module import { xpackInfo } from '../../../xpack_main/public/services/xpack_info'; -import { banners, addAppRedirectMessageToUrl } from 'ui/notify'; import { LICENSE_TYPE } from '../../common/constants/license'; import { LICENSE_STATUS_VALID } from '../../../../common/constants/license_status'; -import chrome from 'ui/chrome'; -import { EuiCallOut } from '@elastic/eui'; - let licenseHasExpired = true; -let licenseType = null; -let expiredLicenseBannerId; +let licenseType: LICENSE_TYPE | null = null; +let expiredLicenseBannerId: string; -export function checkFullLicense(kbnBaseUrl, kbnUrl) { +export function checkFullLicense() { const features = getFeatures(); licenseType = features.licenseType; if (features.isAvailable === false) { // ML is not enabled - return redirectToKibana(features, kbnBaseUrl); - + return redirectToKibana(); } else if (features.licenseType === LICENSE_TYPE.BASIC) { - // ML is enabled, but only with a basic or gold license - return redirectToBasic(kbnUrl); - + return redirectToBasic(); } else { - // ML is enabled setLicenseExpired(features); return Promise.resolve(features); } } -export function checkBasicLicense(kbnBaseUrl) { +export function checkBasicLicense() { const features = getFeatures(); licenseType = features.licenseType; if (features.isAvailable === false) { // ML is not enabled - return redirectToKibana(features, kbnBaseUrl); - + return redirectToKibana(); } else { - // ML is enabled setLicenseExpired(features); return Promise.resolve(features); @@ -58,38 +51,32 @@ export function checkBasicLicense(kbnBaseUrl) { // a wrapper for checkFullLicense which doesn't resolve if the license has expired. // this is used by all create jobs pages to redirect back to the jobs list // if the user's license has expired. -export function checkLicenseExpired(kbnBaseUrl, kbnUrl) { - return checkFullLicense(kbnBaseUrl, kbnUrl) - .then((features) => { +export function checkLicenseExpired() { + return checkFullLicense() + .then((features: any) => { if (features.hasExpired) { - kbnUrl.redirect('/jobs'); - return Promise.halt(); + window.location.href = '#/jobs'; + return Promise.reject(); } else { return Promise.resolve(features); } }) .catch(() => { - return Promise.halt(); + return Promise.reject(); }); } -function setLicenseExpired(features) { - licenseHasExpired = (features.hasExpired || false); +function setLicenseExpired(features: any) { + licenseHasExpired = features.hasExpired || false; // If the license has expired ML app will still work for 7 days and then // the job management endpoints (e.g. create job, start datafeed) will be restricted. // Therefore we need to keep the app enabled but show an info banner to the user. - if(licenseHasExpired) { + if (licenseHasExpired) { const message = features.message; if (expiredLicenseBannerId === undefined) { // Only show the banner once with no way to dismiss it expiredLicenseBannerId = banners.add({ - component: ( - - ), + component: , }); } } @@ -99,16 +86,14 @@ function getFeatures() { return xpackInfo.get('features.ml'); } -function redirectToKibana(features, kbnBaseUrl) { - const { message } = features; - const newUrl = addAppRedirectMessageToUrl(chrome.addBasePath(kbnBaseUrl), (message || '')); - window.location.href = newUrl; - return Promise.halt(); +function redirectToKibana() { + window.location.href = '/'; + return Promise.reject(); } -function redirectToBasic(kbnUrl) { - kbnUrl.redirect('/datavisualizer'); - return Promise.halt(); +function redirectToBasic() { + window.location.href = '#/datavisualizer'; + return Promise.reject(); } export function hasLicenseExpired() { @@ -116,10 +101,10 @@ export function hasLicenseExpired() { } export function isFullLicense() { - return (licenseType === LICENSE_TYPE.FULL); + return licenseType === LICENSE_TYPE.FULL; } -export function xpackFeatureAvailable(feature) { +export function xpackFeatureAvailable(feature: string) { // each plugin can register their own set of features. // so we need specific checks for each one. // this list can grow if we need to check other plugin's features. diff --git a/x-pack/legacy/plugins/ml/public/privilege/check_privilege.ts b/x-pack/legacy/plugins/ml/public/privilege/check_privilege.ts index d930763c3cac5..10842a2d15453 100644 --- a/x-pack/legacy/plugins/ml/public/privilege/check_privilege.ts +++ b/x-pack/legacy/plugins/ml/public/privilege/check_privilege.ts @@ -15,18 +15,18 @@ import { ACCESS_DENIED_PATH } from '../management/management_urls'; let privileges: Privileges = getDefaultPrivileges(); // manage_ml requires all monitor and admin cluster privileges: https://github.com/elastic/elasticsearch/blob/664a29c8905d8ce9ba8c18aa1ed5c5de93a0eabc/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/privilege/ClusterPrivilege.java#L53 -export function canGetManagementMlJobs(kbnUrl: any) { +export function canGetManagementMlJobs() { return new Promise((resolve, reject) => { getManageMlPrivileges().then( ({ capabilities, isPlatinumOrTrialLicense, mlFeatureEnabledInSpace }) => { privileges = capabilities; - // Loop through all privilages to ensure they are all set to true. + // Loop through all privileges to ensure they are all set to true. const isManageML = Object.values(privileges).every(p => p === true); if (isManageML === true && isPlatinumOrTrialLicense === true) { return resolve({ mlFeatureEnabledInSpace }); } else { - kbnUrl.redirect(ACCESS_DENIED_PATH); + window.location.href = ACCESS_DENIED_PATH; return reject(); } } @@ -34,7 +34,7 @@ export function canGetManagementMlJobs(kbnUrl: any) { }); } -export function checkGetJobsPrivilege(kbnUrl: any): Promise { +export function checkGetJobsPrivilege(): Promise { return new Promise((resolve, reject) => { getPrivileges().then(({ capabilities, isPlatinumOrTrialLicense }) => { privileges = capabilities; @@ -46,14 +46,14 @@ export function checkGetJobsPrivilege(kbnUrl: any): Promise { if (privileges.canGetJobs || isPlatinumOrTrialLicense === false) { return resolve(privileges); } else { - kbnUrl.redirect('/access-denied'); + window.location.href = '#/access-denied'; return reject(); } }); }); } -export function checkCreateJobsPrivilege(kbnUrl: any): Promise { +export function checkCreateJobsPrivilege(): Promise { return new Promise((resolve, reject) => { getPrivileges().then(({ capabilities, isPlatinumOrTrialLicense }) => { privileges = capabilities; @@ -65,14 +65,14 @@ export function checkCreateJobsPrivilege(kbnUrl: any): Promise { } else { // if the user has no permission to create a job, // redirect them back to the Transforms Management page - kbnUrl.redirect('/jobs'); + window.location.href = '#/jobs'; return reject(); } }); }); } -export function checkFindFileStructurePrivilege(kbnUrl: any): Promise { +export function checkFindFileStructurePrivilege(): Promise { return new Promise((resolve, reject) => { getPrivileges().then(({ capabilities }) => { privileges = capabilities; @@ -81,7 +81,7 @@ export function checkFindFileStructurePrivilege(kbnUrl: any): Promise; +type IndexPatternIdsByJob = Record; + // Service for accessing FieldFormat objects configured for a Kibana index pattern // for use in formatting the actual and typical values from anomalies. class FieldFormatService { - constructor() { - this.indexPatternIdsByJob = {}; - this.formatsByJob = {}; - } + indexPatternIdsByJob: IndexPatternIdsByJob = {}; + formatsByJob: FormatsByJobId = {}; // Populate the service with the FieldFormats for the list of jobs with the // specified IDs. List of Kibana index patterns is passed, with a title @@ -26,60 +24,57 @@ class FieldFormatService { // configured in the datafeed of each job. // Builds a map of Kibana FieldFormats (plugins/data/common/field_formats) // against detector index by job ID. - populateFormats(jobIds, indexPatterns) { + populateFormats(jobIds: string[]) { return new Promise((resolve, reject) => { // Populate a map of index pattern IDs against job ID, by finding the ID of the index // pattern with a title attribute which matches the index configured in the datafeed. // If a Kibana index pattern has not been created // for this index, then no custom field formatting will occur. - _.each(jobIds, (jobId) => { + jobIds.forEach(jobId => { const jobObj = mlJobService.getJob(jobId); const datafeedIndices = jobObj.datafeed_config.indices; - const indexPattern = _.find(indexPatterns, (index) => { - return _.find(datafeedIndices, (datafeedIndex) => { - return index.get('title') === datafeedIndex; - }); - }); - - // Check if index pattern has been configured to match the index in datafeed. - if (indexPattern !== undefined) { - this.indexPatternIdsByJob[jobId] = indexPattern.id; + const id = getIndexPatternIdFromName(datafeedIndices.length ? datafeedIndices[0] : ''); + if (id !== null) { + this.indexPatternIdsByJob[jobId] = id; } }); - const promises = jobIds.map(jobId => Promise.all([ - this.getFormatsForJob(jobId) - ])); + const promises = jobIds.map(jobId => Promise.all([this.getFormatsForJob(jobId)])); - Promise.all(promises).then((fmtsByJobByDetector) => { - _.each(fmtsByJobByDetector, (formatsByDetector, index) => { - this.formatsByJob[jobIds[index]] = formatsByDetector[0]; - }); - - resolve(this.formatsByJob); - }).catch(err => { - console.log('fieldFormatService error populating formats:', err); - reject({ formats: {}, err }); - }); + Promise.all(promises) + .then(fmtsByJobByDetector => { + fmtsByJobByDetector.forEach((formatsByDetector, i) => { + this.formatsByJob[jobIds[i]] = formatsByDetector[0]; + }); + resolve(this.formatsByJob); + }) + .catch(err => { + reject({ formats: {}, err }); + }); }); } // Return the FieldFormat to use for formatting values from // the detector from the job with the specified ID. - getFieldFormat(jobId, detectorIndex) { - return _.get(this.formatsByJob, [jobId, detectorIndex]); + getFieldFormat(jobId: string, detectorIndex: number) { + if (this.formatsByJob.hasOwnProperty(jobId)) { + return this.formatsByJob[jobId][detectorIndex]; + } } - // Utility for returning the FieldFormat from a full populated Kibana index pattern object // containing the list of fields by name with their formats. - getFieldFormatFromIndexPattern(fullIndexPattern, fieldName, esAggName) { + getFieldFormatFromIndexPattern( + fullIndexPattern: IndexPattern, + fieldName: string, + esAggName: string + ) { // Don't use the field formatter for distinct count detectors as // e.g. distinct_count(clientip) should be formatted as a count, not as an IP address. - let fieldFormat = undefined; + let fieldFormat; if (esAggName !== 'cardinality') { - const fieldList = _.get(fullIndexPattern, 'fields', []); + const fieldList = fullIndexPattern.fields; const field = fieldList.getByName(fieldName); if (field !== undefined) { fieldFormat = field.format; @@ -89,34 +84,34 @@ class FieldFormatService { return fieldFormat; } - getFormatsForJob(jobId) { + getFormatsForJob(jobId: string): Promise { return new Promise((resolve, reject) => { - const jobObj = mlJobService.getJob(jobId); const detectors = jobObj.analysis_config.detectors || []; - const formatsByDetector = {}; + const formatsByDetector: any[] = []; const indexPatternId = this.indexPatternIdsByJob[jobId]; if (indexPatternId !== undefined) { // Load the full index pattern configuration to obtain the formats of each field. getIndexPatternById(indexPatternId) - .then((indexPatternData) => { + .then(indexPatternData => { // Store the FieldFormat for each job by detector_index. - const fieldList = _.get(indexPatternData, 'fields', []); - _.each(detectors, (dtr) => { + const fieldList = indexPatternData.fields; + detectors.forEach(dtr => { const esAgg = mlFunctionToESAggregation(dtr.function); // distinct_count detectors should fall back to the default // formatter as the values are just counts. if (dtr.field_name !== undefined && esAgg !== 'cardinality') { const field = fieldList.getByName(dtr.field_name); if (field !== undefined) { - formatsByDetector[dtr.detector_index] = field.format; + formatsByDetector[dtr.detector_index!] = field.format; } } }); resolve(formatsByDetector); - }).catch(err => { + }) + .catch(err => { reject(err); }); } else { diff --git a/x-pack/legacy/plugins/ml/public/services/job_service.d.ts b/x-pack/legacy/plugins/ml/public/services/job_service.d.ts index 383932c812216..436d13589adcc 100644 --- a/x-pack/legacy/plugins/ml/public/services/job_service.d.ts +++ b/x-pack/legacy/plugins/ml/public/services/job_service.d.ts @@ -5,7 +5,7 @@ */ import { SearchResponse } from 'elasticsearch'; -import { CombinedJob } from '../jobs/new_job_new/common/job_creator/configs'; +import { CombinedJob } from '../jobs/new_job/common/job_creator/configs'; export interface ExistingJobsAndGroups { jobIds: string[]; @@ -34,6 +34,7 @@ declare interface JobService { createResultsUrl(jobId: string[], start: number, end: number, location: string): string; getJobAndGroupIds(): ExistingJobsAndGroups; searchPreview(job: CombinedJob): Promise>; + getJob(jobId: string): CombinedJob; } export const mlJobService: JobService; diff --git a/x-pack/legacy/plugins/ml/public/services/ml_api_service/data_frame_analytics.js b/x-pack/legacy/plugins/ml/public/services/ml_api_service/data_frame_analytics.js index c5147fc4af7d7..3f987a1763140 100644 --- a/x-pack/legacy/plugins/ml/public/services/ml_api_service/data_frame_analytics.js +++ b/x-pack/legacy/plugins/ml/public/services/ml_api_service/data_frame_analytics.js @@ -47,6 +47,13 @@ export const dataFrameAnalytics = { data: evaluateConfig }); }, + estimateDataFrameAnalyticsMemoryUsage(jobConfig) { + return http({ + url: `${basePath}/data_frame/analytics/_estimate_memory_usage`, + method: 'POST', + data: jobConfig + }); + }, deleteDataFrameAnalytics(analyticsId) { return http({ url: `${basePath}/data_frame/analytics/${analyticsId}`, diff --git a/x-pack/legacy/plugins/ml/public/services/ml_api_service/index.d.ts b/x-pack/legacy/plugins/ml/public/services/ml_api_service/index.d.ts index 414229578c217..12f39bfa78dc0 100644 --- a/x-pack/legacy/plugins/ml/public/services/ml_api_service/index.d.ts +++ b/x-pack/legacy/plugins/ml/public/services/ml_api_service/index.d.ts @@ -13,6 +13,8 @@ import { MlServerDefaults, MlServerLimits } from '../../services/ml_server_info' import { ES_AGGREGATION } from '../../../common/constants/aggregation_types'; import { DataFrameAnalyticsStats } from '../../data_frame_analytics/pages/analytics_management/components/analytics_list/common'; import { JobMessage } from '../../../common/types/audit_message'; +import { DataFrameAnalyticsConfig } from '../../data_frame_analytics/common/analytics'; +import { DeepPartial } from '../../../common/types/common'; // TODO This is not a complete representation of all methods of `ml.*`. // It just satisfies needs for other parts of the code area which use @@ -70,6 +72,9 @@ declare interface Ml { getDataFrameAnalyticsStats(analyticsId?: string): Promise; createDataFrameAnalytics(analyticsId: string, analyticsConfig: any): Promise; evaluateDataFrameAnalytics(evaluateConfig: any): Promise; + estimateDataFrameAnalyticsMemoryUsage( + jobConfig: DeepPartial + ): Promise; deleteDataFrameAnalytics(analyticsId: string): Promise; startDataFrameAnalytics(analyticsId: string): Promise; stopDataFrameAnalytics( diff --git a/x-pack/legacy/plugins/ml/public/settings/breadcrumbs.js b/x-pack/legacy/plugins/ml/public/settings/breadcrumbs.ts similarity index 74% rename from x-pack/legacy/plugins/ml/public/settings/breadcrumbs.js rename to x-pack/legacy/plugins/ml/public/settings/breadcrumbs.ts index e4e37b67c1872..2cdfa5bfcf4d0 100644 --- a/x-pack/legacy/plugins/ml/public/settings/breadcrumbs.js +++ b/x-pack/legacy/plugins/ml/public/settings/breadcrumbs.ts @@ -4,19 +4,13 @@ * you may not use this file except in compliance with the Elastic License. */ - -import { ML_BREADCRUMB, ANOMALY_DETECTION_BREADCRUMB, SETTINGS } from '../breadcrumbs'; import { i18n } from '@kbn/i18n'; - +import { ML_BREADCRUMB, ANOMALY_DETECTION_BREADCRUMB, SETTINGS } from '../breadcrumbs'; export function getSettingsBreadcrumbs() { // Whilst top level nav menu with tabs remains, // use root ML breadcrumb. - return [ - ML_BREADCRUMB, - ANOMALY_DETECTION_BREADCRUMB, - SETTINGS - ]; + return [ML_BREADCRUMB, ANOMALY_DETECTION_BREADCRUMB, SETTINGS]; } export function getCalendarManagementBreadcrumbs() { @@ -24,10 +18,10 @@ export function getCalendarManagementBreadcrumbs() { ...getSettingsBreadcrumbs(), { text: i18n.translate('xpack.ml.settings.breadcrumbs.calendarManagementLabel', { - defaultMessage: 'Calendar management' + defaultMessage: 'Calendar management', }), - href: '#/settings/calendars_list' - } + href: '#/settings/calendars_list', + }, ]; } @@ -36,10 +30,10 @@ export function getCreateCalendarBreadcrumbs() { ...getCalendarManagementBreadcrumbs(), { text: i18n.translate('xpack.ml.settings.breadcrumbs.calendarManagement.createLabel', { - defaultMessage: 'Create' + defaultMessage: 'Create', }), - href: '#/settings/calendars_list/new_calendar' - } + href: '#/settings/calendars_list/new_calendar', + }, ]; } @@ -48,10 +42,10 @@ export function getEditCalendarBreadcrumbs() { ...getCalendarManagementBreadcrumbs(), { text: i18n.translate('xpack.ml.settings.breadcrumbs.calendarManagement.editLabel', { - defaultMessage: 'Edit' + defaultMessage: 'Edit', }), - href: '#/settings/calendars_list/edit_calendar' - } + href: '#/settings/calendars_list/edit_calendar', + }, ]; } @@ -60,10 +54,10 @@ export function getFilterListsBreadcrumbs() { ...getSettingsBreadcrumbs(), { text: i18n.translate('xpack.ml.settings.breadcrumbs.filterListsLabel', { - defaultMessage: 'Filter lists' + defaultMessage: 'Filter lists', }), - href: '#/settings/filter_lists' - } + href: '#/settings/filter_lists', + }, ]; } @@ -72,10 +66,10 @@ export function getCreateFilterListBreadcrumbs() { ...getFilterListsBreadcrumbs(), { text: i18n.translate('xpack.ml.settings.breadcrumbs.filterLists.createLabel', { - defaultMessage: 'Create' + defaultMessage: 'Create', }), - href: '#/settings/filter_lists/new' - } + href: '#/settings/filter_lists/new', + }, ]; } @@ -84,9 +78,9 @@ export function getEditFilterListBreadcrumbs() { ...getFilterListsBreadcrumbs(), { text: i18n.translate('xpack.ml.settings.breadcrumbs.filterLists.editLabel', { - defaultMessage: 'Edit' + defaultMessage: 'Edit', }), - href: '#/settings/filter_lists/edit' - } + href: '#/settings/filter_lists/edit', + }, ]; } diff --git a/x-pack/legacy/plugins/ml/public/settings/calendars/edit/directive.js b/x-pack/legacy/plugins/ml/public/settings/calendars/edit/directive.tsx similarity index 87% rename from x-pack/legacy/plugins/ml/public/settings/calendars/edit/directive.js rename to x-pack/legacy/plugins/ml/public/settings/calendars/edit/directive.tsx index 34b647ef370d5..cc1674848d374 100644 --- a/x-pack/legacy/plugins/ml/public/settings/calendars/edit/directive.js +++ b/x-pack/legacy/plugins/ml/public/settings/calendars/edit/directive.tsx @@ -4,21 +4,22 @@ * you may not use this file except in compliance with the Elastic License. */ - import 'ngreact'; import React from 'react'; import ReactDOM from 'react-dom'; +// @ts-ignore import { uiModules } from 'ui/modules'; const module = uiModules.get('apps/ml', ['react']); +import uiRoutes from 'ui/routes'; +import { I18nContext } from 'ui/i18n'; import { checkFullLicense } from '../../../license/check_license'; import { checkGetJobsPrivilege, checkPermission } from '../../../privilege/check_privilege'; import { checkMlNodesAvailable } from '../../../ml_nodes_check'; import { getCreateCalendarBreadcrumbs, getEditCalendarBreadcrumbs } from '../../breadcrumbs'; -import uiRoutes from 'ui/routes'; -import { I18nContext } from 'ui/i18n'; +import { NewCalendar } from './new_calendar'; const template = `
@@ -33,7 +34,7 @@ uiRoutes CheckLicense: checkFullLicense, privileges: checkGetJobsPrivilege, checkMlNodesAvailable, - } + }, }) .when('/settings/calendars_list/edit_calendar/:calendarId', { template, @@ -42,21 +43,19 @@ uiRoutes CheckLicense: checkFullLicense, privileges: checkGetJobsPrivilege, checkMlNodesAvailable, - } + }, }); -import { NewCalendar } from './new_calendar.js'; - -module.directive('mlNewCalendar', function ($route) { +module.directive('mlNewCalendar', function($route: any) { return { restrict: 'E', replace: false, scope: {}, - link: function (scope, element) { + link(scope: ng.IScope, element: ng.IAugmentedJQuery) { const props = { calendarId: $route.current.params.calendarId, canCreateCalendar: checkPermission('canCreateCalendar'), - canDeleteCalendar: checkPermission('canDeleteCalendar') + canDeleteCalendar: checkPermission('canDeleteCalendar'), }; ReactDOM.render( @@ -65,6 +64,6 @@ module.directive('mlNewCalendar', function ($route) { , element[0] ); - } + }, }; }); diff --git a/x-pack/legacy/plugins/ml/public/settings/filter_lists/edit/index.js b/x-pack/legacy/plugins/ml/public/settings/calendars/edit/index.ts similarity index 99% rename from x-pack/legacy/plugins/ml/public/settings/filter_lists/edit/index.js rename to x-pack/legacy/plugins/ml/public/settings/calendars/edit/index.ts index 3839017291326..aa8b2ec2c29c9 100644 --- a/x-pack/legacy/plugins/ml/public/settings/filter_lists/edit/index.js +++ b/x-pack/legacy/plugins/ml/public/settings/calendars/edit/index.ts @@ -4,5 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ - import './directive'; diff --git a/x-pack/legacy/plugins/ml/public/settings/calendars/edit/new_calendar.d.ts b/x-pack/legacy/plugins/ml/public/settings/calendars/edit/new_calendar.d.ts new file mode 100644 index 0000000000000..d6de538d6388a --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/settings/calendars/edit/new_calendar.d.ts @@ -0,0 +1,13 @@ +/* + * 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 { FC } from 'react'; + +declare const NewCalendar: FC<{ + calendarId: string; + canCreateCalendar: boolean; + canDeleteCalendar: boolean; +}>; diff --git a/x-pack/legacy/plugins/ml/public/settings/calendars/list/calendars_list.d.ts b/x-pack/legacy/plugins/ml/public/settings/calendars/list/calendars_list.d.ts new file mode 100644 index 0000000000000..05debad543075 --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/settings/calendars/list/calendars_list.d.ts @@ -0,0 +1,12 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { FC } from 'react'; + +declare const CalendarsList: FC<{ + canCreateCalendar: boolean; + canDeleteCalendar: boolean; +}>; diff --git a/x-pack/legacy/plugins/ml/public/settings/calendars/list/directive.js b/x-pack/legacy/plugins/ml/public/settings/calendars/list/directive.tsx similarity index 92% rename from x-pack/legacy/plugins/ml/public/settings/calendars/list/directive.js rename to x-pack/legacy/plugins/ml/public/settings/calendars/list/directive.tsx index 32085fa0e9939..1b90a27c07ada 100644 --- a/x-pack/legacy/plugins/ml/public/settings/calendars/list/directive.js +++ b/x-pack/legacy/plugins/ml/public/settings/calendars/list/directive.tsx @@ -8,16 +8,18 @@ import 'ngreact'; import React from 'react'; import ReactDOM from 'react-dom'; +// @ts-ignore import { uiModules } from 'ui/modules'; const module = uiModules.get('apps/ml', ['react']); +import uiRoutes from 'ui/routes'; +import { I18nContext } from 'ui/i18n'; import { checkFullLicense } from '../../../license/check_license'; import { checkGetJobsPrivilege, checkPermission } from '../../../privilege/check_privilege'; import { getMlNodeCount } from '../../../ml_nodes_check/check_ml_nodes'; import { getCalendarManagementBreadcrumbs } from '../../breadcrumbs'; -import uiRoutes from 'ui/routes'; -import { I18nContext } from 'ui/i18n'; +import { CalendarsList } from './calendars_list'; const template = `
@@ -34,14 +36,12 @@ uiRoutes.when('/settings/calendars_list', { }, }); -import { CalendarsList } from './calendars_list'; - -module.directive('mlCalendarsList', function () { +module.directive('mlCalendarsList', function() { return { restrict: 'E', replace: false, scope: {}, - link: function (scope, element) { + link(scope: ng.IScope, element: ng.IAugmentedJQuery) { const props = { canCreateCalendar: checkPermission('canCreateCalendar'), canDeleteCalendar: checkPermission('canDeleteCalendar'), diff --git a/x-pack/legacy/plugins/ml/public/settings/filter_lists/list/index.js b/x-pack/legacy/plugins/ml/public/settings/calendars/list/index.ts similarity index 99% rename from x-pack/legacy/plugins/ml/public/settings/filter_lists/list/index.js rename to x-pack/legacy/plugins/ml/public/settings/calendars/list/index.ts index fd75a9ceb9b49..aa8b2ec2c29c9 100644 --- a/x-pack/legacy/plugins/ml/public/settings/filter_lists/list/index.js +++ b/x-pack/legacy/plugins/ml/public/settings/calendars/list/index.ts @@ -4,6 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ - - import './directive'; diff --git a/x-pack/legacy/plugins/ml/public/settings/filter_lists/edit/directive.js b/x-pack/legacy/plugins/ml/public/settings/filter_lists/edit/directive.tsx similarity index 81% rename from x-pack/legacy/plugins/ml/public/settings/filter_lists/edit/directive.js rename to x-pack/legacy/plugins/ml/public/settings/filter_lists/edit/directive.tsx index 1d6c72c13f9f2..b70b7eebfccc9 100644 --- a/x-pack/legacy/plugins/ml/public/settings/filter_lists/edit/directive.js +++ b/x-pack/legacy/plugins/ml/public/settings/filter_lists/edit/directive.tsx @@ -4,22 +4,22 @@ * you may not use this file except in compliance with the Elastic License. */ - import 'ngreact'; import React from 'react'; import ReactDOM from 'react-dom'; +// @ts-ignore import { uiModules } from 'ui/modules'; const module = uiModules.get('apps/ml', ['react']); -import { getCreateFilterListBreadcrumbs, getEditFilterListBreadcrumbs } from '../../breadcrumbs'; -import { checkFullLicense } from 'plugins/ml/license/check_license'; -import { checkGetJobsPrivilege, checkPermission } from 'plugins/ml/privilege/check_privilege'; -import { getMlNodeCount } from 'plugins/ml/ml_nodes_check/check_ml_nodes'; -import { EditFilterList } from './edit_filter_list'; - import uiRoutes from 'ui/routes'; import { I18nContext } from 'ui/i18n'; +import { getMlNodeCount } from '../../../ml_nodes_check/check_ml_nodes'; +import { checkGetJobsPrivilege, checkPermission } from '../../../privilege/check_privilege'; +import { checkFullLicense } from '../../../license/check_license'; +import { getCreateFilterListBreadcrumbs, getEditFilterListBreadcrumbs } from '../../breadcrumbs'; + +import { EditFilterList } from './edit_filter_list'; const template = `
@@ -34,7 +34,7 @@ uiRoutes CheckLicense: checkFullLicense, privileges: checkGetJobsPrivilege, mlNodeCount: getMlNodeCount, - } + }, }) .when('/settings/filter_lists/edit_filter_list/:filterId', { template, @@ -43,15 +43,15 @@ uiRoutes CheckLicense: checkFullLicense, privileges: checkGetJobsPrivilege, mlNodeCount: getMlNodeCount, - } + }, }); -module.directive('mlEditFilterList', function ($route) { +module.directive('mlEditFilterList', function($route: any) { return { restrict: 'E', replace: false, scope: {}, - link: function (scope, element) { + link(scope: ng.IScope, element: ng.IAugmentedJQuery) { const props = { filterId: $route.current.params.filterId, canCreateFilter: checkPermission('canCreateFilter'), @@ -64,6 +64,6 @@ module.directive('mlEditFilterList', function ($route) { , element[0] ); - } + }, }; }); diff --git a/x-pack/legacy/plugins/ml/public/settings/filter_lists/edit/edit_filter_list.d.ts b/x-pack/legacy/plugins/ml/public/settings/filter_lists/edit/edit_filter_list.d.ts new file mode 100644 index 0000000000000..71d82d7694cf0 --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/settings/filter_lists/edit/edit_filter_list.d.ts @@ -0,0 +1,13 @@ +/* + * 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 { FC } from 'react'; + +declare const EditFilterList: FC<{ + filterId: string; + canCreateFilter: boolean; + canDeleteFilter: boolean; +}>; diff --git a/x-pack/legacy/plugins/ml/public/settings/calendars/list/index.js b/x-pack/legacy/plugins/ml/public/settings/filter_lists/edit/index.ts similarity index 99% rename from x-pack/legacy/plugins/ml/public/settings/calendars/list/index.js rename to x-pack/legacy/plugins/ml/public/settings/filter_lists/edit/index.ts index fd75a9ceb9b49..aa8b2ec2c29c9 100644 --- a/x-pack/legacy/plugins/ml/public/settings/calendars/list/index.js +++ b/x-pack/legacy/plugins/ml/public/settings/filter_lists/edit/index.ts @@ -4,6 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ - - import './directive'; diff --git a/x-pack/legacy/plugins/ml/public/settings/filter_lists/index.js b/x-pack/legacy/plugins/ml/public/settings/filter_lists/index.ts similarity index 99% rename from x-pack/legacy/plugins/ml/public/settings/filter_lists/index.js rename to x-pack/legacy/plugins/ml/public/settings/filter_lists/index.ts index 463b602c20c9a..6a942d5c251df 100644 --- a/x-pack/legacy/plugins/ml/public/settings/filter_lists/index.js +++ b/x-pack/legacy/plugins/ml/public/settings/filter_lists/index.ts @@ -4,6 +4,5 @@ * you may not use this file except in compliance with the Elastic License. */ - import './edit'; import './list'; diff --git a/x-pack/legacy/plugins/ml/public/settings/filter_lists/list/directive.js b/x-pack/legacy/plugins/ml/public/settings/filter_lists/list/directive.tsx similarity index 64% rename from x-pack/legacy/plugins/ml/public/settings/filter_lists/list/directive.js rename to x-pack/legacy/plugins/ml/public/settings/filter_lists/list/directive.tsx index 311bf1bcb358a..7b572344c603b 100644 --- a/x-pack/legacy/plugins/ml/public/settings/filter_lists/list/directive.js +++ b/x-pack/legacy/plugins/ml/public/settings/filter_lists/list/directive.tsx @@ -4,45 +4,44 @@ * you may not use this file except in compliance with the Elastic License. */ - import 'ngreact'; import React from 'react'; import ReactDOM from 'react-dom'; +// @ts-ignore import { uiModules } from 'ui/modules'; const module = uiModules.get('apps/ml', ['react']); -import { getFilterListsBreadcrumbs } from '../../breadcrumbs'; -import { checkFullLicense } from 'plugins/ml/license/check_license'; -import { checkGetJobsPrivilege, checkPermission } from 'plugins/ml/privilege/check_privilege'; -import { getMlNodeCount } from 'plugins/ml/ml_nodes_check/check_ml_nodes'; -import { FilterLists } from './filter_lists'; - import uiRoutes from 'ui/routes'; import { I18nContext } from 'ui/i18n'; +import { checkFullLicense } from '../../../license/check_license'; +import { checkGetJobsPrivilege, checkPermission } from '../../../privilege/check_privilege'; +import { getMlNodeCount } from '../../../ml_nodes_check/check_ml_nodes'; +import { getFilterListsBreadcrumbs } from '../../breadcrumbs'; + +import { FilterLists } from './filter_lists'; const template = `
`; -uiRoutes - .when('/settings/filter_lists', { - template, - k7Breadcrumbs: getFilterListsBreadcrumbs, - resolve: { - CheckLicense: checkFullLicense, - privileges: checkGetJobsPrivilege, - mlNodeCount: getMlNodeCount, - } - }); - -module.directive('mlFilterLists', function () { +uiRoutes.when('/settings/filter_lists', { + template, + k7Breadcrumbs: getFilterListsBreadcrumbs, + resolve: { + CheckLicense: checkFullLicense, + privileges: checkGetJobsPrivilege, + mlNodeCount: getMlNodeCount, + }, +}); + +module.directive('mlFilterLists', function() { return { restrict: 'E', replace: false, scope: {}, - link: function (scope, element) { + link(scope: ng.IScope, element: ng.IAugmentedJQuery) { const props = { canCreateFilter: checkPermission('canCreateFilter'), canDeleteFilter: checkPermission('canDeleteFilter'), @@ -54,6 +53,6 @@ module.directive('mlFilterLists', function () { , element[0] ); - } + }, }; }); diff --git a/x-pack/legacy/plugins/ml/common/util/parse_interval.d.ts b/x-pack/legacy/plugins/ml/public/settings/filter_lists/list/filter_lists.d.ts similarity index 67% rename from x-pack/legacy/plugins/ml/common/util/parse_interval.d.ts rename to x-pack/legacy/plugins/ml/public/settings/filter_lists/list/filter_lists.d.ts index 7c4f40cc6c9d7..b14b19594e0b5 100644 --- a/x-pack/legacy/plugins/ml/common/util/parse_interval.d.ts +++ b/x-pack/legacy/plugins/ml/public/settings/filter_lists/list/filter_lists.d.ts @@ -4,6 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import { Duration } from 'moment'; +import { FC } from 'react'; -export function parseInterval(interval: string): Duration; +declare const FilterLists: FC<{ + canCreateFilter: boolean; + canDeleteFilter: boolean; +}>; diff --git a/x-pack/legacy/plugins/ml/public/settings/calendars/edit/index.js b/x-pack/legacy/plugins/ml/public/settings/filter_lists/list/index.ts similarity index 99% rename from x-pack/legacy/plugins/ml/public/settings/calendars/edit/index.js rename to x-pack/legacy/plugins/ml/public/settings/filter_lists/list/index.ts index fd75a9ceb9b49..aa8b2ec2c29c9 100644 --- a/x-pack/legacy/plugins/ml/public/settings/calendars/edit/index.js +++ b/x-pack/legacy/plugins/ml/public/settings/filter_lists/list/index.ts @@ -4,6 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ - - import './directive'; diff --git a/x-pack/legacy/plugins/ml/public/settings/index.js b/x-pack/legacy/plugins/ml/public/settings/index.ts similarity index 99% rename from x-pack/legacy/plugins/ml/public/settings/index.js rename to x-pack/legacy/plugins/ml/public/settings/index.ts index 659f135d98c50..d9fc996ae4a30 100644 --- a/x-pack/legacy/plugins/ml/public/settings/index.js +++ b/x-pack/legacy/plugins/ml/public/settings/index.ts @@ -4,8 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ - - import './settings_directive'; import './calendars'; import './filter_lists'; diff --git a/x-pack/legacy/plugins/ml/public/settings/settings_directive.js b/x-pack/legacy/plugins/ml/public/settings/settings_directive.tsx similarity index 80% rename from x-pack/legacy/plugins/ml/public/settings/settings_directive.js rename to x-pack/legacy/plugins/ml/public/settings/settings_directive.tsx index 8692d903b1bd0..5102c7650a7b1 100644 --- a/x-pack/legacy/plugins/ml/public/settings/settings_directive.js +++ b/x-pack/legacy/plugins/ml/public/settings/settings_directive.tsx @@ -4,44 +4,41 @@ * you may not use this file except in compliance with the Elastic License. */ - import 'ngreact'; import React from 'react'; import ReactDOM from 'react-dom'; +// @ts-ignore import { uiModules } from 'ui/modules'; const module = uiModules.get('apps/ml', ['react']); +import { I18nContext } from 'ui/i18n'; +import uiRoutes from 'ui/routes'; +import { timefilter } from 'ui/timefilter'; import { checkFullLicense } from '../license/check_license'; import { checkGetJobsPrivilege, checkPermission } from '../privilege/check_privilege'; import { getMlNodeCount } from '../ml_nodes_check/check_ml_nodes'; import { getSettingsBreadcrumbs } from './breadcrumbs'; -import { I18nContext } from 'ui/i18n'; -import uiRoutes from 'ui/routes'; -import { timefilter } from 'ui/timefilter'; - const template = `
`; -uiRoutes - .when('/settings', { - template, - k7Breadcrumbs: getSettingsBreadcrumbs, - resolve: { - CheckLicense: checkFullLicense, - privileges: checkGetJobsPrivilege, - mlNodeCount: getMlNodeCount, - } - }); - +uiRoutes.when('/settings', { + template, + k7Breadcrumbs: getSettingsBreadcrumbs, + resolve: { + CheckLicense: checkFullLicense, + privileges: checkGetJobsPrivilege, + mlNodeCount: getMlNodeCount, + }, +}); +// @ts-ignore import { Settings } from './settings.js'; -module.directive('mlSettings', function () { - +module.directive('mlSettings', function() { const canGetFilters = checkPermission('canGetFilters'); const canGetCalendars = checkPermission('canGetCalendars'); @@ -49,7 +46,7 @@ module.directive('mlSettings', function () { restrict: 'E', replace: false, scope: {}, - link: function (scope, element) { + link(scope: ng.IScope, element: ng.IAugmentedJQuery) { timefilter.disableTimeRangeSelector(); timefilter.disableAutoRefreshSelector(); @@ -59,6 +56,6 @@ module.directive('mlSettings', function () { , element[0] ); - } + }, }; }); diff --git a/x-pack/legacy/plugins/ml/public/timeseriesexplorer/timeseriesexplorer.js b/x-pack/legacy/plugins/ml/public/timeseriesexplorer/timeseriesexplorer.js index 857e12cbbe942..1dec12a396578 100644 --- a/x-pack/legacy/plugins/ml/public/timeseriesexplorer/timeseriesexplorer.js +++ b/x-pack/legacy/plugins/ml/public/timeseriesexplorer/timeseriesexplorer.js @@ -68,7 +68,6 @@ import { mlJobService } from '../services/job_service'; import { mlResultsService } from '../services/results_service'; import { mlTimefilterRefresh$ } from '../services/timefilter_refresh_service'; -import { getIndexPatterns } from '../util/index_utils'; import { getBoundsRoundedToInterval } from '../util/time_buckets'; import { APP_STATE_ACTION, CHARTS_POINT_TARGET, TIME_FIELD_NAME } from './timeseriesexplorer_constants'; @@ -827,7 +826,7 @@ export class TimeSeriesExplorer extends React.Component { () => { this.updateControlsForDetector(() => { // Populate the map of jobs / detectors / field formatters for the selected IDs and refresh. - mlFieldFormatService.populateFormats([jobId], getIndexPatterns()) + mlFieldFormatService.populateFormats([jobId]) .catch((err) => { console.log('Error populating field formats:', err); }) // Load the data - if the FieldFormats failed to populate // the default formatting will be used for metric values. diff --git a/x-pack/legacy/plugins/ml/public/util/index_utils.ts b/x-pack/legacy/plugins/ml/public/util/index_utils.ts index 8a1cfda54a5f4..5c15cdd6b8df0 100644 --- a/x-pack/legacy/plugins/ml/public/util/index_utils.ts +++ b/x-pack/legacy/plugins/ml/public/util/index_utils.ts @@ -17,8 +17,6 @@ type IndexPatternSavedObject = SimpleSavedObject; let indexPatternCache: IndexPatternSavedObject[] = []; let fullIndexPatterns: IndexPatterns | null = null; -export let refreshIndexPatterns: (() => Promise) | null = null; - export function loadIndexPatterns() { fullIndexPatterns = data.indexPatterns.indexPatterns; const savedObjectsClient = chrome.getSavedObjectsClient(); @@ -30,20 +28,6 @@ export function loadIndexPatterns() { }) .then(response => { indexPatternCache = response.savedObjects; - if (refreshIndexPatterns === null) { - refreshIndexPatterns = () => { - return new Promise((resolve, reject) => { - loadIndexPatterns() - .then(resp => { - resolve(resp); - }) - .catch(error => { - reject(error); - }); - }); - }; - } - return indexPatternCache; }); } @@ -62,7 +46,7 @@ export function getIndexPatternIdFromName(name: string) { return indexPatternCache[j].id; } } - return name; + return null; } export function loadCurrentIndexPattern(indexPatterns: IndexPatterns, $route: Record) { diff --git a/x-pack/legacy/plugins/ml/server/client/elasticsearch_ml.js b/x-pack/legacy/plugins/ml/server/client/elasticsearch_ml.js index ae2a64e0108f3..3df1d3e2c3bd0 100644 --- a/x-pack/legacy/plugins/ml/server/client/elasticsearch_ml.js +++ b/x-pack/legacy/plugins/ml/server/client/elasticsearch_ml.js @@ -170,6 +170,16 @@ export const elasticsearchJsPlugin = (Client, config, components) => { method: 'POST' }); + ml.estimateDataFrameAnalyticsMemoryUsage = ca({ + urls: [ + { + fmt: '/_ml/data_frame/analytics/_estimate_memory_usage', + } + ], + needBody: true, + method: 'POST' + }); + ml.deleteDataFrameAnalytics = ca({ urls: [ { diff --git a/x-pack/legacy/plugins/ml/server/lib/check_license/__tests__/check_license.js b/x-pack/legacy/plugins/ml/server/lib/check_license/__tests__/check_license.ts similarity index 80% rename from x-pack/legacy/plugins/ml/server/lib/check_license/__tests__/check_license.js rename to x-pack/legacy/plugins/ml/server/lib/check_license/__tests__/check_license.ts index 25411bb2775d5..5a8b4fdcc76db 100644 --- a/x-pack/legacy/plugins/ml/server/lib/check_license/__tests__/check_license.js +++ b/x-pack/legacy/plugins/ml/server/lib/check_license/__tests__/check_license.ts @@ -4,20 +4,18 @@ * you may not use this file except in compliance with the Elastic License. */ - - import expect from '@kbn/expect'; import sinon from 'sinon'; import { set } from 'lodash'; +import { XPackInfo } from '../../../../../../../legacy/plugins/xpack_main/server/lib/xpack_info'; import { checkLicense } from '../check_license'; describe('check_license', () => { - - let mockLicenseInfo; - beforeEach(() => mockLicenseInfo = {}); + let mockLicenseInfo: XPackInfo; + beforeEach(() => (mockLicenseInfo = {} as XPackInfo)); describe('license information is undefined', () => { - beforeEach(() => mockLicenseInfo = undefined); + beforeEach(() => (mockLicenseInfo = {} as XPackInfo)); it('should set isAvailable to false', () => { expect(checkLicense(mockLicenseInfo).isAvailable).to.be(false); @@ -37,7 +35,7 @@ describe('check_license', () => { }); describe('license information is not available', () => { - beforeEach(() => mockLicenseInfo.isAvailable = () => false); + beforeEach(() => (mockLicenseInfo.isAvailable = () => false)); it('should set isAvailable to false', () => { expect(checkLicense(mockLicenseInfo).isAvailable).to.be(false); @@ -64,14 +62,21 @@ describe('check_license', () => { describe('& ML is disabled in Elasticsearch', () => { beforeEach(() => { - set(mockLicenseInfo, 'feature', sinon.stub().withArgs('ml').returns({ isEnabled: () => false })); + set( + mockLicenseInfo, + 'feature', + sinon + .stub() + .withArgs('ml') + .returns({ isEnabled: () => false }) + ); }); - it ('should set showLinks to false', () => { + it('should set showLinks to false', () => { expect(checkLicense(mockLicenseInfo).showLinks).to.be(false); }); - it ('should set isAvailable to false', () => { + it('should set isAvailable to false', () => { expect(checkLicense(mockLicenseInfo).isAvailable).to.be(false); }); @@ -86,7 +91,14 @@ describe('check_license', () => { describe('& ML is enabled in Elasticsearch', () => { beforeEach(() => { - set(mockLicenseInfo, 'feature', sinon.stub().withArgs('ml').returns({ isEnabled: () => true })); + set( + mockLicenseInfo, + 'feature', + sinon + .stub() + .withArgs('ml') + .returns({ isEnabled: () => true }) + ); }); describe('& license is trial or platinum', () => { @@ -99,11 +111,11 @@ describe('check_license', () => { expect(checkLicense(mockLicenseInfo).isAvailable).to.be(true); }); - it ('should set showLinks to true', () => { + it('should set showLinks to true', () => { expect(checkLicense(mockLicenseInfo).showLinks).to.be(true); }); - it ('should set enableLinks to true', () => { + it('should set enableLinks to true', () => { expect(checkLicense(mockLicenseInfo).enableLinks).to.be(true); }); @@ -119,11 +131,11 @@ describe('check_license', () => { expect(checkLicense(mockLicenseInfo).isAvailable).to.be(true); }); - it ('should set showLinks to true', () => { + it('should set showLinks to true', () => { expect(checkLicense(mockLicenseInfo).showLinks).to.be(true); }); - it ('should set enableLinks to true', () => { + it('should set enableLinks to true', () => { expect(checkLicense(mockLicenseInfo).enableLinks).to.be(true); }); @@ -143,7 +155,7 @@ describe('check_license', () => { expect(checkLicense(mockLicenseInfo).isAvailable).to.be(true); }); - it ('should set showLinks to true', () => { + it('should set showLinks to true', () => { expect(checkLicense(mockLicenseInfo).showLinks).to.be(true); }); }); diff --git a/x-pack/legacy/plugins/ml/server/lib/check_license/check_license.d.ts b/x-pack/legacy/plugins/ml/server/lib/check_license/check_license.d.ts deleted file mode 100644 index 6987df3c3c0ba..0000000000000 --- a/x-pack/legacy/plugins/ml/server/lib/check_license/check_license.d.ts +++ /dev/null @@ -1,17 +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 { LICENSE_TYPE } from '../../../common/constants/license'; -interface Response { - isAvailable: boolean; - showLinks: boolean; - enableLinks: boolean; - licenseType: LICENSE_TYPE; - hasExpired: boolean; - message: string; -} - -export function checkLicense(xpackLicenseInfo: any): Response; diff --git a/x-pack/legacy/plugins/ml/server/lib/check_license/check_license.js b/x-pack/legacy/plugins/ml/server/lib/check_license/check_license.ts similarity index 66% rename from x-pack/legacy/plugins/ml/server/lib/check_license/check_license.js rename to x-pack/legacy/plugins/ml/server/lib/check_license/check_license.ts index b64bc98539ffd..bb92705880dde 100644 --- a/x-pack/legacy/plugins/ml/server/lib/check_license/check_license.js +++ b/x-pack/legacy/plugins/ml/server/lib/check_license/check_license.ts @@ -4,11 +4,20 @@ * you may not use this file except in compliance with the Elastic License. */ - -import { LICENSE_TYPE } from '../../../common/constants/license'; import { i18n } from '@kbn/i18n'; +import { LICENSE_TYPE } from '../../../common/constants/license'; +import { XPackInfo } from '../../../../../../legacy/plugins/xpack_main/server/lib/xpack_info'; + +interface Response { + isAvailable: boolean; + showLinks: boolean; + enableLinks: boolean; + licenseType?: LICENSE_TYPE; + hasExpired?: boolean; + message?: string; +} -export function checkLicense(xpackLicenseInfo) { +export function checkLicense(xpackLicenseInfo: XPackInfo): Response { // If, for some reason, we cannot get the license information // from Elasticsearch, assume worst case and disable the Machine Learning UI if (!xpackLicenseInfo || !xpackLicenseInfo.isAvailable()) { @@ -16,9 +25,13 @@ export function checkLicense(xpackLicenseInfo) { isAvailable: false, showLinks: true, enableLinks: false, - message: i18n.translate('xpack.ml.checkLicense.licenseInformationNotAvailableThisTimeMessage', { - defaultMessage: 'You cannot use Machine Learning because license information is not available at this time.' - }) + message: i18n.translate( + 'xpack.ml.checkLicense.licenseInformationNotAvailableThisTimeMessage', + { + defaultMessage: + 'You cannot use Machine Learning because license information is not available at this time.', + } + ), }; } @@ -29,18 +42,15 @@ export function checkLicense(xpackLicenseInfo) { showLinks: false, enableLinks: false, message: i18n.translate('xpack.ml.checkLicense.mlIsUnavailableMessage', { - defaultMessage: 'Machine Learning is unavailable' - }) + defaultMessage: 'Machine Learning is unavailable', + }), }; } - const VALID_FULL_LICENSE_MODES = [ - 'trial', - 'platinum' - ]; + const VALID_FULL_LICENSE_MODES = ['trial', 'platinum']; const isLicenseModeValid = xpackLicenseInfo.license.isOneOf(VALID_FULL_LICENSE_MODES); - const licenseType = (isLicenseModeValid === true) ? LICENSE_TYPE.FULL : LICENSE_TYPE.BASIC; + const licenseType = isLicenseModeValid === true ? LICENSE_TYPE.FULL : LICENSE_TYPE.BASIC; const isLicenseActive = xpackLicenseInfo.license.isActive(); const licenseTypeName = xpackLicenseInfo.license.getType(); @@ -54,8 +64,8 @@ export function checkLicense(xpackLicenseInfo) { licenseType, message: i18n.translate('xpack.ml.checkLicense.licenseHasExpiredMessage', { defaultMessage: 'Your {licenseTypeName} Machine Learning license has expired.', - values: { licenseTypeName } - }) + values: { licenseTypeName }, + }), }; } diff --git a/x-pack/legacy/plugins/ml/server/models/job_validation/validate_bucket_span.js b/x-pack/legacy/plugins/ml/server/models/job_validation/validate_bucket_span.js index 2a9d3064ee825..c80c4851bde59 100644 --- a/x-pack/legacy/plugins/ml/server/models/job_validation/validate_bucket_span.js +++ b/x-pack/legacy/plugins/ml/server/models/job_validation/validate_bucket_span.js @@ -9,7 +9,7 @@ import { estimateBucketSpanFactory } from '../../models/bucket_span_estimator'; import { mlFunctionToESAggregation } from '../../../common/util/job_utils'; import { SKIP_BUCKET_SPAN_ESTIMATION } from '../../../common/constants/validation'; -import { parseInterval } from '../../../common/util/parse_interval.js'; +import { parseInterval } from '../../../common/util/parse_interval'; import { validateJobObject } from './validate_job_object'; diff --git a/x-pack/legacy/plugins/ml/server/models/job_validation/validate_time_range.js b/x-pack/legacy/plugins/ml/server/models/job_validation/validate_time_range.js index 9c48fae1739b9..bffad443b4c14 100644 --- a/x-pack/legacy/plugins/ml/server/models/job_validation/validate_time_range.js +++ b/x-pack/legacy/plugins/ml/server/models/job_validation/validate_time_range.js @@ -9,7 +9,7 @@ import _ from 'lodash'; import { ES_FIELD_TYPES } from '../../../../../../../src/plugins/data/server'; -import { parseInterval } from '../../../common/util/parse_interval.js'; +import { parseInterval } from '../../../common/util/parse_interval'; import { validateJobObject } from './validate_job_object'; const BUCKET_SPAN_COMPARE_FACTOR = 25; diff --git a/x-pack/legacy/plugins/ml/server/routes/data_frame_analytics.js b/x-pack/legacy/plugins/ml/server/routes/data_frame_analytics.js index 41f08736a78e5..d467aeea31f99 100644 --- a/x-pack/legacy/plugins/ml/server/routes/data_frame_analytics.js +++ b/x-pack/legacy/plugins/ml/server/routes/data_frame_analytics.js @@ -91,6 +91,19 @@ export function dataFrameAnalyticsRoutes({ commonRouteConfig, elasticsearchPlugi } }); + route({ + method: 'POST', + path: '/api/ml/data_frame/analytics/_estimate_memory_usage', + handler(request) { + const callWithRequest = callWithRequestFactory(elasticsearchPlugin, request); + return callWithRequest('ml.estimateDataFrameAnalyticsMemoryUsage', { body: request.payload }) + .catch(resp => wrapError(resp)); + }, + config: { + ...commonRouteConfig + } + }); + route({ method: 'DELETE', path: '/api/ml/data_frame/analytics/{analyticsId}', diff --git a/x-pack/legacy/plugins/monitoring/public/components/logs/__snapshots__/reason.test.js.snap b/x-pack/legacy/plugins/monitoring/public/components/logs/__snapshots__/reason.test.js.snap index fa4b11ed57240..cd317dee65c33 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/logs/__snapshots__/reason.test.js.snap +++ b/x-pack/legacy/plugins/monitoring/public/components/logs/__snapshots__/reason.test.js.snap @@ -14,6 +14,7 @@ exports[`Logs should render a default message 1`] = ` Object { "link": `; +exports[`Logs should render with a bad indices reason 1`] = ` + +

+ + Click here for more information + , + } + } + /> +

+
+`; + exports[`Logs should render with a no cluster found reason 1`] = ` setup
, @@ -66,6 +93,7 @@ exports[`Logs should render with a no index found reason 1`] = ` Object { "link": setup , @@ -90,6 +118,7 @@ exports[`Logs should render with a no index pattern found reason 1`] = ` Object { "link": Filebeat , @@ -114,6 +143,7 @@ exports[`Logs should render with a no node found reason 1`] = ` Object { "link": setup , @@ -138,6 +168,7 @@ exports[`Logs should render with a no type found reason 1`] = ` Object { "link": these directions , diff --git a/x-pack/legacy/plugins/monitoring/public/components/logs/reason.js b/x-pack/legacy/plugins/monitoring/public/components/logs/reason.js index a2acbe4ac3a58..7ce6744da5712 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/logs/reason.js +++ b/x-pack/legacy/plugins/monitoring/public/components/logs/reason.js @@ -23,7 +23,7 @@ export const Reason = ({ reason }) => { defaultMessage="We did not find any log data and we are unable to diagnose why. {link}" values={{ link: ( - + { defaultMessage="Set up {link}, then configure your Elasticsearch output to your monitoring cluster." values={{ link: ( - + {i18n.translate('xpack.monitoring.logs.reason.noIndexPatternLink', { defaultMessage: 'Filebeat' })} @@ -75,7 +75,10 @@ export const Reason = ({ reason }) => { defaultMessage="Follow {link} to set up Elasticsearch." values={{ link: ( - + {i18n.translate('xpack.monitoring.logs.reason.noTypeLink', { defaultMessage: 'these directions' })} @@ -95,7 +98,7 @@ export const Reason = ({ reason }) => { defaultMessage="Check that your {link} is correct." values={{ link: ( - + {i18n.translate('xpack.monitoring.logs.reason.noClusterLink', { defaultMessage: 'setup' })} @@ -115,7 +118,7 @@ export const Reason = ({ reason }) => { defaultMessage="Check that your {link} is correct." values={{ link: ( - + {i18n.translate('xpack.monitoring.logs.reason.noNodeLink', { defaultMessage: 'setup' })} @@ -135,8 +138,8 @@ export const Reason = ({ reason }) => { defaultMessage="We found logs, but none for this index. If this problem continues, check that your {link} is correct." values={{ link: ( - - {i18n.translate('xpack.monitoring.logs.reason.noNodeLink', { + + {i18n.translate('xpack.monitoring.logs.reason.noIndexLink', { defaultMessage: 'setup' })} @@ -145,6 +148,29 @@ export const Reason = ({ reason }) => { /> ); } + else if (false === reason.correctIndexName) { + title = i18n.translate('xpack.monitoring.logs.reason.correctIndexNameTitle', { + defaultMessage: 'Corrupted filebeat index' + }); + message = ( + + {i18n.translate('xpack.monitoring.logs.reason.correctIndexNameLink', { + defaultMessage: 'Click here for more information' + })} + + ) + }} + /> + ); + } return ( { />); expect(component).toMatchSnapshot(); }); + + it('should render with a bad indices reason', () => { + const component = shallow(); + expect(component).toMatchSnapshot(); + }); }); diff --git a/x-pack/legacy/plugins/monitoring/public/lib/setup_mode.js b/x-pack/legacy/plugins/monitoring/public/lib/setup_mode.js index 7da419719e70c..607edbd1e8709 100644 --- a/x-pack/legacy/plugins/monitoring/public/lib/setup_mode.js +++ b/x-pack/legacy/plugins/monitoring/public/lib/setup_mode.js @@ -7,6 +7,7 @@ import { ajaxErrorHandlersProvider } from './ajax_error_handler'; import { get, contains } from 'lodash'; import chrome from 'ui/chrome'; +import { toastNotifications } from 'ui/notify'; import { i18n } from '@kbn/i18n'; function isOnPage(hash) { @@ -81,7 +82,26 @@ export const updateSetupModeData = async (uuid, fetchWithoutClusterUuid = false) const oldData = setupModeState.data; const data = await fetchCollectionData(uuid, fetchWithoutClusterUuid); setupModeState.data = data; - if (chrome.getInjected('isOnCloud')) { + + const isCloud = chrome.getInjected('isOnCloud'); + const hasPermissions = get(data, '_meta.hasPermissions', false); + if (isCloud || !hasPermissions) { + const text = !hasPermissions + ? i18n.translate('xpack.monitoring.setupMode.notAvailablePermissions', { + defaultMessage: 'You do not have the necessary permissions to do this.' + }) + : i18n.translate('xpack.monitoring.setupMode.notAvailableCloud', { + defaultMessage: 'This feature is not available on cloud.' + }); + + angularState.scope.$evalAsync(() => { + toastNotifications.addDanger({ + title: i18n.translate('xpack.monitoring.setupMode.notAvailableTitle', { + defaultMessage: 'Setup mode is not available' + }), + text, + }); + }); return toggleSetupMode(false); // eslint-disable-line no-use-before-define } notifySetupModeDataChange(oldData); diff --git a/x-pack/legacy/plugins/monitoring/public/lib/setup_mode.test.js b/x-pack/legacy/plugins/monitoring/public/lib/setup_mode.test.js index 4e3a8045048ae..39ed049ab7492 100644 --- a/x-pack/legacy/plugins/monitoring/public/lib/setup_mode.test.js +++ b/x-pack/legacy/plugins/monitoring/public/lib/setup_mode.test.js @@ -40,7 +40,8 @@ const angularStateMock = { } }, scope: { - $apply: fn => fn && fn() + $apply: fn => fn && fn(), + $evalAsync: fn => fn && fn() } }; @@ -123,6 +124,7 @@ describe('setup_mode', () => { }); it('should not fetch data if on cloud', async (done) => { + const addDanger = jest.fn(); jest.doMock('ui/chrome', () => ({ getInjected: (key) => { if (key === 'isOnCloud') { @@ -130,12 +132,52 @@ describe('setup_mode', () => { } } })); + data = { + _meta: { + hasPermissions: true + } + }; + jest.doMock('ui/notify', () => ({ + toastNotifications: { + addDanger, + } + })); + setModules(); + initSetupModeState(angularStateMock.scope, angularStateMock.injector); + await toggleSetupMode(true); + waitForSetupModeData(() => { + const state = getSetupModeState(); + expect(state.enabled).toBe(false); + expect(addDanger).toHaveBeenCalledWith({ + title: 'Setup mode is not available', + text: 'This feature is not available on cloud.' + }); + done(); + }); + }); + + it('should not fetch data if the user does not have sufficient permissions', async (done) => { + const addDanger = jest.fn(); + jest.doMock('ui/notify', () => ({ + toastNotifications: { + addDanger, + } + })); + data = { + _meta: { + hasPermissions: false + } + }; setModules(); initSetupModeState(angularStateMock.scope, angularStateMock.injector); await toggleSetupMode(true); waitForSetupModeData(() => { const state = getSetupModeState(); expect(state.enabled).toBe(false); + expect(addDanger).toHaveBeenCalledWith({ + title: 'Setup mode is not available', + text: 'You do not have the necessary permissions to do this.' + }); done(); }); }); @@ -144,7 +186,8 @@ describe('setup_mode', () => { const clusterUuid = '1ajy'; data = { _meta: { - liveClusterUuid: clusterUuid + liveClusterUuid: clusterUuid, + hasPermissions: true }, elasticsearch: { byUuid: { @@ -166,7 +209,8 @@ describe('setup_mode', () => { const clusterUuid = '1ajy'; data = { _meta: { - liveClusterUuid: clusterUuid + liveClusterUuid: clusterUuid, + hasPermissions: true }, elasticsearch: { byUuid: { diff --git a/x-pack/legacy/plugins/monitoring/server/lib/logs/detect_reason_from_exception.js b/x-pack/legacy/plugins/monitoring/server/lib/logs/detect_reason_from_exception.js new file mode 100644 index 0000000000000..02787191b7e66 --- /dev/null +++ b/x-pack/legacy/plugins/monitoring/server/lib/logs/detect_reason_from_exception.js @@ -0,0 +1,17 @@ +/* + * 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 function detectReasonFromException(exception) { + const reason = { correctIndexName: true }; + + if (exception) { + if (exception.status === 400 && exception.message.indexOf('Fielddata is disabled on text fields by default') > -1) { + reason.correctIndexName = false; + } + } + + return reason; +} diff --git a/x-pack/legacy/plugins/monitoring/server/lib/logs/get_log_types.js b/x-pack/legacy/plugins/monitoring/server/lib/logs/get_log_types.js index 2a16b0b89b5e8..606a50a3612ee 100644 --- a/x-pack/legacy/plugins/monitoring/server/lib/logs/get_log_types.js +++ b/x-pack/legacy/plugins/monitoring/server/lib/logs/get_log_types.js @@ -8,6 +8,7 @@ import { get } from 'lodash'; import { checkParam } from '../error_missing_required'; import { createTimeFilter } from '../create_query'; import { detectReason } from './detect_reason'; +import { detectReasonFromException } from './detect_reason_from_exception'; async function handleResponse(response, req, filebeatIndexPattern, opts) { const result = { @@ -88,6 +89,13 @@ export async function getLogTypes(req, filebeatIndexPattern, { clusterUuid, node }; const { callWithRequest } = req.server.plugins.elasticsearch.getCluster('monitoring'); - const response = await callWithRequest(req, 'search', params); - return await handleResponse(response, req, filebeatIndexPattern, { clusterUuid, nodeUuid, indexUuid, start, end }); + let result = {}; + try { + const response = await callWithRequest(req, 'search', params); + result = await handleResponse(response, req, filebeatIndexPattern, { clusterUuid, nodeUuid, indexUuid, start, end }); + } + catch (err) { + result.reason = detectReasonFromException(err); + } + return result; } diff --git a/x-pack/legacy/plugins/monitoring/server/lib/logs/get_logs.js b/x-pack/legacy/plugins/monitoring/server/lib/logs/get_logs.js index 0d45b8c6a1c4e..e9c36dd7295c9 100644 --- a/x-pack/legacy/plugins/monitoring/server/lib/logs/get_logs.js +++ b/x-pack/legacy/plugins/monitoring/server/lib/logs/get_logs.js @@ -11,6 +11,7 @@ import { createTimeFilter } from '../create_query'; import { detectReason } from './detect_reason'; import { formatUTCTimestampForTimezone } from '../format_timezone'; import { getTimezone } from '../get_timezone'; +import { detectReasonFromException } from './detect_reason_from_exception'; async function handleResponse(response, req, filebeatIndexPattern, opts) { const result = { @@ -87,8 +88,16 @@ export async function getLogs(config, req, filebeatIndexPattern, { clusterUuid, }; const { callWithRequest } = req.server.plugins.elasticsearch.getCluster('monitoring'); - const response = await callWithRequest(req, 'search', params); - const result = await handleResponse(response, req, filebeatIndexPattern, { clusterUuid, nodeUuid, indexUuid, start, end }); + + let result = {}; + try { + const response = await callWithRequest(req, 'search', params); + result = await handleResponse(response, req, filebeatIndexPattern, { clusterUuid, nodeUuid, indexUuid, start, end }); + } + catch (err) { + result.reason = detectReasonFromException(err); + } + return { ...result, limit: params.size, diff --git a/x-pack/legacy/plugins/monitoring/server/lib/setup/collection/get_collection_status.js b/x-pack/legacy/plugins/monitoring/server/lib/setup/collection/get_collection_status.js index cd5781ccf5344..d25d8af4aaa20 100644 --- a/x-pack/legacy/plugins/monitoring/server/lib/setup/collection/get_collection_status.js +++ b/x-pack/legacy/plugins/monitoring/server/lib/setup/collection/get_collection_status.js @@ -145,6 +145,21 @@ const getRecentMonitoringDocuments = async (req, indexPatterns, clusterUuid, nod return await callWithRequest(req, 'search', params); }; +async function doesIndexExist(req, index) { + const params = { + index, + size: 0, + terminate_after: 1, + ignoreUnavailable: true, + filterPath: [ + 'hits.total.value' + ], + }; + const { callWithRequest } = req.server.plugins.elasticsearch.getCluster('monitoring'); + const response = await callWithRequest(req, 'search', params); + return get(response, 'hits.total.value', 0) > 0; +} + async function detectProducts(req, isLiveCluster) { const result = { [KIBANA_SYSTEM_ID]: { @@ -188,10 +203,9 @@ async function detectProducts(req, isLiveCluster) { ]; if (isLiveCluster) { - const { callWithRequest } = req.server.plugins.elasticsearch.getCluster('data'); for (const { id, indices } of detectionSearch) { - const response = await callWithRequest(req, 'cat.indices', { index: indices, format: 'json' }); - if (response.length) { + const exists = await doesIndexExist(req, indices.join(',')); + if (exists) { result[id].mightExist = true; } } @@ -223,6 +237,19 @@ function isBeatFromAPM(bucket) { return get(beatType, 'buckets[0].key') === 'apm-server'; } +async function hasNecessaryPermissions(req) { + const { callWithRequest } = req.server.plugins.elasticsearch.getCluster('data'); + const response = await callWithRequest(req, 'transport.request', { + method: 'POST', + path: '/_security/user/_has_privileges', + body: { + cluster: ['monitor'], + } + }); + // If there is some problem, assume they do not have access + return get(response, 'has_all_requested', false); +} + /** * Determines if we should ignore this bucket from this product. * @@ -316,6 +343,14 @@ async function getLiveElasticsearchCollectionEnabled(req) { export const getCollectionStatus = async (req, indexPatterns, clusterUuid, nodeUuid, skipLiveData) => { const config = req.server.config(); const kibanaUuid = config.get('server.uuid'); + const hasPermissions = await hasNecessaryPermissions(req); + if (!hasPermissions) { + return { + _meta: { + hasPermissions: false + } + }; + } const liveClusterUuid = skipLiveData ? null : await getLiveElasticsearchClusterUuid(req); const isLiveCluster = !clusterUuid || liveClusterUuid === clusterUuid; @@ -547,6 +582,7 @@ export const getCollectionStatus = async (req, indexPatterns, clusterUuid, nodeU status._meta = { secondsAgo: NUMBER_OF_SECONDS_AGO_TO_LOOK, liveClusterUuid, + hasPermissions, }; return status; diff --git a/x-pack/legacy/plugins/siem/public/components/embeddables/__mocks__/mock.ts b/x-pack/legacy/plugins/siem/public/components/embeddables/__mocks__/mock.ts index 1019bfd172846..d7da585966758 100644 --- a/x-pack/legacy/plugins/siem/public/components/embeddables/__mocks__/mock.ts +++ b/x-pack/legacy/plugins/siem/public/components/embeddables/__mocks__/mock.ts @@ -14,6 +14,7 @@ export const mockSourceLayer = { sourceDescriptor: { id: 'uuid.v4()', type: 'ES_SEARCH', + applyGlobalQuery: true, geoField: 'source.geo.location', filterByMapBounds: false, tooltipProperties: [ @@ -56,7 +57,6 @@ export const mockSourceLayer = { maxZoom: 24, alpha: 1, visible: true, - applyGlobalQuery: true, type: 'VECTOR', query: { query: '', language: 'kuery' }, joins: [], @@ -66,6 +66,7 @@ export const mockDestinationLayer = { sourceDescriptor: { id: 'uuid.v4()', type: 'ES_SEARCH', + applyGlobalQuery: true, geoField: 'destination.geo.location', filterByMapBounds: true, tooltipProperties: [ @@ -108,7 +109,6 @@ export const mockDestinationLayer = { maxZoom: 24, alpha: 1, visible: true, - applyGlobalQuery: true, type: 'VECTOR', query: { query: '', language: 'kuery' }, }; @@ -116,6 +116,7 @@ export const mockDestinationLayer = { export const mockLineLayer = { sourceDescriptor: { type: 'ES_PEW_PEW', + applyGlobalQuery: true, id: 'uuid.v4()', indexPatternId: '8c7323ac-97ad-4b53-ac0a-40f8f691a918', sourceGeoField: 'source.geo.location', @@ -164,7 +165,6 @@ export const mockLineLayer = { maxZoom: 24, alpha: 0.5, visible: true, - applyGlobalQuery: true, type: 'VECTOR', query: { query: '', language: 'kuery' }, }; @@ -178,7 +178,6 @@ export const mockLayerList = [ maxZoom: 24, alpha: 1, visible: true, - applyGlobalQuery: true, style: null, type: 'VECTOR_TILE', }, @@ -196,7 +195,6 @@ export const mockLayerListDouble = [ maxZoom: 24, alpha: 1, visible: true, - applyGlobalQuery: true, style: null, type: 'VECTOR_TILE', }, diff --git a/x-pack/legacy/plugins/siem/public/components/embeddables/map_config.ts b/x-pack/legacy/plugins/siem/public/components/embeddables/map_config.ts index e1d3a4aa62938..fd17e6eaeac64 100644 --- a/x-pack/legacy/plugins/siem/public/components/embeddables/map_config.ts +++ b/x-pack/legacy/plugins/siem/public/components/embeddables/map_config.ts @@ -50,7 +50,6 @@ export const getLayerList = (indexPatternIds: IndexPatternMapping[]) => { maxZoom: 24, alpha: 1, visible: true, - applyGlobalQuery: true, style: null, type: 'VECTOR_TILE', }, @@ -76,6 +75,7 @@ export const getSourceLayer = (indexPatternTitle: string, indexPatternId: string sourceDescriptor: { id: uuid.v4(), type: 'ES_SEARCH', + applyGlobalQuery: true, geoField: 'source.geo.location', filterByMapBounds: false, tooltipProperties: Object.keys(sourceFieldMappings), @@ -112,7 +112,6 @@ export const getSourceLayer = (indexPatternTitle: string, indexPatternId: string maxZoom: 24, alpha: 1, visible: true, - applyGlobalQuery: true, type: 'VECTOR', query: { query: '', language: 'kuery' }, joins: [], @@ -129,6 +128,7 @@ export const getDestinationLayer = (indexPatternTitle: string, indexPatternId: s sourceDescriptor: { id: uuid.v4(), type: 'ES_SEARCH', + applyGlobalQuery: true, geoField: 'destination.geo.location', filterByMapBounds: true, tooltipProperties: Object.keys(destinationFieldMappings), @@ -165,7 +165,6 @@ export const getDestinationLayer = (indexPatternTitle: string, indexPatternId: s maxZoom: 24, alpha: 1, visible: true, - applyGlobalQuery: true, type: 'VECTOR', query: { query: '', language: 'kuery' }, }); @@ -180,6 +179,7 @@ export const getDestinationLayer = (indexPatternTitle: string, indexPatternId: s export const getLineLayer = (indexPatternTitle: string, indexPatternId: string) => ({ sourceDescriptor: { type: 'ES_PEW_PEW', + applyGlobalQuery: true, id: uuid.v4(), indexPatternId, sourceGeoField: 'source.geo.location', @@ -228,7 +228,6 @@ export const getLineLayer = (indexPatternTitle: string, indexPatternId: string) maxZoom: 24, alpha: 0.5, visible: true, - applyGlobalQuery: true, type: 'VECTOR', query: { query: '', language: 'kuery' }, }); diff --git a/x-pack/legacy/plugins/siem/public/components/source_destination/source_destination_ip.test.tsx b/x-pack/legacy/plugins/siem/public/components/source_destination/source_destination_ip.test.tsx new file mode 100644 index 0000000000000..c9fff7328165c --- /dev/null +++ b/x-pack/legacy/plugins/siem/public/components/source_destination/source_destination_ip.test.tsx @@ -0,0 +1,1336 @@ +/* + * 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 { mount } from 'enzyme'; +import { get } from 'lodash/fp'; +import * as React from 'react'; + +import { asArrayIfExists } from '../../lib/helpers'; +import { getMockNetflowData } from '../../mock'; +import { TestProviders } from '../../mock/test_providers'; +import { ID_FIELD_NAME } from '../event_details/event_id'; +import { DESTINATION_IP_FIELD_NAME, SOURCE_IP_FIELD_NAME } from '../ip'; +import { DESTINATION_PORT_FIELD_NAME, SOURCE_PORT_FIELD_NAME } from '../port'; +import * as i18n from '../timeline/body/renderers/translations'; + +import { + getPorts, + hasPorts, + isIpFieldPopulated, + SourceDestinationIp, +} from './source_destination_ip'; +import { + DESTINATION_GEO_CITY_NAME_FIELD_NAME, + DESTINATION_GEO_CONTINENT_NAME_FIELD_NAME, + DESTINATION_GEO_COUNTRY_ISO_CODE_FIELD_NAME, + DESTINATION_GEO_COUNTRY_NAME_FIELD_NAME, + DESTINATION_GEO_REGION_NAME_FIELD_NAME, + SOURCE_GEO_CITY_NAME_FIELD_NAME, + SOURCE_GEO_CONTINENT_NAME_FIELD_NAME, + SOURCE_GEO_COUNTRY_ISO_CODE_FIELD_NAME, + SOURCE_GEO_COUNTRY_NAME_FIELD_NAME, + SOURCE_GEO_REGION_NAME_FIELD_NAME, +} from './geo_fields'; + +jest.mock('../../lib/settings/use_kibana_ui_setting'); + +describe('SourceDestinationIp', () => { + describe('#isIpFieldPopulated', () => { + test('it returns true when type is `source` and sourceIp has an IP address', () => { + expect( + isIpFieldPopulated({ + destinationIp: undefined, + sourceIp: ['10.1.1.1'], + type: 'source', + }) + ).toBe(true); + }); + + test('it returns true when type is `source` and sourceIp contains a mix of empty and non-empty IPs', () => { + expect( + isIpFieldPopulated({ + destinationIp: undefined, + sourceIp: ['', '10.1.1.1'], + type: 'source', + }) + ).toBe(true); + }); + + test('it returns false when type is `source` and sourceIp is undefined', () => { + expect( + isIpFieldPopulated({ + destinationIp: [], + sourceIp: undefined, + type: 'source', + }) + ).toBe(false); + }); + + test('it returns false when type is `source` and sourceIp is empty', () => { + expect( + isIpFieldPopulated({ + destinationIp: [], + sourceIp: [], + type: 'source', + }) + ).toBe(false); + }); + + test('it returns false when type is `source` and sourceIp only contains an array of empty strings', () => { + expect( + isIpFieldPopulated({ + destinationIp: [], + sourceIp: ['', ''], + type: 'source', + }) + ).toBe(false); + }); + + test('it returns true when type is `destination` and destinationIp has an IP address', () => { + expect( + isIpFieldPopulated({ + destinationIp: ['10.1.1.1'], + sourceIp: undefined, + type: 'destination', + }) + ).toBe(true); + }); + + test('it returns true when type is `destination` and destinationIp contains a mix of empty and non-empty IPs', () => { + expect( + isIpFieldPopulated({ + destinationIp: ['', '10.1.1.1'], + sourceIp: undefined, + type: 'destination', + }) + ).toBe(true); + }); + + test('it returns false when type is `destination` and destinationIp is undefined', () => { + expect( + isIpFieldPopulated({ + destinationIp: undefined, + sourceIp: undefined, + type: 'destination', + }) + ).toBe(false); + }); + + test('it returns false when type is `destination` and destinationIp is empty', () => { + expect( + isIpFieldPopulated({ + destinationIp: [], + sourceIp: undefined, + type: 'destination', + }) + ).toBe(false); + }); + + test('it returns false when type is `destination` and destinationIp only contains an array of empty strings', () => { + expect( + isIpFieldPopulated({ + destinationIp: ['', ''], + sourceIp: undefined, + type: 'destination', + }) + ).toBe(false); + }); + }); + + describe('#getPorts', () => { + test('it returns an array of ports when type is `source` and sourcePort contains numeric ports', () => { + expect( + getPorts({ + destinationPort: undefined, + sourcePort: [80, 443], + type: 'source', + }) + ).toEqual(['80', '443']); + }); + + test('it returns an array of ports when type is `source` and sourcePort contains string ports', () => { + expect( + getPorts({ + destinationPort: undefined, + sourcePort: ['80', '443'], + type: 'source', + }) + ).toEqual(['80', '443']); + }); + + test('it returns an empty array when type is `source` and sourcePort is undefined', () => { + expect( + getPorts({ + destinationPort: undefined, + sourcePort: undefined, + type: 'source', + }) + ).toEqual([]); + }); + + test('it returns an empty array when type is `source` and sourcePort is empty', () => { + expect( + getPorts({ + destinationPort: undefined, + sourcePort: [], + type: 'source', + }) + ).toEqual([]); + }); + + test('it returns an empty array when type is `source` and sourcePort only contains an array of empty strings', () => { + expect( + getPorts({ + destinationPort: undefined, + sourcePort: ['', ''], + type: 'source', + }) + ).toEqual([]); + }); + + test('it returns an empty array when type is `source` and sourcePort only contains a null value', () => { + expect( + getPorts({ + destinationPort: [], + sourcePort: [null], // test case was added based on real-world data + type: 'source', + }) + ).toEqual([]); + }); + + test('it returns an array of ports when type is `destination` and destinationPort contains numeric ports', () => { + expect( + getPorts({ + destinationPort: [80, 443], + sourcePort: undefined, + type: 'destination', + }) + ).toEqual(['80', '443']); + }); + + test('it returns an array of ports when type is `destination` and destinationPort contains string ports', () => { + expect( + getPorts({ + destinationPort: ['80', '443'], + sourcePort: undefined, + type: 'destination', + }) + ).toEqual(['80', '443']); + }); + + test('it returns an empty array when type is `destination` and destinationPort is undefined', () => { + expect( + getPorts({ + destinationPort: undefined, + sourcePort: undefined, + type: 'destination', + }) + ).toEqual([]); + }); + + test('it returns an empty array when type is `destination` and destinationPort is empty', () => { + expect( + getPorts({ + destinationPort: [], + sourcePort: undefined, + type: 'destination', + }) + ).toEqual([]); + }); + + test('it returns an empty array when type is `destination` and destinationPort only contains an array of empty strings', () => { + expect( + getPorts({ + destinationPort: ['', ''], + sourcePort: undefined, + type: 'destination', + }) + ).toEqual([]); + }); + + test('it returns an empty array when type is `destination` and destinationPort only contains a null value', () => { + expect( + getPorts({ + destinationPort: [null], // test case was added based on real-world data + sourcePort: [], + type: 'destination', + }) + ).toEqual([]); + }); + }); + + describe('#hasPorts', () => { + test('it returns true when type is `source` and numeric source ports are provided', () => { + expect( + hasPorts({ + destinationPort: undefined, + sourcePort: [80, 443], + type: 'source', + }) + ).toEqual(true); + }); + + test('it returns true when when type is `source` and string source ports are provided', () => { + expect( + hasPorts({ + destinationPort: undefined, + sourcePort: ['80', '443'], + type: 'source', + }) + ).toEqual(true); + }); + + test('it returns false when when type is `source` and invalid source ports are provided', () => { + expect( + hasPorts({ + destinationPort: undefined, + sourcePort: [null], // test case was added based on real-world data + type: 'source', + }) + ).toEqual(false); + }); + + test('it returns true when type is `destination` and numeric destination ports are provided', () => { + expect( + hasPorts({ + destinationPort: [80, 443], + sourcePort: undefined, + type: 'destination', + }) + ).toEqual(true); + }); + + test('it returns true when when type is `destination` and string destination ports are provided', () => { + expect( + hasPorts({ + destinationPort: ['80', '443'], + sourcePort: undefined, + type: 'destination', + }) + ).toEqual(true); + }); + + test('it returns false when when type is `destination` and null destination ports are provided', () => { + expect( + hasPorts({ + destinationPort: [null], // test case was added based on real-world data + sourcePort: undefined, + type: 'destination', + }) + ).toEqual(false); + }); + }); + + test('it renders a `Source` label when type is `source` and (just) the sourceIp field is populated', () => { + const type = 'source'; + const wrapper = mount( + + + + ); + + expect( + wrapper + .find('[data-test-subj="source-label"]') + .first() + .text() + ).toEqual(i18n.SOURCE); + }); + + test('it renders a `Destination` label when type is `destination` and (just) the destinationIp field is populated', () => { + const type = 'destination'; + const wrapper = mount( + + + + ); + + expect( + wrapper + .find('[data-test-subj="destination-label"]') + .first() + .text() + ).toEqual(i18n.DESTINATION); + }); + + test('it renders a `Source` label when type is `source` (just) the sourcePort field is populated', () => { + const type = 'source'; + const wrapper = mount( + + + + ); + + expect( + wrapper + .find('[data-test-subj="source-label"]') + .first() + .text() + ).toEqual(i18n.SOURCE); + }); + + test('it renders a `Destination` label when type is `destination` and (just) the destinationPort field is populated', () => { + const type = 'destination'; + const wrapper = mount( + + + + ); + + expect( + wrapper + .find('[data-test-subj="destination-label"]') + .first() + .text() + ).toEqual(i18n.DESTINATION); + }); + + test('it renders a `Source` label when type is `source` and both sourceIp and sourcePort are populated', () => { + const type = 'source'; + + const wrapper = mount( + + + + ); + + expect( + wrapper + .find('[data-test-subj="source-label"]') + .first() + .text() + ).toEqual(i18n.SOURCE); + }); + + test('it renders a `Destination` label when type is `destination` and both destinationIp and destinationPort are populated', () => { + const type = 'destination'; + const wrapper = mount( + + + + ); + + expect( + wrapper + .find('[data-test-subj="destination-label"]') + .first() + .text() + ).toEqual(i18n.DESTINATION); + }); + + test('it does NOT render a `Source` label when type is `source` and both sourceIp and sourcePort are empty', () => { + const type = 'source'; + const wrapper = mount( + + + + ); + + expect(wrapper.exists('[data-test-subj="source-label"]')).toBe(false); + }); + + test('it does NOT render a `Destination` label when type is `destination` and both destinationIp and destinationPort are empty', () => { + const type = 'destination'; + const wrapper = mount( + + + + ); + + expect(wrapper.exists('[data-test-subj="destination-label"]')).toBe(false); + }); + + test('it renders the expected source IP when type is `source`, and both sourceIp and sourcePort are populated', () => { + const type = 'source'; + const wrapper = mount( + + + + ); + + expect( + wrapper + .find('[data-test-subj="draggable-content-source.ip"]') + .first() + .text() + ).toEqual('192.168.1.2'); + }); + + test('it renders the expected source IP when type is `source`, but the length of the sourceIp and sourcePort arrays is different', () => { + const type = 'source'; + const wrapper = mount( + + + + ); + + expect( + wrapper + .find('[data-test-subj="draggable-content-source.ip"]') + .first() + .text() + ).toEqual('192.168.1.2'); + }); + + test('it renders the expected destination IP when type is `destination`, and both destinationIp and destinationPort are populated', () => { + const type = 'destination'; + const wrapper = mount( + + + + ); + + expect( + wrapper + .find('[data-test-subj="draggable-content-destination.ip"]') + .first() + .text() + ).toEqual('10.1.2.3'); + }); + + test('it renders the expected destination IP when type is `destination`, but the length of the destinationIp and destinationPort port arrays is different', () => { + const type = 'destination'; + const wrapper = mount( + + + + ); + + expect( + wrapper + .find('[data-test-subj="draggable-content-destination.ip"]') + .first() + .text() + ).toEqual('10.1.2.3'); + }); + + test('it renders the expected source port when type is `source`, and both sourceIp and sourcePort are populated', () => { + const type = 'source'; + const wrapper = mount( + + + + ); + + expect( + wrapper + .find('[data-test-subj="draggable-content-source.port"]') + .first() + .text() + ).toEqual('9987'); + }); + + test('it renders the expected destination port when type is `destination`, and both destinationIp and destinationPort are populated', () => { + const type = 'destination'; + const wrapper = mount( + + + + ); + + expect( + wrapper + .find('[data-test-subj="draggable-content-destination.port"]') + .first() + .text() + ).toEqual('80'); + }); + + test('it renders the expected source port when type is `source`, but only sourcePort is populated', () => { + const type = 'source'; + const wrapper = mount( + + + + ); + + expect( + wrapper + .find('[data-test-subj="draggable-content-source.port"]') + .first() + .text() + ).toEqual('9987'); + }); + + test('it renders the expected destination port when type is `destination`, and only destinationPort is populated', () => { + const type = 'destination'; + + const wrapper = mount( + + + + ); + + expect( + wrapper + .find('[data-test-subj="draggable-content-destination.port"]') + .first() + .text() + ).toEqual('80'); + }); + + test('it does NOT render the badge when type is `source`, but both sourceIp and sourcePort are undefined', () => { + const type = 'source'; + + const wrapper = mount( + + + + ); + + expect(wrapper.exists(`[data-test-subj="${type}-ip-badge"]`)).toBe(false); + }); + + test('it does NOT render the badge when type is `destination`, but both destinationIp and destinationPort are undefined', () => { + const type = 'destination'; + + const wrapper = mount( + + + + ); + + expect(wrapper.exists(`[data-test-subj="${type}-ip-badge"]`)).toBe(false); + }); + + test('it renders geo fields', () => { + const type = 'source'; + const wrapper = mount( + + + + ); + + expect( + wrapper + .find('[data-test-subj="draggable-content-source.geo.continent_name"]') + .first() + .text() + ).toEqual('North America'); + }); +}); diff --git a/x-pack/legacy/plugins/siem/public/components/source_destination/source_destination_ip.tsx b/x-pack/legacy/plugins/siem/public/components/source_destination/source_destination_ip.tsx index 6264219c57bae..ebc5beaa4e354 100644 --- a/x-pack/legacy/plugins/siem/public/components/source_destination/source_destination_ip.tsx +++ b/x-pack/legacy/plugins/siem/public/components/source_destination/source_destination_ip.tsx @@ -5,12 +5,11 @@ */ import { EuiBadge, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; -import { isEqual, uniqWith } from 'lodash/fp'; +import { isEmpty, isEqual, uniqWith } from 'lodash/fp'; import * as React from 'react'; -import { pure } from 'recompose'; import { DESTINATION_IP_FIELD_NAME, SOURCE_IP_FIELD_NAME } from '../ip'; -import { DESTINATION_PORT_FIELD_NAME, SOURCE_PORT_FIELD_NAME } from '../port'; +import { DESTINATION_PORT_FIELD_NAME, SOURCE_PORT_FIELD_NAME, Port } from '../port'; import * as i18n from '../timeline/body/renderers/translations'; import { GeoFields } from './geo_fields'; @@ -26,7 +25,8 @@ export interface IpPortPair { /** * Returns `true` if the ip field (i.e. `sourceIp`, `destinationIp`) that * corresponds with the specified `type` (i.e. `source`, `destination`) is - * populated + * populated. This function will return `false` when the array only contains + * empty values. */ export const isIpFieldPopulated = ({ destinationIp, @@ -37,15 +37,57 @@ export const isIpFieldPopulated = ({ sourceIp?: string[] | null; type: SourceDestinationType; }): boolean => - (type === 'source' && sourceIp != null) || (type === 'destination' && destinationIp != null); + (type === 'source' && sourceIp != null && sourceIp.some(ip => !isEmpty(ip))) || + (type === 'destination' && destinationIp != null && destinationIp.some(ip => !isEmpty(ip))); -const IpAdressesWithPorts = pure<{ +/** + * Returns an array of ports, filtered such that `null` entries are removed. If + * the provided `destinationPort` and `sourcePort` do not contain valid ports, + * an empty array will be returned. + */ +export const getPorts = ({ + destinationPort, + sourcePort, + type, +}: { + destinationPort?: Array | null; + sourcePort?: Array | null; + type: SourceDestinationType; +}): string[] => { + const ports = + type === 'source' && sourcePort != null + ? sourcePort + : type === 'destination' && destinationPort != null + ? destinationPort + : []; + + return ports + .filter(p => p != null) + .map(p => `${p}`) + .filter(p => !isEmpty(p)); +}; + +/** + * Returns `true` if the array of ports, filtered to remove invalid entries, + * has at least one port. + */ +export const hasPorts = ({ + destinationPort, + sourcePort, + type, +}: { + destinationPort?: Array | null; + sourcePort?: Array | null; + type: SourceDestinationType; +}): boolean => getPorts({ destinationPort, sourcePort, type }).length > 0; + +const IpAdressesWithPorts = React.memo<{ contextId: string; destinationIp?: string[] | null; - destinationPort?: string[] | null; + destinationPort?: Array | null; eventId: string; sourceIp?: string[] | null; - sourcePort?: string[] | null; + sourcePort?: Array | null; type: SourceDestinationType; }>(({ contextId, destinationIp, destinationPort, eventId, sourceIp, sourcePort, type }) => { const ip = type === 'source' ? sourceIp : destinationIp; @@ -64,14 +106,14 @@ const IpAdressesWithPorts = pure<{ port != null && ip.length === port.length ? ip.map((address, i) => ({ ip: address, - port: port[i], // use the corresponding port in the parallel array + port: port[i] != null ? `${port[i]}` : null, // use the corresponding port in the parallel array })) : ip.map(address => ({ ip: address, - port: null, // drop the port, because the length of the ip and port arrays is different + port: null, // drop the port, because the length of the parallel ip and port arrays is different })); - return ip != null ? ( + return ( {uniqWith(isEqual, ipPortPairs).map( ipPortPair => @@ -90,7 +132,7 @@ const IpAdressesWithPorts = pure<{ ) )} - ) : null; + ); }); IpAdressesWithPorts.displayName = 'IpAdressesWithPorts'; @@ -104,7 +146,7 @@ IpAdressesWithPorts.displayName = 'IpAdressesWithPorts'; * - a port, hyperlinked to a port lookup service, when it's populated * - a summary of geolocation details, when they are populated */ -export const SourceDestinationIp = pure( +export const SourceDestinationIp = React.memo( ({ contextId, destinationGeoContinentName, @@ -125,7 +167,9 @@ export const SourceDestinationIp = pure( type, }) => { const label = type === 'source' ? i18n.SOURCE : i18n.DESTINATION; - return isIpFieldPopulated({ destinationIp, sourceIp, type }) ? ( + + return isIpFieldPopulated({ destinationIp, sourceIp, type }) || + hasPorts({ destinationPort, sourcePort, type }) ? ( ( - + {isIpFieldPopulated({ destinationIp, sourceIp, type }) ? ( + + ) : ( + + {getPorts({ destinationPort, sourcePort, type }).map((port, i) => ( + + + + ))} + + )} | null; eventId: string; sourceGeoContinentName?: string[] | null; sourceGeoCountryName?: string[] | null; @@ -68,7 +68,7 @@ export interface SourceDestinationIpProps { sourceGeoRegionName?: string[] | null; sourceGeoCityName?: string[] | null; sourceIp?: string[] | null; - sourcePort?: string[] | null; + sourcePort?: Array | null; type: SourceDestinationType; } diff --git a/x-pack/legacy/plugins/siem/public/lib/settings/use_kibana_ui_setting.ts b/x-pack/legacy/plugins/siem/public/lib/settings/use_kibana_ui_setting.ts index ab798949a4d61..0a89edb85e6ea 100644 --- a/x-pack/legacy/plugins/siem/public/lib/settings/use_kibana_ui_setting.ts +++ b/x-pack/legacy/plugins/siem/public/lib/settings/use_kibana_ui_setting.ts @@ -34,22 +34,22 @@ export const useKibanaUiSetting = (key: string, defaultValue?: GenericValue) => const core = useKibanaCore(); const uiSettingsClient = core.uiSettings; const uiInjectedMetadata = core.injectedMetadata; - const uiSetting$ = useMemo(() => uiSettingsClient.get$(key, defaultValue), [uiSettingsClient]); - const uiSetting = useObservable(uiSetting$); - const setUiSetting = useCallback((value: GenericValue) => uiSettingsClient.set(key, value), [ - uiSettingsClient, - ]); - const defaultTimezoneProvider = useMemo(() => timezoneProvider(uiSettingsClient)(), [ - uiSettingsClient, - ]); if (key === DEFAULT_KBN_VERSION) { return [uiInjectedMetadata.getKibanaVersion()]; } + /* eslint-disable react-hooks/rules-of-hooks */ if (key === DEFAULT_TIMEZONE_BROWSER) { - return [defaultTimezoneProvider]; + return [useMemo(() => timezoneProvider(uiSettingsClient)(), [uiSettingsClient])]; } + const uiSetting$ = useMemo(() => uiSettingsClient.get$(key, defaultValue), [uiSettingsClient]); + const uiSetting = useObservable(uiSetting$); + const setUiSetting = useCallback((value: GenericValue) => uiSettingsClient.set(key, value), [ + uiSettingsClient, + ]); + /* eslint-enable react-hooks/rules-of-hooks */ + return [uiSetting, setUiSetting]; }; diff --git a/x-pack/plugins/spaces/kibana.json b/x-pack/plugins/spaces/kibana.json index ae121e299cc55..313e4415a8e7c 100644 --- a/x-pack/plugins/spaces/kibana.json +++ b/x-pack/plugins/spaces/kibana.json @@ -4,7 +4,7 @@ "kibanaVersion": "kibana", "configPath": ["xpack", "spaces"], "requiredPlugins": ["features", "licensing"], - "optionalPlugins": ["security"], + "optionalPlugins": ["security", "home"], "server": true, "ui": false } diff --git a/x-pack/plugins/spaces/server/plugin.ts b/x-pack/plugins/spaces/server/plugin.ts index aabdc5bcb97e8..21120ab37b06a 100644 --- a/x-pack/plugins/spaces/server/plugin.ts +++ b/x-pack/plugins/spaces/server/plugin.ts @@ -31,7 +31,7 @@ import { ConfigType } from './config'; import { toggleUICapabilities } from './lib/toggle_ui_capabilities'; import { initSpacesRequestInterceptors } from './lib/request_interceptors'; import { initExternalSpacesApi } from './routes/api/external'; - +import { HomePluginSetup } from '../../../../src/plugins/home/server'; /** * Describes a set of APIs that is available in the legacy platform only and required by this plugin * to function properly. @@ -62,6 +62,7 @@ export interface PluginsSetup { features: FeaturesPluginSetup; licensing: LicensingPluginSetup; security?: SecurityPluginSetup; + home?: HomePluginSetup; } export interface SpacesPluginSetup { @@ -138,6 +139,12 @@ export class Plugin { plugins.security.registerSpacesService(spacesService); } + if (plugins.home) { + plugins.home.tutorials.addScopedTutorialContextFactory( + createSpacesTutorialContextFactory(spacesService) + ); + } + return { spacesService, __legacyCompat: { diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 2154adf87e29b..11777cfd5175f 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -6445,7 +6445,6 @@ "xpack.maps.layerControl.tocEntry.hideDetailsButtonTitle": "レイヤー詳細を非表示", "xpack.maps.layerControl.tocEntry.showDetailsButtonAriaLabel": "レイヤー詳細を表示", "xpack.maps.layerControl.tocEntry.showDetailsButtonTitle": "レイヤー詳細を表示", - "xpack.maps.layerPanel.applyGlobalQueryCheckbox.disableTooltip": "レイヤーはフィルタリングをサポートしていません。", "xpack.maps.layerPanel.applyGlobalQueryCheckboxLabel": "レイヤーにグローバルフィルターを適用", "xpack.maps.layerPanel.filterEditor.addFilterButtonLabel": "フィルターを追加します", "xpack.maps.layerPanel.filterEditor.editFilterButtonLabel": "フィルターを編集", @@ -6701,7 +6700,6 @@ "xpack.maps.tooltip.toolsControl.cancelDrawButtonLabel": "キャンセル", "xpack.maps.xyztmssource.attributionLink": "属性テキストにはリンクが必要です", "xpack.maps.xyztmssource.attributionText": "属性 URL にはテキストが必要です", - "xpack.maps.layerPanel.settingsPanel.layerGlobalFilterLabel": "グローバルフィルター", "xpack.maps.layerPanel.settingsPanel.percentageLabel": "%", "xpack.maps.layerPanel.settingsPanel.visibleZoom": "ズームレベル", "xpack.maps.source.esSearch.sortFieldSelectPlaceholder": "ソートフィールドを選択", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index c758239423883..a29dc7ad599ab 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -6447,7 +6447,6 @@ "xpack.maps.layerControl.tocEntry.hideDetailsButtonTitle": "隐藏图层详情", "xpack.maps.layerControl.tocEntry.showDetailsButtonAriaLabel": "显示图层详情", "xpack.maps.layerControl.tocEntry.showDetailsButtonTitle": "显示图层详情", - "xpack.maps.layerPanel.applyGlobalQueryCheckbox.disableTooltip": "图层不支持筛选", "xpack.maps.layerPanel.applyGlobalQueryCheckboxLabel": "将全局筛选应用到图层", "xpack.maps.layerPanel.filterEditor.addFilterButtonLabel": "添加筛选", "xpack.maps.layerPanel.filterEditor.editFilterButtonLabel": "编辑筛选", @@ -6703,7 +6702,6 @@ "xpack.maps.tooltip.toolsControl.cancelDrawButtonLabel": "取消", "xpack.maps.xyztmssource.attributionLink": "属性文本必须附带链接", "xpack.maps.xyztmssource.attributionText": "属性 url 必须附带文本", - "xpack.maps.layerPanel.settingsPanel.layerGlobalFilterLabel": "全局筛选", "xpack.maps.layerPanel.settingsPanel.percentageLabel": "%", "xpack.maps.layerPanel.settingsPanel.visibleZoom": "缩放级别", "xpack.maps.source.esSearch.sortFieldSelectPlaceholder": "选择排序字段", diff --git a/x-pack/scripts/functional_tests.js b/x-pack/scripts/functional_tests.js index 7b2c2c2b7840f..2ac8fff6ef8ab 100644 --- a/x-pack/scripts/functional_tests.js +++ b/x-pack/scripts/functional_tests.js @@ -13,11 +13,7 @@ require('@kbn/test').runTestsCli([ require.resolve('../test/api_integration/config_security_basic.js'), require.resolve('../test/api_integration/config.js'), require.resolve('../test/alerting_api_integration/spaces_only/config.ts'), - // FLAKY: https://github.com/elastic/kibana/issues/50079 - // FLAKY: https://github.com/elastic/kibana/issues/50074 - // FLAKY: https://github.com/elastic/kibana/issues/48709 - // FLAKY: https://github.com/elastic/kibana/issues/50078 - // require.resolve('../test/alerting_api_integration/security_and_spaces/config.ts'), + require.resolve('../test/alerting_api_integration/security_and_spaces/config.ts'), require.resolve('../test/plugin_api_integration/config.js'), require.resolve('../test/kerberos_api_integration/config'), require.resolve('../test/kerberos_api_integration/anonymous_access.config'), diff --git a/x-pack/test/alerting_api_integration/common/lib/get_test_alert_data.ts b/x-pack/test/alerting_api_integration/common/lib/get_test_alert_data.ts index ed6775a0fb984..44f796e9a0ac7 100644 --- a/x-pack/test/alerting_api_integration/common/lib/get_test_alert_data.ts +++ b/x-pack/test/alerting_api_integration/common/lib/get_test_alert_data.ts @@ -9,7 +9,7 @@ export function getTestAlertData(overwrites = {}) { enabled: true, name: 'abc', alertTypeId: 'test.noop', - interval: '10s', + interval: '1m', throttle: '1m', actions: [], alertTypeParams: {}, diff --git a/x-pack/test/alerting_api_integration/common/lib/index.ts b/x-pack/test/alerting_api_integration/common/lib/index.ts index 444b767456bde..31d257e3b25ac 100644 --- a/x-pack/test/alerting_api_integration/common/lib/index.ts +++ b/x-pack/test/alerting_api_integration/common/lib/index.ts @@ -9,3 +9,4 @@ export { getUrlPrefix } from './space_test_utils'; export { ES_TEST_INDEX_NAME, ESTestIndexTool } from './es_test_index_tool'; export { getTestAlertData } from './get_test_alert_data'; export { AlertUtils } from './alert_utils'; +export { TaskManagerUtils } from './task_manager_utils'; diff --git a/x-pack/test/alerting_api_integration/common/lib/task_manager_utils.ts b/x-pack/test/alerting_api_integration/common/lib/task_manager_utils.ts new file mode 100644 index 0000000000000..b72960b162e76 --- /dev/null +++ b/x-pack/test/alerting_api_integration/common/lib/task_manager_utils.ts @@ -0,0 +1,46 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export class TaskManagerUtils { + private readonly es: any; + private readonly retry: any; + + constructor(es: any, retry: any) { + this.es = es; + this.retry = retry; + } + + async waitForIdle(taskRunAtFilter: Date) { + return await this.retry.try(async () => { + const searchResult = await this.es.search({ + index: '.kibana_task_manager', + body: { + query: { + bool: { + must: [ + { + terms: { + 'task.scope': ['actions', 'alerting'], + }, + }, + { + range: { + 'task.scheduledAt': { + gte: taskRunAtFilter, + }, + }, + }, + ], + }, + }, + }, + }); + if (searchResult.hits.total.value) { + throw new Error(`Expected 0 tasks but received ${searchResult.hits.total.value}`); + } + }); + } +} diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/alerts.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/alerts.ts index 1252dd1400807..0a300c4ce65da 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/alerts.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/alerts.ts @@ -14,6 +14,7 @@ import { getTestAlertData, ObjectRemover, AlertUtils, + TaskManagerUtils, } from '../../../common/lib'; // eslint-disable-next-line import/no-default-export @@ -23,6 +24,7 @@ export default function alertTests({ getService }: FtrProviderContext) { const retry = getService('retry'); const supertestWithoutAuth = getService('supertestWithoutAuth'); const esTestIndexTool = new ESTestIndexTool(es, retry); + const taskManagerUtils = new TaskManagerUtils(es, retry); describe('alerts', () => { const authorizationIndex = '.kibana-test-authorization'; @@ -73,6 +75,7 @@ export default function alertTests({ getService }: FtrProviderContext) { after(() => objectRemover.add(space.id, indexRecordActionId, 'action')); it('should schedule task, run alert and schedule actions when appropriate', async () => { + const testStart = new Date(); const reference = alertUtils.generateReference(); const response = await alertUtils.createAlwaysFiringAction({ reference }); @@ -90,10 +93,19 @@ export default function alertTests({ getService }: FtrProviderContext) { case 'superuser at space1': case 'space_1_all at space1': expect(response.statusCode).to.eql(200); - const alertTestRecord = ( - await esTestIndexTool.waitForDocs('alert:test.always-firing', reference) - )[0]; - expect(alertTestRecord._source).to.eql({ + + // Wait for the action to index a document before disabling the alert and waiting for tasks to finish + await esTestIndexTool.waitForDocs('action:test.index-record', reference); + await alertUtils.disable(response.body.id); + await taskManagerUtils.waitForIdle(testStart); + + // Ensure only 1 alert executed with proper params + const alertSearchResult = await esTestIndexTool.search( + 'alert:test.always-firing', + reference + ); + expect(alertSearchResult.hits.total.value).to.eql(1); + expect(alertSearchResult.hits.hits[0]._source).to.eql({ source: 'alert:test.always-firing', reference, state: {}, @@ -102,10 +114,14 @@ export default function alertTests({ getService }: FtrProviderContext) { reference, }, }); - const actionTestRecord = ( - await esTestIndexTool.waitForDocs('action:test.index-record', reference) - )[0]; - expect(actionTestRecord._source).to.eql({ + + // Ensure only 1 action executed with proper params + const actionSearchResult = await esTestIndexTool.search( + 'action:test.index-record', + reference + ); + expect(actionSearchResult.hits.total.value).to.eql(1); + expect(actionSearchResult.hits.hits[0]._source).to.eql({ config: { unencrypted: `This value shouldn't get encrypted`, }, @@ -127,7 +143,6 @@ export default function alertTests({ getService }: FtrProviderContext) { }); it('should handle custom retry logic when appropriate', async () => { - // We'll use this start time to query tasks created after this point const testStart = new Date(); // We have to provide the test.rate-limit the next runAt, for testing purposes const retryDate = new Date(Date.now() + 60000); @@ -150,7 +165,6 @@ export default function alertTests({ getService }: FtrProviderContext) { .auth(user.username, user.password) .send( getTestAlertData({ - interval: '1m', alertTypeId: 'test.always-firing', alertTypeParams: { index: ES_TEST_INDEX_NAME, @@ -185,6 +199,8 @@ export default function alertTests({ getService }: FtrProviderContext) { case 'space_1_all at space1': expect(response.statusCode).to.eql(200); objectRemover.add(space.id, response.body.id, 'alert'); + + // Wait for the task to be attempted once and idle const scheduledActionTask = await retry.try(async () => { const searchResult = await es.search({ index: '.kibana_task_manager', @@ -222,6 +238,8 @@ export default function alertTests({ getService }: FtrProviderContext) { expect(searchResult.hits.total.value).to.eql(1); return searchResult.hits.hits[0]; }); + + // Ensure the next runAt is set to the retryDate by custom logic expect(scheduledActionTask._source.task.runAt).to.eql(retryDate.toISOString()); break; default: @@ -230,7 +248,8 @@ export default function alertTests({ getService }: FtrProviderContext) { }); it('should have proper callCluster and savedObjectsClient authorization for alert type executor when appropriate', async () => { - let alertTestRecord: any; + let searchResult: any; + const testStart = new Date(); const reference = alertUtils.generateReference(); const response = await supertestWithoutAuth .post(`${getUrlPrefix(space.id)}/api/alert`) @@ -263,20 +282,26 @@ export default function alertTests({ getService }: FtrProviderContext) { case 'space_1_all at space1': expect(response.statusCode).to.eql(200); objectRemover.add(space.id, response.body.id, 'alert'); - alertTestRecord = ( - await esTestIndexTool.waitForDocs('alert:test.authorization', reference) - )[0]; - expect(alertTestRecord._source.state).to.eql({ + + // Wait for test.authorization to index a document before disabling the alert and waiting for tasks to finish + await esTestIndexTool.waitForDocs('alert:test.authorization', reference); + await alertUtils.disable(response.body.id); + await taskManagerUtils.waitForIdle(testStart); + + // Ensure only 1 document exists with proper params + searchResult = await esTestIndexTool.search('alert:test.authorization', reference); + expect(searchResult.hits.total.value).to.eql(1); + expect(searchResult.hits.hits[0]._source.state).to.eql({ callClusterSuccess: false, savedObjectsClientSuccess: false, callClusterError: { - ...alertTestRecord._source.state.callClusterError, + ...searchResult.hits.hits[0]._source.state.callClusterError, statusCode: 403, }, savedObjectsClientError: { - ...alertTestRecord._source.state.savedObjectsClientError, + ...searchResult.hits.hits[0]._source.state.savedObjectsClientError, output: { - ...alertTestRecord._source.state.savedObjectsClientError.output, + ...searchResult.hits.hits[0]._source.state.savedObjectsClientError.output, statusCode: 403, }, }, @@ -285,16 +310,22 @@ export default function alertTests({ getService }: FtrProviderContext) { case 'superuser at space1': expect(response.statusCode).to.eql(200); objectRemover.add(space.id, response.body.id, 'alert'); - alertTestRecord = ( - await esTestIndexTool.waitForDocs('alert:test.authorization', reference) - )[0]; - expect(alertTestRecord._source.state).to.eql({ + + // Wait for test.authorization to index a document before disabling the alert and waiting for tasks to finish + await esTestIndexTool.waitForDocs('alert:test.authorization', reference); + await alertUtils.disable(response.body.id); + await taskManagerUtils.waitForIdle(testStart); + + // Ensure only 1 document exists with proper params + searchResult = await esTestIndexTool.search('alert:test.authorization', reference); + expect(searchResult.hits.total.value).to.eql(1); + expect(searchResult.hits.hits[0]._source.state).to.eql({ callClusterSuccess: true, savedObjectsClientSuccess: false, savedObjectsClientError: { - ...alertTestRecord._source.state.savedObjectsClientError, + ...searchResult.hits.hits[0]._source.state.savedObjectsClientError, output: { - ...alertTestRecord._source.state.savedObjectsClientError.output, + ...searchResult.hits.hits[0]._source.state.savedObjectsClientError.output, statusCode: 404, }, }, @@ -306,7 +337,8 @@ export default function alertTests({ getService }: FtrProviderContext) { }); it('should have proper callCluster and savedObjectsClient authorization for action type executor when appropriate', async () => { - let actionTestRecord: any; + let searchResult: any; + const testStart = new Date(); const reference = alertUtils.generateReference(); const { body: createdAction } = await supertest .post(`${getUrlPrefix(space.id)}/api/action`) @@ -358,20 +390,26 @@ export default function alertTests({ getService }: FtrProviderContext) { case 'space_1_all at space1': expect(response.statusCode).to.eql(200); objectRemover.add(space.id, response.body.id, 'alert'); - actionTestRecord = ( - await esTestIndexTool.waitForDocs('action:test.authorization', reference) - )[0]; - expect(actionTestRecord._source.state).to.eql({ + + // Ensure test.authorization indexed 1 document before disabling the alert and waiting for tasks to finish + await esTestIndexTool.waitForDocs('action:test.authorization', reference); + await alertUtils.disable(response.body.id); + await taskManagerUtils.waitForIdle(testStart); + + // Ensure only 1 document with proper params exists + searchResult = await esTestIndexTool.search('action:test.authorization', reference); + expect(searchResult.hits.total.value).to.eql(1); + expect(searchResult.hits.hits[0]._source.state).to.eql({ callClusterSuccess: false, savedObjectsClientSuccess: false, callClusterError: { - ...actionTestRecord._source.state.callClusterError, + ...searchResult.hits.hits[0]._source.state.callClusterError, statusCode: 403, }, savedObjectsClientError: { - ...actionTestRecord._source.state.savedObjectsClientError, + ...searchResult.hits.hits[0]._source.state.savedObjectsClientError, output: { - ...actionTestRecord._source.state.savedObjectsClientError.output, + ...searchResult.hits.hits[0]._source.state.savedObjectsClientError.output, statusCode: 403, }, }, @@ -380,16 +418,22 @@ export default function alertTests({ getService }: FtrProviderContext) { case 'superuser at space1': expect(response.statusCode).to.eql(200); objectRemover.add(space.id, response.body.id, 'alert'); - actionTestRecord = ( - await esTestIndexTool.waitForDocs('action:test.authorization', reference) - )[0]; - expect(actionTestRecord._source.state).to.eql({ + + // Ensure test.authorization indexed 1 document before disabling the alert and waiting for tasks to finish + await esTestIndexTool.waitForDocs('action:test.authorization', reference); + await alertUtils.disable(response.body.id); + await taskManagerUtils.waitForIdle(testStart); + + // Ensure only 1 document with proper params exists + searchResult = await esTestIndexTool.search('action:test.authorization', reference); + expect(searchResult.hits.total.value).to.eql(1); + expect(searchResult.hits.hits[0]._source.state).to.eql({ callClusterSuccess: true, savedObjectsClientSuccess: false, savedObjectsClientError: { - ...actionTestRecord._source.state.savedObjectsClientError, + ...searchResult.hits.hits[0]._source.state.savedObjectsClientError, output: { - ...actionTestRecord._source.state.savedObjectsClientError.output, + ...searchResult.hits.hits[0]._source.state.savedObjectsClientError.output, statusCode: 404, }, }, @@ -401,6 +445,7 @@ export default function alertTests({ getService }: FtrProviderContext) { }); it('should throttle alerts when appropriate', async () => { + const testStart = new Date(); const reference = alertUtils.generateReference(); const response = await alertUtils.createAlwaysFiringAction({ reference, @@ -422,13 +467,17 @@ export default function alertTests({ getService }: FtrProviderContext) { break; case 'space_1_all at space1': case 'superuser at space1': - // Wait until alerts scheduled actions 3 times to ensure actions had a chance to execute twice + // Wait until alerts scheduled actions 3 times before disabling the alert and waiting for tasks to finish await esTestIndexTool.waitForDocs('alert:test.always-firing', reference, 3); - const executedActionsResult = await esTestIndexTool.search( + await alertUtils.disable(response.body.id); + await taskManagerUtils.waitForIdle(testStart); + + // Ensure actions only executed once + const searchResult = await esTestIndexTool.search( 'action:test.index-record', reference ); - expect(executedActionsResult.hits.total.value).to.eql(1); + expect(searchResult.hits.total.value).to.eql(1); break; default: throw new Error(`Scenario untested: ${JSON.stringify(scenario)}`); @@ -436,6 +485,7 @@ export default function alertTests({ getService }: FtrProviderContext) { }); it('should not throttle when changing groups', async () => { + const testStart = new Date(); const reference = alertUtils.generateReference(); const response = await alertUtils.createAlwaysFiringAction({ reference, @@ -482,14 +532,18 @@ export default function alertTests({ getService }: FtrProviderContext) { break; case 'space_1_all at space1': case 'superuser at space1': - // Wait until alerts scheduled actions 3 times to ensure actions had a chance to execute twice - await esTestIndexTool.waitForDocs('alert:test.always-firing', reference, 3); - const executedActionsResult = await esTestIndexTool.search( + // Wait for actions to execute twice before disabling the alert and waiting for tasks to finish + await esTestIndexTool.waitForDocs('action:test.index-record', reference, 2); + await alertUtils.disable(response.body.id); + await taskManagerUtils.waitForIdle(testStart); + + // Ensure only 2 actions with proper params exists + const searchResult = await esTestIndexTool.search( 'action:test.index-record', reference ); - expect(executedActionsResult.hits.total.value).to.eql(2); - const messages: string[] = executedActionsResult.hits.hits.map( + expect(searchResult.hits.total.value).to.eql(2); + const messages: string[] = searchResult.hits.hits.map( (hit: { _source: { params: { message: string } } }) => hit._source.params.message ); expect(messages.sort()).to.eql(['from:default', 'from:other']); @@ -500,6 +554,7 @@ export default function alertTests({ getService }: FtrProviderContext) { }); it('should reset throttle window when not firing', async () => { + const testStart = new Date(); const reference = alertUtils.generateReference(); const response = await alertUtils.createAlwaysFiringAction({ reference, @@ -526,13 +581,17 @@ export default function alertTests({ getService }: FtrProviderContext) { break; case 'space_1_all at space1': case 'superuser at space1': - // Wait until alerts scheduled actions 4 times to ensure actions had a chance to execute twice - await esTestIndexTool.waitForDocs('alert:test.always-firing', reference, 4); - const executedActionsResult = await esTestIndexTool.search( + // Actions should execute twice before widning things down + await esTestIndexTool.waitForDocs('action:test.index-record', reference, 2); + await alertUtils.disable(response.body.id); + await taskManagerUtils.waitForIdle(testStart); + + // Ensure only 2 actions are executed + const searchResult = await esTestIndexTool.search( 'action:test.index-record', reference ); - expect(executedActionsResult.hits.total.value).to.eql(2); + expect(searchResult.hits.total.value).to.eql(2); break; default: throw new Error(`Scenario untested: ${JSON.stringify(scenario)}`); @@ -540,6 +599,7 @@ export default function alertTests({ getService }: FtrProviderContext) { }); it(`shouldn't schedule actions when alert is muted`, async () => { + const testStart = new Date(); const reference = alertUtils.generateReference(); const response = await alertUtils.createAlwaysFiringAction({ reference, @@ -564,8 +624,14 @@ export default function alertTests({ getService }: FtrProviderContext) { case 'superuser at space1': await alertUtils.muteAll(response.body.id); await alertUtils.enable(response.body.id); - // Wait until alerts schedule actions twice to ensure actions had a chance to skip execution once + + // Wait until alerts schedule actions twice to ensure actions had a chance to skip + // execution once before disabling the alert and waiting for tasks to finish await esTestIndexTool.waitForDocs('alert:test.always-firing', reference, 2); + await alertUtils.disable(response.body.id); + await taskManagerUtils.waitForIdle(testStart); + + // Should not have executed any action const executedActionsResult = await esTestIndexTool.search( 'action:test.index-record', reference @@ -578,6 +644,7 @@ export default function alertTests({ getService }: FtrProviderContext) { }); it(`shouldn't schedule actions when alert instance is muted`, async () => { + const testStart = new Date(); const reference = alertUtils.generateReference(); const response = await alertUtils.createAlwaysFiringAction({ reference, @@ -602,8 +669,14 @@ export default function alertTests({ getService }: FtrProviderContext) { case 'superuser at space1': await alertUtils.muteInstance(response.body.id, '1'); await alertUtils.enable(response.body.id); - // Wait until alerts scheduled actions twice to ensure actions had a chance to execute once + + // Wait until alerts scheduled actions twice to ensure actions had a chance to execute + // once before disabling the alert and waiting for tasks to finish await esTestIndexTool.waitForDocs('alert:test.always-firing', reference, 2); + await alertUtils.disable(response.body.id); + await taskManagerUtils.waitForIdle(testStart); + + // Should not have executed any action const executedActionsResult = await esTestIndexTool.search( 'action:test.index-record', reference @@ -616,6 +689,7 @@ export default function alertTests({ getService }: FtrProviderContext) { }); it(`should unmute all instances when unmuting an alert`, async () => { + const testStart = new Date(); const reference = alertUtils.generateReference(); const response = await alertUtils.createAlwaysFiringAction({ reference, @@ -642,13 +716,18 @@ export default function alertTests({ getService }: FtrProviderContext) { await alertUtils.muteAll(response.body.id); await alertUtils.unmuteAll(response.body.id); await alertUtils.enable(response.body.id); - // Wait until alerts scheduled actions twice to ensure actions had a chance to execute once - await esTestIndexTool.waitForDocs('alert:test.always-firing', reference, 2); - const executedActionsResult = await esTestIndexTool.search( + + // Ensure actions are executed once before disabling the alert and waiting for tasks to finish + await esTestIndexTool.waitForDocs('action:test.index-record', reference, 1); + await alertUtils.disable(response.body.id); + await taskManagerUtils.waitForIdle(testStart); + + // Should have one document indexed by the action + const searchResult = await esTestIndexTool.search( 'action:test.index-record', reference ); - expect(executedActionsResult.hits.total.value).to.eql(1); + expect(searchResult.hits.total.value).to.eql(1); break; default: throw new Error(`Scenario untested: ${JSON.stringify(scenario)}`); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/create.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/create.ts index 21b27cfb6f8f8..f51f188d5f737 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/create.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/create.ts @@ -60,7 +60,7 @@ export default function createAlertTests({ getService }: FtrProviderContext) { alertTypeId: 'test.noop', alertTypeParams: {}, createdBy: user.username, - interval: '10s', + interval: '1m', scheduledTaskId: response.body.scheduledTaskId, throttle: '1m', updatedBy: user.username, diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/find.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/find.ts index 935ae3ed96915..a2912c9b022b3 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/find.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/find.ts @@ -58,7 +58,7 @@ export default function createFindTests({ getService }: FtrProviderContext) { id: createdAlert.id, name: 'abc', alertTypeId: 'test.noop', - interval: '10s', + interval: '1m', enabled: true, actions: [], alertTypeParams: {}, @@ -114,7 +114,7 @@ export default function createFindTests({ getService }: FtrProviderContext) { id: createdAlert.id, name: 'abc', alertTypeId: 'test.noop', - interval: '10s', + interval: '1m', enabled: true, actions: [], alertTypeParams: {}, diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/get.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/get.ts index db798b0d8bc7c..f6c65d286b266 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/get.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/get.ts @@ -52,7 +52,7 @@ export default function createGetTests({ getService }: FtrProviderContext) { id: createdAlert.id, name: 'abc', alertTypeId: 'test.noop', - interval: '10s', + interval: '1m', enabled: true, actions: [], alertTypeParams: {}, diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/update.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/update.ts index ae5853eead7e7..52c8571ae5929 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/update.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/update.ts @@ -233,7 +233,7 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { .auth(user.username, user.password) .send({ name: 'bcd', - interval: '10s', + interval: '1m', throttle: '1m', alertTypeParams: {}, actions: [], diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/index.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/index.ts index af9804473a448..a643bd8f9f64f 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/index.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/index.ts @@ -18,11 +18,7 @@ export default function alertingApiIntegrationTests({ const spacesService: SpacesService = getService('spaces'); const esArchiver = getService('esArchiver'); - // FLAKY: https://github.com/elastic/kibana/issues/50079 - // FLAKY: https://github.com/elastic/kibana/issues/50074 - // FLAKY: https://github.com/elastic/kibana/issues/48709 - // FLAKY: https://github.com/elastic/kibana/issues/50078 - describe.skip('alerting api integration security and spaces enabled', function() { + describe('alerting api integration security and spaces enabled', function() { this.tags('ciGroup1'); before(async () => { diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/create.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/create.ts index 6ad6a54d3dccb..152f441cf8b02 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/create.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/create.ts @@ -42,7 +42,7 @@ export default function createAlertTests({ getService }: FtrProviderContext) { alertTypeId: 'test.noop', alertTypeParams: {}, createdBy: null, - interval: '10s', + interval: '1m', scheduledTaskId: response.body.scheduledTaskId, updatedBy: null, throttle: '1m', diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/find.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/find.ts index 97892e3a95d3f..e3ec322fbf1cd 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/find.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/find.ts @@ -41,7 +41,7 @@ export default function createFindTests({ getService }: FtrProviderContext) { id: createdAlert.id, name: 'abc', alertTypeId: 'test.noop', - interval: '10s', + interval: '1m', enabled: true, actions: [], alertTypeParams: {}, diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/get.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/get.ts index 391d78dda6647..c3d56adc0708a 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/get.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/get.ts @@ -35,7 +35,7 @@ export default function createGetTests({ getService }: FtrProviderContext) { id: createdAlert.id, name: 'abc', alertTypeId: 'test.noop', - interval: '10s', + interval: '1m', enabled: true, actions: [], alertTypeParams: {}, diff --git a/x-pack/test/api_integration/apis/maps/migrations.js b/x-pack/test/api_integration/apis/maps/migrations.js index e4ef5e5784249..fdf4ec228f634 100644 --- a/x-pack/test/api_integration/apis/maps/migrations.js +++ b/x-pack/test/api_integration/apis/maps/migrations.js @@ -42,7 +42,7 @@ export default function ({ getService }) { type: 'index-pattern' } ]); - expect(resp.body.migrationVersion).to.eql({ map: '7.5.0' }); + expect(resp.body.migrationVersion).to.eql({ map: '7.6.0' }); expect(resp.body.attributes.layerListJSON.includes('indexPatternRefName')).to.be(true); }); }); diff --git a/x-pack/test/api_integration/apis/monitoring/setup/collection/fixtures/detect_apm.json b/x-pack/test/api_integration/apis/monitoring/setup/collection/fixtures/detect_apm.json index ddd8d8c9a1de6..d8852f9555ac1 100644 --- a/x-pack/test/api_integration/apis/monitoring/setup/collection/fixtures/detect_apm.json +++ b/x-pack/test/api_integration/apis/monitoring/setup/collection/fixtures/detect_apm.json @@ -51,6 +51,7 @@ }, "_meta": { "secondsAgo": 30, - "liveClusterUuid": null + "liveClusterUuid": null, + "hasPermissions": true } } diff --git a/x-pack/test/api_integration/apis/monitoring/setup/collection/fixtures/detect_beats.json b/x-pack/test/api_integration/apis/monitoring/setup/collection/fixtures/detect_beats.json index fcde71551a4f3..bf4d07f623c39 100644 --- a/x-pack/test/api_integration/apis/monitoring/setup/collection/fixtures/detect_beats.json +++ b/x-pack/test/api_integration/apis/monitoring/setup/collection/fixtures/detect_beats.json @@ -60,6 +60,7 @@ }, "_meta": { "secondsAgo": 30, - "liveClusterUuid": null + "liveClusterUuid": null, + "hasPermissions": true } } diff --git a/x-pack/test/api_integration/apis/monitoring/setup/collection/fixtures/detect_beats_management.json b/x-pack/test/api_integration/apis/monitoring/setup/collection/fixtures/detect_beats_management.json index 9186006415759..61f9a46081810 100644 --- a/x-pack/test/api_integration/apis/monitoring/setup/collection/fixtures/detect_beats_management.json +++ b/x-pack/test/api_integration/apis/monitoring/setup/collection/fixtures/detect_beats_management.json @@ -51,6 +51,7 @@ }, "_meta": { "secondsAgo": 30, - "liveClusterUuid": null + "liveClusterUuid": null, + "hasPermissions": true } } diff --git a/x-pack/test/api_integration/apis/monitoring/setup/collection/fixtures/detect_logstash.json b/x-pack/test/api_integration/apis/monitoring/setup/collection/fixtures/detect_logstash.json index 7311230d108e9..aaa576d05c446 100644 --- a/x-pack/test/api_integration/apis/monitoring/setup/collection/fixtures/detect_logstash.json +++ b/x-pack/test/api_integration/apis/monitoring/setup/collection/fixtures/detect_logstash.json @@ -51,6 +51,7 @@ }, "_meta": { "secondsAgo": 30, - "liveClusterUuid": null + "liveClusterUuid": null, + "hasPermissions": true } } diff --git a/x-pack/test/api_integration/apis/monitoring/setup/collection/fixtures/detect_logstash_management.json b/x-pack/test/api_integration/apis/monitoring/setup/collection/fixtures/detect_logstash_management.json index 7311230d108e9..aaa576d05c446 100644 --- a/x-pack/test/api_integration/apis/monitoring/setup/collection/fixtures/detect_logstash_management.json +++ b/x-pack/test/api_integration/apis/monitoring/setup/collection/fixtures/detect_logstash_management.json @@ -51,6 +51,7 @@ }, "_meta": { "secondsAgo": 30, - "liveClusterUuid": null + "liveClusterUuid": null, + "hasPermissions": true } } diff --git a/x-pack/test/api_integration/apis/monitoring/setup/collection/fixtures/es_and_kibana_exclusive_mb.json b/x-pack/test/api_integration/apis/monitoring/setup/collection/fixtures/es_and_kibana_exclusive_mb.json index 69688bc46c27e..a0f5c2617af07 100644 --- a/x-pack/test/api_integration/apis/monitoring/setup/collection/fixtures/es_and_kibana_exclusive_mb.json +++ b/x-pack/test/api_integration/apis/monitoring/setup/collection/fixtures/es_and_kibana_exclusive_mb.json @@ -71,6 +71,7 @@ }, "_meta": { "secondsAgo": 30, - "liveClusterUuid": null + "liveClusterUuid": null, + "hasPermissions": true } } diff --git a/x-pack/test/api_integration/apis/monitoring/setup/collection/fixtures/es_and_kibana_mb.json b/x-pack/test/api_integration/apis/monitoring/setup/collection/fixtures/es_and_kibana_mb.json index 8b207b418dae7..50a59ed5c7b41 100644 --- a/x-pack/test/api_integration/apis/monitoring/setup/collection/fixtures/es_and_kibana_mb.json +++ b/x-pack/test/api_integration/apis/monitoring/setup/collection/fixtures/es_and_kibana_mb.json @@ -71,6 +71,7 @@ }, "_meta": { "secondsAgo": 30, - "liveClusterUuid": null + "liveClusterUuid": null, + "hasPermissions": true } } diff --git a/x-pack/test/api_integration/apis/monitoring/setup/collection/fixtures/kibana_exclusive_mb.json b/x-pack/test/api_integration/apis/monitoring/setup/collection/fixtures/kibana_exclusive_mb.json index 319844a7e093d..2022ef2a99f35 100644 --- a/x-pack/test/api_integration/apis/monitoring/setup/collection/fixtures/kibana_exclusive_mb.json +++ b/x-pack/test/api_integration/apis/monitoring/setup/collection/fixtures/kibana_exclusive_mb.json @@ -71,6 +71,7 @@ }, "_meta": { "secondsAgo": 30, - "liveClusterUuid": null + "liveClusterUuid": null, + "hasPermissions": true } } diff --git a/x-pack/test/api_integration/apis/monitoring/setup/collection/fixtures/kibana_mb.json b/x-pack/test/api_integration/apis/monitoring/setup/collection/fixtures/kibana_mb.json index f65436ce28616..d0dc8d44b29c4 100644 --- a/x-pack/test/api_integration/apis/monitoring/setup/collection/fixtures/kibana_mb.json +++ b/x-pack/test/api_integration/apis/monitoring/setup/collection/fixtures/kibana_mb.json @@ -71,6 +71,7 @@ }, "_meta": { "secondsAgo": 30, - "liveClusterUuid": null + "liveClusterUuid": null, + "hasPermissions": true } } diff --git a/x-pack/test/api_integration/apis/monitoring/setup/collection/index.js b/x-pack/test/api_integration/apis/monitoring/setup/collection/index.js index a88dc2f43c9b4..e5860bbc7ffc6 100644 --- a/x-pack/test/api_integration/apis/monitoring/setup/collection/index.js +++ b/x-pack/test/api_integration/apis/monitoring/setup/collection/index.js @@ -15,5 +15,6 @@ export default function ({ loadTestFile }) { loadTestFile(require.resolve('./detect_logstash')); loadTestFile(require.resolve('./detect_logstash_management')); loadTestFile(require.resolve('./detect_apm')); + loadTestFile(require.resolve('./security')); }); } diff --git a/x-pack/test/api_integration/apis/monitoring/setup/collection/security.js b/x-pack/test/api_integration/apis/monitoring/setup/collection/security.js new file mode 100644 index 0000000000000..420abe26103d0 --- /dev/null +++ b/x-pack/test/api_integration/apis/monitoring/setup/collection/security.js @@ -0,0 +1,60 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import expect from '@kbn/expect'; + +export default function ({ getService }) { + const supertest = getService('supertest'); + const esArchiver = getService('esArchiver'); + const security = getService('security'); + const supertestWithoutAuth = getService('supertestWithoutAuth'); + + describe('security', () => { + const archive = 'monitoring/setup/collection/kibana_exclusive_mb'; + const timeRange = { + min: '2019-04-09T00:00:00.741Z', + max: '2019-04-09T23:59:59.741Z' + }; + + before('load archive', () => { + return esArchiver.load(archive); + }); + + after('unload archive', () => { + return esArchiver.unload(archive); + }); + + it('should allow access to elevated user', async () => { + const { body } = await supertest + .post('/api/monitoring/v1/setup/collection/cluster?skipLiveData=true') + .set('kbn-xsrf', 'xxx') + .send({ timeRange }) + .expect(200); + + expect(body.hasPermissions).to.not.be(false); + }); + + it('should say permission denied for limited user', async () => { + const username = 'limited_user'; + const password = 'changeme'; + + await security.user.create(username, { + password: password, + full_name: 'Limited User', + roles: ['kibana_user', 'monitoring_user'] + }); + + const { body } = await supertestWithoutAuth + .post('/api/monitoring/v1/setup/collection/cluster?skipLiveData=true') + .auth(username, password) + .set('kbn-xsrf', 'xxx') + .send({ timeRange }) + .expect(200); + + expect(body._meta.hasPermissions).to.be(false); + }); + }); +} diff --git a/x-pack/test/api_integration/apis/telemetry/index.js b/x-pack/test/api_integration/apis/telemetry/index.js index 6f794d56ae713..5f13b0b728468 100644 --- a/x-pack/test/api_integration/apis/telemetry/index.js +++ b/x-pack/test/api_integration/apis/telemetry/index.js @@ -9,5 +9,6 @@ export default function ({ loadTestFile }) { loadTestFile(require.resolve('./telemetry')); loadTestFile(require.resolve('./telemetry_local')); loadTestFile(require.resolve('./opt_in')); + loadTestFile(require.resolve('./telemetry_optin_notice_seen')); }); } diff --git a/x-pack/test/api_integration/apis/telemetry/telemetry_optin_notice_seen.ts b/x-pack/test/api_integration/apis/telemetry/telemetry_optin_notice_seen.ts new file mode 100644 index 0000000000000..de03fff7edcf7 --- /dev/null +++ b/x-pack/test/api_integration/apis/telemetry/telemetry_optin_notice_seen.ts @@ -0,0 +1,40 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import expect from '@kbn/expect'; +import { Client, DeleteDocumentParams, GetParams, GetResponse } from 'elasticsearch'; +import { TelemetrySavedObjectAttributes } from '../../../../../src/legacy/core_plugins/telemetry/server/telemetry_repository'; +import { FtrProviderContext } from '../../ftr_provider_context'; + +export default function optInTest({ getService }: FtrProviderContext) { + const client: Client = getService('es'); + const supertest = getService('supertest'); + + describe('/api/telemetry/v2/optIn API Telemetry User has seen OptIn Notice', () => { + it('should update telemetry setting field via PUT', async () => { + await client.delete({ + index: '.kibana', + id: 'telemetry:telemetry', + } as DeleteDocumentParams); + + await supertest + .put('/api/telemetry/v2/userHasSeenNotice') + .set('kbn-xsrf', 'xxx') + .expect(200); + + const { + _source: { telemetry }, + }: GetResponse<{ + telemetry: TelemetrySavedObjectAttributes; + }> = await client.get({ + index: '.kibana', + id: 'telemetry:telemetry', + } as GetParams); + + expect(telemetry.userHasSeenNotice).to.be(true); + }); + }); +} diff --git a/x-pack/test/functional/apps/canvas/feature_controls/canvas_security.ts b/x-pack/test/functional/apps/canvas/feature_controls/canvas_security.ts index a55ada12b4749..e9e1436241308 100644 --- a/x-pack/test/functional/apps/canvas/feature_controls/canvas_security.ts +++ b/x-pack/test/functional/apps/canvas/feature_controls/canvas_security.ts @@ -86,7 +86,7 @@ export default function({ getPageObjects, getService }: FtrProviderContext) { it(`allows a workpad to be created`, async () => { await PageObjects.common.navigateToActualUrl('canvas', 'workpad/create', { ensureCurrentUrl: true, - showLoginIfPrompted: false, + shouldLoginIfPrompted: false, }); await PageObjects.canvas.expectAddElementButton(); @@ -98,7 +98,7 @@ export default function({ getPageObjects, getService }: FtrProviderContext) { 'workpad/workpad-1705f884-6224-47de-ba49-ca224fe6ec31', { ensureCurrentUrl: true, - showLoginIfPrompted: false, + shouldLoginIfPrompted: false, } ); diff --git a/x-pack/test/functional/apps/maps/embeddable/dashboard.js b/x-pack/test/functional/apps/maps/embeddable/dashboard.js index f458c38093e4f..0bc764b0d76bd 100644 --- a/x-pack/test/functional/apps/maps/embeddable/dashboard.js +++ b/x-pack/test/functional/apps/maps/embeddable/dashboard.js @@ -40,7 +40,7 @@ export default function ({ getPageObjects, getService }) { it('should pass index patterns to container', async () => { const indexPatterns = await filterBar.getIndexPatterns(); - expect(indexPatterns).to.equal('geo_shapes*,meta_for_geo_shapes*,logstash-*'); + expect(indexPatterns).to.equal('meta_for_geo_shapes*,logstash-*'); }); it('should populate inspector with requests for map embeddable', async () => { diff --git a/x-pack/test/functional/apps/maps/joins.js b/x-pack/test/functional/apps/maps/joins.js index 41c777ad67c77..1634bea47a69f 100644 --- a/x-pack/test/functional/apps/maps/joins.js +++ b/x-pack/test/functional/apps/maps/joins.js @@ -111,14 +111,15 @@ export default function ({ getPageObjects, getService }) { describe('query bar', () => { before(async () => { - await PageObjects.maps.setAndSubmitQuery('prop1 < 10 or _index : "geo_shapes*"'); + await PageObjects.maps.setAndSubmitQuery('prop1 < 10'); }); - afterEach(async () => { + after(async () => { await inspector.close(); + await PageObjects.maps.setAndSubmitQuery(''); }); - it('should apply query to join request', async () => { + it('should not apply query to source and apply query to join', async () => { await PageObjects.maps.openInspectorRequest('meta_for_geo_shapes*.shape_name'); const requestStats = await inspector.getTableData(); const totalHits = PageObjects.maps.getInspectorStatRowHit(requestStats, 'Hits (total)'); @@ -128,20 +129,6 @@ export default function ({ getPageObjects, getService }) { const indexPatternName = PageObjects.maps.getInspectorStatRowHit(requestStats, 'Index pattern'); expect(indexPatternName).to.equal('meta_for_geo_shapes*'); }); - - it('should not apply query to join request when apply global query is disabled', async () => { - await PageObjects.maps.openLayerPanel('geo_shapes*'); - await PageObjects.maps.disableApplyGlobalQuery(); - - await PageObjects.maps.openInspectorRequest('meta_for_geo_shapes*.shape_name'); - const requestStats = await inspector.getTableData(); - const totalHits = PageObjects.maps.getInspectorStatRowHit(requestStats, 'Hits (total)'); - expect(totalHits).to.equal('6'); - const hits = PageObjects.maps.getInspectorStatRowHit(requestStats, 'Hits'); - expect(hits).to.equal('0'); // aggregation requests do not return any documents - const indexPatternName = PageObjects.maps.getInspectorStatRowHit(requestStats, 'Index pattern'); - expect(indexPatternName).to.equal('meta_for_geo_shapes*'); - }); }); describe('where clause', () => { diff --git a/x-pack/test/functional/apps/monitoring/_get_lifecycle_methods.js b/x-pack/test/functional/apps/monitoring/_get_lifecycle_methods.js index 6e2f0e2f00bcc..c1faa25ed9c70 100644 --- a/x-pack/test/functional/apps/monitoring/_get_lifecycle_methods.js +++ b/x-pack/test/functional/apps/monitoring/_get_lifecycle_methods.js @@ -6,7 +6,8 @@ export const getLifecycleMethods = (getService, getPageObjects) => { const esArchiver = getService('esArchiver'); - const PageObjects = getPageObjects(['monitoring', 'timePicker']); + const security = getService('security'); + const PageObjects = getPageObjects(['monitoring', 'timePicker', 'security']); const noData = getService('monitoringNoData'); let _archive; @@ -33,7 +34,9 @@ export const getLifecycleMethods = (getService, getPageObjects) => { await PageObjects.timePicker.setAbsoluteRange(from, to); }, - tearDown() { + async tearDown() { + await PageObjects.security.logout(); + await security.user.delete('basic_monitoring_user'); return esArchiver.unload(_archive); } }; diff --git a/x-pack/test/functional/apps/monitoring/enable_monitoring/index.js b/x-pack/test/functional/apps/monitoring/enable_monitoring/index.js index 2cdecc58266a6..aa96d71228799 100644 --- a/x-pack/test/functional/apps/monitoring/enable_monitoring/index.js +++ b/x-pack/test/functional/apps/monitoring/enable_monitoring/index.js @@ -17,7 +17,7 @@ export default function ({ getService, getPageObjects }) { before(async () => { const browser = getService('browser'); await browser.setWindowSize(1600, 1000); - await PageObjects.monitoring.navigateTo(); + await PageObjects.monitoring.navigateTo(true); await noData.isOnNoDataPage(); }); diff --git a/x-pack/test/functional/apps/monitoring/feature_controls/monitoring_security.ts b/x-pack/test/functional/apps/monitoring/feature_controls/monitoring_security.ts index 2d645d161c134..84a4a2697a278 100644 --- a/x-pack/test/functional/apps/monitoring/feature_controls/monitoring_security.ts +++ b/x-pack/test/functional/apps/monitoring/feature_controls/monitoring_security.ts @@ -13,7 +13,7 @@ export default function({ getPageObjects, getService }: FtrProviderContext) { const appsMenu = getService('appsMenu'); const PageObjects = getPageObjects(['common', 'security']); - describe('securty', () => { + describe('security', () => { before(async () => { await esArchiver.load('empty_kibana'); diff --git a/x-pack/test/functional/apps/monitoring/feature_controls/monitoring_spaces.ts b/x-pack/test/functional/apps/monitoring/feature_controls/monitoring_spaces.ts index 94714f7b0ca34..4508d6a8e5a18 100644 --- a/x-pack/test/functional/apps/monitoring/feature_controls/monitoring_spaces.ts +++ b/x-pack/test/functional/apps/monitoring/feature_controls/monitoring_spaces.ts @@ -19,6 +19,12 @@ export default function({ getPageObjects, getService }: FtrProviderContext) { await esArchiver.load('empty_kibana'); }); + after(async () => { + await esArchiver.unload('empty_kibana'); + await PageObjects.common.navigateToApp('home'); + await PageObjects.security.logout(); + }); + describe('space with no features disabled', () => { before(async () => { await spacesService.create({ diff --git a/x-pack/test/functional/apps/monitoring/index.js b/x-pack/test/functional/apps/monitoring/index.js index 06c8dc292869e..77ca4087da13a 100644 --- a/x-pack/test/functional/apps/monitoring/index.js +++ b/x-pack/test/functional/apps/monitoring/index.js @@ -13,7 +13,6 @@ export default function ({ loadTestFile }) { loadTestFile(require.resolve('./cluster/list')); loadTestFile(require.resolve('./cluster/overview')); loadTestFile(require.resolve('./cluster/alerts')); - loadTestFile(require.resolve('./enable_monitoring')); // loadTestFile(require.resolve('./cluster/license')); loadTestFile(require.resolve('./elasticsearch/overview')); @@ -40,5 +39,6 @@ export default function ({ loadTestFile }) { loadTestFile(require.resolve('./beats/beat_detail')); loadTestFile(require.resolve('./time_filter')); + loadTestFile(require.resolve('./enable_monitoring')); }); } diff --git a/x-pack/test/functional/apps/saved_objects_management/feature_controls/saved_objects_management_security.ts b/x-pack/test/functional/apps/saved_objects_management/feature_controls/saved_objects_management_security.ts index 692dc589cc157..619a85c616b2e 100644 --- a/x-pack/test/functional/apps/saved_objects_management/feature_controls/saved_objects_management_security.ts +++ b/x-pack/test/functional/apps/saved_objects_management/feature_controls/saved_objects_management_security.ts @@ -115,7 +115,7 @@ export default function({ getPageObjects, getService }: FtrProviderContext) { 'kibana', '/management/kibana/objects/savedVisualizations/75c3e060-1e7c-11e9-8488-65449e65d0ed', { - loginIfPrompted: false, + shouldLoginIfPrompted: false, } ); }); @@ -233,7 +233,7 @@ export default function({ getPageObjects, getService }: FtrProviderContext) { 'kibana', '/management/kibana/objects/savedVisualizations/75c3e060-1e7c-11e9-8488-65449e65d0ed', { - loginIfPrompted: false, + shouldLoginIfPrompted: false, } ); await testSubjects.existOrFail('savedObjectsEdit'); @@ -316,7 +316,7 @@ export default function({ getPageObjects, getService }: FtrProviderContext) { 'kibana', '/management/kibana/objects/savedVisualizations/75c3e060-1e7c-11e9-8488-65449e65d0ed', { - loginIfPrompted: false, + shouldLoginIfPrompted: false, ensureCurrentUrl: false, } ); diff --git a/x-pack/test/functional/es_archives/maps/kibana/data.json b/x-pack/test/functional/es_archives/maps/kibana/data.json index 52a454eeeb743..1291e3dd10cff 100644 --- a/x-pack/test/functional/es_archives/maps/kibana/data.json +++ b/x-pack/test/functional/es_archives/maps/kibana/data.json @@ -411,7 +411,7 @@ "type": "envelope" }, "description": "", - "layerListJSON": "[{\"id\":\"0hmz5\",\"label\":\"EMS base layer (road_map)\",\"sourceDescriptor\":{\"type\":\"EMS_TMS\",\"id\":\"road_map\"},\"visible\":true,\"temporary\":false,\"style\":{\"type\":\"TILE\",\"properties\":{}},\"type\":\"TILE\",\"minZoom\":0,\"maxZoom\":24},{\"id\":\"n1t6f\",\"label\":null,\"minZoom\":0,\"maxZoom\":24,\"sourceDescriptor\":{\"id\":\"62eca1fc-fe42-11e8-8eb2-f2801f1b9fd1\",\"type\":\"ES_SEARCH\",\"geoField\":\"geometry\",\"limit\":2048,\"filterByMapBounds\":false,\"showTooltip\":true,\"tooltipProperties\":[\"name\"],\"indexPatternRefName\":\"layer_1_source_index_pattern\"},\"visible\":true,\"temporary\":false,\"style\":{\"type\":\"VECTOR\",\"properties\":{\"fillColor\":{\"type\":\"DYNAMIC\",\"options\":{\"field\":{\"label\":\"max(prop1) group by meta_for_geo_shapes*.shape_name\",\"name\":\"__kbnjoin__max_of_prop1_groupby_meta_for_geo_shapes*.shape_name\",\"origin\":\"join\"},\"color\":\"Blues\"}},\"iconSize\":{\"type\":\"STATIC\",\"options\":{\"size\":10}}},\"temporary\":true,\"previousStyle\":null},\"type\":\"VECTOR\",\"joins\":[{\"leftField\":\"name\",\"right\":{\"id\":\"855ccb86-fe42-11e8-8eb2-f2801f1b9fd1\",\"indexPatternTitle\":\"meta_for_geo_shapes*\",\"term\":\"shape_name\",\"metrics\":[{\"type\":\"max\",\"field\":\"prop1\"}],\"indexPatternRefName\":\"layer_1_join_0_index_pattern\"}}]}]", + "layerListJSON" : "[{\"id\":\"0hmz5\",\"label\":\"EMS base layer (road_map)\",\"sourceDescriptor\":{\"type\":\"EMS_TMS\",\"id\":\"road_map\"},\"visible\":true,\"temporary\":false,\"style\":{\"type\":\"TILE\",\"properties\":{}},\"type\":\"VECTOR_TILE\",\"minZoom\":0,\"maxZoom\":24},{\"id\":\"n1t6f\",\"label\":null,\"minZoom\":0,\"maxZoom\":24,\"sourceDescriptor\":{\"id\":\"62eca1fc-fe42-11e8-8eb2-f2801f1b9fd1\",\"type\":\"ES_SEARCH\",\"geoField\":\"geometry\",\"limit\":2048,\"filterByMapBounds\":false,\"showTooltip\":true,\"tooltipProperties\":[\"name\"],\"applyGlobalQuery\":false,\"indexPatternRefName\":\"layer_1_source_index_pattern\"},\"visible\":true,\"temporary\":false,\"style\":{\"type\":\"VECTOR\",\"properties\":{\"fillColor\":{\"type\":\"DYNAMIC\",\"options\":{\"field\":{\"label\":\"max(prop1) group by meta_for_geo_shapes*.shape_name\",\"name\":\"__kbnjoin__max_of_prop1_groupby_meta_for_geo_shapes*.shape_name\",\"origin\":\"join\"},\"color\":\"Blues\"}},\"iconSize\":{\"type\":\"STATIC\",\"options\":{\"size\":10}}},\"temporary\":true,\"previousStyle\":null},\"type\":\"VECTOR\",\"joins\":[{\"leftField\":\"name\",\"right\":{\"id\":\"855ccb86-fe42-11e8-8eb2-f2801f1b9fd1\",\"indexPatternTitle\":\"meta_for_geo_shapes*\",\"term\":\"shape_name\",\"metrics\":[{\"type\":\"max\",\"field\":\"prop1\"}],\"applyGlobalQuery\":true,\"indexPatternRefName\":\"layer_1_join_0_index_pattern\"}}]}]", "mapStateJSON": "{\"zoom\":3.02,\"center\":{\"lon\":77.33426,\"lat\":-0.04647},\"timeFilters\":{\"from\":\"now-17m\",\"to\":\"now\",\"mode\":\"quick\"},\"refreshConfig\":{\"isPaused\":true,\"interval\":1000}}", "title": "join example", "uiStateJSON": "{\"isLayerTOCOpen\":true,\"openTOCDetails\":[\"n1t6f\"]}" @@ -430,7 +430,7 @@ } ], "migrationVersion" : { - "map" : "7.2.0" + "map" : "7.6.0" } } } diff --git a/x-pack/test/functional/page_objects/monitoring_page.js b/x-pack/test/functional/page_objects/monitoring_page.js index 933962c160bc9..58214f17f4ff0 100644 --- a/x-pack/test/functional/page_objects/monitoring_page.js +++ b/x-pack/test/functional/page_objects/monitoring_page.js @@ -5,11 +5,26 @@ */ export function MonitoringPageProvider({ getPageObjects, getService }) { - const PageObjects = getPageObjects(['common', 'header']); + const PageObjects = getPageObjects(['common', 'header', 'shield', 'spaceSelector']); const testSubjects = getService('testSubjects'); + const security = getService('security'); return new class MonitoringPage { - async navigateTo() { + async navigateTo(useSuperUser = false) { + // always create this because our tear down tries to delete it + await security.user.create('basic_monitoring_user', { + password: 'monitoring_user_password', + roles: ['monitoring_user', 'kibana_user'], + full_name: 'basic monitoring', + }); + + if (!useSuperUser) { + await PageObjects.common.navigateToApp('login'); + await PageObjects.shield.login( + 'basic_monitoring_user', + 'monitoring_user_password' + ); + } await PageObjects.common.navigateToApp('monitoring'); } diff --git a/x-pack/test/pki_api_integration/apis/security/pki_auth.ts b/x-pack/test/pki_api_integration/apis/security/pki_auth.ts index 8c29db674aaf3..afb27168d6d5c 100644 --- a/x-pack/test/pki_api_integration/apis/security/pki_auth.ts +++ b/x-pack/test/pki_api_integration/apis/security/pki_auth.ts @@ -113,7 +113,7 @@ export default function({ getService }: FtrProviderContext) { enabled: true, metadata: { pki_delegated_by_realm: 'reserved', - pki_delegated_by_user: 'elastic', + pki_delegated_by_user: 'kibana', pki_dn: 'CN=first_client', }, authentication_realm: { name: 'pki1', type: 'pki' }, @@ -155,7 +155,7 @@ export default function({ getService }: FtrProviderContext) { enabled: true, metadata: { pki_delegated_by_realm: 'reserved', - pki_delegated_by_user: 'elastic', + pki_delegated_by_user: 'kibana', pki_dn: 'CN=second_client', }, authentication_realm: { name: 'pki1', type: 'pki' }, diff --git a/x-pack/test/plugin_api_integration/plugins/task_manager/index.js b/x-pack/test/plugin_api_integration/plugins/task_manager/index.js index 85dd0fed9a000..938324c12a377 100644 --- a/x-pack/test/plugin_api_integration/plugins/task_manager/index.js +++ b/x-pack/test/plugin_api_integration/plugins/task_manager/index.js @@ -41,7 +41,7 @@ export default function TaskTestingAPI(kibana) { const callCluster = server.plugins.elasticsearch.getCluster('admin').callWithInternalUser; await callCluster('index', { - index: '.task_manager_test_result', + index: '.kibana_task_manager_test_result', body: { type: 'task', taskId: taskInstance.id, diff --git a/x-pack/test/plugin_api_integration/test_suites/task_manager/task_manager_integration.js b/x-pack/test/plugin_api_integration/test_suites/task_manager/task_manager_integration.js index 07877f3c09d84..a8ff03dc71d24 100644 --- a/x-pack/test/plugin_api_integration/test_suites/task_manager/task_manager_integration.js +++ b/x-pack/test/plugin_api_integration/test_suites/task_manager/task_manager_integration.js @@ -16,7 +16,7 @@ export default function ({ getService }) { const log = getService('log'); const retry = getService('retry'); const config = getService('config'); - const testHistoryIndex = '.task_manager_test_result'; + const testHistoryIndex = '.kibana_task_manager_test_result'; const supertest = supertestAsPromised(url.format(config.get('servers.kibana'))); describe('scheduling and running tasks', () => { diff --git a/x-pack/test/reporting/configs/generate_api.js b/x-pack/test/reporting/configs/generate_api.js index 92f16d0951ee5..8b8a95ad19a33 100644 --- a/x-pack/test/reporting/configs/generate_api.js +++ b/x-pack/test/reporting/configs/generate_api.js @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { esTestConfig, kbnTestConfig } from '@kbn/test'; +import { esTestConfig, kbnTestConfig, kibanaServerTestUser } from '@kbn/test'; import { format as formatUrl } from 'url'; import { getApiIntegrationConfig } from '../../api_integration/config'; import { getReportingApiConfig } from './api'; @@ -35,8 +35,8 @@ export default async function ({ readConfigFile }) { `--server.maxPayloadBytes=1679958`, `--server.port=${kbnTestConfig.getPort()}`, `--elasticsearch.hosts=${formatUrl(servers.elasticsearch)}`, - `--elasticsearch.password=${servers.elasticsearch.password}`, - `--elasticsearch.username=${servers.elasticsearch.username}`, + `--elasticsearch.username=${kibanaServerTestUser.username}`, + `--elasticsearch.password=${kibanaServerTestUser.password}`, `--xpack.reporting.csv.enablePanelActionDownload=true`, `--xpack.reporting.csv.maxSizeBytes=2850`, `--xpack.reporting.queue.pollInterval=3000`,