diff --git a/docs/getting-started/tutorial-dashboard.asciidoc b/docs/getting-started/tutorial-dashboard.asciidoc index aab93eb51ca23..87a1e38efcfe0 100644 --- a/docs/getting-started/tutorial-dashboard.asciidoc +++ b/docs/getting-started/tutorial-dashboard.asciidoc @@ -2,11 +2,12 @@ === Add visualizations to a dashboard A dashboard is a collection of visualizations that you can arrange and share. -You'll build a dashboard that contains the visualizations you saved during +You'll build a dashboard that contains the visualizations and map that you saved during this tutorial. . Open *Dashboard*. . On the Dashboard overview page, click *Create new dashboard*. +. Set the time filter to May 18, 2015 to May 20, 2015. . Click *Add* in the menu bar. . Add *Bar Example*, *Map Example*, *Markdown Example*, and *Pie Example*. + @@ -26,12 +27,12 @@ is on the lower right. ==== Inspect the data -Seeing visualizations of your data is great, +Seeing visualizations of your data is great, but sometimes you need to look at the actual data to understand what's really going on. You can inspect the data behind any visualization and view the {es} query used to retrieve it. -. In the dashboard, hover the pointer over the pie chart, and then click the icon in the upper right. +. In the dashboard, hover the pointer over the pie chart, and then click the icon in the upper right. . From the *Options* menu, select *Inspect*. + [role="screenshot"] diff --git a/docs/getting-started/tutorial-visualizing.asciidoc b/docs/getting-started/tutorial-visualizing.asciidoc index 5e61475cf2839..a16343aa4850a 100644 --- a/docs/getting-started/tutorial-visualizing.asciidoc +++ b/docs/getting-started/tutorial-visualizing.asciidoc @@ -3,11 +3,11 @@ In the Visualize application, you can shape your data using a variety of charts, tables, and maps, and more. In this tutorial, you'll create four -visualizations: +visualizations: * <> * <> -* <> +* <> * <> [float] @@ -25,7 +25,7 @@ types in Kibana. image::images/tutorial-visualize-wizard-step-1.png[] . Click *Pie*. -. In *Choose a source*, select the `ba*` index pattern. +. In *Choose a source*, select the `ba*` index pattern. + Initially, the pie contains a single "slice." That's because the default search matched all documents. @@ -76,7 +76,7 @@ in a ring around the balance ranges. [role="screenshot"] image::images/tutorial-visualize-pie-3.png[] -. To save this chart so you can use it later, click *Save* in +. To save this chart so you can use it later, click *Save* in the top menu bar and enter `Pie Example`. [float] @@ -123,14 +123,36 @@ you did at the beginning of the tutorial, when you marked the `play_name` field as `not analyzed`. [float] -[[tutorial-visualize-map]] -=== Coordinate map +[[tutorial-visualize-markdown]] +=== Markdown -Using a coordinate map, you can visualize geographic information in the log file sample data. +Create a Markdown widget to add formatted text to your dashboard. + +. Create a *Markdown* visualization. +. Copy the following text into the text box. ++ +[source,markdown] +# This is a tutorial dashboard! +The Markdown widget uses **markdown** syntax. +> Blockquotes in Markdown use the > character. -. Create a *Coordinate map* and set the search source to `logstash*`. +. Click *Apply changes* image:images/apply-changes-button.png[]. + -You haven't defined any buckets yet, so the visualization is a map of the world. +The Markdown renders in the preview pane. ++ +[role="screenshot"] +image::images/tutorial-visualize-md-2.png[] + +. *Save* this visualization with the name `Markdown Example`. + +[float] +[[tutorial-visualize-map]] +=== Map + +Using <>, you can visualize geographic information in the log file sample data. + +. Click *Maps* in the New Visualization +menu to create a Map. . Set the time. .. In the time filter, click *Show dates*. @@ -138,14 +160,19 @@ You haven't defined any buckets yet, so the visualization is a map of the world. .. Set the *Start date* to May 18, 2015. .. In the time filter, click *now*, then *Absolute*. .. Set the *End date* to May 20, 2015. +.. Click *Update* . Map the geo coordinates from the log files. -.. In the *Buckets* pane, click *Add > Geo coordinates*. -.. Set *Aggregation* to *Geohash*. -.. Set *Field* to *geo.coordinates*. +.. Click *Add layer*. +.. Click the *Grid aggregation* data source. +.. Set *Index pattern* to *logstash*. +.. Click the *Add layer* button. -. Click *Apply changes* image:images/apply-changes-button.png[]. +. Set the layer style. +.. For *Fill color*, select the yellow to red color ramp. +.. For *Border color*, select white. +.. Click *Save & close*. + The map now looks like this: + @@ -155,26 +182,3 @@ image::images/tutorial-visualize-map-2.png[] . Navigate the map by clicking and dragging. Use the controls on the left to zoom the map and set filters. . *Save* this map with the name `Map Example`. - -[float] -[[tutorial-visualize-markdown]] -=== Markdown - -The final visualization is a Markdown widget that renders formatted text. - -. Create a *Markdown* visualization. -. Copy the following text into the text box. -+ -[source,markdown] -# This is a tutorial dashboard! -The Markdown widget uses **markdown** syntax. -> Blockquotes in Markdown use the > character. - -. Click *Apply changes* image:images/apply-changes-button.png[]. -+ -The Markdown renders in the preview pane. -+ -[role="screenshot"] -image::images/tutorial-visualize-md-2.png[] - -. *Save* this visualization with the name `Markdown Example`. diff --git a/docs/images/tutorial-visualize-map-2.png b/docs/images/tutorial-visualize-map-2.png index db9f0d56bc963..f4d1d0e47fe6a 100644 Binary files a/docs/images/tutorial-visualize-map-2.png and b/docs/images/tutorial-visualize-map-2.png differ diff --git a/docs/maps/maps-getting-started.asciidoc b/docs/maps/maps-getting-started.asciidoc index 88ad6a26d3697..3ff44b97de635 100644 --- a/docs/maps/maps-getting-started.asciidoc +++ b/docs/maps/maps-getting-started.asciidoc @@ -84,7 +84,7 @@ the {es} index `kibana_sample_data_logs` on the shared key iso2 = geo.src. . Set *Right source* to *kibana_sample_data_logs*. . Set *Right field* to *geo.src*. -===== Set the vector style +===== Set the layer style All of the world countries are still a single color because the layer is using <>. To shade the world countries based on which country is sending the most requests, you'll need to use <>. @@ -161,9 +161,9 @@ image::maps/images/grid_metrics_both.png[] . Select *Sum* in the aggregation select. . Select *bytes* in the field select. -===== Set the vector style +===== Set the layer style -. In *Vector style*, change *Symbol size*: +. In *Layer style*, change *Symbol size*: .. Set *Min size* to 1. .. Set *Max size* to 25. .. In the field select, select *sum of bytes*. diff --git a/src/legacy/core_plugins/kibana/server/lib/__tests__/manage_uuid.js b/src/legacy/core_plugins/kibana/server/lib/__tests__/manage_uuid.js index fe870c2b04ff8..8239e119aef4f 100644 --- a/src/legacy/core_plugins/kibana/server/lib/__tests__/manage_uuid.js +++ b/src/legacy/core_plugins/kibana/server/lib/__tests__/manage_uuid.js @@ -23,7 +23,8 @@ import { createTestServers } from '../../../../../../test_utils/kbn_server'; import manageUuid from '../manage_uuid'; describe('legacy/core_plugins/kibana/server/lib', function () { - describe('manage_uuid', function () { + // failing test, see #48426 and #48427 + describe.skip('manage_uuid', function () { const testUuid = 'c4add484-0cba-4e05-86fe-4baa112d9e53'; let kbn; let kbnServer; diff --git a/src/legacy/core_plugins/telemetry/index.ts b/src/legacy/core_plugins/telemetry/index.ts index 4b6566415f3e1..50a25423b5eb8 100644 --- a/src/legacy/core_plugins/telemetry/index.ts +++ b/src/legacy/core_plugins/telemetry/index.ts @@ -17,6 +17,7 @@ * under the License. */ +import * as Rx from 'rxjs'; import { resolve } from 'path'; import JoiNamespace from 'joi'; import { Server } from 'hapi'; @@ -45,6 +46,14 @@ const telemetry = (kibana: any) => { config(Joi: typeof JoiNamespace) { return Joi.object({ enabled: Joi.boolean().default(true), + optIn: Joi.when('allowChangingOptInStatus', { + is: false, + then: Joi.valid(true), + otherwise: Joi.boolean() + .allow(null) + .default(null), + }), + allowChangingOptInStatus: Joi.boolean().default(true), // `config` is used internally and not intended to be set config: Joi.string().default(Joi.ref('$defaultConfigPath')), banner: Joi.boolean().default(true), @@ -80,8 +89,25 @@ const telemetry = (kibana: any) => { }, }, async replaceInjectedVars(originalInjectedVars: any, request: any) { + const config = request.server.config(); + const optIn = config.get('telemetry.optIn'); + const allowChangingOptInStatus = config.get('telemetry.allowChangingOptInStatus'); const currentKibanaVersion = getCurrentKibanaVersion(request.server); - const telemetryOptedIn = await getTelemetryOptIn({ request, currentKibanaVersion }); + let telemetryOptedIn: boolean | null; + + if (typeof optIn === 'boolean' && !allowChangingOptInStatus) { + // When not allowed to change optIn status and an optIn value is set, we'll overwrite with that + telemetryOptedIn = optIn; + } else { + telemetryOptedIn = await getTelemetryOptIn({ + request, + currentKibanaVersion, + }); + if (telemetryOptedIn === null) { + // In the senario there's no value set in telemetryOptedIn, we'll return optIn value + telemetryOptedIn = optIn; + } + } return { ...originalInjectedVars, @@ -93,20 +119,36 @@ const telemetry = (kibana: any) => { return { telemetryEnabled: getXpackConfigWithDeprecated(config, 'telemetry.enabled'), telemetryUrl: getXpackConfigWithDeprecated(config, 'telemetry.url'), - telemetryBanner: getXpackConfigWithDeprecated(config, 'telemetry.banner'), - telemetryOptedIn: null, + telemetryBanner: + config.get('telemetry.allowChangingOptInStatus') !== false && + getXpackConfigWithDeprecated(config, 'telemetry.banner'), + telemetryOptedIn: config.get('telemetry.optIn'), + allowChangingOptInStatus: config.get('telemetry.allowChangingOptInStatus'), }; }, hacks: ['plugins/telemetry/hacks/telemetry_init', 'plugins/telemetry/hacks/telemetry_opt_in'], mappings, }, - init(server: Server) { + async init(server: Server) { const initializerContext = { env: { packageInfo: { version: getCurrentKibanaVersion(server), }, }, + config: { + create() { + const config = server.config(); + return Rx.of({ + enabled: config.get('telemetry.enabled'), + optIn: config.get('telemetry.optIn'), + config: config.get('telemetry.config'), + banner: config.get('telemetry.banner'), + url: config.get('telemetry.url'), + allowChangingOptInStatus: config.get('telemetry.allowChangingOptInStatus'), + }); + }, + }, } as PluginInitializerContext; const coreSetup = ({ @@ -114,7 +156,7 @@ const telemetry = (kibana: any) => { log: server.log, } as any) as CoreSetup; - telemetryPlugin(initializerContext).setup(coreSetup); + await telemetryPlugin(initializerContext).setup(coreSetup); // register collectors server.usage.collectorSet.register(createLocalizationUsageCollector(server)); diff --git a/src/legacy/core_plugins/telemetry/public/components/__snapshots__/telemetry_form.test.js.snap b/src/legacy/core_plugins/telemetry/public/components/__snapshots__/telemetry_form.test.js.snap index c1ad6276aee25..e1aead3798de7 100644 --- a/src/legacy/core_plugins/telemetry/public/components/__snapshots__/telemetry_form.test.js.snap +++ b/src/legacy/core_plugins/telemetry/public/components/__snapshots__/telemetry_form.test.js.snap @@ -1,6 +1,8 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`TelemetryForm renders as expected 1`] = ` +exports[`TelemetryForm doesn't render form when not allowed to change optIn status 1`] = `""`; + +exports[`TelemetryForm renders as expected when allows to change optIn status 1`] = ` { switch (key) { case '$http': return mockHttp; + case 'allowChangingOptInStatus': + return true; default: return null; } @@ -47,7 +49,23 @@ const buildTelemetryOptInProvider = () => { }; describe('TelemetryForm', () => { - it('renders as expected', () => { + it('renders as expected when allows to change optIn status', () => { + mockInjectedMetadata({ telemetryOptedIn: null, allowChangingOptInStatus: true }); + + expect(shallowWithIntl( + ) + ).toMatchSnapshot(); + }); + + it(`doesn't render form when not allowed to change optIn status`, () => { + mockInjectedMetadata({ telemetryOptedIn: null, allowChangingOptInStatus: false }); + expect(shallowWithIntl( { const optIn = true; const bannerId = 'bruce-banner'; - mockInjectedMetadata({ telemetryOptedIn: optIn }); + mockInjectedMetadata({ telemetryOptedIn: optIn, allowChangingOptInStatus: true }); const telemetryOptInProvider = getTelemetryOptInProvider(); telemetryOptInProvider.setBannerId(bannerId); @@ -92,7 +92,7 @@ describe('click_banner', () => { remove: sinon.spy() }; const optIn = true; - mockInjectedMetadata({ telemetryOptedIn: null }); + mockInjectedMetadata({ telemetryOptedIn: null, allowChangingOptInStatus: true }); const telemetryOptInProvider = getTelemetryOptInProvider({ simulateFailure: true }); await clickBanner(telemetryOptInProvider, optIn, { _banners: banners, _toastNotifications: toastNotifications }); @@ -110,7 +110,7 @@ describe('click_banner', () => { remove: sinon.spy() }; const optIn = false; - mockInjectedMetadata({ telemetryOptedIn: null }); + mockInjectedMetadata({ telemetryOptedIn: null, allowChangingOptInStatus: true }); const telemetryOptInProvider = getTelemetryOptInProvider({ simulateError: true }); await clickBanner(telemetryOptInProvider, optIn, { _banners: banners, _toastNotifications: toastNotifications }); diff --git a/src/legacy/core_plugins/telemetry/public/hacks/welcome_banner/handle_old_settings.test.js b/src/legacy/core_plugins/telemetry/public/hacks/welcome_banner/handle_old_settings.test.js index fd21a5122b594..f26ca0ca0e3c5 100644 --- a/src/legacy/core_plugins/telemetry/public/hacks/welcome_banner/handle_old_settings.test.js +++ b/src/legacy/core_plugins/telemetry/public/hacks/welcome_banner/handle_old_settings.test.js @@ -38,7 +38,7 @@ const getTelemetryOptInProvider = (enabled, { simulateFailure = false } = {}) => const chrome = { addBasePath: url => url }; - mockInjectedMetadata({ telemetryOptedIn: enabled }); + mockInjectedMetadata({ telemetryOptedIn: enabled, allowChangingOptInStatus: true }); const $injector = { get: (key) => { diff --git a/src/legacy/core_plugins/telemetry/public/hacks/welcome_banner/should_show_banner.test.js b/src/legacy/core_plugins/telemetry/public/hacks/welcome_banner/should_show_banner.test.js index 19e7ccbe61866..240c991a75b64 100644 --- a/src/legacy/core_plugins/telemetry/public/hacks/welcome_banner/should_show_banner.test.js +++ b/src/legacy/core_plugins/telemetry/public/hacks/welcome_banner/should_show_banner.test.js @@ -38,7 +38,7 @@ const getMockInjector = () => { }; const getTelemetryOptInProvider = ({ telemetryOptedIn = null } = {}) => { - mockInjectedMetadata({ telemetryOptedIn }); + mockInjectedMetadata({ telemetryOptedIn, allowChangingOptInStatus: true }); const injector = getMockInjector(); const chrome = { addBasePath: (url) => url 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 0034fa4438238..26f14fc87d937 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 @@ -34,7 +34,7 @@ describe('TelemetryOptInProvider', () => { addBasePath: (url) => url }; - mockInjectedMetadata({ telemetryOptedIn: optedIn }); + mockInjectedMetadata({ telemetryOptedIn: optedIn, allowChangingOptInStatus: true }); const mockInjector = { get: (key) => { 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 f98f5e16e00c3..012f8de640042 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,10 +24,11 @@ import { } from '../../../../../core/public/mocks'; const injectedMetadataMock = injectedMetadataServiceMock.createStartContract(); -export function mockInjectedMetadata({ telemetryOptedIn }) { +export function mockInjectedMetadata({ telemetryOptedIn, allowChangingOptInStatus }) { const mockGetInjectedVar = jest.fn().mockImplementation((key) => { switch (key) { case 'telemetryOptedIn': return telemetryOptedIn; + case 'allowChangingOptInStatus': return allowChangingOptInStatus; 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 f4462ffea7a33..4d27bad352cd4 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 @@ -28,11 +28,15 @@ let currentOptInStatus = false; export function TelemetryOptInProvider($injector: any, chrome: any) { currentOptInStatus = npStart.core.injectedMetadata.getInjectedVar('telemetryOptedIn') as boolean; + const allowChangingOptInStatus = npStart.core.injectedMetadata.getInjectedVar( + 'allowChangingOptInStatus' + ) as boolean; setCanTrackUiMetrics(currentOptInStatus); const provider = { getBannerId: () => bannerId, getOptIn: () => currentOptInStatus, + canChangeOptInStatus: () => allowChangingOptInStatus, setBannerId(id: string) { bannerId = id; }, diff --git a/src/legacy/core_plugins/telemetry/server/plugin.ts b/src/legacy/core_plugins/telemetry/server/plugin.ts index a5f0f1234799a..813aa0df09e8c 100644 --- a/src/legacy/core_plugins/telemetry/server/plugin.ts +++ b/src/legacy/core_plugins/telemetry/server/plugin.ts @@ -29,7 +29,7 @@ export class TelemetryPlugin { this.currentKibanaVersion = initializerContext.env.packageInfo.version; } - public setup(core: CoreSetup) { + public async setup(core: CoreSetup) { const currentKibanaVersion = this.currentKibanaVersion; telemetryCollectionManager.setStatsGetter(getStats, 'local'); registerRoutes({ core, currentKibanaVersion }); diff --git a/src/legacy/core_plugins/telemetry/server/routes/index.ts b/src/legacy/core_plugins/telemetry/server/routes/index.ts index 2eb6bf95b4f45..549b3ef6068ec 100644 --- a/src/legacy/core_plugins/telemetry/server/routes/index.ts +++ b/src/legacy/core_plugins/telemetry/server/routes/index.ts @@ -27,6 +27,6 @@ interface RegisterRoutesParams { } export function registerRoutes({ core, currentKibanaVersion }: RegisterRoutesParams) { - registerOptInRoutes({ core, currentKibanaVersion }); registerTelemetryDataRoutes(core); + registerOptInRoutes({ core, currentKibanaVersion }); } diff --git a/x-pack/legacy/plugins/license_management/__jest__/__snapshots__/telemetry_opt_in.test.js.snap b/x-pack/legacy/plugins/license_management/__jest__/__snapshots__/telemetry_opt_in.test.js.snap index 642b8399ff6d1..f82e8b03527c0 100644 --- a/x-pack/legacy/plugins/license_management/__jest__/__snapshots__/telemetry_opt_in.test.js.snap +++ b/x-pack/legacy/plugins/license_management/__jest__/__snapshots__/telemetry_opt_in.test.js.snap @@ -104,7 +104,261 @@ exports[`TelemetryOptIn should display when telemetry not opted in 1`] = ` "timeZone": null, } } -/> +> + +
+ + +

+ + Help Elastic support provide better service + +

+
+ +
+ + + + + + } + className="eui-AlignBaseline" + closePopover={[Function]} + display="inlineBlock" + hasArrow={true} + id="readMorePopover" + isOpen={false} + ownFocus={true} + panelPaddingSize="m" + > + +

+ + + , + "telemetryPrivacyStatementLink": + + , + } + } + /> +

+
+ , + } + } + /> + + } + onChange={[Function]} + > +
+ +
+ +
+ + `; exports[`TelemetryOptIn should not display when telemetry is opted in 1`] = ` @@ -213,3 +467,110 @@ exports[`TelemetryOptIn should not display when telemetry is opted in 1`] = ` } /> `; + +exports[`TelemetryOptIn shouldn't display when telemetry optIn status can't change 1`] = ` + +`; diff --git a/x-pack/legacy/plugins/license_management/__jest__/telemetry_opt_in.test.js b/x-pack/legacy/plugins/license_management/__jest__/telemetry_opt_in.test.js index 4e94657e03dee..a92ca384e8a37 100644 --- a/x-pack/legacy/plugins/license_management/__jest__/telemetry_opt_in.test.js +++ b/x-pack/legacy/plugins/license_management/__jest__/telemetry_opt_in.test.js @@ -4,6 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ import React from 'react'; +import { setTelemetryEnabled, setTelemetryOptInService } from '../public/lib/telemetry'; import { TelemetryOptIn } from '../public/components/telemetry_opt_in'; import { mountWithIntl } from '../../../../test_utils/enzyme_helpers'; @@ -11,16 +12,30 @@ jest.mock('ui/capabilities', () => ({ get: jest.fn(), })); +setTelemetryEnabled(true); + describe('TelemetryOptIn', () => { test('should display when telemetry not opted in', () => { - const telemetry = require('../public/lib/telemetry'); - telemetry.showTelemetryOptIn = () => { return true; }; + setTelemetryOptInService({ + getOptIn: () => false, + canChangeOptInStatus: () => true, + }); const rendered = mountWithIntl(); expect(rendered).toMatchSnapshot(); }); test('should not display when telemetry is opted in', () => { - const telemetry = require('../public/lib/telemetry'); - telemetry.showTelemetryOptIn = () => { return false; }; + setTelemetryOptInService({ + getOptIn: () => true, + canChangeOptInStatus: () => true, + }); + const rendered = mountWithIntl(); + expect(rendered).toMatchSnapshot(); + }); + test(`shouldn't display when telemetry optIn status can't change`, () => { + setTelemetryOptInService({ + getOptIn: () => false, + canChangeOptInStatus: () => false, + }); const rendered = mountWithIntl(); expect(rendered).toMatchSnapshot(); }); diff --git a/x-pack/legacy/plugins/license_management/public/lib/telemetry.js b/x-pack/legacy/plugins/license_management/public/lib/telemetry.js index bf8bed05aabed..61d0322227d8e 100644 --- a/x-pack/legacy/plugins/license_management/public/lib/telemetry.js +++ b/x-pack/legacy/plugins/license_management/public/lib/telemetry.js @@ -25,7 +25,7 @@ export const optInToTelemetry = async (enableTelemetry) => { await telemetryOptInService.setOptIn(enableTelemetry); }; export const shouldShowTelemetryOptIn = () => { - return telemetryEnabled && !telemetryOptInService.getOptIn(); + return telemetryEnabled && !telemetryOptInService.getOptIn() && telemetryOptInService.canChangeOptInStatus(); }; export const getTelemetryFetcher = () => { return fetchTelemetry(httpClient, { unencrypted: true }); diff --git a/x-pack/legacy/plugins/ml/public/jobs/jobs_list/components/node_available_warning/index.js b/x-pack/legacy/plugins/ml/public/jobs/jobs_list/components/node_available_warning/index.ts similarity index 99% rename from x-pack/legacy/plugins/ml/public/jobs/jobs_list/components/node_available_warning/index.js rename to x-pack/legacy/plugins/ml/public/jobs/jobs_list/components/node_available_warning/index.ts index 3e3ca96a4d4c3..3ed859580762e 100644 --- a/x-pack/legacy/plugins/ml/public/jobs/jobs_list/components/node_available_warning/index.js +++ b/x-pack/legacy/plugins/ml/public/jobs/jobs_list/components/node_available_warning/index.ts @@ -4,5 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ - export { NodeAvailableWarning } from './node_available_warning'; diff --git a/x-pack/legacy/plugins/ml/public/jobs/jobs_list/components/node_available_warning/node_available_warning.js b/x-pack/legacy/plugins/ml/public/jobs/jobs_list/components/node_available_warning/node_available_warning.js deleted file mode 100644 index b8bf465eea576..0000000000000 --- a/x-pack/legacy/plugins/ml/public/jobs/jobs_list/components/node_available_warning/node_available_warning.js +++ /dev/null @@ -1,67 +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 { mlNodesAvailable, permissionToViewMlNodeCount } from 'plugins/ml/ml_nodes_check/check_ml_nodes'; - -import React from 'react'; - -import { - EuiCallOut, - EuiLink, - EuiSpacer, -} from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n/react'; - -export function NodeAvailableWarning() { - const isCloud = false; // placeholder for future specific cloud functionality - if ((mlNodesAvailable() === true) || (permissionToViewMlNodeCount() === false)) { - return (); - } else { - return ( - - )} - color="warning" - iconType="alert" - > -

-
- - - - ) - }} - /> - : '', - }} - /> -

