diff --git a/src/core_plugins/kibana/public/home/components/__snapshots__/add_data.test.js.snap b/src/core_plugins/kibana/public/home/components/__snapshots__/add_data.test.js.snap index 51d080ee62c4c4..eeb15bf7877518 100644 --- a/src/core_plugins/kibana/public/home/components/__snapshots__/add_data.test.js.snap +++ b/src/core_plugins/kibana/public/home/components/__snapshots__/add_data.test.js.snap @@ -23,14 +23,22 @@ exports[`apmUiEnabled 1`] = ` size="m" >

- Add Data to Kibana +

- Use these solutions to quickly turn your data into pre-built dashboards and monitoring systems. +

@@ -63,7 +71,11 @@ exports[`apmUiEnabled 1`] = ` iconSide="left" type="button" > - Add APM + } icon={ @@ -95,7 +107,11 @@ exports[`apmUiEnabled 1`] = ` iconSide="left" type="button" > - Add log data + } icon={ @@ -127,7 +143,11 @@ exports[`apmUiEnabled 1`] = ` iconSide="left" type="button" > - Add metric data + } icon={ @@ -159,7 +179,11 @@ exports[`apmUiEnabled 1`] = ` iconSide="left" type="button" > - Add security events + } icon={ @@ -204,7 +228,11 @@ exports[`apmUiEnabled 1`] = ` } } > - Sample Data + - Load a data set and a Kibana dashboard + @@ -235,7 +267,11 @@ exports[`apmUiEnabled 1`] = ` } } > - Your Data + - Connect to your Elasticsearch index + @@ -278,14 +318,22 @@ exports[`isNewKibanaInstance 1`] = ` size="m" >

- Add Data to Kibana +

- Use these solutions to quickly turn your data into pre-built dashboards and monitoring systems. +

@@ -318,7 +366,11 @@ exports[`isNewKibanaInstance 1`] = ` iconSide="left" type="button" > - Add log data + } icon={ @@ -350,7 +402,11 @@ exports[`isNewKibanaInstance 1`] = ` iconSide="left" type="button" > - Add metric data + } icon={ @@ -382,7 +438,11 @@ exports[`isNewKibanaInstance 1`] = ` iconSide="left" type="button" > - Add security events + } icon={ @@ -427,7 +487,11 @@ exports[`isNewKibanaInstance 1`] = ` } } > - Sample Data + - Load a data set and a Kibana dashboard + @@ -458,7 +526,11 @@ exports[`isNewKibanaInstance 1`] = ` } } > - Your Data + - Connect to your Elasticsearch index + @@ -501,14 +577,22 @@ exports[`render 1`] = ` size="m" >

- Add Data to Kibana +

- Use these solutions to quickly turn your data into pre-built dashboards and monitoring systems. +

