diff --git a/x-pack/plugins/ml/public/components/confirm_modal/confirm_modal.html b/x-pack/plugins/ml/public/components/confirm_modal/confirm_modal.html index c4505e464dfbe..d048eded3f1be 100644 --- a/x-pack/plugins/ml/public/components/confirm_modal/confirm_modal.html +++ b/x-pack/plugins/ml/public/components/confirm_modal/confirm_modal.html @@ -6,7 +6,7 @@ ng-click="ok()" ng-disabled="(saveLock === true)" class="kuiButton kuiButton--primary" - aria-label="OK"> + aria-label="{{ ::'xpack.ml.confirmModal.okButtonAriaLabel' | i18n: {defaultMessage: 'Ok'} }}"> {{okLabel}} diff --git a/x-pack/plugins/ml/public/components/confirm_modal/confirm_modal_controller.js b/x-pack/plugins/ml/public/components/confirm_modal/confirm_modal_controller.js index 15518e89b8426..a83b94bfe83f2 100644 --- a/x-pack/plugins/ml/public/components/confirm_modal/confirm_modal_controller.js +++ b/x-pack/plugins/ml/public/components/confirm_modal/confirm_modal_controller.js @@ -9,7 +9,7 @@ import { uiModules } from 'ui/modules'; const module = uiModules.get('apps/ml'); -module.controller('MlConfirmModal', function ($scope, $modalInstance, params) { +module.controller('MlConfirmModal', function ($scope, $modalInstance, params, i18n) { $scope.okFunc = params.ok; $scope.cancelFunc = params.cancel; @@ -17,8 +17,13 @@ module.controller('MlConfirmModal', function ($scope, $modalInstance, params) { $scope.message = params.message || ''; $scope.title = params.title || ''; - $scope.okLabel = params.okLabel || 'OK'; - $scope.cancelLabel = params.cancelLabel || 'Cancel'; + $scope.okLabel = params.okLabel || i18n('xpack.ml.confirmModal.okButtonLabel', { + defaultMessage: 'OK', + }); + + $scope.cancelLabel = params.cancelLabel || i18n('xpack.ml.confirmModal.cancelButtonLabel', { + defaultMessage: 'Cancel', + }); $scope.hideCancel = params.hideCancel || false; diff --git a/x-pack/plugins/ml/public/components/field_title_bar/field_title_bar.js b/x-pack/plugins/ml/public/components/field_title_bar/field_title_bar.js index 350d005ccd3e2..99f9991f1f035 100644 --- a/x-pack/plugins/ml/public/components/field_title_bar/field_title_bar.js +++ b/x-pack/plugins/ml/public/components/field_title_bar/field_title_bar.js @@ -10,6 +10,7 @@ import React from 'react'; import { EuiText, EuiToolTip } from '@elastic/eui'; import { FieldTypeIcon } from '../field_type_icon'; +import { i18n } from '@kbn/i18n'; export function FieldTitleBar({ card }) { // don't render and fail gracefully if card prop isn't set @@ -26,7 +27,9 @@ export function FieldTitleBar({ card }) { classNames.push(card.type); } - const fieldName = card.fieldName || 'document count'; + const fieldName = card.fieldName || i18n.translate('xpack.ml.fieldTitleBar.documentCountLabel', { + defaultMessage: 'document count' + }); return ( diff --git a/x-pack/plugins/ml/public/components/field_title_bar/field_title_bar.test.js b/x-pack/plugins/ml/public/components/field_title_bar/field_title_bar.test.js index 52b38a35c7c81..c8c2a05745c3b 100644 --- a/x-pack/plugins/ml/public/components/field_title_bar/field_title_bar.test.js +++ b/x-pack/plugins/ml/public/components/field_title_bar/field_title_bar.test.js @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { mount } from 'enzyme'; +import { mountWithIntl } from 'test_utils/enzyme_helpers'; import React from 'react'; import { FieldTitleBar } from './field_title_bar'; @@ -27,7 +27,7 @@ describe('FieldTitleBar', () => { test(`card prop is an empty object`, () => { const props = { card: {} }; - const wrapper = mount(); + const wrapper = mountWithIntl(); const fieldName = wrapper.find({ className: 'field-name' }).text(); expect(fieldName).toEqual('document count'); @@ -40,7 +40,7 @@ describe('FieldTitleBar', () => { const testFieldName = 'foo'; const props = { card: { fieldName: testFieldName, isUnsupportedType: true } }; - const wrapper = mount(); + const wrapper = mountWithIntl(); const fieldName = wrapper.find({ className: 'field-name' }).text(); expect(fieldName).toEqual(testFieldName); @@ -54,7 +54,7 @@ describe('FieldTitleBar', () => { const testType = 'bar'; const props = { card: { fieldName: testFieldName, type: testType } }; - const wrapper = mount(); + const wrapper = mountWithIntl(); const fieldName = wrapper.find({ className: 'field-name' }).text(); expect(fieldName).toEqual(testFieldName); @@ -65,7 +65,7 @@ describe('FieldTitleBar', () => { test(`tooltip hovering`, () => { const props = { card: { fieldName: 'foo', type: 'bar' } }; - const wrapper = mount(); + const wrapper = mountWithIntl(); const container = wrapper.find({ className: 'field-name' }); expect(wrapper.find('EuiToolTip').children()).toHaveLength(1); diff --git a/x-pack/plugins/ml/public/components/field_title_bar/field_title_bar_directive.js b/x-pack/plugins/ml/public/components/field_title_bar/field_title_bar_directive.js index 642de0c27ab72..18f18a5949f1c 100644 --- a/x-pack/plugins/ml/public/components/field_title_bar/field_title_bar_directive.js +++ b/x-pack/plugins/ml/public/components/field_title_bar/field_title_bar_directive.js @@ -10,6 +10,7 @@ import React from 'react'; import ReactDOM from 'react-dom'; import { FieldTitleBar } from './field_title_bar'; +import { I18nProvider } from '@kbn/i18n/react'; import { uiModules } from 'ui/modules'; const module = uiModules.get('apps/ml'); @@ -32,7 +33,9 @@ module.directive('mlFieldTitleBar', function () { }; ReactDOM.render( - React.createElement(FieldTitleBar, props), + + {React.createElement(FieldTitleBar, props)} + , element[0] ); } diff --git a/x-pack/plugins/ml/public/components/field_type_icon/field_type_icon.js b/x-pack/plugins/ml/public/components/field_type_icon/field_type_icon.js index 5b1868d0598d5..4db0dd65b7d17 100644 --- a/x-pack/plugins/ml/public/components/field_type_icon/field_type_icon.js +++ b/x-pack/plugins/ml/public/components/field_type_icon/field_type_icon.js @@ -12,43 +12,68 @@ import { EuiToolTip } from '@elastic/eui'; // don't use something like plugins/ml/../common // because it won't work with the jest tests import { ML_JOB_FIELD_TYPES } from '../../../common/constants/field_types'; +import { FormattedMessage, injectI18n } from '@kbn/i18n/react'; -export function FieldTypeIcon({ tooltipEnabled = false, type }) { +export const FieldTypeIcon = injectI18n(function FieldTypeIcon({ tooltipEnabled = false, type, intl }) { let ariaLabel = ''; let iconClass = ''; let iconChar = ''; switch (type) { case ML_JOB_FIELD_TYPES.BOOLEAN: - ariaLabel = 'boolean type'; + ariaLabel = intl.formatMessage({ + id: 'xpack.ml.fieldTypeIcon.booleanTypeAriaLabel', + defaultMessage: 'boolean type' + }); iconClass = 'fa-adjust'; break; case ML_JOB_FIELD_TYPES.DATE: - ariaLabel = 'date type'; + ariaLabel = intl.formatMessage({ + id: 'xpack.ml.fieldTypeIcon.dateTypeAriaLabel', + defaultMessage: 'date type' + }); iconClass = 'fa-clock-o'; break; case ML_JOB_FIELD_TYPES.NUMBER: - ariaLabel = 'number type'; + ariaLabel = intl.formatMessage({ + id: 'xpack.ml.fieldTypeIcon.numberTypeAriaLabel', + defaultMessage: 'number type' + }); iconChar = '#'; break; case ML_JOB_FIELD_TYPES.GEO_POINT: - ariaLabel = 'geo_point type'; + ariaLabel = intl.formatMessage({ + id: 'xpack.ml.fieldTypeIcon.geoPointTypeAriaLabel', + defaultMessage: '{geoPointParam} type' + }, { geoPointParam: 'geo_point' }); iconClass = 'fa-globe'; break; case ML_JOB_FIELD_TYPES.KEYWORD: - ariaLabel = 'keyword type'; + ariaLabel = intl.formatMessage({ + id: 'xpack.ml.fieldTypeIcon.keywordTypeAriaLabel', + defaultMessage: 'keyword type' + }); iconChar = 't'; break; case ML_JOB_FIELD_TYPES.TEXT: - ariaLabel = 'text type'; + ariaLabel = intl.formatMessage({ + id: 'xpack.ml.fieldTypeIcon.textTypeAriaLabel', + defaultMessage: 'text type' + }); iconClass = 'fa-file-text-o'; break; case ML_JOB_FIELD_TYPES.IP: - ariaLabel = 'IP type'; + ariaLabel = intl.formatMessage({ + id: 'xpack.ml.fieldTypeIcon.ipTypeAriaLabel', + defaultMessage: 'IP type' + }); iconClass = 'fa-laptop'; break; case ML_JOB_FIELD_TYPES.UNKNOWN: - ariaLabel = 'Unknown type'; + ariaLabel = intl.formatMessage({ + id: 'xpack.ml.fieldTypeIcon.unknownTypeAriaLabel', + defaultMessage: 'Unknown type' + }); iconChar = '?'; break; default: @@ -73,15 +98,22 @@ export function FieldTypeIcon({ tooltipEnabled = false, type }) { // to support having another component directly inside the tooltip anchor // see https://github.com/elastic/eui/issues/839 return ( - + } + > ); } return ; -} -FieldTypeIcon.propTypes = { +}); +FieldTypeIcon.WrappedComponent.propTypes = { tooltipEnabled: PropTypes.bool, type: PropTypes.string }; diff --git a/x-pack/plugins/ml/public/components/field_type_icon/field_type_icon.test.js b/x-pack/plugins/ml/public/components/field_type_icon/field_type_icon.test.js index 975319f942739..5b32c0ab8c1bc 100644 --- a/x-pack/plugins/ml/public/components/field_type_icon/field_type_icon.test.js +++ b/x-pack/plugins/ml/public/components/field_type_icon/field_type_icon.test.js @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { mount, shallow } from 'enzyme'; +import { mountWithIntl, shallowWithIntl } from 'test_utils/enzyme_helpers'; import React from 'react'; import { FieldTypeIcon } from './field_type_icon'; @@ -13,22 +13,22 @@ import { ML_JOB_FIELD_TYPES } from '../../../common/constants/field_types'; describe('FieldTypeIcon', () => { test(`don't render component when type is undefined`, () => { - const wrapper = shallow(); + const wrapper = shallowWithIntl(); expect(wrapper.isEmptyRender()).toBeTruthy(); }); test(`don't render component when type doesn't match a field type`, () => { - const wrapper = shallow(); + const wrapper = shallowWithIntl(); expect(wrapper.isEmptyRender()).toBeTruthy(); }); test(`render component when type matches a field type`, () => { - const wrapper = shallow(); + const wrapper = shallowWithIntl(); expect(wrapper).toMatchSnapshot(); }); test(`render with tooltip and test hovering`, () => { - const wrapper = mount(); + const wrapper = mountWithIntl(); const container = wrapper.find({ className: 'field-type-icon-container' }); expect(wrapper.find('EuiToolTip').children()).toHaveLength(1); @@ -41,7 +41,7 @@ describe('FieldTypeIcon', () => { }); test(`update component`, () => { - const wrapper = shallow(); + const wrapper = shallowWithIntl(); expect(wrapper.isEmptyRender()).toBeTruthy(); wrapper.setProps({ type: ML_JOB_FIELD_TYPES.IP }); expect(wrapper).toMatchSnapshot(); diff --git a/x-pack/plugins/ml/public/components/field_type_icon/field_type_icon_directive.js b/x-pack/plugins/ml/public/components/field_type_icon/field_type_icon_directive.js index 283f610d24226..a134ebfcb6912 100644 --- a/x-pack/plugins/ml/public/components/field_type_icon/field_type_icon_directive.js +++ b/x-pack/plugins/ml/public/components/field_type_icon/field_type_icon_directive.js @@ -10,6 +10,7 @@ import React from 'react'; import ReactDOM from 'react-dom'; import { FieldTypeIcon } from './field_type_icon.js'; +import { I18nProvider } from '@kbn/i18n/react'; import { uiModules } from 'ui/modules'; const module = uiModules.get('apps/ml'); @@ -34,7 +35,9 @@ module.directive('mlFieldTypeIcon', function () { }; ReactDOM.render( - React.createElement(FieldTypeIcon, props), + + {React.createElement(FieldTypeIcon, props)} + , element[0] ); } diff --git a/x-pack/plugins/ml/public/components/form_filter_input/form_filter_input.html b/x-pack/plugins/ml/public/components/form_filter_input/form_filter_input.html index 9a246e45a03de..fd82e5b07f6cb 100644 --- a/x-pack/plugins/ml/public/components/form_filter_input/form_filter_input.html +++ b/x-pack/plugins/ml/public/components/form_filter_input/form_filter_input.html @@ -2,7 +2,7 @@ @@ -11,7 +11,10 @@ diff --git a/x-pack/plugins/ml/public/components/form_filter_input/form_filter_input_directive.js b/x-pack/plugins/ml/public/components/form_filter_input/form_filter_input_directive.js index 0cdfc9f897362..0130fb7c39890 100644 --- a/x-pack/plugins/ml/public/components/form_filter_input/form_filter_input_directive.js +++ b/x-pack/plugins/ml/public/components/form_filter_input/form_filter_input_directive.js @@ -12,7 +12,7 @@ import angular from 'angular'; import { uiModules } from 'ui/modules'; const module = uiModules.get('apps/ml'); -module.directive('mlFormFilterInput', function () { +module.directive('mlFormFilterInput', function (i18n) { return { scope: { placeholder: '@?', @@ -25,7 +25,15 @@ module.directive('mlFormFilterInput', function () { replace: false, template, link(scope) { - scope.placeholder = angular.isDefined(scope.placeholder) ? scope.placeholder : 'Filter'; + const placeholderIsDefined = angular.isDefined(scope.placeholder); + + scope.placeholder = placeholderIsDefined + ? scope.placeholder + : i18n('xpack.ml.formFilterInput.filterPlaceholder', { defaultMessage: 'Filter' }); + + scope.ariaLabel = placeholderIsDefined + ? scope.placeholder + : i18n('xpack.ml.formFilterInput.filterAriaLabel', { defaultMessage: 'Filter' }); } }; }); diff --git a/x-pack/plugins/ml/public/components/full_time_range_selector/full_time_range_selector.html b/x-pack/plugins/ml/public/components/full_time_range_selector/full_time_range_selector.html index 605ff4bf366e0..9e61a98f158d5 100644 --- a/x-pack/plugins/ml/public/components/full_time_range_selector/full_time_range_selector.html +++ b/x-pack/plugins/ml/public/components/full_time_range_selector/full_time_range_selector.html @@ -3,7 +3,10 @@ type="button" ng-disabled="disabled" class="euiButton euiButton--primary euiButton--small euiButton--fill"> - - Use full {{indexPattern.title}} data - + diff --git a/x-pack/plugins/ml/public/components/influencers_list/influencers_list.js b/x-pack/plugins/ml/public/components/influencers_list/influencers_list.js index eedac15ef0442..341c7a5df5980 100644 --- a/x-pack/plugins/ml/public/components/influencers_list/influencers_list.js +++ b/x-pack/plugins/ml/public/components/influencers_list/influencers_list.js @@ -20,6 +20,7 @@ import { EuiTitle, EuiToolTip } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n/react'; import { abbreviateWholeNumber } from 'plugins/ml/formatters/abbreviate_whole_number'; import { getSeverity } from 'plugins/ml/../common/util/anomaly_utils'; @@ -28,8 +29,20 @@ import { getSeverity } from 'plugins/ml/../common/util/anomaly_utils'; function getTooltipContent(maxScoreLabel, totalScoreLabel) { return ( -

Maximum anomaly score: {maxScoreLabel}

-

Total anomaly score: {totalScoreLabel}

+

+ +

+

+ +

); } @@ -124,7 +137,12 @@ export function InfluencersList({ influencers }) { -

No influencers found

+

+ +

diff --git a/x-pack/plugins/ml/public/components/job_group_select/job_group_select.html b/x-pack/plugins/ml/public/components/job_group_select/job_group_select.html index 430abe4ff8fe5..adf12a79b8328 100644 --- a/x-pack/plugins/ml/public/components/job_group_select/job_group_select.html +++ b/x-pack/plugins/ml/public/components/job_group_select/job_group_select.html @@ -8,19 +8,25 @@ tagging='mlGroupSelect.createNewItem' append-to-body=true > - + + > {{$item.id}} -
+
- - Other jobs in this group: {{group.count}} - +
diff --git a/x-pack/plugins/ml/public/components/job_group_select/job_group_select.js b/x-pack/plugins/ml/public/components/job_group_select/job_group_select.js index b4c77ebe94ac3..c49d9afd992ff 100644 --- a/x-pack/plugins/ml/public/components/job_group_select/job_group_select.js +++ b/x-pack/plugins/ml/public/components/job_group_select/job_group_select.js @@ -16,7 +16,7 @@ import { InitAfterBindingsWorkaround } from 'ui/compat'; import { uiModules } from 'ui/modules'; const module = uiModules.get('apps/ml'); -module.directive('mlJobGroupSelect', function () { +module.directive('mlJobGroupSelect', function (i18n) { return { restrict: 'E', template, @@ -33,6 +33,7 @@ module.directive('mlJobGroupSelect', function () { this.$scope = $scope; this.selectedGroups = []; this.groups = []; + this.$scope.newGroupLabel = i18n('xpack.ml.jobGroupSelect.newGroupLabel', { defaultMessage: '(new group)' }); // load the jobs, in case they've not been loaded before // in order to get the job groups @@ -111,7 +112,7 @@ module.directive('mlJobGroupSelect', function () { groupTypes(group) { if(group.isTag === false) { - return 'Existing groups'; + return i18n('xpack.ml.jobGroupSelect.existingGroupsLabel', { defaultMessage: 'Existing groups' }); } } } diff --git a/x-pack/plugins/ml/public/components/nav_menu/nav_menu.html b/x-pack/plugins/ml/public/components/nav_menu/nav_menu.html index 345ed3bddb97e..b0a38b8144945 100644 --- a/x-pack/plugins/ml/public/components/nav_menu/nav_menu.html +++ b/x-pack/plugins/ml/public/components/nav_menu/nav_menu.html @@ -16,23 +16,38 @@ diff --git a/x-pack/plugins/ml/public/components/nav_menu/nav_menu.js b/x-pack/plugins/ml/public/components/nav_menu/nav_menu.js index da2915450449f..09d92f3e28ca4 100644 --- a/x-pack/plugins/ml/public/components/nav_menu/nav_menu.js +++ b/x-pack/plugins/ml/public/components/nav_menu/nav_menu.js @@ -14,7 +14,7 @@ import { isFullLicense } from '../../license/check_license'; import { uiModules } from 'ui/modules'; const module = uiModules.get('apps/ml'); -module.directive('mlNavMenu', function (config) { +module.directive('mlNavMenu', function (config, i18n) { return { restrict: 'E', transclude: true, @@ -43,27 +43,81 @@ module.directive('mlNavMenu', function (config) { const isK7Design = chrome.getUiSettingsClient().get('k7design', false); if (isK7Design === false) { // Breadcrumbs + const crumbNames = { - jobs: { label: 'Job Management', url: '#/jobs' }, - new_job: { label: 'Create New Job', url: '#/jobs/new_job' }, - single_metric: { label: 'Single Metric Job', url: '' }, - multi_metric: { label: 'Multi Metric job', url: '' }, - population: { label: 'Population job', url: '' }, - advanced: { label: 'Advanced Job Configuration', url: '' }, - datavisualizer: { label: 'Data Visualizer', url: '' }, - filedatavisualizer: { label: 'File Data Visualizer (Experimental)', url: '' }, - explorer: { label: 'Anomaly Explorer', url: '#/explorer' }, - timeseriesexplorer: { label: 'Single Metric Viewer', url: '#/timeseriesexplorer' }, - settings: { label: 'Settings', url: '#/settings' }, - calendars_list: { label: 'Calendar Management', url: '#/settings/calendars_list' }, - new_calendar: { label: 'New Calendar', url: '#/settings/calendars_list/new_calendar' }, - edit_calendar: { label: 'Edit Calendar', url: '#/settings/calendars_list/edit_calendar' }, - filter_lists: { label: 'Filter Lists', url: '#/settings/filter_lists' }, - new_filter_list: { label: 'New Filter List', url: '#/settings/filter_lists/new' }, - edit_filter_list: { label: 'Edit Filter List', url: '#/settings/filter_lists/edit' }, + jobs: { + label: i18n('xpack.ml.navMenu.breadcrumbs.jobManagementLabel', { defaultMessage: 'Job Management' }), + url: '#/jobs' + }, + new_job: { + label: i18n('xpack.ml.navMenu.breadcrumbs.createNewJobLabel', { defaultMessage: 'Create New Job' }), + url: '#/jobs/new_job' + }, + single_metric: { + label: i18n('xpack.ml.navMenu.breadcrumbs.singleMetricJobLabel', { defaultMessage: 'Single Metric Job' }), + url: '' + }, + multi_metric: { + label: i18n('xpack.ml.navMenu.breadcrumbs.multiMetricJobLabel', { defaultMessage: 'Multi Metric job' }), + url: '' + }, + population: { + label: i18n('xpack.ml.navMenu.breadcrumbs.populationJobLabel', { defaultMessage: 'Population job' }), + url: '' + }, + advanced: { + label: i18n('xpack.ml.navMenu.breadcrumbs.advancedJobConfigurationLabel', { defaultMessage: 'Advanced Job Configuration' }), + url: '' + }, + datavisualizer: { + label: i18n('xpack.ml.navMenu.breadcrumbs.dataVisualizerLabel', { defaultMessage: 'Data Visualizer' }), + url: '' + }, + filedatavisualizer: { + label: i18n('xpack.ml.navMenu.breadcrumbs.fileDataVisualizerLabel', { defaultMessage: 'File Data Visualizer (Experimental)' }), + url: '' + }, + explorer: { + label: i18n('xpack.ml.navMenu.breadcrumbs.anomalyExplorerLabel', { defaultMessage: 'Anomaly Explorer' }), + url: '#/explorer' + }, + timeseriesexplorer: { + label: i18n('xpack.ml.navMenu.breadcrumbs.singleMetricViewerLabel', { defaultMessage: 'Single Metric Viewer' }), + url: '#/timeseriesexplorer' + }, + settings: { + label: i18n('xpack.ml.navMenu.breadcrumbs.settingsLabel', { defaultMessage: 'Settings' }), + url: '#/settings' + }, + calendars_list: { + label: i18n('xpack.ml.navMenu.breadcrumbs.calendarManagementLabel', { defaultMessage: 'Calendar Management' }), + url: '#/settings/calendars_list' + }, + new_calendar: { + label: i18n('xpack.ml.navMenu.breadcrumbs.newCalendarLabel', { defaultMessage: 'New Calendar' }), + url: '#/settings/calendars_list/new_calendar' + }, + edit_calendar: { + label: i18n('xpack.ml.navMenu.breadcrumbs.editCalendarLabel', { defaultMessage: 'Edit Calendar' }), + url: '#/settings/calendars_list/edit_calendar' + }, + filter_lists: { + label: i18n('xpack.ml.navMenu.breadcrumbs.filterListsLabel', { defaultMessage: 'Filter Lists' }), + url: '#/settings/filter_lists' + }, + new_filter_list: { + label: i18n('xpack.ml.navMenu.breadcrumbs.newFilterListLabel', { defaultMessage: 'New Filter List' }), + url: '#/settings/filter_lists/new' + }, + edit_filter_list: { + label: i18n('xpack.ml.navMenu.breadcrumbs.editFilterListLabel', { defaultMessage: 'Edit Filter List' }), + url: '#/settings/filter_lists/edit' + }, }; - - const breadcrumbs = [{ label: 'Machine Learning', url: '#/' }]; + const breadcrumbs = [{ + label: i18n('xpack.ml.navMenu.breadcrumbs.machineLearningLabel', { defaultMessage: 'Machine Learning' }), + url: '#/' + }]; // get crumbs from url const crumbs = uiRouter.getBreadcrumbs(); diff --git a/x-pack/plugins/ml/public/components/validate_job/__snapshots__/validate_job_view.test.js.snap b/x-pack/plugins/ml/public/components/validate_job/__snapshots__/validate_job_view.test.js.snap index e5ecbd03bf28a..f4c34cf29ade4 100644 --- a/x-pack/plugins/ml/public/components/validate_job/__snapshots__/validate_job_view.test.js.snap +++ b/x-pack/plugins/ml/public/components/validate_job/__snapshots__/validate_job_view.test.js.snap @@ -13,11 +13,25 @@ exports[`ValidateJob renders button and modal with a message 1`] = ` size="s" type="button" > - Validate Job + + } > - Job validation performs certain checks against job configurations and underlying source data and provides specific advice on how to adjust settings that are more likely to produce insightful results. +
- For more information, see - - Machine Learning Job Tips - - . + + + , + } + } + /> @@ -69,7 +97,11 @@ exports[`ValidateJob renders the button 1`] = ` size="s" type="button" > - Validate Job + `; @@ -87,32 +119,60 @@ exports[`ValidateJob renders the button and modal with a success message 1`] = ` size="s" type="button" > - Validate Job + + } > - Job validation performs certain checks against job configurations and underlying source data and provides specific advice on how to adjust settings that are more likely to produce insightful results. + - For more information, see - - Machine Learning Job Tips - - . + + + , + } + } + /> diff --git a/x-pack/plugins/ml/public/components/validate_job/validate_job_directive.js b/x-pack/plugins/ml/public/components/validate_job/validate_job_directive.js index eb9184fb9db04..e2d8ce2141799 100644 --- a/x-pack/plugins/ml/public/components/validate_job/validate_job_directive.js +++ b/x-pack/plugins/ml/public/components/validate_job/validate_job_directive.js @@ -14,10 +14,11 @@ const module = uiModules.get('apps/ml', ['react']); import { ValidateJob } from './validate_job_view'; import { mlJobService } from 'plugins/ml/services/job_service'; +import { injectI18nProvider } from '@kbn/i18n/react'; module.directive('mlValidateJob', function (reactDirective) { return reactDirective( - ValidateJob, + injectI18nProvider(ValidateJob), undefined, { restrict: 'E' }, { mlJobService } diff --git a/x-pack/plugins/ml/public/components/validate_job/validate_job_view.js b/x-pack/plugins/ml/public/components/validate_job/validate_job_view.js index adfd66bdd7722..d4ad8f946924b 100644 --- a/x-pack/plugins/ml/public/components/validate_job/validate_job_view.js +++ b/x-pack/plugins/ml/public/components/validate_job/validate_job_view.js @@ -27,6 +27,8 @@ import { EuiText } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n/react'; + import { metadata } from 'ui/metadata'; // metadata.branch corresponds to the version used in documentation links. const jobTipsUrl = `https://www.elastic.co/guide/en/kibana/${metadata.branch}/job-tips.html`; @@ -82,7 +84,14 @@ const statusToEuiIconType = (status) => { } }; -const Link = ({ url }) => (Learn more); +const Link = ({ url }) => ( + + + +); Link.propTypes = { url: PropTypes.string.isRequired }; @@ -101,6 +110,7 @@ Message.propTypes = { }) }; + const Callout = ({ message }) => ( ( size="s" fill > - Close + @@ -230,23 +243,46 @@ class ValidateJob extends Component { isDisabled={isDisabled} isLoading={this.state.ui.isLoading} > - Validate Job + {!isDisabled && this.state.ui.isModalVisible && } > {this.state.data.messages.map( (m, i) => )} - Job validation performs certain checks against job configurations and underlying source data - and provides specific advice on how to adjust settings that are more likely to produce insightful results. + - For more information, see Machine Learning Job Tips. + + + + ) + }} + /> } diff --git a/x-pack/plugins/ml/public/components/validate_job/validate_job_view.test.js b/x-pack/plugins/ml/public/components/validate_job/validate_job_view.test.js index 258e7b55eb44e..8ec8e9af3c319 100644 --- a/x-pack/plugins/ml/public/components/validate_job/validate_job_view.test.js +++ b/x-pack/plugins/ml/public/components/validate_job/validate_job_view.test.js @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { shallow } from 'enzyme'; +import { shallowWithIntl } from 'test_utils/enzyme_helpers'; import React from 'react'; import { ValidateJob } from './validate_job_view'; @@ -26,7 +26,7 @@ function prepareTest(messages) { ); - const wrapper = shallow(component); + const wrapper = shallowWithIntl(component); return { wrapper, p }; }