-
- -
- ); - } -} diff --git a/x-pack/legacy/plugins/ml/public/jobs/jobs_list/components/node_available_warning/node_available_warning.tsx b/x-pack/legacy/plugins/ml/public/jobs/jobs_list/components/node_available_warning/node_available_warning.tsx new file mode 100644 index 0000000000000..17562aba8e45a --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/jobs/jobs_list/components/node_available_warning/node_available_warning.tsx @@ -0,0 +1,66 @@ +/* + * 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, { Fragment, FC } from 'react'; + +import { EuiCallOut, EuiLink, EuiSpacer } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { mlNodesAvailable, permissionToViewMlNodeCount } from '../../../../ml_nodes_check'; +import { cloudDeploymentId, isCloud } from '../../../../jobs/new_job_new/utils/new_job_defaults'; + +export const NodeAvailableWarning: FC = () => { + if (mlNodesAvailable() === true || permissionToViewMlNodeCount() === false) { + return null; + } else { + const id = cloudDeploymentId(); + return ( + + + } + color="warning" + iconType="alert" + > +

+ +
+ + {isCloud && id !== null && ( + +
+ + + + ), + }} + /> +
+ )} +

+
+ +
+ ); + } +}; diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/utils/new_job_defaults.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job_new/utils/new_job_defaults.ts index c86a5a7861b64..e3c4bc8a4a28c 100644 --- a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/utils/new_job_defaults.ts +++ b/x-pack/legacy/plugins/ml/public/jobs/new_job_new/utils/new_job_defaults.ts @@ -19,20 +19,32 @@ export interface MlServerLimits { max_model_memory_limit?: string; } +export interface CloudInfo { + cloudId: string | null; + isCloud: boolean; +} + let defaults: MlServerDefaults = { anomaly_detectors: {}, datafeeds: {}, }; let limits: MlServerLimits = {}; +const cloudInfo: CloudInfo = { + cloudId: null, + isCloud: false, +}; + export async function loadNewJobDefaults() { try { const resp = await ml.mlInfo(); defaults = resp.defaults; limits = resp.limits; - return { defaults, limits }; + cloudInfo.cloudId = resp.cloudId || null; + cloudInfo.isCloud = resp.cloudId !== undefined; + return { defaults, limits, cloudId: cloudInfo }; } catch (error) { - return { defaults, limits }; + return { defaults, limits, cloudId: cloudInfo }; } } @@ -43,3 +55,24 @@ export function newJobDefaults(): MlServerDefaults { export function newJobLimits(): MlServerLimits { return limits; } + +export function cloudId(): string | null { + return cloudInfo.cloudId; +} + +export function isCloud(): boolean { + return cloudInfo.isCloud; +} + +export function cloudDeploymentId(): string | null { + if (cloudInfo.cloudId === null) { + return null; + } + const tempCloudId = cloudInfo.cloudId.replace(/^.+:/, ''); + try { + const matches = atob(tempCloudId).match(/^.+\$(.+)(?=\$)/); + return matches !== null && matches.length === 2 ? matches[1] : null; + } catch (error) { + return null; + } +} 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 2e7da6fb9cc69..22062331bb380 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 @@ -54,6 +54,7 @@ export interface MlInfoResponse { version: string; }; upgrade_mode: boolean; + cloudId?: string; } declare interface Ml { diff --git a/x-pack/legacy/plugins/ml/server/routes/system.js b/x-pack/legacy/plugins/ml/server/routes/system.js index 8ca285eb23608..a686971672c58 100644 --- a/x-pack/legacy/plugins/ml/server/routes/system.js +++ b/x-pack/legacy/plugins/ml/server/routes/system.js @@ -21,6 +21,7 @@ import { isSecurityDisabled } from '../lib/security_utils'; export function systemRoutes({ commonRouteConfig, elasticsearchPlugin, + config, route, xpackMainPlugin, spacesPlugin @@ -168,10 +169,17 @@ export function systemRoutes({ route({ method: 'GET', path: '/api/ml/info', - handler(request) { + async handler(request) { const callWithRequest = callWithRequestFactory(elasticsearchPlugin, request); - return callWithRequest('ml.info') - .catch(resp => wrapError(resp)); + + try { + const info = await callWithRequest('ml.info'); + const cloudIdKey = 'xpack.cloud.id'; + const cloudId = config.has(cloudIdKey) && config.get(cloudIdKey); + return { ...info, cloudId }; + } catch (error) { + return wrapError(error); + } }, config: { ...commonRouteConfig diff --git a/x-pack/legacy/plugins/uptime/common/constants/plugin.ts b/x-pack/legacy/plugins/uptime/common/constants/plugin.ts index eeb0683fc9bbb..93c3f00a0a45c 100644 --- a/x-pack/legacy/plugins/uptime/common/constants/plugin.ts +++ b/x-pack/legacy/plugins/uptime/common/constants/plugin.ts @@ -7,6 +7,6 @@ export const PLUGIN = { APP_ROOT_ID: 'react-uptime-root', ID: 'uptime', - ROUTER_BASE_NAME: '/app/uptime', + ROUTER_BASE_NAME: '/app/uptime#', LOCAL_STORAGE_KEY: 'xpack.uptime', }; diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 50752b6bf11c3..0f3bc1b08d306 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -7438,10 +7438,8 @@ "xpack.ml.jobsList.multiJobsActions.startDatafeedsLabel": "{jobsCount, plural, one {データフィード} other {データフィード}}を開始", "xpack.ml.jobsList.multiJobsActions.stopDatafeedsLabel": "{jobsCount, plural, one {データフィード} other {データフィード}}を停止", "xpack.ml.jobsList.nodeAvailableWarning.linkToCloud.hereLinkText": "こちら", - "xpack.ml.jobsList.nodeAvailableWarning.linkToCloudDescription": "これはクラウド {hereCloudLink} で構成できます。", "xpack.ml.jobsList.nodeAvailableWarning.noMLNodesAvailableDescription": "利用可能な ML ノードがありません。", "xpack.ml.jobsList.nodeAvailableWarning.noMLNodesAvailableTitle": "利用可能な ML ノードがありません", - "xpack.ml.jobsList.nodeAvailableWarning.unavailableCreateOrRunJobsDescription": "ジョブの作成または実行はできません. {cloudConfigLink}", "xpack.ml.jobsList.noJobsFoundLabel": "ジョブが見つかりません", "xpack.ml.jobsList.processedRecordsLabel": "処理済みレコード", "xpack.ml.jobsList.refreshButtonLabel": "更新", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 29dcb2c2af35e..8311ed350a796 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -7440,10 +7440,8 @@ "xpack.ml.jobsList.multiJobsActions.startDatafeedsLabel": "开始 {jobsCount, plural, one { 个数据馈送} other { 个数据馈送}}", "xpack.ml.jobsList.multiJobsActions.stopDatafeedsLabel": "停止 {jobsCount, plural, one { 个数据馈送} other { 个数据馈送}}", "xpack.ml.jobsList.nodeAvailableWarning.linkToCloud.hereLinkText": "此处", - "xpack.ml.jobsList.nodeAvailableWarning.linkToCloudDescription": "这可以在云 {hereCloudLink} 中进行配置。", "xpack.ml.jobsList.nodeAvailableWarning.noMLNodesAvailableDescription": "没有可用的 ML 节点。", "xpack.ml.jobsList.nodeAvailableWarning.noMLNodesAvailableTitle": "没有可用的 ML 节点", - "xpack.ml.jobsList.nodeAvailableWarning.unavailableCreateOrRunJobsDescription": "您将无法创建或运行作业。{cloudConfigLink}", "xpack.ml.jobsList.noJobsFoundLabel": "找不到作业", "xpack.ml.jobsList.processedRecordsLabel": "已处理记录", "xpack.ml.jobsList.refreshButtonLabel": "刷新", @@ -13008,4 +13006,4 @@ "xpack.lens.xyVisualization.stackedBarLabel": "堆叠条形图", "xpack.lens.xyVisualization.xyLabel": "XY" } -} +} \ No newline at end of file