@@ -541,7 +625,11 @@ exports[`render 1`] = ` iconSide="left" type="button" > - Add log data + } icon={ @@ -573,7 +661,11 @@ exports[`render 1`] = ` iconSide="left" type="button" > - Add metric data + } icon={ @@ -605,7 +697,11 @@ exports[`render 1`] = ` iconSide="left" type="button" > - Add security events + } icon={ @@ -650,7 +746,11 @@ exports[`render 1`] = ` } } > - Sample Data + - Load a data set and a Kibana dashboard + @@ -681,7 +785,11 @@ exports[`render 1`] = ` } } > - Your Data + - Connect to your Elasticsearch index + diff --git a/src/core_plugins/kibana/public/home/components/__snapshots__/home.test.js.snap b/src/core_plugins/kibana/public/home/components/__snapshots__/home.test.js.snap index 4f245a6cc8ef7d..1781469eacfeff 100644 --- a/src/core_plugins/kibana/public/home/components/__snapshots__/home.test.js.snap +++ b/src/core_plugins/kibana/public/home/components/__snapshots__/home.test.js.snap @@ -8,7 +8,7 @@ exports[`home directories should not render directory entry when showOnHomePage - @@ -37,7 +37,11 @@ exports[`home directories should not render directory entry when showOnHomePage size="m" >

- Visualize and Explore Data +

- Manage and Administer the Elastic Stack +

- Didn’t find what you were looking for? +

- View full directory of Kibana plugins + @@ -126,7 +142,7 @@ exports[`home directories should render ADMIN directory entry in "Manage" panel - @@ -155,7 +171,11 @@ exports[`home directories should render ADMIN directory entry in "Manage" panel size="m" >

- Visualize and Explore Data +

- Manage and Administer the Elastic Stack +

- Didn’t find what you were looking for? +

- View full directory of Kibana plugins + @@ -263,7 +295,7 @@ exports[`home directories should render DATA directory entry in "Explore Data" p - @@ -292,7 +324,11 @@ exports[`home directories should render DATA directory entry in "Explore Data" p size="m" >

- Visualize and Explore Data +

- Manage and Administer the Elastic Stack +

- Didn’t find what you were looking for? +

- View full directory of Kibana plugins + @@ -400,7 +448,7 @@ exports[`home isNewKibanaInstance should safely handle execeptions 1`] = ` - @@ -429,7 +477,11 @@ exports[`home isNewKibanaInstance should safely handle execeptions 1`] = ` size="m" >

- Visualize and Explore Data +

- Manage and Administer the Elastic Stack +

- Didn’t find what you were looking for? +

- View full directory of Kibana plugins + @@ -518,7 +582,7 @@ exports[`home isNewKibanaInstance should set isNewKibanaInstance to false when t - @@ -547,7 +611,11 @@ exports[`home isNewKibanaInstance should set isNewKibanaInstance to false when t size="m" >

- Visualize and Explore Data +

- Manage and Administer the Elastic Stack +

- Didn’t find what you were looking for? +

- View full directory of Kibana plugins + @@ -636,7 +716,7 @@ exports[`home isNewKibanaInstance should set isNewKibanaInstance to true when th - @@ -665,7 +745,11 @@ exports[`home isNewKibanaInstance should set isNewKibanaInstance to true when th size="m" >

- Visualize and Explore Data +

- Manage and Administer the Elastic Stack +

- Didn’t find what you were looking for? +

- View full directory of Kibana plugins + @@ -754,7 +850,7 @@ exports[`home should not contain RecentlyAccessed panel when there is no recentl - @@ -783,7 +879,11 @@ exports[`home should not contain RecentlyAccessed panel when there is no recentl size="m" >

- Visualize and Explore Data +

- Manage and Administer the Elastic Stack +

- Didn’t find what you were looking for? +

- View full directory of Kibana plugins + @@ -888,7 +1000,7 @@ exports[`home should render home component 1`] = ` size="l" /> - @@ -917,7 +1029,11 @@ exports[`home should render home component 1`] = ` size="m" >

- Visualize and Explore Data +

- Manage and Administer the Elastic Stack +

- Didn’t find what you were looking for? +

- View full directory of Kibana plugins + @@ -1006,7 +1134,7 @@ exports[`home welcome should show the normal home page if loading fails 1`] = ` - @@ -1035,7 +1163,11 @@ exports[`home welcome should show the normal home page if loading fails 1`] = ` size="m" >

- Visualize and Explore Data +

- Manage and Administer the Elastic Stack +

- Didn’t find what you were looking for? +

- View full directory of Kibana plugins + @@ -1124,7 +1268,7 @@ exports[`home welcome should show the normal home page if welcome screen is disa - @@ -1153,7 +1297,11 @@ exports[`home welcome should show the normal home page if welcome screen is disa size="m" >

- Visualize and Explore Data +

- Manage and Administer the Elastic Stack +

- Didn’t find what you were looking for? +

- View full directory of Kibana plugins + @@ -1249,7 +1409,7 @@ exports[`home welcome stores skip welcome setting if skipped 1`] = ` - @@ -1278,7 +1438,11 @@ exports[`home welcome stores skip welcome setting if skipped 1`] = ` size="m" >

- Visualize and Explore Data +

- Manage and Administer the Elastic Stack +

- Didn’t find what you were looking for? +

- View full directory of Kibana plugins + diff --git a/src/core_plugins/kibana/public/home/components/__snapshots__/recently_accessed.test.js.snap b/src/core_plugins/kibana/public/home/components/__snapshots__/recently_accessed.test.js.snap index 98bd8db229a85d..c0e0c3ad3f2b4e 100644 --- a/src/core_plugins/kibana/public/home/components/__snapshots__/recently_accessed.test.js.snap +++ b/src/core_plugins/kibana/public/home/components/__snapshots__/recently_accessed.test.js.snap @@ -14,7 +14,11 @@ exports[`render 1`] = ` color="subdued" component="span" > - Recently viewed + diff --git a/src/core_plugins/kibana/public/home/components/add_data.js b/src/core_plugins/kibana/public/home/components/add_data.js index 1b2e04164a7295..827143d1bffb8e 100644 --- a/src/core_plugins/kibana/public/home/components/add_data.js +++ b/src/core_plugins/kibana/public/home/components/add_data.js @@ -20,6 +20,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import classNames from 'classnames'; +import { injectI18n, FormattedMessage } from '@kbn/i18n/react'; import { EuiButton, @@ -35,22 +36,54 @@ import { EuiHorizontalRule, } from '@elastic/eui'; -export function AddData({ apmUiEnabled, isNewKibanaInstance }) { +const AddDataUi = ({ apmUiEnabled, isNewKibanaInstance, intl }) => { const renderCards = () => { + const apmTitle = intl.formatMessage({ + id: 'kbn.home.addData.apm.nameTitle', defaultMessage: 'APM' + }); + const apmDescription = intl.formatMessage({ + id: 'kbn.home.addData.apm.nameDescription', + defaultMessage: 'APM automatically collects in-depth performance metrics and errors from inside your applications.' + }); + const loggingTitle = intl.formatMessage({ + id: 'kbn.home.addData.logging.nameTitle', defaultMessage: 'Logging' + }); + const loggingDescription = intl.formatMessage({ + id: 'kbn.home.addData.logging.nameDescription', + defaultMessage: 'Ingest logs from popular data sources and easily visualize in preconfigured dashboards.' + }); + const metricsTitle = intl.formatMessage({ + id: 'kbn.home.addData.metrics.nameTitle', defaultMessage: 'Metrics' + }); + const metricsDescription = intl.formatMessage({ + id: 'kbn.home.addData.metrics.nameDescription', + defaultMessage: 'Collect metrics from the operating system and services running on your servers.' + }); + const securityTitle = intl.formatMessage({ + id: 'kbn.home.addData.security.nameTitle', defaultMessage: 'Security Analytics' + }); + const securityDescription = intl.formatMessage({ + id: 'kbn.home.addData.security.nameDescription', + defaultMessage: 'Centralize security events for interactive investigation in ready-to-go visualizations.' + }); + const getApmCard = () => ( } - title="APM" - description="APM automatically collects in-depth performance metrics and errors from inside your applications." + title={apmTitle} + description={apmDescription} footer={ - Add APM + } /> @@ -66,14 +99,17 @@ export function AddData({ apmUiEnabled, isNewKibanaInstance }) { } - title="Logging" - description="Ingest logs from popular data sources and easily visualize in preconfigured dashboards." + title={loggingTitle} + description={loggingDescription} footer={ - Add log data + } /> @@ -83,14 +119,17 @@ export function AddData({ apmUiEnabled, isNewKibanaInstance }) { } - title="Metrics" - description="Collect metrics from the operating system and services running on your servers." + title={metricsTitle} + description={metricsDescription} footer={ - Add metric data + } /> @@ -100,14 +139,17 @@ export function AddData({ apmUiEnabled, isNewKibanaInstance }) { } - title="Security Analytics" - description="Centralize security events for interactive investigation in ready-to-go visualizations." + title={securityTitle} + description={securityDescription} footer={ - Add security events + } /> @@ -123,11 +165,19 @@ export function AddData({ apmUiEnabled, isNewKibanaInstance }) { -

Add Data to Kibana

+

+ +

- Use these solutions to quickly turn your data into pre-built dashboards and monitoring systems. +

@@ -143,26 +193,38 @@ export function AddData({ apmUiEnabled, isNewKibanaInstance }) { - Sample Data + - Load a data set and a Kibana dashboard + - Your Data + - Connect to your Elasticsearch index + @@ -172,9 +234,11 @@ export function AddData({ apmUiEnabled, isNewKibanaInstance }) { ); -} +}; -AddData.propTypes = { +AddDataUi.propTypes = { apmUiEnabled: PropTypes.bool.isRequired, isNewKibanaInstance: PropTypes.bool.isRequired, }; + +export const AddData = injectI18n(AddDataUi); diff --git a/src/core_plugins/kibana/public/home/components/add_data.test.js b/src/core_plugins/kibana/public/home/components/add_data.test.js index 3ed8dafe860a80..549990eb99ffa4 100644 --- a/src/core_plugins/kibana/public/home/components/add_data.test.js +++ b/src/core_plugins/kibana/public/home/components/add_data.test.js @@ -18,11 +18,11 @@ */ import React from 'react'; -import { shallow } from 'enzyme'; import { AddData } from './add_data'; +import { shallowWithIntl } from 'test_utils/enzyme_helpers'; test('render', () => { - const component = shallow(); @@ -30,7 +30,7 @@ test('render', () => { }); test('apmUiEnabled', () => { - const component = shallow(); @@ -38,7 +38,7 @@ test('apmUiEnabled', () => { }); test('isNewKibanaInstance', () => { - const component = shallow(); diff --git a/src/core_plugins/kibana/public/home/components/feature_directory.js b/src/core_plugins/kibana/public/home/components/feature_directory.js index ce7371fbff092f..e3ccd6774f4a7a 100644 --- a/src/core_plugins/kibana/public/home/components/feature_directory.js +++ b/src/core_plugins/kibana/public/home/components/feature_directory.js @@ -33,6 +33,9 @@ import { import { FeatureCatalogueCategory } from 'ui/registry/feature_catalogue'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; + const ALL_TAB_ID = 'all'; const OTHERS_TAB_ID = 'others'; @@ -47,18 +50,18 @@ export class FeatureDirectory extends React.Component { this.tabs = [{ id: ALL_TAB_ID, - name: 'All', + name: i18n.translate('kbn.home.directory.tabs.allTitle', { defaultMessage: 'All' }), }, { id: FeatureCatalogueCategory.DATA, - name: 'Data Exploration & Visualization', + name: i18n.translate('kbn.home.directory.tabs.dataTitle', { defaultMessage: 'Data Exploration & Visualization' }), }, { id: FeatureCatalogueCategory.ADMIN, - name: 'Administrative', + name: i18n.translate('kbn.home.directory.tabs.administrativeTitle', { defaultMessage: 'Administrative' }), }]; if (props.directories.some(isOtherCategory)) { this.tabs.push({ id: OTHERS_TAB_ID, - name: 'Other', + name: i18n.translate('kbn.home.directory.tabs.otherTitle', { defaultMessage: 'Other' }), }); } @@ -117,7 +120,10 @@ export class FeatureDirectory extends React.Component {

- Directory +

diff --git a/src/core_plugins/kibana/public/home/components/home.js b/src/core_plugins/kibana/public/home/components/home.js index 5cf09eb239d2a0..4bcd66ca56a326 100644 --- a/src/core_plugins/kibana/public/home/components/home.js +++ b/src/core_plugins/kibana/public/home/components/home.js @@ -22,6 +22,7 @@ import PropTypes from 'prop-types'; import { Synopsis } from './synopsis'; import { AddData } from './add_data'; import { RecentlyAccessed, recentlyAccessedShape } from './recently_accessed'; +import { FormattedMessage } from '@kbn/i18n/react'; import { EuiButton, @@ -156,7 +157,12 @@ export class Home extends Component { -

Visualize and Explore Data

+

+ +

@@ -167,7 +173,12 @@ export class Home extends Component { -

Manage and Administer the Elastic Stack

+

+ +

@@ -182,11 +193,19 @@ export class Home extends Component { -

Didn’t find what you were looking for?

+

+ +

- View full directory of Kibana plugins +
diff --git a/src/core_plugins/kibana/public/home/components/home_app.js b/src/core_plugins/kibana/public/home/components/home_app.js index d277fd542f70d7..e27356b06196df 100644 --- a/src/core_plugins/kibana/public/home/components/home_app.js +++ b/src/core_plugins/kibana/public/home/components/home_app.js @@ -32,6 +32,7 @@ import { getTutorial } from '../load_tutorials'; import { replaceTemplateStrings } from './tutorial/replace_template_strings'; import chrome from 'ui/chrome'; import { recentlyAccessedShape } from './recently_accessed'; +import { I18nProvider } from '@kbn/i18n/react'; export function HomeApp({ addBasePath, @@ -73,39 +74,41 @@ export function HomeApp({ }; return ( - - - - - - + + + - - - - - - + + + + + + + + + ); } diff --git a/src/core_plugins/kibana/public/home/components/recently_accessed.js b/src/core_plugins/kibana/public/home/components/recently_accessed.js index b0dbfb888d0bf5..a14d494b0ef5e9 100644 --- a/src/core_plugins/kibana/public/home/components/recently_accessed.js +++ b/src/core_plugins/kibana/public/home/components/recently_accessed.js @@ -34,6 +34,8 @@ import { EuiTitle, } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n/react'; + export const NUM_LONG_LINKS = 5; export class RecentlyAccessed extends Component { @@ -197,7 +199,10 @@ export class RecentlyAccessed extends Component {

- Recently viewed +

diff --git a/src/core_plugins/kibana/public/home/components/recently_accessed.test.js b/src/core_plugins/kibana/public/home/components/recently_accessed.test.js index c412664be696e8..8986586a0cf1ea 100644 --- a/src/core_plugins/kibana/public/home/components/recently_accessed.test.js +++ b/src/core_plugins/kibana/public/home/components/recently_accessed.test.js @@ -18,9 +18,10 @@ */ import React from 'react'; -import { shallow, mount } from 'enzyme'; +import { shallow } from 'enzyme'; import { RecentlyAccessed, NUM_LONG_LINKS } from './recently_accessed'; import { findTestSubject } from '@elastic/eui/lib/test'; +import { mountWithIntl } from 'test_utils/enzyme_helpers'; const createRecentlyAccessed = (length) => { const recentlyAccessed = []; @@ -44,7 +45,7 @@ test('render', () => { describe('more popover', () => { test('should not be rendered when recently accessed list size is less than NUM_LONG_LINKS', () => { - const component = mount(); @@ -53,7 +54,7 @@ describe('more popover', () => { }); test('should not be rendered when recently accessed list size is NUM_LONG_LINKS', () => { - const component = mount(); @@ -63,7 +64,7 @@ describe('more popover', () => { describe('recently accessed list size exceeds NUM_LONG_LINKS', () => { test('should be rendered', () => { - const component = mount(); @@ -73,7 +74,7 @@ describe('more popover', () => { test('should only contain overflow recently accessed items when opened', () => { const numberOfRecentlyAccessed = NUM_LONG_LINKS + 2; - const component = mount(); diff --git a/src/core_plugins/kibana/public/home/components/sample_data_set_card.js b/src/core_plugins/kibana/public/home/components/sample_data_set_card.js index a19eaf1c5dd8a8..74a08f84cc76c2 100644 --- a/src/core_plugins/kibana/public/home/components/sample_data_set_card.js +++ b/src/core_plugins/kibana/public/home/components/sample_data_set_card.js @@ -31,6 +31,8 @@ import { export const INSTALLED_STATUS = 'installed'; export const UNINSTALLED_STATUS = 'not_installed'; +import { FormattedMessage } from '@kbn/i18n/react'; + export class SampleDataSetCard extends React.Component { isInstalled = () => { @@ -61,7 +63,15 @@ export class SampleDataSetCard extends React.Component { color="danger" data-test-subj={`removeSampleDataSet${this.props.id}`} > - {this.props.isProcessing ? 'Removing' : 'Remove'} + {this.props.isProcessing + ? + : }
@@ -69,7 +79,10 @@ export class SampleDataSetCard extends React.Component { href={this.props.launchUrl} data-test-subj={`launchSampleDataSet${this.props.id}`} > - View data +
@@ -84,7 +97,16 @@ export class SampleDataSetCard extends React.Component { onClick={this.install} data-test-subj={`addSampleDataSet${this.props.id}`} > - {this.props.isProcessing ? 'Adding' : 'Add'} + {this.props.isProcessing + ? + : + }
@@ -96,13 +118,24 @@ export class SampleDataSetCard extends React.Component { {`Unable to verify dataset status, error: ${this.props.statusMsg}`}

} + content={ +

+ +

+ } > - {'Add'} +
diff --git a/src/core_plugins/kibana/public/home/components/sample_data_set_cards.js b/src/core_plugins/kibana/public/home/components/sample_data_set_cards.js index 4f50af96778764..6d0c25498f3d3d 100644 --- a/src/core_plugins/kibana/public/home/components/sample_data_set_cards.js +++ b/src/core_plugins/kibana/public/home/components/sample_data_set_cards.js @@ -39,6 +39,8 @@ import { uninstallSampleDataSet } from '../sample_data_sets'; +import { i18n } from '@kbn/i18n'; + export class SampleDataSetCards extends React.Component { constructor(props) { @@ -66,7 +68,9 @@ export class SampleDataSetCards extends React.Component { sampleDataSets = await listSampleDataSets(); } catch (fetchError) { toastNotifications.addDanger({ - title: `Unable to load sample data sets list`, + title: i18n.translate('kbn.home.sampleDataSet.unableToLoadListErrorMessage', { + defaultMessage: 'Unable to load sample data sets list' } + ), text: `${fetchError.message}`, }); sampleDataSets = []; @@ -109,7 +113,9 @@ export class SampleDataSetCards extends React.Component { })); } toastNotifications.addDanger({ - title: `Unable to install sample data set: ${targetSampleDataSet.name}`, + title: i18n.translate('kbn.home.sampleDataSet.unableToInstallErrorMessage', { + defaultMessage: 'Unable to install sample data set: {name}', values: { name: targetSampleDataSet.name } } + ), text: `${fetchError.message}`, }); return; @@ -125,7 +131,9 @@ export class SampleDataSetCards extends React.Component { }), })); toastNotifications.addSuccess({ - title: `${targetSampleDataSet.name} installed`, + title: i18n.translate('kbn.home.sampleDataSet.installedLabel', { + defaultMessage: '{name} installed', values: { name: targetSampleDataSet.name } } + ), ['data-test-subj']: 'sampleDataSetInstallToast' }); } @@ -154,7 +162,9 @@ export class SampleDataSetCards extends React.Component { })); } toastNotifications.addDanger({ - title: `Unable to uninstall sample data set: ${targetSampleDataSet.name}`, + title: i18n.translate('kbn.home.sampleDataSet.unableToUninstallErrorMessage', { + defaultMessage: 'Unable to uninstall sample data set: {name}', values: { name: targetSampleDataSet.name } } + ), text: `${fetchError.message}`, }); return; @@ -170,7 +180,9 @@ export class SampleDataSetCards extends React.Component { }), })); toastNotifications.addSuccess({ - title: `${targetSampleDataSet.name} uninstalled`, + title: i18n.translate('kbn.home.sampleDataSet.uninstalledLabel', { + defaultMessage: '{name} uninstalled', values: { name: targetSampleDataSet.name } } + ), ['data-test-subj']: 'sampleDataSetUninstallToast' }); } diff --git a/src/core_plugins/kibana/public/home/components/tutorial/__snapshots__/footer.test.js.snap b/src/core_plugins/kibana/public/home/components/tutorial/__snapshots__/footer.test.js.snap index 3520cd93cbb8e5..e72aadd0bcae71 100644 --- a/src/core_plugins/kibana/public/home/components/tutorial/__snapshots__/footer.test.js.snap +++ b/src/core_plugins/kibana/public/home/components/tutorial/__snapshots__/footer.test.js.snap @@ -23,7 +23,11 @@ exports[`render 1`] = ` grow={true} >

- When all steps are complete, you're ready to explore your data. +

diff --git a/src/core_plugins/kibana/public/home/components/tutorial/__snapshots__/introduction.test.js.snap b/src/core_plugins/kibana/public/home/components/tutorial/__snapshots__/introduction.test.js.snap index 48e1bc15b6ea61..9ada357a7380dc 100644 --- a/src/core_plugins/kibana/public/home/components/tutorial/__snapshots__/introduction.test.js.snap +++ b/src/core_plugins/kibana/public/home/components/tutorial/__snapshots__/introduction.test.js.snap @@ -57,7 +57,11 @@ exports[`props exportedFieldsUrl 1`] = ` target="_blank" type="button" > - View exported fields + diff --git a/src/core_plugins/kibana/public/home/components/tutorial/__snapshots__/saved_objects_installer.test.js.snap b/src/core_plugins/kibana/public/home/components/tutorial/__snapshots__/saved_objects_installer.test.js.snap index 802135f11e8092..6a0f123c229070 100644 --- a/src/core_plugins/kibana/public/home/components/tutorial/__snapshots__/saved_objects_installer.test.js.snap +++ b/src/core_plugins/kibana/public/home/components/tutorial/__snapshots__/saved_objects_installer.test.js.snap @@ -1,8 +1,144 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`bulkCreate should display error message when bulkCreate request fails 1`] = ` - , "key": "installStep", @@ -199,7 +335,7 @@ exports[`bulkCreate should display error message when bulkCreate request fails 1 color="warning" data-test-subj="loadSavedObjects_failed" size="m" - title="Request failed, Error: simulated bulkRequest error" + title="Request failed, Error: {message}" >
- Request failed, Error: simulated bulkRequest error + Request failed, Error: {message}
@@ -221,12 +357,97 @@ exports[`bulkCreate should display error message when bulkCreate request fails 1 -
+ `; exports[`bulkCreate should display success message when bulkCreate is successful 1`] = ` - , "key": "installStep", @@ -463,7 +684,7 @@ exports[`bulkCreate should display success message when bulkCreate is successful color="success" data-test-subj="loadSavedObjects_success" size="m" - title="1 saved objects successfully added" + title="{savedObjectsLength} saved objects successfully added" >
- 1 saved objects successfully added + {savedObjectsLength} saved objects successfully added
@@ -485,7 +706,7 @@ exports[`bulkCreate should display success message when bulkCreate is successful -
+ `; exports[`renders 1`] = ` diff --git a/src/core_plugins/kibana/public/home/components/tutorial/__snapshots__/tutorial.test.js.snap b/src/core_plugins/kibana/public/home/components/tutorial/__snapshots__/tutorial.test.js.snap index debe5319704b8c..84a98a3a7b7848 100644 --- a/src/core_plugins/kibana/public/home/components/tutorial/__snapshots__/tutorial.test.js.snap +++ b/src/core_plugins/kibana/public/home/components/tutorial/__snapshots__/tutorial.test.js.snap @@ -48,7 +48,7 @@ exports[`isCloudEnabled is false should not render instruction toggle when ON_PR hasShadow={false} paddingSize="l" > - - - @@ -38,7 +40,10 @@ export function Footer({ url, label }) {

- {`When all steps are complete, you're ready to explore your data.`} +

diff --git a/src/core_plugins/kibana/public/home/components/tutorial/instruction.js b/src/core_plugins/kibana/public/home/components/tutorial/instruction.js index 07418f35ba883c..b8cf63c171dbb8 100644 --- a/src/core_plugins/kibana/public/home/components/tutorial/instruction.js +++ b/src/core_plugins/kibana/public/home/components/tutorial/instruction.js @@ -30,6 +30,8 @@ import { EuiButton, } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n/react'; + export function Instruction({ commands, paramValues, textPost, textPre, replaceTemplateStrings }) { let pre; if (textPre) { @@ -65,7 +67,7 @@ export function Instruction({ commands, paramValues, textPost, textPre, replaceT size="s" onClick={copy} > - Copy snippet + )} diff --git a/src/core_plugins/kibana/public/home/components/tutorial/instruction_set.js b/src/core_plugins/kibana/public/home/components/tutorial/instruction_set.js index 9d5a4cbc5f0bf7..d3b5ea4744177d 100644 --- a/src/core_plugins/kibana/public/home/components/tutorial/instruction_set.js +++ b/src/core_plugins/kibana/public/home/components/tutorial/instruction_set.js @@ -40,7 +40,9 @@ import { } from '@elastic/eui'; import * as StatusCheckStates from './status_check_states'; -export class InstructionSet extends React.Component { +import { injectI18n, FormattedMessage } from '@kbn/i18n/react'; + +class InstructionSetUi extends React.Component { constructor(props) { super(props); @@ -93,12 +95,18 @@ export class InstructionSet extends React.Component { case StatusCheckStates.FETCHING: return null; // Don't show any message while fetching or if you haven't yet checked. case StatusCheckStates.HAS_DATA: - message = this.props.statusCheckConfig.success ? this.props.statusCheckConfig.success : 'Success'; + message = this.props.statusCheckConfig.success + ? this.props.statusCheckConfig.success + : this.props.intl.formatMessage({ id: 'kbn.home.tutorial.instractionSet.successLabel', + defaultMessage: 'Success' }); color = 'success'; break; case StatusCheckStates.ERROR: case StatusCheckStates.NO_DATA: - message = this.props.statusCheckConfig.error ? this.props.statusCheckConfig.error : 'No data found'; + message = this.props.statusCheckConfig.error + ? this.props.statusCheckConfig.error + : this.props.intl.formatMessage({ id: 'kbn.home.tutorial.instractionSet.noDataLabel', + defaultMessage: 'No data found' }); color = 'warning'; break; } @@ -145,7 +153,10 @@ export class InstructionSet extends React.Component { onClick={onStatusCheck} isLoading={statusCheckState === StatusCheckStates.FETCHING} > - {statusCheckConfig.btnLabel || 'Check status'} + {statusCheckConfig.btnLabel || } @@ -157,7 +168,9 @@ export class InstructionSet extends React.Component { ); return { - title: statusCheckConfig.title || 'Status Check', + title: statusCheckConfig.title || this.props.intl.formatMessage({ id: 'kbn.home.tutorial.instractionSet.statusCheckTitle', + defaultMessage: 'Status Check' + }), status: this.getStepStatus(statusCheckState), children: checkStatusStep, key: 'checkStatusStep' @@ -208,16 +221,22 @@ export class InstructionSet extends React.Component { 'fa-caret-right': !this.state.isParamFormVisible, 'fa-caret-down': this.state.isParamFormVisible }); + const ariaLabel = this.props.intl.formatMessage({ id: 'kbn.home.tutorial.instractionSet.toggleAriaLabel', + defaultMessage: 'toggle command parameters visibility' + }); paramsVisibilityToggle = (
- Customize your code snippets +
@@ -291,7 +310,7 @@ const statusCheckConfigShape = PropTypes.shape({ btnLabel: PropTypes.string, }); -InstructionSet.propTypes = { +InstructionSetUi.propTypes = { title: PropTypes.string.isRequired, instructionVariants: PropTypes.arrayOf(instructionVariantShape).isRequired, statusCheckConfig: statusCheckConfigShape, @@ -309,3 +328,5 @@ InstructionSet.propTypes = { setParameter: PropTypes.func, replaceTemplateStrings: PropTypes.func.isRequired, }; + +export const InstructionSet = injectI18n(InstructionSetUi); diff --git a/src/core_plugins/kibana/public/home/components/tutorial/instruction_set.test.js b/src/core_plugins/kibana/public/home/components/tutorial/instruction_set.test.js index f3ce7770dff821..84ed073f277441 100644 --- a/src/core_plugins/kibana/public/home/components/tutorial/instruction_set.test.js +++ b/src/core_plugins/kibana/public/home/components/tutorial/instruction_set.test.js @@ -18,7 +18,7 @@ */ import React from 'react'; -import { shallow } from 'enzyme'; +import { shallowWithIntl } from 'test_utils/enzyme_helpers'; import { InstructionSet, @@ -52,7 +52,7 @@ const instructionVariants = [ ]; test('render', () => { - const component = shallow( {}} @@ -73,7 +73,7 @@ describe('statusCheckState', () => { }; test('initial state - no check has been attempted', () => { - const component = shallow( {}} @@ -87,7 +87,7 @@ describe('statusCheckState', () => { }); test('checking status', () => { - const component = shallow( {}} @@ -101,7 +101,7 @@ describe('statusCheckState', () => { }); test('failed status check - error', () => { - const component = shallow( {}} @@ -115,7 +115,7 @@ describe('statusCheckState', () => { }); test('failed status check - no data', () => { - const component = shallow( {}} @@ -129,7 +129,7 @@ describe('statusCheckState', () => { }); test('successful status check', () => { - const component = shallow( {}} diff --git a/src/core_plugins/kibana/public/home/components/tutorial/introduction.js b/src/core_plugins/kibana/public/home/components/tutorial/introduction.js index 1b3e06e35b2942..56bb11a5016783 100644 --- a/src/core_plugins/kibana/public/home/components/tutorial/introduction.js +++ b/src/core_plugins/kibana/public/home/components/tutorial/introduction.js @@ -31,6 +31,8 @@ import { EuiBetaBadge, } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n/react'; + export function Introduction({ description, previewUrl, title, exportedFieldsUrl, iconType, isBeta }) { let img; if (previewUrl) { @@ -55,7 +57,7 @@ export function Introduction({ description, previewUrl, title, exportedFieldsUrl target="_blank" rel="noopener noreferrer" > - View exported fields + ); diff --git a/src/core_plugins/kibana/public/home/components/tutorial/saved_objects_installer.js b/src/core_plugins/kibana/public/home/components/tutorial/saved_objects_installer.js index fd4ac6578df3d1..69aaa716f3619e 100644 --- a/src/core_plugins/kibana/public/home/components/tutorial/saved_objects_installer.js +++ b/src/core_plugins/kibana/public/home/components/tutorial/saved_objects_installer.js @@ -17,6 +17,10 @@ * under the License. */ +/* eslint-disable no-multi-str*/ + +import { injectI18n } from '@kbn/i18n/react'; + import React, { Fragment } from 'react'; import PropTypes from 'prop-types'; @@ -30,14 +34,17 @@ import { EuiCallOut, } from '@elastic/eui'; -const DEFAULT_BUTTON_LABEL = 'Load Kibana objects'; +class SavedObjectsInstallerUi extends React.Component { + DEFAULT_BUTTON_LABEL = this.props.intl.formatMessage({ + id: 'kbn.home.tutorial.savedObject.defaultButtonLabel', + defaultMessage: 'Load Kibana objects' + }); -export class SavedObjectsInstaller extends React.Component { state = { isInstalling: false, isInstalled: false, overwrite: false, - buttonLabel: DEFAULT_BUTTON_LABEL, + buttonLabel: this.DEFAULT_BUTTON_LABEL, }; componentDidMount() { @@ -63,10 +70,12 @@ export class SavedObjectsInstaller extends React.Component { this.setState({ isInstalling: false, - installStatusMsg: `Request failed, Error: ${error.message}`, + installStatusMsg: this.props.intl.formatMessage( + { id: 'kbn.home.tutorial.savedObject.requestFailedErrorMessage', defaultMessage: 'Request failed, Error: {message}' }, + { message: error.message }), isInstalled: false, overwrite: false, - buttonLabel: DEFAULT_BUTTON_LABEL + buttonLabel: this.DEFAULT_BUTTON_LABEL }); return; } @@ -85,26 +94,37 @@ export class SavedObjectsInstaller extends React.Component { if (overwriteErrors.length > 0) { this.setState({ isInstalling: false, - installStatusMsg: `${overwriteErrors.length} of ${this.props.savedObjects.length} objects already exist. ` + - `Click 'Confirm overwrite' to import and overwrite existing objects. ` + - `Any changes to the objects will be lost.`, + installStatusMsg: this.props.intl.formatMessage( + { id: 'kbn.home.tutorial.savedObject.installStatusLabel', + defaultMessage: '{overwriteErrorsLength} of {savedObjectsLength} objects already exist. \ +Click \'Confirm overwrite\' to import and overwrite existing objects. Any changes to the objects will be lost.' }, + { overwriteErrorsLength: overwriteErrors.length, savedObjectsLength: this.props.savedObjects.length }), isInstalled: false, overwrite: true, - buttonLabel: 'Confirm overwrite' + buttonLabel: this.props.intl.formatMessage({ id: 'kbn.home.tutorial.savedObject.confirmButtonLabel', + defaultMessage: 'Confirm overwrite' }) }); return; } const hasErrors = errors.length > 0; const statusMsg = hasErrors - ? `Unable to add ${errors.length} of ${this.props.savedObjects.length} kibana objects, Error: ${errors[0].error.message}` - : `${this.props.savedObjects.length} saved objects successfully added`; + ? this.props.intl.formatMessage( + { id: 'kbn.home.tutorial.savedObject.unableToAddErrorMessage', + defaultMessage: 'Unable to add {errorsLength} of {savedObjectsLength} kibana objects, Error: ${errors[0].error.message}' + }, + { errorsLength: errors.length, savedObjectsLength: this.props.savedObjects.length }) + : this.props.intl.formatMessage( + { id: 'kbn.home.tutorial.savedObject.addedLabel', + defaultMessage: '{savedObjectsLength} saved objects successfully added' + }, + { savedObjectsLength: this.props.savedObjects.length }); this.setState({ isInstalling: false, installStatusMsg: statusMsg, isInstalled: !hasErrors, overwrite: false, - buttonLabel: DEFAULT_BUTTON_LABEL, + buttonLabel: this.DEFAULT_BUTTON_LABEL, }); } @@ -125,7 +145,8 @@ export class SavedObjectsInstaller extends React.Component { renderInstallStep = () => { const installMsg = this.props.installMsg ? this.props.installMsg - : 'Imports index pattern, visualizations and pre-defined dashboards.'; + : this.props.intl.formatMessage({ id: 'kbn.home.tutorial.savedObject.installLabel', + defaultMessage: 'Imports index pattern, visualizations and pre-defined dashboards.' }); const installStep = ( @@ -155,7 +176,7 @@ export class SavedObjectsInstaller extends React.Component { ); return { - title: 'Load Kibana objects', + title: this.props.intl.formatMessage({ id: 'kbn.home.tutorial.savedObject.loadTitle', defaultMessage: 'Load Kibana objects' }), status: this.state.isInstalled ? 'complete' : 'incomplete', children: installStep, key: 'installStep' @@ -177,8 +198,10 @@ const savedObjectShape = PropTypes.shape({ attributes: PropTypes.object.isRequired, }); -SavedObjectsInstaller.propTypes = { +SavedObjectsInstallerUi.propTypes = { bulkCreate: PropTypes.func.isRequired, savedObjects: PropTypes.arrayOf(savedObjectShape).isRequired, installMsg: PropTypes.string, }; + +export const SavedObjectsInstaller = injectI18n(SavedObjectsInstallerUi); diff --git a/src/core_plugins/kibana/public/home/components/tutorial/saved_objects_installer.test.js b/src/core_plugins/kibana/public/home/components/tutorial/saved_objects_installer.test.js index 1c28831679a246..38a83424421ec7 100644 --- a/src/core_plugins/kibana/public/home/components/tutorial/saved_objects_installer.test.js +++ b/src/core_plugins/kibana/public/home/components/tutorial/saved_objects_installer.test.js @@ -18,13 +18,13 @@ */ import React from 'react'; -import { shallow, mount } from 'enzyme'; import { findTestSubject } from '@elastic/eui/lib/test'; +import { shallowWithIntl, mountWithIntl } from 'test_utils/enzyme_helpers'; import { SavedObjectsInstaller } from './saved_objects_installer'; test('renders', () => { - const component = shallow( {}} savedObjects={[]} />); @@ -43,7 +43,7 @@ describe('bulkCreate', () => { savedObjects: [savedObject] }); }; - const component = mount(); @@ -62,7 +62,7 @@ describe('bulkCreate', () => { const bulkCreateMock = () => { return Promise.reject(new Error('simulated bulkRequest error')); }; - const component = mount(); diff --git a/src/core_plugins/kibana/public/home/components/tutorial/tutorial.js b/src/core_plugins/kibana/public/home/components/tutorial/tutorial.js index f42dab9c16ff63..847265af794d81 100644 --- a/src/core_plugins/kibana/public/home/components/tutorial/tutorial.js +++ b/src/core_plugins/kibana/public/home/components/tutorial/tutorial.js @@ -36,6 +36,7 @@ import { EuiFlexItem, } from '@elastic/eui'; import * as StatusCheckStates from './status_check_states'; +import { injectI18n, FormattedMessage } from '@kbn/i18n/react'; const INSTRUCTIONS_TYPE = { ELASTIC_CLOUD: 'elasticCloud', @@ -43,7 +44,7 @@ const INSTRUCTIONS_TYPE = { ON_PREM_ELASTIC_CLOUD: 'onPremElasticCloud' }; -export class Tutorial extends React.Component { +class TutorialUi extends React.Component { constructor(props) { super(props); @@ -187,14 +188,18 @@ export class Tutorial extends React.Component { renderInstructionSetsToggle = () => { if (!this.props.isCloudEnabled && this.state.tutorial.onPremElasticCloud) { + const selfManagedLabel = this.props.intl.formatMessage({ id: 'kbn.home.tutorial.selfManagedButtonLabel', + defaultMessage: 'Self managed' }); + const cloudLabel = this.props.intl.formatMessage({ id: 'kbn.home.tutorial.elasticCloudButtonLabel', + defaultMessage: 'Elastic Cloud' }); const radioButtons = [ { id: INSTRUCTIONS_TYPE.ON_PREM, - label: 'Self managed', + label: selfManagedLabel, }, { id: INSTRUCTIONS_TYPE.ON_PREM_ELASTIC_CLOUD, - label: 'Elastic Cloud', + label: cloudLabel, } ]; return ( @@ -296,7 +301,11 @@ export class Tutorial extends React.Component {

- Unable to find tutorial {this.props.tutorialId} +

@@ -356,7 +365,7 @@ export class Tutorial extends React.Component { } } -Tutorial.propTypes = { +TutorialUi.propTypes = { addBasePath: PropTypes.func.isRequired, isCloudEnabled: PropTypes.bool.isRequired, getTutorial: PropTypes.func.isRequired, @@ -364,3 +373,5 @@ Tutorial.propTypes = { tutorialId: PropTypes.string.isRequired, bulkCreate: PropTypes.func.isRequired, }; + +export const Tutorial = injectI18n(TutorialUi); diff --git a/src/core_plugins/kibana/public/home/components/tutorial/tutorial.test.js b/src/core_plugins/kibana/public/home/components/tutorial/tutorial.test.js index 040fd671fc0279..cf6745cf9445a0 100644 --- a/src/core_plugins/kibana/public/home/components/tutorial/tutorial.test.js +++ b/src/core_plugins/kibana/public/home/components/tutorial/tutorial.test.js @@ -18,8 +18,8 @@ */ import React from 'react'; -import { shallow, mount } from 'enzyme'; import { findTestSubject } from '@elastic/eui/lib/test'; +import { shallowWithIntl, mountWithIntl } from 'test_utils/enzyme_helpers'; import { Tutorial, @@ -64,9 +64,8 @@ const replaceTemplateStrings = (text) => { }; describe('isCloudEnabled is false', () => { - test('should render ON_PREM instructions with instruction toggle', () => { - const component = shallow( { const getBasicTutorial = () => { return loadBasicTutorialPromise; }; - const component = shallow( { }); test('should display ON_PREM_ELASTIC_CLOUD instructions when toggle is clicked', () => { - const component = mount( { }); test('should render ELASTIC_CLOUD instructions when isCloudEnabled is true', () => { - const component = shallow( - Home + + +

- Add Data to Kibana +

@@ -206,7 +218,7 @@ export class TutorialDirectory extends React.Component { } } -TutorialDirectory.propTypes = { +TutorialDirectoryUi.propTypes = { addBasePath: PropTypes.func.isRequired, openTab: PropTypes.string, isCloudEnabled: PropTypes.bool.isRequired, @@ -214,3 +226,5 @@ TutorialDirectory.propTypes = { setConfig: PropTypes.func.isRequired, clearIndexPatternsCache: PropTypes.func.isRequired, }; + +export const TutorialDirectory = injectI18n(TutorialDirectoryUi); diff --git a/src/core_plugins/kibana/public/home/components/welcome.js b/src/core_plugins/kibana/public/home/components/welcome.js index 237a6de55507ef..c95a00323c367e 100644 --- a/src/core_plugins/kibana/public/home/components/welcome.js +++ b/src/core_plugins/kibana/public/home/components/welcome.js @@ -37,6 +37,8 @@ import { EuiButtonEmpty, } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n/react'; + /** * Shows a full-screen welcome page that gives helpful quick links to beginners. */ @@ -67,10 +69,14 @@ export class Welcome extends React.Component { -

Welcome to Kibana

+

+ +

-

Your window into the Elastic Stack

+

+ +

@@ -81,9 +87,13 @@ export class Welcome extends React.Component { } + description={ + } footer={ } diff --git a/src/core_plugins/kibana/public/home/load_tutorials.js b/src/core_plugins/kibana/public/home/load_tutorials.js index 8894a0e78b8b8d..d6b264154d4248 100644 --- a/src/core_plugins/kibana/public/home/load_tutorials.js +++ b/src/core_plugins/kibana/public/home/load_tutorials.js @@ -19,6 +19,7 @@ import _ from 'lodash'; import chrome from 'ui/chrome'; +import { i18n } from '@kbn/i18n'; import { toastNotifications } from 'ui/notify'; const baseUrl = chrome.addBasePath('/api/kibana/home/tutorials'); @@ -38,14 +39,18 @@ async function loadTutorials() { headers: headers, }); if (response.status >= 300) { - throw new Error(`Request failed with status code: ${response.status}`); + throw new Error(i18n.translate('kbn.home.loadTutorials.requestFailedErrorMessage', { + defaultMessage: 'Request failed with status code: {status}', values: { status: response.status } } + )); } tutorials = await response.json(); tutorialsLoaded = true; } catch(err) { toastNotifications.addDanger({ - title: 'Unable to load tutorials', + title: i18n.translate('kbn.home.loadTutorials.unableToLoadErrorMessage', { + defaultMessage: 'Unable to load tutorials' } + ), text: err.message, }); } diff --git a/src/test_utils/public/enzyme_helpers.js b/src/test_utils/public/enzyme_helpers.js index ca7618d38705fd..4bbaefe515f6f9 100644 --- a/src/test_utils/public/enzyme_helpers.js +++ b/src/test_utils/public/enzyme_helpers.js @@ -19,24 +19,57 @@ import PropTypes from 'prop-types'; import React from 'react'; -import { shallow } from 'enzyme'; +import { shallow, mount } from 'enzyme'; import { intl } from './mocks/intl'; /** - * Creates the wrapper instance with provided intl object into context + * Creates the wrapper instance using shallow with provided intl object into context * * @param node The React element or cheerio wrapper * @param options properties to pass into shallow wrapper * @return The wrapper instance around the rendered output with intl object in context */ export function shallowWithIntl(node, { context = {}, childContextTypes = {}, ...props } = {}) { + const clonedNode = cloneNode(node); + const options = getOptions(context, childContextTypes, props); + + if (React.isValidElement(node)) { + return shallow(clonedNode, options); + } + + return clonedNode.shallow(options); +} + +/** + * Creates the wrapper instance using mount with provided intl object into context + * + * @param node The React element or cheerio wrapper + * @param options properties to pass into mount wrapper + * @return The wrapper instance around the rendered output with intl object in context + */ +export function mountWithIntl(node, { context = {}, childContextTypes = {}, ...props } = {}) { + const clonedNode = cloneNode(node); + const options = getOptions(context, childContextTypes, props); + + if (React.isValidElement(node)) { + return mount(clonedNode, options); + } + + return clonedNode.mount(options); +} + +export { intl }; + +function cloneNode(node) { if (!node) { throw new Error(`First argument should be cheerio object or React element, not ${node}`); } - const clonedNode = React.cloneElement(node, { intl }); + return React.cloneElement(node, { intl }); +} - const options = { +function getOptions(context, childContextTypes, props) { + return { context: { ...context, intl, @@ -47,12 +80,4 @@ export function shallowWithIntl(node, { context = {}, childContextTypes = {}, .. }, ...props, }; - - if (React.isValidElement(node)) { - return shallow(clonedNode, options); - } - - return clonedNode.shallow(options); } - -export { intl };