[i18n] Translate ML - New Job - Advanced (#27777)

* Translate new_job -> advanced

* Resolve issues from review comments

* Resolve issues from review comments
This commit is contained in:
Nox911 2019-01-03 15:37:37 +03:00 committed by GitHub
parent 5f8d53c29f
commit 80020795fd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 514 additions and 165 deletions

View file

@ -49,13 +49,34 @@
</div>
<div class="conditions-list-container" >
<div class="title"><span aria-describedby="ml_aria_description_new_action_ruleconditions">Conditions</span><i ml-info-icon="new_action_ruleconditions" /></div>
<div class="title">
<span
aria-describedby="ml_aria_description_new_action_ruleconditions"
i18n-id="xpack.ml.newJob.advanced.detectorFilterModal.conditionsTitle"
i18n-default-message="Conditions"
></span>
<i ml-info-icon="new_action_ruleconditions" />
</div>
<div class="table-title">
<div><span aria-describedby="ml_aria_description_new_action_conditiontype">Type</span><i ml-info-icon="new_action_conditiontype" /></div>
<div>
<span
aria-describedby="ml_aria_description_new_action_conditiontype"
i18n-id="xpack.ml.newJob.advanced.detectorFilterModal.conditionTypeTitle"
i18n-default-message="Type"
></span>
<i ml-info-icon="new_action_conditiontype" />
</div>
<div><span aria-describedby="ml_aria_description_new_action_fieldname">field_name</span><i ml-info-icon="new_action_fieldname" /></div>
<div><span aria-describedby="ml_aria_description_new_action_fieldvalue">field_value</span><i ml-info-icon="new_action_fieldvalue" /></div>
<div><span aria-describedby="ml_aria_description_new_action_condition">lt/gt</span><i ml-info-icon="new_action_condition" /></div>
<div><span aria-describedby="ml_aria_description_new_action_value">value</span><i ml-info-icon="new_action_value" /></div>
<div>
<span
aria-describedby="ml_aria_description_new_action_value"
i18n-id="xpack.ml.newJob.advanced.detectorFilterModal.conditionValueLabel"
i18n-default-message="value"
></span>
<i ml-info-icon="new_action_value" />
</div>
<div></div>
</div>
<div ng-repeat="cond in filter.ruleConditions track by $index" class="rule-condition">
@ -103,7 +124,7 @@
</div>
<div>
<button
aria-label="Remove Condition"
aria-label="{{ ::'xpack.ml.newJob.advanced.detectorFilterModal.removeConditionButtonAriaLabel' | i18n: {defaultMessage: 'Remove Condition'} }}"
ng-click="removeCondition($index)"
tooltip-append-to-body="true"
type="button"
@ -114,12 +135,14 @@
</div>
</div>
<button
aria-label="Add new condition"
aria-label="{{ ::'xpack.ml.newJob.advanced.detectorFilterModal.addNewConditionButtonAriaLabel' | i18n: {defaultMessage: 'Add new condition'} }}"
ng-click="addNewCondition()"
type="button"
class="kuiButton kuiButton--primary kuiButton--small add-new">
<i aria-hidden="true" class="fa fa-plus"></i> Add new condition
</button>
class="kuiButton kuiButton--primary kuiButton--small add-new"
i18n-id="xpack.ml.newJob.advanced.detectorFilterModal.addNewConditionButtonLabel"
i18n-default-message="{icon} Add new condition"
i18n-values="{ html_icon: '<i aria-hidden=\'true\' class=\'fa fa-plus\'></i>' }"
></button>
<hr class="euiHorizontalRule euiHorizontalRule--full euiHorizontalRule--marginMedium">
@ -127,14 +150,15 @@
ng-click="save()"
ng-disabled="(saveLock === true || filter.ruleConditions.length === 0)"
class="kuiButton kuiButton--primary"
aria-label="Save">
{{ (editMode? "Update" : "Add") }}
aria-label="{{ ::'xpack.ml.newJob.advanced.detectorFilterModal.saveButtonAriaLabel' | i18n: {defaultMessage: 'Save'} }}">
{{ (editMode? updateButtonLabel : addButtonLabel) }}
</button>
<button
ng-click="cancel()"
ng-disabled="(saveLock === true)"
class="kuiButton kuiButton--primary"
aria-label="Cancel">
Cancel
</button>
aria-label="{{ ::'xpack.ml.newJob.advanced.detectorFilterModal.cancelButtonAriaLabel' | i18n: {defaultMessage: 'Cancel'} }}"
i18n-id="xpack.ml.newJob.advanced.detectorFilterModal.cancelButtonLabel"
i18n-default-message="Cancel"
></button>
</div>

View file

@ -14,10 +14,12 @@ import { mlMessageBarService } from 'plugins/ml/components/messagebar/messagebar
import { uiModules } from 'ui/modules';
const module = uiModules.get('apps/ml');
module.controller('MlDetectorFilterModal', function ($scope, $modalInstance, params) {
module.controller('MlDetectorFilterModal', function ($scope, $modalInstance, params, i18n) {
const msgs = mlMessageBarService;
msgs.clear();
$scope.title = 'Add new filter';
$scope.title = i18n('xpack.ml.newJob.advanced.detectorFilterModal.addNewFilterTitle', {
defaultMessage: 'Add new filter'
});
$scope.detector = params.detector;
$scope.saveLock = false;
$scope.editMode = false;
@ -25,6 +27,13 @@ module.controller('MlDetectorFilterModal', function ($scope, $modalInstance, par
const add = params.add;
const validate = params.validate;
$scope.updateButtonLabel = i18n('xpack.ml.newJob.advanced.detectorFilterModal.updateButtonLabel', {
defaultMessage: 'Update'
});
$scope.addButtonLabel = i18n('xpack.ml.newJob.advanced.detectorFilterModal.addButtonLabel', {
defaultMessage: 'Add'
});
/*
$scope.functions = [
{id: 'count', uri: 'count.html#count'},
@ -90,7 +99,9 @@ module.controller('MlDetectorFilterModal', function ($scope, $modalInstance, par
// editing an existing filter
$scope.editMode = true;
$scope.filter = params.filter;
$scope.title = 'Edit filter';
$scope.title = i18n('xpack.ml.newJob.advanced.detectorFilterModal.editFilterTitle', {
defaultMessage: 'Edit filter'
});
index = params.index;
}

View file

@ -4,7 +4,9 @@
<div class="euiSpacer euiSpacer--m"></div>
<div class="form-group">
<ml-form-label label-id="new_job_detector_description">Description</ml-form-label>
<ml-form-label label-id="new_job_detector_description">
{{ ::'xpack.ml.newJob.advanced.detectorModal.descriptionLabel' | i18n: {defaultMessage: 'Description'} }}
</ml-form-label>
<input
aria-labelledby="ml_aria_label_new_job_detector_description"
aria-describedby="ml_aria_description_new_job_detector_description"
@ -105,14 +107,15 @@
ng-click="save()"
ng-disabled="(saveLock === true) || (detector.function === '')"
class="kuiButton kuiButton--primary"
aria-label="Save">
{{ (editMode? "Update" : "Add") }}
aria-label="{{ ::'xpack.ml.newJob.advanced.detectorModal.saveButtonAriaLabel' | i18n: {defaultMessage: 'Save'} }}">
{{ (editMode ? updateButtonLabel : addButtonLabel) }}
</button>
<button
ng-click="cancel()"
ng-disabled="(saveLock === true)"
class="kuiButton kuiButton--primary"
aria-label="Cancel">
Cancel
</button>
aria-label="{{ ::'xpack.ml.newJob.advanced.detectorModal.cancelButtonAriaLabel' | i18n: {defaultMessage: 'Cancel'} }}"
i18n-id="xpack.ml.newJob.advanced.detectorModal.cancelButtonLabel"
i18n-default-message="Cancel"
></button>
</div>

View file

@ -14,15 +14,24 @@ import { mlMessageBarService } from 'plugins/ml/components/messagebar/messagebar
import { uiModules } from 'ui/modules';
const module = uiModules.get('apps/ml');
module.controller('MlDetectorModal', function ($scope, $modalInstance, params) {
module.controller('MlDetectorModal', function ($scope, $modalInstance, params, i18n) {
const msgs = mlMessageBarService;
msgs.clear();
$scope.title = 'Add new detector';
$scope.title = i18n('xpack.ml.newJob.advanced.detectorModal.addNewDetectorTitle', {
defaultMessage: 'Add new detector'
});
$scope.detector = { 'function': '' };
$scope.saveLock = false;
$scope.editMode = false;
let index = -1;
$scope.updateButtonLabel = i18n('xpack.ml.newJob.advanced.detectorModal.updateButtonLabel', {
defaultMessage: 'Update'
});
$scope.addButtonLabel = i18n('xpack.ml.newJob.advanced.detectorModal.addButtonLabel', {
defaultMessage: 'Add'
});
$scope.functions = [
{ id: 'count', uri: 'ml-count-functions.html#ml-count' },
{ id: 'low_count', uri: 'ml-count-functions.html#ml-count' },
@ -81,7 +90,9 @@ module.controller('MlDetectorModal', function ($scope, $modalInstance, params) {
if (params.detector) {
$scope.detector = params.detector;
index = params.index;
$scope.title = 'Edit detector';
$scope.title = i18n('xpack.ml.newJob.advanced.detectorModal.editDetectorTitle', {
defaultMessage: 'Edit detector'
});
$scope.editMode = true;
}
@ -91,12 +102,17 @@ module.controller('MlDetectorModal', function ($scope, $modalInstance, params) {
$scope.functionChange = function () {
const func = _.findWhere($scope.functions, { id: $scope.detector.function });
$scope.helpLink.label = 'Help for analytical functions';
$scope.helpLink.label = i18n('xpack.ml.newJob.advanced.detectorModal.helpForAnalyticalFunctionsLabel', {
defaultMessage: 'Help for analytical functions'
});
$scope.helpLink.uri = 'ml-functions.html';
if (func) {
$scope.helpLink.uri = func.uri;
$scope.helpLink.label = `Help for ${func.id}`;
$scope.helpLink.label = i18n('xpack.ml.newJob.advanced.detectorModal.helpForAnalyticalFunctionLabel', {
defaultMessage: 'Help for {funcId}',
values: { funcId: func.id }
});
}
};

View file

@ -3,12 +3,30 @@
<div ng-repeat="detector in detectors track by $index">
<div class="detector" ng-class="{'detector-edit-mode':(editMode==='EDIT')}">
<div class="detector-fields">
<label ng-show="editMode==='EDIT'">Detector:</label>
<div aria-label="Customised description" ng-hide="editMode==='EDIT' || detector.detector_description === '' || detector.detector_description === detectorToString(detector) ">{{ detector.detector_description }}</div>
<div aria-label="Default description" style="font-style:italic;" >{{ detectorToString(detector) }}</div>
<label
ng-show="editMode==='EDIT'"
i18n-id="xpack.ml.newJob.advanced.detectorsList.detectorLabel"
i18n-default-message="Detector:"
></label>
<div
aria-label="{{ ::'xpack.ml.newJob.advanced.detectorsList.customisedDescriptionAriaLabel' | i18n: {defaultMessage: 'Customised description'} }}"
ng-hide="editMode==='EDIT' || detector.detector_description === '' || detector.detector_description === detectorToString(detector) "
>
{{ detector.detector_description }}
</div>
<div
aria-label="{{ ::'xpack.ml.newJob.advanced.detectorsList.defaultDescriptionAriaLabel' | i18n: {defaultMessage: 'Default description'} }}"
style="font-style:italic;"
>
{{ detectorToString(detector) }}
</div>
<div ng-show="editMode==='EDIT'">
<label class="kuiFormLabel">Description:</label>
<label
class="kuiFormLabel"
i18n-id="xpack.ml.newJob.advanced.detectorsList.descriptionLabel"
i18n-default-message="Description:"
></label>
<input
ng-model="detector.detector_description"
class="form-control" />
@ -19,15 +37,15 @@
<div class="button-container" ng-show="editMode==='NEW'">
<button
ng-click="editDetector($index)"
aria-label="Edit"
aria-label="{{ ::'xpack.ml.newJob.advanced.detectorsList.editButtonAriaLabel' | i18n: {defaultMessage: 'Edit'} }}"
class="kuiButton kuiButton--basic kuiButton--small"
data-toggle="tooltip"
tooltip="Edit Detector">
tooltip="{{ ::'xpack.ml.newJob.advanced.detectorsList.editButtonTooltip' | i18n: {defaultMessage: 'Edit Detector'} }}">
<i aria-hidden="true" class="fa fa-pencil"></i>
</button>
<button
aria-label="Remove Detector"
aria-label="{{ ::'xpack.ml.newJob.advanced.detectorsList.removeDetectorButtonAriaLabel' | i18n: {defaultMessage: 'Remove Detector'} }}"
ng-click="removeDetector($index)"
tooltip-append-to-body="true"
type="button"
@ -48,7 +66,11 @@
type="button"
class="kuiButton kuiButton--primary kuiButton--small">
<i aria-hidden="true" class="fa fa-plus"></i>
<span id="ml_aria_label_new_job_add_detector">Add Detector</span>
<span
id="ml_aria_label_new_job_add_detector"
i18n-id="xpack.ml.newJob.advanced.detectorsList.addDetectorButtonLabel"
i18n-default-message="Add Detector"
></span>
</button>
</div>
</div>

View file

@ -21,7 +21,7 @@ import { mlJobService } from 'plugins/ml/services/job_service';
import { uiModules } from 'ui/modules';
const module = uiModules.get('apps/ml');
module.directive('mlJobDetectorsList', function ($modal) {
module.directive('mlJobDetectorsList', function ($modal, i18n) {
return {
restrict: 'AE',
replace: true,
@ -97,7 +97,16 @@ module.directive('mlJobDetectorsList', function ($modal) {
then: function (callback) {
callback({
success: false,
message: 'exclude_frequent value must be: "all", "none", "by" or "over"'
message: i18n('xpack.ml.newJob.advanced.detectorsList.invalidExcludeFrequentParameterErrorMessage', {
defaultMessage: '{excludeFrequentParam} value must be: {allValue}, {noneValue}, {byValue} or {overValue}',
values: {
excludeFrequentParam: 'exclude_frequent',
allValue: '"all"',
noneValue: '"none"',
byValue: '"by"',
overValue: '"over"'
}
})
});
}
};
@ -114,7 +123,11 @@ module.directive('mlJobDetectorsList', function ($modal) {
.catch((resp) => {
return {
success: false,
message: (resp.message || 'Validation failed')
message: (
resp.message || i18n('xpack.ml.newJob.advanced.detectorsList.validationFailedErrorMessage', {
defaultMessage: 'Validation failed'
})
)
};
});
}

View file

@ -5,7 +5,7 @@
*/
import React from 'react';
import { mount } from 'enzyme';
import { mountWithIntl } from 'test_utils/enzyme_helpers';
import { EnableModelPlotCallout } from './enable_model_plot_callout_view.js';
const message = 'Test message';
@ -13,7 +13,7 @@ const message = 'Test message';
describe('EnableModelPlotCallout', () => {
test('Callout is rendered correctly with message', () => {
const wrapper = mount(<EnableModelPlotCallout message={message} />);
const wrapper = mountWithIntl(<EnableModelPlotCallout message={message} />);
const calloutText = wrapper.find('EuiText');
expect(calloutText.text()).toBe(message);

View file

@ -12,11 +12,14 @@ import { uiModules } from 'ui/modules';
const module = uiModules.get('apps/ml', ['react']);
import { EnableModelPlotCallout } from './enable_model_plot_callout_view.js';
import { injectI18nProvider } from '@kbn/i18n/react';
module.directive('mlEnableModelPlotCallout', function (reactDirective) {
return reactDirective(
EnableModelPlotCallout,
undefined,
{ restrict: 'E' }
injectI18nProvider(
EnableModelPlotCallout,
undefined,
{ restrict: 'E' }
)
);
});

View file

@ -14,6 +14,7 @@ import {
EuiFlexGroup,
EuiFlexItem,
} from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
export const EnableModelPlotCallout = ({ message }) => (
@ -21,7 +22,10 @@ export const EnableModelPlotCallout = ({ message }) => (
<EuiFlexGroup direction="column">
<EuiFlexItem grow={false}>
<EuiCallOut
title={'Proceed with caution!'}
title={<FormattedMessage
id="xpack.ml.newJob.advanced.enableModelPlot.proceedWithCautionTitle"
defaultMessage="Proceed with caution!"
/>}
color="warning"
iconType="help"
>

View file

@ -28,31 +28,40 @@
<div class="tab_contents">
<!-- ID -->
<div class="form-group">
<ml-form-label label-id="new_job_id" tooltip-append-to-body="true">Name</ml-form-label>
<ml-form-label label-id="new_job_id" tooltip-append-to-body="true">
{{ ::'xpack.ml.newJob.advanced.jobDetails.nameLabel' | i18n: {defaultMessage: 'Name'} }}
</ml-form-label>
<input
aria-labelledby="ml_aria_label_new_job_id"
aria-describedby="ml_aria_description_new_job_id"
ng-model="job.job_id"
required
placeholder="Job ID"
placeholder="{{ ::'xpack.ml.newJob.advanced.jobDetails.jobIdPlaceholder' | i18n: {defaultMessage: 'Job ID'} }}"
ng-change="changeJobIDCase()"
input-focus
class="form-control lowercase" />
<div ng-hide="ui.validation.tabs[0].checks.jobId.valid" class="validation-error">{{ ( ui.validation.tabs[0].checks.jobId.message || "Enter a name for the job" ) }}</div>
<div
ng-hide="ui.validation.tabs[0].checks.jobId.valid"
class="validation-error"
>{{ ( ui.validation.tabs[0].checks.jobId.message || enterJobNameLabel ) }}</div>
</div>
<!-- description -->
<div class="form-group">
<ml-form-label label-id="new_job_description">Description</ml-form-label>
<ml-form-label label-id="new_job_description">
{{ ::'xpack.ml.newJob.advanced.jobDetails.descriptionLabel' | i18n: {defaultMessage: 'Description'} }}
</ml-form-label>
<input
aria-labelledby="ml_aria_label_new_job_description"
aria-describedby="ml_aria_description_new_job_description"
ng-model="job.description"
placeholder="Job description"
placeholder="{{ ::'xpack.ml.newJob.advanced.jobDetails.jobDescriptionPlaceholder' | i18n: {defaultMessage: 'Job description'} }}"
class="form-control" />
</div>
<div class="form-group">
<ml-form-label label-id="new_job_group">Job Groups</ml-form-label>
<ml-form-label label-id="new_job_group">
{{ ::'xpack.ml.newJob.advanced.jobDetails.jobGroupsLabel' | i18n: {defaultMessage: 'Job Groups'} }}
</ml-form-label>
<ml-job-group-select
aria-labelledby="ml_aria_label_new_job_group"
aria-describedby="ml_aria_description_new_job_group"
@ -62,14 +71,23 @@
</div>
<div class="form-group">
<label class="kuiFormLabel">Custom URLs</label><i ml-info-icon="new_job_custom_urls" />
<label
class="kuiFormLabel"
i18n-id="xpack.ml.newJob.advanced.jobDetails.customUrlsLabel"
i18n-default-message="Custom URLs"
></label><i ml-info-icon="new_job_custom_urls" />
<div class="euiSpacer euiSpacer--s"></div>
<div ng-if="job.custom_settings && job.custom_settings.custom_urls">
<div ng-repeat="item in job.custom_settings.custom_urls track by $index" class="custom-url">
<div class="field-cols">
<div class="form-group">
<label class="kuiFormLabel" id="ml_aria_label_custom_url_label_{{$index}}">Label</label>
<label
class="kuiFormLabel"
id="ml_aria_label_custom_url_label_{{$index}}"
i18n-id="xpack.ml.newJob.advanced.jobDetails.labelLabel"
i18n-default-message="Label"
></label>
<input
aria-labelledby="ml_aria_label_custom_url_label_{{$index}}"
ng-model="item.url_name"
@ -80,7 +98,12 @@
<div class="field-cols">
<div class="form-group">
<label class="kuiFormLabel" id="ml_aria_label_custom_url_{{$index}}">URL</label>
<label
class="kuiFormLabel"
id="ml_aria_label_custom_url_{{$index}}"
i18n-id="xpack.ml.newJob.advanced.jobDetails.urlLabel"
i18n-default-message="URL"
></label>
<textarea
aria-labelledby="ml_aria_label_custom_url_{{$index}}"
ng-model="item.url_value"
@ -90,7 +113,7 @@
</div>
<button
aria-label="Remove Custom URL"
aria-label="{{ ::'xpack.ml.newJob.advanced.jobDetails.removeCustomUrlButtonAriaLabel' | i18n: {defaultMessage: 'Remove Custom URL'} }}"
ng-click="removeCustomUrl($index)"
tooltip-append-to-body="true"
type="button"
@ -107,7 +130,11 @@
type="button"
class="kuiButton kuiButton--primary kuiButton--small">
<i aria-hidden="true" class="fa fa-plus" />
<span id="ml_aria_label_new_job_custom_urls">Add Custom URL</span>
<span
id="ml_aria_label_new_job_custom_urls"
i18n-id="xpack.ml.newJob.advanced.jobDetails.addCustomUrlButtonLabel"
i18n-default-message="Add Custom URL"
></span>
</button>
</div>
@ -120,16 +147,22 @@
aria-describedby="ml_aria_description_new_job_dedicated_index"
class='kuiCheckBox'
ng-change="setDedicatedIndex()"
ng-model ="ui.useDedicatedIndex" />
ng-model ="ui.useDedicatedIndex" />
<span class='kuiCheckBoxLabel__text'>
<span id="ml_aria_label_new_job_dedicated_index">Use dedicated index</span>
<span
id="ml_aria_label_new_job_dedicated_index"
i18n-id="xpack.ml.newJob.advanced.jobDetails.useDedicatedIndexLabel"
i18n-default-message="Use dedicated index"
></span>
<i ml-info-icon="new_job_dedicated_index" />
</span>
</label>
</div>
<div class="form-group">
<ml-form-label label-id="new_job_model_memory_limit">Model memory limit</ml-form-label>
<ml-form-label label-id="new_job_model_memory_limit">
{{ ::'xpack.ml.newJob.advanced.jobDetails.modelMemoryLimitLabel' | i18n: {defaultMessage: 'Model memory limit'} }}
</ml-form-label>
<input
aria-labelledby="ml_aria_label_new_job_model_memory_limit"
aria-describedby="ml_aria_description_new_job_model_memory_limit"
@ -156,7 +189,7 @@
ng-change="calculateDatafeedFrequencyDefaultSeconds()"
class="form-control" />
<div ng-hide="ui.validation.tabs[1].checks.bucketSpan.valid" class="validation-error">
{{ ( ui.validation.tabs[1].checks.bucketSpan.message || "bucket_span is not a valid time interval format" ) }}
{{ ( ui.validation.tabs[1].checks.bucketSpan.message || bucketSpanNotValidFormatLabel ) }}
</div>
</div>
<div class="form-group">
@ -184,7 +217,12 @@
ng-show="(job.analysis_config.categorization_field_name !== undefined && job.analysis_config.categorization_field_name !== '') ||
(job.analysis_config.categorization_filters && job.analysis_config.categorization_filters.length)">
<label class="kuiFormLabel" aria-describedby="ml_aria_description_new_job_categorizationfilters">Categorization Filters</label>
<label
class="kuiFormLabel"
aria-describedby="ml_aria_description_new_job_categorizationfilters"
i18n-id="xpack.ml.newJob.advanced.analysisConfiguration.categorizationFiltersLabel"
i18n-default-message="Categorization Filters"
></label>
<i ml-info-icon="new_job_categorizationfilters" />
<div class="euiSpacer euiSpacer--s"></div>
<div ng-if="job.analysis_config && job.analysis_config.categorization_filters">
@ -193,7 +231,7 @@
<div class="form-group">
<input
aria-label="Categorization filter regular expression"
aria-label="{{ ::'xpack.ml.newJob.advanced.analysisConfiguration.categorizationFilterRegularExpressionAriaLabel' | i18n: {defaultMessage: 'Categorization filter regular expression'} }}"
ng-model="job.analysis_config.categorization_filters[$index]"
type="text"
class="form-control" />
@ -201,7 +239,7 @@
</div>
<button
aria-label="Remove categorization filter"
aria-label="{{ ::'xpack.ml.newJob.advanced.analysisConfiguration.removeCategorizationFilterButtonAriaLabel' | i18n: {defaultMessage: 'Remove categorization filter'} }}"
ng-click="removeCategorizationFilter($index)"
tooltip-append-to-body="true"
type="button"
@ -218,16 +256,25 @@
ng-disabled="job.analysis_config.categorization_field_name === undefined || job.analysis_config.categorization_field_name === ''"
class="kuiButton kuiButton--primary kuiButton--small">
<i aria-hidden="true" class="fa fa-plus" />
<span id="ml_aria_label_add_categorization_filter">Add Categorization Filter</span>
<span
id="ml_aria_label_add_categorization_filter"
i18n-id="xpack.ml.newJob.advanced.analysisConfiguration.addCategorizationFilterButtonLabel"
i18n-default-message="Add Categorization Filter"
></span>
</button>
</div>
</div>
<div ng-hide="ui.validation.tabs[1].checks.categorizationFilters.valid" class="validation-error">
{{ ( ui.validation.tabs[1].checks.categorizationFilters.message || "Categorization filters must all be valid regular expressions" ) }}
{{ ( ui.validation.tabs[1].checks.categorizationFilters.message || categorizationFiltersNotValidLabel ) }}
</div>
<hr class="euiHorizontalRule euiHorizontalRule--full euiHorizontalRule--marginMedium">
<label class="kuiFormLabel" aria-describedby="ml_aria_description_new_job_detectors">Detectors</label>
<label
class="kuiFormLabel"
aria-describedby="ml_aria_description_new_job_detectors"
i18n-id="xpack.ml.newJob.advanced.analysisConfiguration.detectorsLabel"
i18n-default-message="Detectors"
></label>
<i ml-info-icon="new_job_detectors" />
<div class="euiSpacer euiSpacer--s"></div>
@ -241,12 +288,17 @@
ml-on-detectors-update="onDetectorsUpdate"
></div>
<div ng-hide="ui.validation.tabs[1].checks.detectors.valid" class="validation-error">
{{ ( ui.validation.tabs[1].checks.detectors.message || "At least one detector should be configured" ) }}
{{ ( ui.validation.tabs[1].checks.detectors.message || detectorNotConfiguredLabel ) }}
</div>
<hr class="euiHorizontalRule euiHorizontalRule--full euiHorizontalRule--marginMedium">
<label class="kuiFormLabel" aria-describedby="ml_aria_description_new_job_influencers">Influencers</label>
<label
class="kuiFormLabel"
aria-describedby="ml_aria_description_new_job_influencers"
i18n-id="xpack.ml.newJob.advanced.analysisConfiguration.influencersLabel"
i18n-default-message="Influencers"
></label>
<i ml-info-icon="new_job_influencers" />
<div class="influencer-list-container">
@ -261,20 +313,22 @@
<input
type="text"
ng-model="ui.tempCustomInfluencer"
placeholder="Custom influencer"
placeholder="{{ ::'xpack.ml.newJob.advanced.analysisConfiguration.customInfluencerPlaceholder' | i18n: {defaultMessage: 'Custom influencer'} }}"
class="form-control" />
<button
aria-label="Add Custom Influencer"
aria-label="{{ ::'xpack.ml.newJob.advanced.analysisConfiguration.addCustomInfluencerButtonAriaLabel' | i18n: {defaultMessage: 'Add Custom Influencer'} }}"
ng-click="addCustomInfluencer()"
ng-disabled="ui.tempCustomInfluencer===''"
type="button"
class="kuiButton kuiButton--primary kuiButton--small">
<i aria-hidden="true" class="fa fa-plus" /> Add
</button>
class="kuiButton kuiButton--primary kuiButton--small"
i18n-id="xpack.ml.newJob.advanced.analysisConfiguration.addLabel"
i18n-default-message="{icon} Add"
i18n-values="{ html_icon: '<i aria-hidden=\'true\' class=\'fa fa-plus\' />' }"
></button>
</div>
</div>
<div ng-hide="ui.validation.tabs[1].checks.influencers.valid" class="validation-error">
{{ ( ui.validation.tabs[1].checks.influencers.message || "At least one influencer should be selected" ) }}
{{ ( ui.validation.tabs[1].checks.influencers.message || influencerNotSelectedLabel ) }}
</div>
<hr class="euiHorizontalRule euiHorizontalRule--full euiHorizontalRule--marginMedium">
@ -290,7 +344,7 @@
ng-model="ui.enableModelPlot" />
<span class='kuiCheckBoxLabel__text'>
<span id="ml_aria_label_new_job_enable_model_plot">
{{ ui.cardinalityValidator.status === ui.cardinalityValidator.STATUS.RUNNING ? 'Validating cardinality...' : 'Enable model plot' }}
{{ ui.cardinalityValidator.status === ui.cardinalityValidator.STATUS.RUNNING ? validatingCardinalityLabel : enableModelPlotLabel }}
</span>
<i ml-info-icon="new_job_enable_model_plot" />
</span>
@ -311,7 +365,9 @@
<ml-job-tab-2 ng-show="ui.currentTab === 2">
<div class="tab_contents">
<div class="form-group">
<ml-form-label label-id="new_job_data_format">Data format</ml-form-label>
<ml-form-label label-id="new_job_data_format">
{{ ::'xpack.ml.newJob.advanced.dataDescription.dataFormatLabel' | i18n: {defaultMessage: 'Data format'} }}
</ml-form-label>
<select
aria-labelledby="ml_aria_label_new_job_data_format"
aria-describedby="ml_aria_description_new_job_data_format"
@ -323,7 +379,9 @@
</div>
<ml-job-delimited-options ng-show="job.data_description.format==='delimited'">
<div class="form-group">
<ml-form-label label-id="new_job_delimiter">Delimiter</ml-form-label>
<ml-form-label label-id="new_job_delimiter">
{{ ::'xpack.ml.newJob.advanced.dataDescription.delimiterLabel' | i18n: {defaultMessage: 'Delimiter'} }}
</ml-form-label>
<select
aria-labelledby="ml_aria_label_new_job_delimiter"
aria-describedby="ml_aria_description_new_job_delimiter"
@ -339,7 +397,9 @@
class="form-control" />
</div>
<div class="form-group">
<ml-form-label label-id="new_job_quote_character">Quote character</ml-form-label>
<ml-form-label label-id="new_job_quote_character">
{{ ::'xpack.ml.newJob.advanced.dataDescription.quoteCharacterLabel' | i18n: {defaultMessage: 'Quote character'} }}
</ml-form-label>
<input
aria-labelledby="ml_aria_label_new_job_quote_character"
aria-describedby="ml_aria_description_new_job_quote_character"
@ -351,7 +411,9 @@
</ml-job-delimited-options>
<div class="form-group">
<ml-form-label label-id="new_job_time_field">Time field</ml-form-label>
<ml-form-label label-id="new_job_time_field">
{{ ::'xpack.ml.newJob.advanced.dataDescription.timeFieldLabel' | i18n: {defaultMessage: 'Time field'} }}
</ml-form-label>
<input
aria-labelledby="ml_aria_label_new_job_time_field"
aria-describedby="ml_aria_description_new_job_time_field"
@ -360,12 +422,14 @@
placeholder=""
class="form-control" />
<div ng-hide="ui.validation.tabs[2].checks.timeField.valid" class="validation-error">
{{ ( ui.validation.tabs[2].checks.timeField.message || "Time field should be specified" ) }}
{{ ( ui.validation.tabs[2].checks.timeField.message || specifyTimeFieldLabel ) }}
</div>
</div>
<div class="form-group">
<ml-form-label label-id="new_job_time_format">Time format</ml-form-label>
<ml-form-label label-id="new_job_time_format">
{{ ::'xpack.ml.newJob.advanced.dataDescription.timeFormatLabel' | i18n: {defaultMessage: 'Time format'} }}
</ml-form-label>
<input
aria-labelledby="ml_aria_label_new_job_time_format"
aria-describedby="ml_aria_description_new_job_time_format"
@ -374,9 +438,15 @@
placeholder=""
class="form-control" />
<div ng-hide="ui.validation.tabs[2].checks.timeFormat.valid" class="validation-error">
{{ ( ui.validation.tabs[2].checks.timeFormat.message || "Time format should be specified" ) }}
{{ ( ui.validation.tabs[2].checks.timeFormat.message || specifyTimeFormatLabel ) }}
</div>
<div class="time-example">{{ ((exampleTime)?"e.g. "+ exampleTime:"") }}</div>
<div
ng-if="exampleTime"
class="time-example"
i18n-id="xpack.ml.newJob.advanced.dataDescription.exampleTimeDescription"
i18n-default-message="e.g. {exampleTime}"
i18n-values="{ exampleTime }"
></div>
</div>
</div>
</ml-job-tab-2>
@ -394,18 +464,28 @@
ng-disabled="job.data_description.format!=='json'"
type="checkbox" />
<span class='kuiCheckBoxLabel__text'>
<span id="ml_aria_label_new_job_enable_datafeed_job">Datafeed job</span>
<span
id="ml_aria_label_new_job_enable_datafeed_job"
i18n-id="xpack.ml.newJob.advanced.datafeed.datafeedJobLabel"
i18n-default-message="Datafeed job"
></span>
<i ml-info-icon="new_job_enable_datafeed_job" />
</span>
</label>
<div class="euiSpacer euiSpacer--s"></div>
<div class="form-group help-pane" ng-show="job.data_description.format!=='json' && job.data_description.format!==undefined">
<small class="info">Data format must be set to 'JSON' to enable the datafeed.</small>
<small
class="info"
i18n-id="xpack.ml.newJob.advanced.datafeed.enableDatafeedDescription"
i18n-default-message="Data format must be set to 'JSON' to enable the datafeed."
></small>
</div>
<div ng-if="ui.isDatafeed">
<div class="form-group">
<ml-form-label label-id="new_job_datafeed_query" tooltip-append-to-body="true">Query</ml-form-label>
<ml-form-label label-id="new_job_datafeed_query" tooltip-append-to-body="true">
{{ ::'xpack.ml.newJob.advanced.datafeed.queryLabel' | i18n: {defaultMessage: 'Query'} }}
</ml-form-label>
<input
aria-labelledby="ml_aria_label_new_job_datafeed_query"
aria-describedby="ml_aria_description_new_job_datafeed_query"
@ -415,7 +495,9 @@
</div>
<div class="form-group" >
<ml-form-label label-id="new_job_datafeed_query_delay">Query delay</ml-form-label>
<ml-form-label label-id="new_job_datafeed_query_delay">
{{ ::'xpack.ml.newJob.advanced.datafeed.queryDelayLabel' | i18n: {defaultMessage: 'Query delay'} }}
</ml-form-label>
<input
aria-labelledby="ml_aria_label_new_job_datafeed_query_delay"
aria-describedby="ml_aria_description_new_job_datafeed_query_delay"
@ -426,7 +508,9 @@
</div>
<div class="form-group" >
<ml-form-label label-id="new_job_datafeed_frequency">Frequency</ml-form-label>
<ml-form-label label-id="new_job_datafeed_frequency">
{{ ::'xpack.ml.newJob.advanced.datafeed.frequencyLabel' | i18n: {defaultMessage: 'Frequency'} }}
</ml-form-label>
<input
aria-labelledby="ml_aria_label_new_job_datafeed_frequency"
aria-describedby="ml_aria_description_new_job_datafeed_frequency"
@ -450,7 +534,11 @@
</div>
<div class="form-group" >
<div class="form-group">
<label class="kuiFormLabel">Index</label>
<label
class="kuiFormLabel"
i18n-id="xpack.ml.newJob.advanced.datafeed.indexLabel"
i18n-default-message="Index"
></label>
<div class="input-group">
<input
ng-model="ui.datafeed.indicesText"
@ -472,12 +560,19 @@
type="button"
class="kuiButton kuiButton--primary kuiButton--small">
<i aria-hidden="true" class="fa fa-refresh"></i>
<span>Reload index</span>
<span
i18n-id="xpack.ml.newJob.advanced.datafeed.reloadIndexButtonLabel"
i18n-default-message="Reload index"
></span>
</button>
</div>
<div ng-show="ui.indexTextOk && ui.fieldsUpToDate === true" class="form-group">
<label class="kuiFormLabel">Time-field name</label>
<label
class="kuiFormLabel"
i18n-id="xpack.ml.newJob.advanced.datafeed.timeFieldNameLabel"
i18n-default-message="Time-field name"
></label>
<select
ng-model="job.data_description.time_field"
class="form-control">
@ -495,7 +590,12 @@
<!-- tab 4 Edit JSON -->
<ml-job-tab-4 ng-show="ui.currentTab === 4" class="ml_json_tab">
<div class="tab_contents">
<label class="kuiFormLabel" id="ml_aria_label_new_job_json">JSON</label>
<label
class="kuiFormLabel"
id="ml_aria_label_new_job_json"
i18n-id="xpack.ml.newJob.advanced.json.jsonLabel"
i18n-default-message="JSON"
></label>
<div
class="form-control json-textarea"
ui-ace="{
@ -510,9 +610,11 @@
<!-- tab 5 Data preview -->
<ml-job-tab-5 ng-show="ui.currentTab === 5" class="ml_data_preview_tab">
<div class="tab_contents">
<ml-form-label label-id="new_job_data_preview">Data preview</ml-form-label>
<ml-form-label label-id="new_job_data_preview">
{{ ::'xpack.ml.newJob.advanced.dataPreview.dataPreviewLabel' | i18n: {defaultMessage: 'Data preview'} }}
</ml-form-label>
<ml-loading-indicator
label="Loading data preview"
label="{{ ::'xpack.ml.newJob.advanced.dataPreview.loadingDataPreviewLabel' | i18n: {defaultMessage: 'Loading data preview'} }}"
is-loading="(ui.dataPreview === '')"
/>
<div ng-hide="(ui.dataPreview === '')">
@ -525,9 +627,12 @@
}"
ng-model="ui.dataPreview"
></div>
<div class="note">
Preview returns the content of the _source field only.
</div>
<div
class="note"
i18n-id="xpack.ml.newJob.advanced.dataPreview.previewContentReturnedDescription"
i18n-default-message="Preview returns the content of the {source} field only."
i18n-values="{ source: '_source' }"
></div>
</div>
</div>
</ml-job-tab-5>
@ -550,9 +655,12 @@
ng-click="save()"
ng-disabled="(saveLock === true)"
class="euiButton euiButton--primary euiButton--small euiButton--fill"
aria-label="Save">
aria-label="{{ ::'xpack.ml.newJob.advanced.saveButtonAriaLabel' | i18n: {defaultMessage: 'Save'} }}">
<span class="euiButton__content">
<span>Save</span>
<span
i18n-id="xpack.ml.newJob.advanced.saveButtonLabel"
i18n-default-message="Save"
></span>
</span>
</button>
</div>
@ -561,9 +669,12 @@
ng-click="cancel()"
ng-disabled="(saveLock === true)"
class="euiButton euiButton--primary euiButton--small euiButton--fill"
aria-label="Cancel">
aria-label="{{ ::'xpack.ml.newJob.advanced.cancelButtonAriaLabel' | i18n: {defaultMessage: 'Cancel'} }}">
<span class="euiButton__content">
<span>Cancel</span>
<span
i18n-id="xpack.ml.newJob.advanced.cancelButtonLabel"
i18n-default-message="Cancel"
></span>
</span>
</button>
</div>

View file

@ -81,7 +81,8 @@ module.controller('MlNewJob',
$modal,
Private,
mlDatafeedService,
mlConfirmModalService) {
mlConfirmModalService,
i18n) {
timefilter.disableTimeRangeSelector(); // remove time picker from top of page
timefilter.disableAutoRefreshSelector(); // remove time picker from top of page
@ -138,18 +139,53 @@ module.controller('MlNewJob',
$scope.elasticServerInfo = {};
$scope.jobGroupsUpdateFunction = {};
$scope.enterJobNameLabel = i18n('xpack.ml.newJob.advanced.jobDetails.enterJobNameLabel', {
defaultMessage: 'Enter a name for the job'
});
$scope.bucketSpanNotValidFormatLabel = i18n('xpack.ml.newJob.advanced.analysisConfiguration.bucketSpanNotValidFormatLabel', {
defaultMessage: '{bucketSpan} is not a valid time interval format',
values: { bucketSpan: 'bucket_span' }
});
$scope.categorizationFiltersNotValidLabel = i18n('xpack.ml.newJob.advanced.analysisConfiguration.categorizationFiltersNotValidLabel', {
defaultMessage: 'Categorization filters must all be valid regular expressions'
});
$scope.detectorNotConfiguredLabel = i18n('xpack.ml.newJob.advanced.analysisConfiguration.detectorNotConfiguredLabel', {
defaultMessage: 'At least one detector should be configured'
});
$scope.influencerNotSelectedLabel = i18n('xpack.ml.newJob.advanced.analysisConfiguration.influencerNotSelectedLabel', {
defaultMessage: 'At least one influencer should be selected'
});
$scope.validatingCardinalityLabel = i18n('xpack.ml.newJob.advanced.analysisConfiguration.validatingCardinalityLabel', {
defaultMessage: 'Validating cardinality…'
});
$scope.enableModelPlotLabel = i18n('xpack.ml.newJob.advanced.analysisConfiguration.enableModelPlotLabel', {
defaultMessage: 'Enable model plot'
});
$scope.specifyTimeFieldLabel = i18n('xpack.ml.newJob.advanced.dataDescription.specifyTimeFieldLabel', {
defaultMessage: 'Time field should be specified'
});
$scope.specifyTimeFormatLabel = i18n('xpack.ml.newJob.advanced.dataDescription.specifyTimeFormatLabel', {
defaultMessage: 'Time format should be specified'
});
$scope.ui = {
pageTitle: 'Create a new job',
pageTitle: i18n('xpack.ml.newJob.advanced.createNewJobTitle', {
defaultMessage: 'Create a new job'
}),
dataLocation: 'ES',
dataPreview: '',
currentTab: 0,
tabs: [
{ index: 0, title: 'Job Details' },
{ index: 1, title: 'Analysis Configuration' },
{ index: 2, title: 'Data Description', hidden: true },
{ index: 3, title: 'Datafeed' },
{ index: 4, title: 'Edit JSON' },
{ index: 5, title: 'Data Preview', hidden: true },
{ index: 0, title: i18n('xpack.ml.newJob.advanced.tabs.jobDetailsLabel', { defaultMessage: 'Job Details' }) },
{ index: 1, title: i18n('xpack.ml.newJob.advanced.tabs.analysisConfigurationLabel', { defaultMessage: 'Analysis Configuration' }) },
{
index: 2,
title: i18n('xpack.ml.newJob.advanced.tabs.dataDescriptionLabel', { defaultMessage: 'Data Description' }),
hidden: true
},
{ index: 3, title: i18n('xpack.ml.newJob.advanced.tabs.datafeedLabel', { defaultMessage: 'Datafeed' }) },
{ index: 4, title: i18n('xpack.ml.newJob.advanced.tabs.editJsonLabel', { defaultMessage: 'Edit JSON' }) },
{ index: 5, title: i18n('xpack.ml.newJob.advanced.tabs.dataPreviewLabel', { defaultMessage: 'Data Preview' }), hidden: true },
],
validation: {
tabs: [
@ -182,15 +218,15 @@ module.controller('MlNewJob',
customInfluencers: [],
tempCustomInfluencer: '',
inputDataFormat: [
{ value: 'delimited', title: 'Delimited' },
{ value: 'delimited', title: i18n('xpack.ml.newJob.advanced.delimitedLabel', { defaultMessage: 'Delimited' }) },
{ value: 'json', title: 'JSON' },
],
fieldDelimiterOptions: [
{ value: '\t', title: 'tab' },
{ value: ' ', title: 'space' },
{ value: '\t', title: i18n('xpack.ml.newJob.advanced.tabLabel', { defaultMessage: 'tab' }) },
{ value: ' ', title: i18n('xpack.ml.newJob.advanced.spaceLabel', { defaultMessage: 'space' }) },
{ value: ',', title: ',' },
{ value: ';', title: ';' },
{ value: 'custom', title: 'custom' }
{ value: 'custom', title: i18n('xpack.ml.newJob.advanced.customLabel', { defaultMessage: 'custom' }) }
],
selectedFieldDelimiter: ',',
customFieldDelimiter: '',
@ -236,7 +272,10 @@ module.controller('MlNewJob',
if (jobId) {
$scope.mode = MODE.EDIT;
console.log('Editing job', mlJobService.currentJob);
$scope.ui.pageTitle = 'Editing Job ' + $scope.job.job_id;
$scope.ui.pageTitle = i18n('xpack.ml.newJob.advanced.editingJobPageTitle', {
defaultMessage: 'Editing Job {jobId}',
values: { jobId: $scope.job.job_id }
});
} else {
// if the job_version is undefined, assume we have transferred to this page from
// a new job wizard.
@ -251,7 +290,10 @@ module.controller('MlNewJob',
} else {
$scope.mode = MODE.CLONE;
console.log('Cloning job', mlJobService.currentJob);
$scope.ui.pageTitle = 'Clone Job from ' + $scope.job.job_id;
$scope.ui.pageTitle = i18n('xpack.ml.newJob.advanced.cloneJobFromPageTitle', {
defaultMessage: 'Clone Job from {jobId}',
values: { jobId: $scope.job.job_id }
});
$scope.job.job_id = '';
if ($scope.job.results_index_name === 'shared') {
@ -472,7 +514,10 @@ module.controller('MlNewJob',
const tab = $scope.ui.validation.tabs[0];
tab.valid = false;
tab.checks.jobId.valid = false;
tab.checks.jobId.message = '\'' + $scope.job.job_id + '\' already exists, please choose a different name';
tab.checks.jobId.message = i18n('xpack.ml.newJob.advanced.jobAlreadyExistsLabel', {
defaultMessage: `'{jobId}' already exists, please choose a different name`,
values: { jobId: $scope.job.job_id }
});
changeTab({ index: 0 });
} else {
checkInfluencers();
@ -486,8 +531,12 @@ module.controller('MlNewJob',
} else {
// if there are no influencers set, open a confirmation
mlConfirm.open({
message: 'You have not chosen any influencers, do you want to continue?',
title: 'No Influencers'
message: i18n('xpack.ml.newJob.advanced.noInfluencersChosenConfirmModalDescription', {
defaultMessage: 'You have not chosen any influencers, do you want to continue?'
}),
title: i18n('xpack.ml.newJob.advanced.noInfluencersChosenConfirmModalTitle', {
defaultMessage: 'No Influencers'
})
})
.then(saveFunc)
.catch(() => {
@ -538,7 +587,12 @@ module.controller('MlNewJob',
// .then(() => {
// console.log('refreshed fields for index pattern .ml-anomalies-*');
// wait for mappings refresh before continuing on with the post save stuff
msgs.info('New Job \'' + result.resp.job_id + '\' added');
msgs.info(
i18n('xpack.ml.newJob.advanced.newJobAddedNotificationMessage', {
defaultMessage: `New Job '{jobId}' added`,
values: { jobId: result.resp.job_id }
})
);
// update status
$scope.ui.saveStatus.job = 2;
@ -548,8 +602,17 @@ module.controller('MlNewJob',
saveNewDatafeed($scope.job.datafeed_config, $scope.job.job_id);
})
.catch((resp) => {
msgs.error('Could not open job: ', resp);
msgs.error('Job created, creating datafeed anyway');
msgs.error(
i18n('xpack.ml.newJob.advanced.couldNotOpenJobErrorMessage', {
defaultMessage: 'Could not open job:'
}),
resp
);
msgs.error(
i18n('xpack.ml.newJob.advanced.jobCreatedAndCreatingDatafeedAnywayErrorMessage', {
defaultMessage: 'Job created, creating datafeed anyway'
})
);
saveNewDatafeed($scope.job.datafeed_config, $scope.job.job_id);
});
@ -561,7 +624,12 @@ module.controller('MlNewJob',
$scope.saveLock = false;
})
.catch((resp) => {
msgs.error('Could not create datafeed: ', resp);
msgs.error(
i18n('xpack.ml.newJob.advanced.couldNotCreateDatafeedErrorMessage', {
defaultMessage: 'Could not create datafeed:'
}),
resp
);
$scope.saveLock = false;
});
} else {
@ -576,17 +644,31 @@ module.controller('MlNewJob',
// save failed, unlock the buttons and tell the user
$scope.ui.saveStatus.job = -1;
$scope.saveLock = false;
msgs.error('Save failed: ' + result.resp.message);
msgs.error(
i18n('xpack.ml.newJob.advanced.unsuccessfulSavingResultErrorMessage', {
defaultMessage: 'Save failed: {message}',
values: { message: result.resp.message }
})
);
}
}).catch((result) => {
$scope.ui.saveStatus.job = -1;
$scope.saveLock = false;
msgs.error('Save failed: ' + result.resp.message);
msgs.error(
i18n('xpack.ml.newJob.advanced.saveFailedWithMessageErrorMessage', {
defaultMessage: 'Save failed: {message}',
values: { message: result.resp.message }
})
);
});
}
})
.catch(() => {
msgs.error('Save failed');
msgs.error(
i18n('xpack.ml.newJob.advanced.saveFailedErrorMessage', {
defaultMessage: 'Save failed'
})
);
console.log('save(): job validation failed. Jobs list could not be loaded.');
});
}
@ -598,8 +680,12 @@ module.controller('MlNewJob',
$scope.cancel = function () {
mlConfirm.open({
message: 'Are you sure you want to cancel job creation?',
title: 'Are you sure?'
message: i18n('xpack.ml.newJob.advanced.cancelJobCreationConfirmModalDescription', {
defaultMessage: 'Are you sure you want to cancel job creation?'
}),
title: i18n('xpack.ml.newJob.advanced.cancelJobCreationConfirmModalTitle', {
defaultMessage: 'Are you sure?'
})
})
.then(() => {
msgs.clear();
@ -713,22 +799,32 @@ module.controller('MlNewJob',
$scope.ui.cardinalityValidator.status = STATUS.FINISHED;
$scope.ui.cardinalityValidator.message = '';
} else {
$scope.ui.cardinalityValidator.message = `Creating model plots is resource intensive and not recommended
where the cardinality of the selected fields is greater than 100. Estimated cardinality
for this job is ${validationResult.highCardinality}.
If you enable model plot with this configuration
we recommend you select a dedicated results index on the Job Details tab.`;
$scope.ui.cardinalityValidator.message = i18n(
'xpack.ml.newJob.advanced.recommendationForUsingModelPlotWithCardinalityDescription',
{
defaultMessage: 'Creating model plots is resource intensive and not recommended' +
'where the cardinality of the selected fields is greater than 100. Estimated cardinality' +
'for this job is {highCardinality}.' +
'If you enable model plot with this configuration' +
'we recommend you select a dedicated results index on the Job Details tab.',
values: { highCardinality: validationResult.highCardinality }
}
);
$scope.ui.cardinalityValidator.status = STATUS.WARNING;
}
})
.catch((error) => {
console.log('Cardinality check error:', error);
$scope.ui.cardinalityValidator.message = `An error occurred validating the configuration
for running the job with model plot enabled.
Creating model plots can be resource intensive and not recommended where the cardinality of the selected fields is high.
You may want to select a dedicated results index on the Job Details tab.`;
$scope.ui.cardinalityValidator.message = i18n(
'xpack.ml.newJob.advanced.cardinalityNotValidErrorMessage',
{
defaultMessage: 'An error occurred validating the configuration' +
'for running the job with model plot enabled.' +
'Creating model plots can be resource intensive and not recommended where the cardinality of the selected fields is high.' +
'You may want to select a dedicated results index on the Job Details tab.'
}
);
$scope.ui.cardinalityValidator.status = STATUS.FAILED;
});
}
@ -1102,7 +1198,9 @@ module.controller('MlNewJob',
const validationResults = basicJobValidation($scope.job, $scope.fields, limits);
const valid = validationResults.valid;
const message = 'Fill in all required fields';
const message = i18n('xpack.ml.newJob.advanced.fillInAllrequiredFieldsValidationMessage', {
defaultMessage: 'Fill in all required fields'
});
const tabs = $scope.ui.validation.tabs;
// reset validations
@ -1125,34 +1223,49 @@ module.controller('MlNewJob',
tabs[0].checks.jobId.valid = false;
} else if (validationResults.contains('job_id_invalid')) {
tabs[0].checks.jobId.valid = false;
let msg = 'Job name can contain lowercase alphanumeric (a-z and 0-9), hyphens or underscores; ';
msg += 'must start and end with an alphanumeric character';
const msg = i18n('xpack.ml.newJob.advanced.validateJob.jobNameAllowedCharactersDescription', {
defaultMessage: 'Job name can contain lowercase alphanumeric (a-z and 0-9), hyphens or underscores; ' +
'must start and end with an alphanumeric character'
});
tabs[0].checks.jobId.message = msg;
}
if (validationResults.contains('job_group_id_invalid')) {
tabs[0].checks.groupIds.valid = false;
let msg = 'Job group names can contain lowercase alphanumeric (a-z and 0-9), hyphens or underscores; ';
msg += 'must start and end with an alphanumeric character';
const msg = i18n('xpack.ml.newJob.advanced.validateJob.jobGroupNamesAllowedCharactersDescription', {
defaultMessage: 'Job group names can contain lowercase alphanumeric (a-z and 0-9), hyphens or underscores; ' +
'must start and end with an alphanumeric character'
});
tabs[0].checks.groupIds.message = msg;
}
if (validationResults.contains('model_memory_limit_units_invalid')) {
tabs[0].checks.modelMemoryLimit.valid = false;
const str = `${(ALLOWED_DATA_UNITS.slice(0, ALLOWED_DATA_UNITS.length - 1).join(', '))} or ${([...ALLOWED_DATA_UNITS].pop())}`;
const msg = `Model memory limit data unit unrecognized. It must be ${str}`;
const msg = i18n('xpack.ml.newJob.advanced.validateJob.modelMemoryLimitUnrecognizedUnitsErrorMessage', {
defaultMessage: 'Model memory limit data unit unrecognized. It must be {allowedDataUnits} or {allowedDataUnit}',
values: {
allowedDataUnits: (ALLOWED_DATA_UNITS.slice(0, ALLOWED_DATA_UNITS.length - 1).join(', ')),
allowedDataUnit: ([...ALLOWED_DATA_UNITS].pop())
}
});
tabs[0].checks.modelMemoryLimit.message = msg;
}
if (validationResults.contains('model_memory_limit_invalid')) {
tabs[0].checks.modelMemoryLimit.valid = false;
const msg = `Model memory limit cannot be higher than the maximum value of ${limits.max_model_memory_limit.toUpperCase()}`;
const msg = i18n('xpack.ml.newJob.advanced.validateJob.modelMemoryLimitInvalidRangeErrorMessage', {
defaultMessage: 'Model memory limit cannot be higher than the maximum value of {maxModelMemoryLimit}',
values: { maxModelMemoryLimit: limits.max_model_memory_limit.toUpperCase() }
});
tabs[0].checks.modelMemoryLimit.message = msg;
}
// tab 1 - Analysis Configuration
if (validationResults.contains('categorization_filter_invalid')) {
tabs[1].checks.categorizationFilters.message = 'categorizationFieldName must be set to allow filters';
tabs[1].checks.categorizationFilters.message = i18n('xpack.ml.newJob.advanced.validateJob.howToAllowFiltersDescription', {
defaultMessage: '{categorizationFieldName} must be set to allow filters',
values: { categorizationFieldName: 'categorizationFieldName' }
});
tabs[1].checks.categorizationFilters.valid = false;
}
@ -1160,9 +1273,18 @@ module.controller('MlNewJob',
tabs[1].checks.detectors.valid = false;
}
if (validationResults.contains('detectors_duplicates')) {
let msg = 'Duplicate detectors were found. Detectors having the same combined configuration for';
msg += ` 'function', 'field_name', 'by_field_name', 'over_field_name' and`;
msg += ` 'partition_field_name' are not allowed within the same job.`;
const msg = i18n('xpack.ml.newJob.advanced.validateJob.duplicateDetectorsFoundErrorMessage', {
defaultMessage: 'Duplicate detectors were found. Detectors having the same combined configuration for ' +
`'{function}', '{fieldName}', '{byFieldName}', '{overFieldName}' and '{partitionFieldName}' ` +
'are not allowed within the same job.',
values: {
function: 'function',
fieldName: 'field_name',
byFieldName: 'by_field_name',
overFieldName: 'over_field_name',
partitionFieldName: 'partition_field_name'
}
});
tabs[1].checks.detectors.message = msg;
tabs[1].checks.detectors.valid = false;
}
@ -1172,11 +1294,17 @@ module.controller('MlNewJob',
}
if (validationResults.contains('bucket_span_empty')) {
tabs[1].checks.bucketSpan.message = 'bucket_span must be set';
tabs[1].checks.bucketSpan.message = i18n('xpack.ml.newJob.advanced.validateJob.bucketSpanMustBeSetErrorMessage', {
defaultMessage: '{bucketSpan} must be set',
values: { bucketSpan: 'bucket_span' }
});
tabs[1].checks.bucketSpan.valid = false;
} else if (validationResults.contains('bucket_span_invalid')) {
let msg = `${job.analysis_config.bucket_span} is not a valid time interval format e.g. 10m, 1h.`;
msg += ' It also needs to be higher than zero.';
const msg = i18n('xpack.ml.newJob.advanced.validateJob.bucketSpanInvalidTimeIntervalFormatErrorMessage', {
defaultMessage:
'{bucketSpan} is not a valid time interval format e.g. {tenMinutes}, {oneHour}. It also needs to be higher than zero.',
values: { bucketSpan: job.analysis_config.bucket_span, tenMinutes: '10m', oneHour: '1h' }
});
tabs[1].checks.bucketSpan.message = msg;
tabs[1].checks.bucketSpan.valid = false;
}
@ -1206,7 +1334,9 @@ module.controller('MlNewJob',
// it can be overridden with a custom function to do an alternative test
function validateIndex(tabs, dataFeedTest = () => (Object.keys($scope.fields).length === 0)) {
if (dataFeedTest()) {
const msg = 'Could not load fields from index';
const msg = i18n('xpack.ml.newJob.advanced.validateJob.couldNotLoadFieldsFromIndexErrorMessage', {
defaultMessage: 'Could not load fields from index'
});
tabs[3].checks.hasAccessToIndex.valid = false;
tabs[3].checks.hasAccessToIndex.message = msg;
tabs[3].valid = false;
@ -1261,7 +1391,9 @@ module.controller('MlNewJob',
$scope.ui.dataPreview = angular.toJson(resp, true);
});
} else {
$scope.ui.dataPreview = 'Datafeed does not exist';
$scope.ui.dataPreview = i18n('xpack.ml.newJob.advanced.dataPreview.datafeedDoesNotExistLabel', {
defaultMessage: 'Datafeed does not exist'
});
}
}

View file

@ -1,10 +1,18 @@
<div class="save-status-modal">
<!-- <ml-message-bar ></ml-message-bar> -->
<h3 class="euiTitle euiTitle--small">Saving new job</h3>
<div class="status-item">Saving job...
<i ng-show="pscope.ui.saveStatus.job === -1" aria-hidden="true" style="color:red;" class="fa fa-remove"></i>
<i ng-show="pscope.ui.saveStatus.job === 1" aria-hidden="true" class="fa fa-spinner fa-spin"></i>
<i ng-show="pscope.ui.saveStatus.job === 2" aria-hidden="true" style="color:green;" class="fa fa-check"></i>
<h3
class="euiTitle euiTitle--small"
i18n-id="xpack.ml.newJob.advanced.saveStatusModal.savingNewJobTitle"
i18n-default-message="Saving new job"
></h3>
<div class="status-item">
<span
i18n-id="xpack.ml.newJob.advanced.saveStatusModal.savingJobLabel"
i18n-default-message="Saving job…"
></span>
<i ng-show="pscope.ui.saveStatus.job === -1" aria-hidden="true" style="color:red;" class="fa fa-remove"></i>
<i ng-show="pscope.ui.saveStatus.job === 1" aria-hidden="true" class="fa fa-spinner fa-spin"></i>
<i ng-show="pscope.ui.saveStatus.job === 2" aria-hidden="true" style="color:green;" class="fa fa-check"></i>
</div>
<hr class="euiHorizontalRule euiHorizontalRule--full euiHorizontalRule--marginMedium">
@ -14,15 +22,17 @@
ng-disabled="pscope.saveLock"
ng-click="openDatafeed();"
class="kuiButton kuiButton--primary"
aria-label="Back">
Start datafeed
</button>
aria-label="{{ ::'xpack.ml.newJob.advanced.saveStatusModal.startDatafeedButtonAriaLabel' | i18n: {defaultMessage: 'Back'} }}"
i18n-id="xpack.ml.newJob.advanced.saveStatusModal.startDatafeedButtonLabel"
i18n-default-message="Start datafeed"
></button>
<button
ng-disabled="pscope.saveLock"
ng-disabled="pscope.saveLock"
ng-click="close();"
class="kuiButton kuiButton--primary"
aria-label="Back">
Close
</button>
aria-label="{{ ::'xpack.ml.newJob.advanced.saveStatusModal.closeButtonAriaLabel' | i18n: {defaultMessage: 'Back'} }}"
i18n-id="xpack.ml.newJob.advanced.saveStatusModal.closeButtonLabel"
i18n-default-message="Close"
></button>
</div>